<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Threading on Welcome to Christophe Nasarre's Blog</title><link>https://chrisnas.github.io/tags/threading/</link><description>Recent content in Threading on Welcome to Christophe Nasarre's Blog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 28 Sep 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://chrisnas.github.io/tags/threading/index.xml" rel="self" type="application/rss+xml"/><item><title>Monitor Finalizers, contention and threads in your application</title><link>https://chrisnas.github.io/posts/2018-09-28_monitor-finalizers-contention-threads/</link><pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate><guid>https://chrisnas.github.io/posts/2018-09-28_monitor-finalizers-contention-threads/</guid><description>This post of the series details more complicated CLR events related to finalizers and threading.</description><content:encoded><![CDATA[<p>Part 1: <a href="/posts/2018-06-19_replace-net-performance-counters/">Replace .NET performance counters by CLR event tracing</a>.</p>
<p>Part 2: <a href="/posts/2018-07-26_grab-etw-session-providers/">Grab ETW Session, Providers and Events</a>.</p>
<h2 id="introduction">Introduction</h2>
<p>In the previous post, you saw how the TraceEvent nuget helps you deciphering simple ETW events such as the one emitted when a first chance exception happens. Most situations trigger more than one event and could make their processing more complicated.</p>
<h2 id="who-said-finalizer">Who said Finalizer?</h2>
<p>In the early days of .NET, you might had to deal with native resources that you were responsible for cleaning up with the related unmanaged API or legacy COM component. It was a best practice to implement a ~finalizer method to ensure that everything was deleted the right way. These times are over for most of us now. If you don’t have an <strong>IntPtr</strong> field in your class, chances are that you don’t need a ~finalizer method.</p>
<p>The <a href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose?WT.mc_id=DT-MVP-5003325">Microsoft documentation about IDisposable/Finalizer</a> often leads people to implement both even though only <strong>IDisposable</strong> is needed (i.e. some fields of the class implement <strong>IDisposable</strong>). Having a large number of finalizers could impact memory consumption by having objects staying alive for a longer time and maybe even increase garbage collection total duration. Last but not least, some finalizers code outside of your code base could “block” on locks during their cleanup and… drastically slow down everything else.</p>
<p>Getting the name of these types with TraceEvent is a two steps process. First, a <strong>TypeBulkType</strong> event is received: it contains a list of <strong>GCBulkTypeValues</strong> which binds a <strong>TypeID</strong> integer to a string type name:</p>
<p><strong>OnTypeBulkType.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="k">void</span> <span class="n">OnTypeBulkType</span><span class="p">(</span><span class="n">GCBulkTypeTraceData</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">ProcessID</span> <span class="p">!=</span> <span class="n">_processId</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="c1">// keep track of the id/name type associations</span>
</span></span><span class="line"><span class="cl">   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">currentType</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">currentType</span> <span class="p">&lt;</span> <span class="n">data</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span> <span class="n">currentType</span><span class="p">++)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">GCBulkTypeValues</span> <span class="k">value</span> <span class="p">=</span> <span class="n">data</span><span class="p">.</span><span class="n">Values</span><span class="p">(</span><span class="n">currentType</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="n">_types</span><span class="p">[</span><span class="k">value</span><span class="p">.</span><span class="n">TypeID</span><span class="p">]</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">TypeName</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This association is needed because when a finalizer is notified via the <strong>GCFinalizeObject</strong> event, the received data only contains the type ID:</p>
<p><strong>OnGCFinalizeObject.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="k">void</span> <span class="n">OnGCFinalizeObject</span><span class="p">(</span><span class="n">FinalizeObjectTraceData</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">ProcessID</span> <span class="p">!=</span> <span class="n">_processId</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="c1">// the type id should have been associated to a name via a previous TypeBulkType event</span>
</span></span><span class="line"><span class="cl">   <span class="n">NotifyFinalize</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">TimeStamp</span><span class="p">,</span> <span class="n">data</span><span class="p">.</span><span class="n">ProcessID</span><span class="p">,</span> <span class="n">data</span><span class="p">.</span><span class="n">TypeID</span><span class="p">,</span> <span class="n">_types</span><span class="p">[</span><span class="n">data</span><span class="p">.</span><span class="n">TypeID</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Note that in the two code snippets, there is an explicit check to keep the events only from the process we are interested in: as explained in part 1, this is needed for older versions of Windows.</p>
<h2 id="thread-contention-duration">Thread contention duration</h2>
<p>With .NET CLR LocksAndThreads “Contention Rate / sec” and “Total # of Contentions” performance counters, you can monitor how many times threads have been blocked while waiting for a lock owned by another thread. However, you don’t know for how long. The two TraceEvent <strong>ContentionStart</strong> and <strong>ContentionStop</strong> events allow you to get this crucial piece of information.</p>
<p>As their names imply and <a href="https://docs.microsoft.com/en-us/dotnet/framework/performance/contention-etw-events?WT.mc_id=DT-MVP-5003325">the corresponding documentation explains</a>, these two events let you know respectively when a thread starts to wait on a lock and when the lock has been acquired. In addition to the process and thread identifiers, the <strong>ContentionTraceData</strong> event argument gives you the type of contention with its <strong>ContentionFlags</strong> property: either managed or native</p>
<p><strong>ContentionTraceData.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">sealed</span> <span class="k">class</span> <span class="nc">ContentionTraceData</span> <span class="p">:</span> <span class="n">TraceEvent</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="n">ContentionFlags</span> <span class="n">ContentionFlags</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Since contention is a per-thread waiting operation, you need to keep track of the starting time on a per-thread basis when <strong>ContentionStart</strong> happens.</p>
<p><strong>OnContentionStart.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="k">void</span> <span class="n">OnContentionStart</span><span class="p">(</span><span class="n">ContentionTraceData</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">ContentionInfo</span> <span class="n">info</span> <span class="p">=</span> <span class="n">_contentionStore</span><span class="p">.</span><span class="n">GetContentionInfo</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">ProcessID</span><span class="p">,</span> <span class="n">data</span><span class="p">.</span><span class="n">ThreadID</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="n">info</span><span class="p">.</span><span class="n">TimeStamp</span> <span class="p">=</span> <span class="n">data</span><span class="p">.</span><span class="n">TimeStamp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="n">info</span><span class="p">.</span><span class="n">ContentionStartRelativeMSec</span> <span class="p">=</span> <span class="n">data</span><span class="p">.</span><span class="n">TimeStampRelativeMSec</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <strong>ContentionStore</strong> class keeps track of the monitored processes and assign them a <strong>ContentionInfo</strong> instance where the contention details are stored.</p>
<p>Now you retrieve it back when the matching <strong>ContentionStop</strong> event occurs. The rest is just a matter of computing the time difference between the two events based on their <strong>TimeStampRelativeMSec</strong> property.</p>
<p><strong>OnContentionStop.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="k">void</span> <span class="n">OnContentionStop</span><span class="p">(</span><span class="n">ContentionTraceData</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">ContentionInfo</span> <span class="n">info</span> <span class="p">=</span> <span class="n">_contentionStore</span><span class="p">.</span><span class="n">GetContentionInfo</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">ProcessID</span><span class="p">,</span> <span class="n">data</span><span class="p">.</span><span class="n">ThreadID</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="c1">// unlucky case when we start to listen just after the ContentionStart event</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">ContentionStartRelativeMSec</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">contentionDurationMSec</span> <span class="p">=</span> <span class="n">data</span><span class="p">.</span><span class="n">TimeStampRelativeMSec</span> <span class="p">-</span> <span class="n">info</span><span class="p">.</span><span class="n">ContentionStartRelativeMSec</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">isManaged</span> <span class="p">=</span> <span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">ContentionFlags</span> <span class="p">==</span> <span class="n">ContentionFlags</span><span class="p">.</span><span class="n">Managed</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>You are now able to detect when thread contention occurs but also if the contention duration increases over time.</p>
<p><img loading="lazy" src="/posts/2018-09-28_monitor-finalizers-contention-threads/0_SEfZiyEmSjrA-UGR.png"></p>
<p>If you want to test contention, here is the kind of code you could use:</p>
<p><strong>TestContention.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">_workers</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Task</span><span class="p">[</span><span class="n">workerCount</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">workerCount</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">_workers</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="p">=</span> <span class="n">Task</span><span class="p">.</span><span class="n">Run</span><span class="p">(</span><span class="kd">async</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="k">lock</span> <span class="p">(</span><span class="n">_lock</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">Thread</span><span class="p">.</span><span class="n">Sleep</span><span class="p">(</span><span class="m">5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">         <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>A few tasks are created to acquire the same lock over and over and sleeping 5 milliseconds before releasing it.</p>
<h2 id="how-to-count-threads-or-monitor-the-threadpool-usage">How to count threads or monitor the ThreadPool usage?</h2>
<p>In <a href="/posts/2018-06-19_replace-net-performance-counters/">a previous post</a>, it was mentioned that CLR performance counters related to threads were not able to provide an accurate count of the running threads. In fact, you could use the <strong>Process/Thread Count</strong> Windows kernel performance counter to get the accurate value. If you build .NET Core applications to run on Linux, you have to find other ways such as described <a href="https://stackoverflow.com/questions/268680/how-can-i-monitor-the-thread-count-of-a-process-on-linux">on stackoverflow</a>. However, there is an easy programmatic way to get the number of running threads in an application that works both on Windows and Linux: call <strong>Process.GetProcessById(<pid>).Threads.Count</strong> with its process ID.</p>
<p>Since this is a series dedicated to ETW, you would expect to simply listen to a few events to get the thread count. Well… It is almost that simple. Each time a thread gets started, the <strong>AppDomainResourceManagement/ThreadCreated</strong> event is emitted with basically the ID of the created thread as payload. In order to receive the sibling <strong>AppDomainResourceManagement/ThreadTerminated</strong> event, you need to call <strong>AppDomain.MonitoringIsEnabled</strong> in the monitored application. The <a href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/app-domain-resource-monitoring?WT.mc_id=DT-MVP-5003325">other ways described by the documentation</a> did not work for me.</p>
<p>If you want to figure out if your applications are not hammering too much the .NET thread pool, the CLR provides <a href="https://docs.microsoft.com/en-us/dotnet/framework/performance/thread-pool-etw-events?WT.mc_id=DT-MVP-5003325">many ETW events</a> for you to listen that map to the following TraceEvent events:</p>
<p><img loading="lazy" src="/posts/2018-09-28_monitor-finalizers-contention-threads/1_l13vhZSphdzzg1RQdQW8Fg.png"></p>
<p>The <a href="https://docs.microsoft.com/en-us/dotnet/framework/performance/thread-pool-etw-events#threadpoolworkerthreadadjustmentadjustment?WT.mc_id=DT-MVP-5003325">ThreadPoolWorkerThreadAdjustementAdjustment</a> event (there is no typo in this name) provides a <strong>Reason</strong> property. If its value is 0x06, then it means <strong>Starvation</strong>: if this event frequency is ~1 per second, it could be a good indication that the <strong>ThreadPool</strong> is receiving a burst of workitems or tasks to process. In addition, the <strong>ThreadPoolWorkerThreadAdjustmentTraceData</strong> argument received by the handler also gives the count of threads via the <strong>NewWorkerThreadCount</strong> property.</p>
<p>With all these events, you should be able to monitor how the .NET <strong>ThreadPool</strong> is used in your application.</p>
<p>The next post will be entirely dedicated to garbage collection analysis.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/kookiz">Kevin Gosse</a></em></p>
]]></content:encoded></item></channel></rss>