<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Christy Henriksson</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/christy/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/christy/feed.xml</link>
    <description>Currently focused on ASP.NET WebStack performance, among other things</description>
    <lastBuildDate>Tue, 16 Apr 2019 04:54:44 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>ASP.NET Performance Counters on Windows Client + IIS Express</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/asp-net-performance-counters-on-windows-client-iis-express</link>
      <pubDate>Wed, 12 Sep 2012 15:05:22 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/09/12/asp-net-performance-counters-on-windows-client-iis-express/</guid>
      <description><![CDATA[I learned recently that ASP.NET performance counters are not available on Windows 7 or 8 (client)...]]></description>
      <content:encoded><![CDATA[<p>I learned recently that ASP.NET performance counters are not available on Windows 7 or 8 (client) when running with IIS Express (or the Dev10 default of Cassini).&#160; Fortunately, the fix is easy: run Visual Studio as Administrator.</p>  <p>If you’re using IIS Express without Visual Studio installed (for example, WebMatrix), then you’ll first need to install ASP.NET 4.5 features:</p>  <p><em>dism /online /enable-feature /featureName:NetFx4Extended-ASPNET45 /all</em></p>  <p><strong>UPDATE: </strong>The above dism command is specific to Win8.&#160; Basically, you need to make sure ASP.NET features are enabled on the machine in order for performance counters to get registered.&#160; This happens automatically when you install VS.&#160; For Win7 client, you can enable ASP.NET 3.5 features with a command like the following (note that /all isn’t available for automatically enabling parent features):</p>  <p><em>dism /online /enable-feature /featurename:IIS-WebServerRole /featurename:WAS-WindowsActivationService /featurename:WAS-ProcessModel /featurename:WAS-NetFxEnvironment /featurename:WAS-ConfigurationAPI /featurename:IIS-ApplicationDevelopment /featurename:IIS-ASPNET /featurename:IIS-DefaultDocument /featurename:IIS-NetFxExtensibility /featurename:IIS-ISAPIExtensions /featurename:IIS-ISAPIFilter /featurename:IIS-RequestFiltering /featurename:IIS-Metabase /featurename:IIS-WMICompatibility /featurename:IIS-LegacyScripts /featurename:IIS-IIS6ManagementCompatibility /featurename:IIS-WebServerManagementTools /featurename:IIS-HttpTracing</em></p>]]></content:encoded>
    </item>
    <item>
      <title>Receive-Side Scaling: Maximizing Web Server CPU</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/receive-side-scaling-maximizing-web-server-cpu</link>
      <pubDate>Mon, 26 Mar 2012 13:57:00 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/03/26/receive-side-scaling-maximizing-web-server-cpu/</guid>
      <description><![CDATA[UPDATE 1/7/2013: I recently re-ran the scenario on the original hardware and could not reproduce the...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #ff0000;">UPDATE 1/7/2013: <span style="color: #ff0000;">I recently re-ran the scenario on the original hardware and could not reproduce the RSS issue below.&nbsp; I found that by setting 'Number of RSS Queues' to 4 for each of the Broadcom NICs, I could get an even distribution of load across all 16 server cores.&nbsp; There was likely an RSS configuration issue, but I can't confirm what that was.</span></span>&nbsp;</p>
<p>Re-running on the original hardware after setting 'Number of RSS Queues' to 4 for each NIC:</p>
<ul>
<li>4 Intel Xeon Quad-Core processors (16 cores total)</li>
<li>4 Broadcom BCM5708C NetXtreme II GigE NICs</li>
</ul>
<p><span style="color: #ff0000;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/1440.ASP_RSS-2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72/1440.ASP_5F00_RSS_2D00_2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/1440.ASP_RSS-2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72/1440.ASP_5F00_RSS_2D00_2.png" alt="" border="0" /></a></span>&nbsp;</p>
<hr style="width: 1px;" width="1" />
<p>&nbsp;</p>
<p><strong>ORIGINAL POST:</strong></p>
<p>In the <a href="https://blogs.msdn.com/b/web_performance_blog/archive/2012/03/14/load-balancing-your-web-server.aspx">previous post</a>, I stated that when adding multiple NICs to a web server you should ensure that the network load is balanced across those NICs.&nbsp; In order to maximize CPU on your multi-processor server you will still need to ensure that those NICs support <a href="https://technet.microsoft.com/en-us/network/dd277646">Receive Side Scaling (RSS)</a>, a technology that distributes network processing across multiple CPUs.&nbsp; In this post I will demonstrate how to verify that RSS is working.</p>
<p>Recall our webserver specs:</p>
<ul>
<li>4 Intel Xeon Quad-Core processors (16 cores total)</li>
<li>4 Broadcom BCM5708C NetXtreme II GigE NICs</li>
</ul>
<p>After load-balancing our server and clients, we now have the following <a href="https://www.iis.net/community/default.aspx?tabid=34&amp;g=6&amp;i=1467">wcat</a> node configuration:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/3542.ASP_LoadBalancing_0D5283E8.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/3542.ASP_5F00_LoadBalancing_5F00_0D5283E8.png"><img style="border: 0px currentcolor; float: left; display: inline; background-image: none;" title="ASP_LoadBalancing" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/1488.ASP_LoadBalancing_thumb_34209A28.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/1488.ASP_5F00_LoadBalancing_5F00_thumb_5F00_34209A28.png" alt="ASP_LoadBalancing" width="225" height="101" align="left" border="0" />&nbsp;</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>After collecting data on the server NICs, enabling processor counters for all processors and running my wcat scenario, I was able to see what happened to incoming network traffic.&nbsp; In the the table below, notice that only 8 of the 16 CPUs processed the Deferred Procedure Calls (DPCs).&nbsp; Meanwhile, the other 8 CPUs spent more time Idle.&nbsp; Something in my server configuration was preventing RSS from utilizing all 16 cores.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/5773.ASP_RSS_41F2E023.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/5773.ASP_5F00_RSS_5F00_41F2E023.png"><img style="border: 0px currentcolor; display: inline; background-image: none;" title="ASP_RSS" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/7652.ASP_RSS_thumb_3AD3A3AB.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/7652.ASP_5F00_RSS_5F00_thumb_5F00_3AD3A3AB.png" alt="ASP_RSS" width="571" height="285" border="0" /></a></p>
<p>To compare, we borrowed some hardware from the IIS performance lab which had previously gone through this RSS exercise.</p>
<p>The new webserver has a total of 20 processors and 10 NICs:</p>
<ul>
<li>20 Intel Xeon CPU E7 &ndash; 4860 processors</li>
<li>6 Intel Gigabit ET Dual Port Server Adapter NICs</li>
<li>4 Intel 82576NS Gigabit Ethernet Controller NICS</li>
</ul>
<p>The following is the new load-balanced wcat node configuration:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/1300.IIS_LoadBalancing_737E4DB8.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/1300.IIS_5F00_LoadBalancing_5F00_737E4DB8.png"><img style="border: 0px currentcolor; display: inline; background-image: none;" title="IIS_LoadBalancing" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/3036.IIS_LoadBalancing_thumb_6C5F1140.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/3036.IIS_5F00_LoadBalancing_5F00_thumb_5F00_6C5F1140.png" alt="IIS_LoadBalancing" width="233" height="228" border="0" /></a></p>
<p>And the following was the compilation of NIC and counter data for a wcat run.&nbsp; RSS was configured properly on this node &ndash; notice how the DPC processing was evenly distributed across all processors (taking into account that RSS CPUs 8-9 and e-f had increased load).</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/3058.IIS_RSS_132D2781.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/3058.IIS_5F00_RSS_5F00_132D2781.png"><img style="border: 0px currentcolor; display: inline; background-image: none;" title="IIS_RSS" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/0410.IIS_RSS_thumb_0C0DEB09.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/0410.IIS_5F00_RSS_5F00_thumb_5F00_0C0DEB09.png" alt="IIS_RSS" width="574" height="349" border="0" /></a></p>
<p>To compile this data, I did the following:</p>
<ol>
<li>Noted which client(s) pointed to which IP(s), based on my load balancing</li>
<li>Found the # of requests sent in the per-client statistics section of the wcat log</li>
<li>Used <a href="https://technet.microsoft.com/en-us/library/bb490921.aspx">IPConfig</a> to find the physical address for each NIC</li>
<li>Used NICStats.exe (available from the <a href="https://www.microsoft.com/download/en/details.aspx?id=11800">Windows Driver Kit</a>) to map the NIC physical addresses to the RSS CPUs*</li>
<li>Collected Processor performance counters for all CPU instances:</li>
<ul>
<li>Processor(N)\% Processor Time</li>
<li>Processor(N)\% Idle Time</li>
<li>Processor(N)\% Interrupt Time</li>
<li>Processor(N)\% DPC Time</li>
</ul>
</ol>
<p><strong>Conclusion:</strong></p>
<p>When running a web server with multiple NICs, be sure to verify that RSS is working properly.&nbsp; If you have questions, check with the NIC vendor and do your own testing once the NICs are installed.</p>]]></content:encoded>
    </item>
    <item>
      <title>Debugging W3WP Startup</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/debugging-w3wp-startup</link>
      <pubDate>Mon, 19 Mar 2012 16:45:00 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/03/19/debugging-w3wp-startup/</guid>
      <description><![CDATA[On a few occasions, I have needed to debug the startup of the IIS worker process (w3wp).&#160; I...]]></description>
      <content:encoded><![CDATA[<p>On a few occasions, I have needed to debug the startup of the IIS worker process (w3wp).&#160; I finally decided to create a script so that I no longer need to search for <a href="https://blogs.technet.com/b/marcelofartura/archive/2007/08/09/how-to-attach-a-debugger-from-the-creation-time-of-the-worker-process-w3wp-exe.aspx">the answer</a>.&#160; The script starts w3wp by requesting a non-existent ASPX page.&#160; After windbg is closed, the script will kill the debug session and clean up the registry.</p>  <p><strong>Script requirements:</strong></p>  <ul>   <li><a href="https://msdn.microsoft.com/en-us/windows/hardware/gg463009">Debugging Tools for Windows</a></li>    <li>TinyGet, from the <a href="https://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=17275">IIS Resource Kit Tools</a></li>    <li>PsKill from <a href="https://technet.microsoft.com/en-us/sysinternals/bb896649">PsTools</a></li> </ul>  <p><strong>Debug Script:</strong></p>  <p><font face="Courier New">reg add &quot;HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe&quot; /v Debugger /t REG_SZ /d &quot;cdb.exe -c \&quot;.server tcp:port=9999\&quot;&quot; /f     <br />iisreset /restart      <br />start /b tinyget5 -srv:localhost -uri:/notfound.aspx -status:404      <br />sleep 3      <br />windbg -remote tcp:port=9999,server=localhost      <br />pskill cdb      <br />pskill w3wp      <br />reg delete &quot;HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe&quot; /f</font></p>]]></content:encoded>
    </item>
    <item>
      <title>Load Balancing Your Web Server</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/load-balancing-your-web-server</link>
      <pubDate>Wed, 14 Mar 2012 14:13:07 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/03/14/load-balancing-your-web-server/</guid>
      <description><![CDATA[A recent regression in the ASP.NET performance lab prompted us to make a change to our...]]></description>
      <content:encoded><![CDATA[<p>A recent regression in the ASP.NET performance lab prompted us to make a change to our infrastructure. Our <a href="https://blogs.msdn.com/b/web_performance_blog/archive/2012/02/06/asp-net-performance-lab-hello-world.aspx">“Hello, World”</a> scenario showed a 23% regression in throughput and 5% decrease in %CPU.&#160; I won’t go into the source change which triggered the regression, but I will demonstrate how tuning our web server performance made big impacts on throughput.&#160; The change: balancing and increasing the load on the web server.</p>  <p>For reference, the web server has the following specs:</p>  <ul>   <li>4 Intel Xeon Quad-Core processors (16 cores total)</li>    <li>4 Broadcom BCM5708C NetXtreme II GigE NICs</li> </ul>  <p>Each NIC on the web server has a separate IP address:</p>  <blockquote>   <pre class="csharpcode"><font color="#666666">&gt; nslookup webserver

Server:  dnsserver
Address:  192.168.0.1

Name:    webserver</font></pre>

  <pre class="csharpcode"><font color="#666666">Addresses:  192.168.0.2
          192.168.0.3
          192.168.0.4
          192.168.0.5</font></pre>
</blockquote>

<p>If you remember from my <a href="https://blogs.msdn.com/b/web_performance_blog/archive/2012/02/06/asp-net-performance-lab-hello-world.aspx">“Hello, World”</a> post, we use <a href="https://www.iis.net/community/default.aspx?tabid=34&amp;g=6&amp;i=1467">wcat</a> to apply load from 3 remote, physical clients. Each client uses the web server’s hostname when issuing requests, which should ideally use a round robin rotation across the web server IPs.</p>

<p>Before I proceed, let me describe what happens to incoming network traffic as I understand it:</p>

<ul>
  <li>tcpip.sys issues network interrupt when it receives data</li>

  <li>OS dispatches an ISR (interrupt service routine) to handle the interrupt</li>

  <li>tcpip.sys can’t issue another interrupt while the ISR is running</li>

  <li>ISR schedules a lower priority DPC (deferred procedure call) to handle the rest of the work</li>

  <li>ISR quickly returns so that tcpip.sys can issue more interrupts</li>
</ul>

<p>If the NICs are getting equal load and <a href="https://technet.microsoft.com/en-us/network/dd277646">RSS</a> (receive-side scaling) is enabled on the web server, then the network interrupts and their corresponding DPCs should be distributed across the multiple cores.&#160; We collected ETW profiles and found that while our interrupts were handled by all cores, DPCs were only handled by 8 of the 16 cores with cpu0 doing most of the work:</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/4428.LoadBalancing_XPerf_DPCs-2_1B81994E.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/4428.LoadBalancing_5F00_XPerf_5F00_DPCs_2D00_2_5F00_1B81994E.png"><img style="display: inline; background-image: none;" title="LoadBalancing_XPerf_DPCs-2" border="0" alt="LoadBalancing_XPerf_DPCs-2" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/35/72/metablogapi/6177.LoadBalancing_XPerf_DPCs-2_thumb_414799E4.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-35-72-metablogapi/6177.LoadBalancing_5F00_XPerf_5F00_DPCs_2D00_2_5F00_thumb_5F00_414799E4.png" width="417" height="528" /></a></p>

<p>This led us to wonder if the NICs really were getting equal load from a round robin DNS lookup.&#160; The quickest and easiest way to ensure a balanced load was to manually edit the client etc\hosts files and force each client to use a separate NIC.&#160; Since there were 4 NICs we needed a 4th client, which also means an increase in load.</p>

<p>The following results are for Server R2 with .NET 4. Baseline is not load balanced, Result is.</p>

<table border="1" cellspacing="0" cellpadding="0" width="585"><tbody><font size="1"></font>

    <tr><font size="1"></font>

      <td width="129" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Test Name</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="89" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Metric</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="57" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Unit</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="59" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Baseline</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="57" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Result</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="48" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Diff</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="43" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Status</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="52" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Baseline StdDev %</strong></font></p>
      </td>
      <font size="1"></font>

      <td width="49" align="center"><font size="1"></font>

        <p><font color="#333333" size="1"><strong>Result StdDev %</strong></font></p>
      </td>
    </tr>
    <font size="1"></font>

    <tr><font size="1"></font>

      <td width="128" align="center"><font size="1"></font>

        <p><font size="1">Helloworld.Helloworld</font></p>
      </td>
      <font size="1"></font>

      <td width="89" align="center"><font size="1"></font>

        <p><font size="1">Processor Time</font></p>
      </td>
      <font size="1"></font>

      <td width="56" align="center"><font size="1"></font>

        <p><font size="1">%</font></p>
      </td>
      <font size="1"></font>

      <td width="59" align="center"><font size="1"></font>

        <p><font size="1">95.60</font></p>
      </td>
      <font size="1"></font>

      <td width="57" align="center"><font size="1"></font>

        <p><font size="1">99.16</font></p>
      </td>
      <font size="1"></font>

      <td width="48" align="center"><font size="1"></font>

        <p><font color="#008000" size="1">3.73%</font></p>
      </td>
      <font size="1"></font>

      <td width="43" align="center"><font size="1"></font>

        <p><font size="1">Pass</font></p>
      </td>
      <font size="1"></font>

      <td width="53" align="center"><font size="1"></font>

        <p><font size="1">0.68</font></p>
      </td>
      <font size="1"></font>

      <td width="49" align="center"><font size="1"></font>

        <p><font size="1">0.27</font></p>
      </td>
    </tr>
    <font size="1"></font>

    <tr><font size="1"></font>

      <td width="128" align="center"><font size="1"></font>

        <p><font size="1">Helloworld.Helloworld</font></p>
      </td>
      <font size="1"></font>

      <td width="89" align="center"><font size="1"></font>

        <p><font size="1">Throughput</font></p>
      </td>
      <font size="1"></font>

      <td width="57" align="center"><font size="1"></font>

        <p><font size="1">req/sec</font></p>
      </td>
      <font size="1"></font>

      <td width="59" align="center"><font size="1"></font>

        <p><font size="1">28403.67</font></p>
      </td>
      <font size="1"></font>

      <td width="57" align="center"><font size="1"></font>

        <p><font size="1">32125.67</font></p>
      </td>
      <font size="1"></font>

      <td width="48" align="center"><font size="1"></font>

        <p><font color="#008000" size="1">13.10%</font></p>
      </td>
      <font size="1"></font>

      <td width="44" align="center"><font size="1"></font>

        <p><font size="1">Pass</font></p>
      </td>
      <font size="1"></font>

      <td width="53" align="center"><font size="1"></font>

        <p><font size="1">0.85</font></p>
      </td>
      <font size="1"></font>

      <td width="49" align="center"><font size="1"></font>

        <p><font size="1">0.57</font></p>
      </td>
    </tr>
  </tbody></table>

<p>&#160;</p>

<p>Notice the improvements in %CPU and throughput?&#160; Using Result as our new load-balanced baseline, we re-ran HelloWorld on the same build where we saw the original regression.&#160; After maxing our CPU and increasing our load, throughput is now less than 5% off from the baseline.</p>

<p><strong>Conclusion:</strong> When adding multiple NICs, carefully <a href="https://msdn.microsoft.com/en-us/windows/hardware/gg463392">tune your web server</a> and infrastructure in order to maximize its performance.&#160; Profile to verify that your server is behaving as expected.&#160; I recognize that it is not this easy to load balance production servers, but there should be tools available to help you do this.&#160; I don’t work on production servers, so don’t ask me which tools – but I would love to hear about them from you!</p>

<p><strong>Update:</strong> To collect the ETW profiles above, I enabled INTERRUPT and DPC on the xperf command-line:</p>

<p><em>xperf –on PROC_THREAD+LOADER+INTERRUPT+DPC –f &lt;etwFile&gt;</em></p>]]></content:encoded>
    </item>
    <item>
      <title>A Look Inside the IE Performance Lab</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/a-look-inside-the-ie-performance-lab</link>
      <pubDate>Fri, 17 Feb 2012 14:22:04 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/02/17/a-look-inside-the-ie-performance-lab/</guid>
      <description><![CDATA[The Windows 8 blog details the Internet Explorer Performance Lab.&#160; It’s always fun to see how...]]></description>
      <content:encoded><![CDATA[<p>The Windows 8 blog details the <a title="https://blogs.msdn.com/b/b8/archive/2012/02/16/internet-explorer-performance-lab-reliably-measuring-browser-performance.aspx" href="https://blogs.msdn.com/b/b8/archive/2012/02/16/internet-explorer-performance-lab-reliably-measuring-browser-performance.aspx">Internet Explorer Performance Lab</a>.&#160; It’s always fun to see how other performance teams operate.</p>]]></content:encoded>
    </item>
    <item>
      <title>Performance Counter Collection</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/performance-counter-collection</link>
      <pubDate>Mon, 13 Feb 2012 21:55:10 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/02/13/performance-counter-collection/</guid>
      <description><![CDATA[As mentioned in my “Hello, World” post, performance counters are a great diagnostic tool for...]]></description>
      <content:encoded><![CDATA[<p>As mentioned in my <a href="https://blogs.msdn.com/b/web_performance_blog/archive/2012/02/06/asp-net-performance-lab-hello-world.aspx">“Hello, World” post</a>, performance counters are a great diagnostic tool for starting performance investigations. Logging performance counters during your runs does not add much overhead, unlike profilers. Still, this is not a replacement for profilers which are necessary for in-depth investigations. The following are some tools you can use to collect performance counters.</p>  <p><strong></strong></p>  <p><strong>Performance Monitor</strong></p>  <p>Windows ships with the <a href="https://technet.microsoft.com/en-us/library/cc749249.aspx">Performance Monitor</a> tool, or PerfMon for short. This GUI allows you to view live performance counter data on either the local machine or on remote systems. Simply run `perfmon` and navigate to Performance-&gt;Monitoring Tools-&gt;Performance Monitor. Right click to add or remove counters. Press ‘Ctrl+G’ to switch the graph type.&#160; Report View is handy when monitoring multiple counters.</p>  <p><strong>Perfecto and LogMan</strong></p>  <p><a href="https://blogs.msdn.com/b/josere/archive/2010/04/09/taking-a-quick-peek-at-the-performance-of-your-asp-net-app.aspx">Perfecto</a> is a Data Collector Set that plugs into PerfMon, and was created by <a href="https://blogs.msdn.com/b/josere">Jose Reyes</a>. This is a quick, simple way to collect ASP.NET, IIS, CLR and system counters which give a good overview of ASP.NET performance.</p>  <p><a href="https://technet.microsoft.com/en-us/library/bb490956.aspx">LogMan</a> is a command line tool for managing PerfMon Data Collector Sets.</p>  <p>Try the following:</p>  <ol>   <li>Download <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/09/99/34/34/perfecto.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Components-PostAttachments/00-09-99-34-34/perfecto.zip">Perfecto</a>, unzip and run the setup script </li>    <li>Run `logman start –n “Service\ASPNET Perfecto”` </li>    <li>Make a few web requests to localhost</li>    <li>Run `logman stop –n “Service\ASPNET Perfecto”` </li>    <li>View the report at &quot;%SystemDrive%\PerfLogs\Admin\ASPNET Perfecto\000001\report.html” </li> </ol>  <p>Don’t be afraid to customize Perfecto to your needs: add performance counters, change the report directory, etc.&#160; Right click ‘ASPNET Perfecto’ to edit the properties in PerfMon.&#160; Right click again and Save Template… to create an updated version of Perfecto.DataCollectorSet.xml.</p>  <p><strong>TypePerf and TList</strong></p>  <p>For basic counter collections, you can use the <a href="https://technet.microsoft.com/en-us/library/bb490960.aspx">TypePerf</a> command-line tool. It can be combined with the <a href="https://www.microsoft.com/downloads/details.aspx?FamilyID=C055060B-9553-4593-B937-C84881BCA6A5&amp;amp;amp;displaylang=e&amp;displaylang=en">TList</a> command in order to collect counters which are specific to a given process. For example, you can collect the Processor Time for all processes by running:</p>  <blockquote>   <p>`for /t “tokens=2 delims=. “ %a in (‘tlist’) do typeperf –sc 1 “Process(%a)\% Processor Time”</p> </blockquote>  <p><strong>WCat</strong></p>  <p><a href="https://technet.microsoft.com/en-us/query/ms951774#usingwcat_topic5">WCat</a> also supports the collection of performance counters.&#160; This is our primary way of collecting performance counters since most of our scenarios use WCat.&#160; Take a look at our settings.ubr file to see which counters we track:</p>  <pre class="csharpcode">settings
{
    counters
    {
        interval = 10;

        counter = <span class="str">&quot;.NET CLR Exceptions(w3wp)\\# of Exceps Thrown / sec&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Jit(w3wp)\\% Time in Jit&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Jit(w3wp)\\IL Bytes Jitted / sec&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Loading(w3wp)\\% Time Loading&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Loading(w3wp)\\Current appdomains&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Loading(w3wp)\\Current Assemblies&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\# of current logical Threads&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\# of current physical Threads&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\# of current recognized threads&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\# of total recognized threads&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\Queue Length / sec&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\Total # of Contentions&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\Contention Rate / sec&quot;</span>;
        counter = <span class="str">&quot;.NET CLR LocksAndThreads(w3wp)\\Current Queue Length&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\% Time in GC&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\# Bytes in all Heaps&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\# Gen 0 Collections&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\# Gen 1 Collections&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\# Gen 2 Collections&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\# Induced GC&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\Allocated Bytes/sec&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\Finalization Survivors&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\Gen 0 heap size&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\Gen 1 heap size&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\Gen 2 heap size&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\Large Object Heap size&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\Large Object Heap size&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Memory(w3wp)\\# of Pinned Objects&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Security(w3wp)\\% Time in RT checks&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Security(w3wp)\\Stack Walk Depth&quot;</span>;
        counter = <span class="str">&quot;.NET CLR Security(w3wp)\\Total Runtime Checks&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Cache Total Entries&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Cache Total Hit Ratio&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Cache Total Turnover Rate&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Output Cache Entries&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Output Cache Hits&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Output Cache Hit Ratio&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Output Cache Turnover Rate&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Compilations Total&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Errors Total/Sec&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Pipeline Instance Count&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Requests Executing&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Requests in Application Queue&quot;</span>;
        counter = <span class="str">&quot;ASP.NET Applications(__Total__)\\Requests/Sec&quot;</span>;
        counter = <span class="str">&quot;ASP.NET\\Application Restarts&quot;</span>;
        counter = <span class="str">&quot;ASP.NET\\Request Wait Time&quot;</span>;
        counter = <span class="str">&quot;ASP.NET\\Requests Current&quot;</span>;
        counter = <span class="str">&quot;ASP.NET\\Requests Queued&quot;</span>;
        counter = <span class="str">&quot;ASP.NET\\Requests Rejected&quot;</span>;
        counter = <span class="str">&quot;Memory\\Available MBytes&quot;</span>;
        counter = <span class="str">&quot;Memory\\Cache Faults/sec&quot;</span>;
        counter = <span class="str">&quot;Memory\\Demand Zero Faults/sec&quot;</span>;
        counter = <span class="str">&quot;Memory\\Page Faults/sec&quot;</span>;
        counter = <span class="str">&quot;Memory\\Pages/sec&quot;</span>;
        counter = <span class="str">&quot;Memory\\Transition Faults/sec&quot;</span>;
        counter = <span class="str">&quot;Memory\\Pool Nonpaged Bytes&quot;</span>;
        counter = <span class="str">&quot;Memory\\Pool Paged Bytes&quot;</span>;
        counter = <span class="str">&quot;PhysicalDisk(_Total)\\% Disk Time&quot;</span>;
        counter = <span class="str">&quot;PhysicalDisk(_Total)\\% Disk Read Time&quot;</span>;
        counter = <span class="str">&quot;PhysicalDisk(_Total)\\% Disk Write Time&quot;</span>;
        counter = <span class="str">&quot;Process(w3wp)\\% Processor Time&quot;</span>;
        counter = <span class="str">&quot;Process(w3wp)\\Handle Count&quot;</span>;
        counter = <span class="str">&quot;Process(w3wp)\\ID Process&quot;</span>;
        counter = <span class="str">&quot;Process(w3wp)\\Private Bytes&quot;</span>;
        counter = <span class="str">&quot;Process(w3wp)\\Thread Count&quot;</span>;
        counter = <span class="str">&quot;Process(w3wp)\\Virtual Bytes&quot;</span>;
        counter = <span class="str">&quot;Process(w3wp)\\Working Set&quot;</span>;
        counter = <span class="str">&quot;Processor(_Total)\\% Interrupt Time&quot;</span>;
        counter = <span class="str">&quot;Processor(_Total)\\% Privileged Time&quot;</span>;
        counter = <span class="str">&quot;Processor(_Total)\\% Processor Time&quot;</span>;
        counter = <span class="str">&quot;Processor(_Total)\\% User Time&quot;</span>;
        counter = <span class="str">&quot;System\\Context Switches/sec&quot;</span>;
        counter = <span class="str">&quot;System\\System Calls/sec&quot;</span>;
        counter = <span class="str">&quot;Web Service(_Total)\\Get Requests/sec&quot;</span>;
        counter = <span class="str">&quot;Web Service(_Total)\\Post Requests/sec&quot;</span>;
        counter = <span class="str">&quot;Web Service(_Total)\\Connection Attempts/sec&quot;</span>;
        counter = <span class="str">&quot;Web Service(_Total)\\Current Connections&quot;</span>;
        counter = <span class="str">&quot;Web Service(_Total)\\ISAPI Extension Requests/sec&quot;</span>;
        counter = <span class="str">&quot;Web Service Cache\\URI Cache Hits %&quot;</span>;
        counter = <span class="str">&quot;Web Service Cache\\Kernel: URI Cache Hits %&quot;</span>;
        counter = <span class="str">&quot;Web Service Cache\\File Cache Hits %&quot;</span>;
    }
}</pre>


<p><strong></strong></p>

<p><strong>PAL</strong></p>

<p><a href="https://pal.codeplex.com/">Performance Analysis of Logs (PAL)</a> is a tool by Microsoft Premier Field Engineer, <a href="https://blogs.technet.com/b/clinth/">Clint Huffman</a>. I haven’t had a chance to preview this tool yet, so I don’t want to speculate. It does seem to have a powerful feature set and following, so it’s definitely worth a look if you need a more comprehensive view.</p>]]></content:encoded>
    </item>
    <item>
      <title>ASP.NET Performance Lab: Hello, World!</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/asp-net-performance-lab-hello-world</link>
      <pubDate>Mon, 06 Feb 2012 20:38:00 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/02/06/asp-net-performance-lab-hello-world/</guid>
      <description><![CDATA[I thought I could shed some light on the ASP.NET performance testing by presenting our most basic...]]></description>
      <content:encoded><![CDATA[<p>I thought I could shed some light on the ASP.NET performance testing by presenting our most basic scenario: Hello, World!</p>  <p><strong>Step 1: State the Objective</strong></p>  <p>We want to ensure that the basic ASP.NET pipeline does not regress from one release to the next.&#160; We use server throughput (requests per second) as our performance metric.&#160; We want throughput to be on-par or better than the previous release (aka, baseline).</p>  <p><strong>Step 2: Create the Scenario</strong></p>  <p>We have a basic IIS website with the following ASPX page:</p>  <pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">html</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span>=”Hello, World!” <span class="asp">%&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span></pre>


<p><strong>Step 3: Run the Scenario</strong></p>

<p>Most of our scenarios use the <a href="https://technet.microsoft.com/en-us/query/ms951774">wcat</a> load tool to test the web server.&#160; You can download wcat <a href="https://www.iis.net/community/default.aspx?tabid=34&amp;g=6&amp;i=1467">here</a>.</p>

<p>In order to detect regressions we need to have reproducible results.&#160; Here are some of the ways that we reduce variability:</p>

<ul>
  <li>Eliminate the variables.&#160; Since I am measuring ASP.NET performance, .NET should be my one variable.&#160; Other factors such as hardware, OS, IIS, wcat version and the scenario itself should remain constant.</li>

  <li>Use a private network.&#160; Eliminate unnecessary network traffic to the web server which could affect results.</li>

  <li>Minimize server processes.&#160; Again, we want to avoid competition for server resources.&#160; We usually disable Windows Firewall and run the wcat controller and clients from separate machines.</li>

  <li>Measure warm.&#160; Since we are testing throughput and not startup, we can reduce the variability by adding a warm-up period.&#160; This will reduce JIT compilation and population of caches which could cause more variance.</li>

  <li>Max the CPU.&#160; Server load and system resources factor into the equation as well.&#160; We try to keep this near-constant by applying a full load during testing.&#160; Our goal is to achieve at least 90% CPU usage during our runs. </li>
</ul>

<p>We quantify our test variance (aka, noise) by running multiple iterations.&#160; We ignore the first iteration which we’ve found to have greater variance, and calculate the average and standard deviation for the remaining three.&#160; Standard deviation is our noise indicator.</p>

<p><strong>Step 4: Analyze the Results</strong></p>

<p>After doing our baseline and test runs, we should have results like the following:</p>

<table border="1" cellspacing="0" cellpadding="2" width="400"><tbody>
    <tr>
      <td valign="top" width="57">Scenario</td>

      <td valign="top" width="57">Baseline</td>

      <td valign="top" width="57">Result</td>

      <td valign="top" width="57">Diff</td>

      <td valign="top" width="57">Baseline StdDev</td>

      <td valign="top" width="57">Result StdDev</td>

      <td valign="top" width="57">Pass/Fail</td>
    </tr>

    <tr>
      <td valign="top" width="57">HelloWorld</td>

      <td valign="top" width="57">41549.67</td>

      <td valign="top" width="57">40432.67</td>

      <td valign="top" width="57">-2.69%</td>

      <td valign="top" width="57">0.64%</td>

      <td valign="top" width="57">0.35%</td>

      <td valign="top" width="57">PASS</td>
    </tr>
  </tbody></table>

<p>These are the columns:</p>

<ul>
  <li>Baseline, Result – Requests per second average for the last 3 iterations of the run</li>

  <li>Diff – Percentage of how far off the Result is from the Baseline</li>

  <li>Baseline StdDev, Result StdDev – Percentage of variance between the run iterations</li>

  <li>Pass / Fail – Whether the Diff is above our threshold.</li>
</ul>

<p>Based on our experience we’ve set our threshold at 5%.&#160; We define failures as runs that are more than 5% regressed.&#160; Runs that show &gt;5% improvement should also be investigated in order to understand and validate the cause.</p>

<p>We consider a run noisy if the standard deviation exceeds a threshold, which we also set at 5%.&#160; If a failed run is noisy, we throw out one more iteration to see if the Diff and StdDev improve.&#160; If they do we may ignore the failure and wait for the next run.&#160; If the runs continue to be noisy, then the scenario should be investigated in order to further reduce the variance.</p>

<p><strong>Step 5: Investigate Regressions</strong></p>

<p>As the saying goes, “Measure Early, Measure Often”.&#160; The less changes there are between your runs, the easier it will be to track down the cause of your regressions.&#160; This is why the ASP.NET performance lab runs daily with builds from multiple branches.&#160; Often times I’m able to quickly identify a regression simply by looking at the source control history.</p>

<p>Another way to quickly diagnose regressions is to enable performance counters or other non-invasive tracing which could help identify the cause.&#160; We always save the wcat logs with our performance counters and other useful information such as throughput, working set, percent cpu usage, and HTTP responses.&#160; The HTTP responses can rule out test failures, while the other diagnostics (combined with source control) can help narrow down the cause.</p>

<p>Finally, if a quick diagnosis is not possible, find a good profiler.&#160; Some of the tools we use are the Visual Studio (F1) profiler, CLR Profiler, and XPerf.&#160; I hope to demonstrate some of these in future posts.</p>]]></content:encoded>
    </item>
    <item>
      <title>Web Performance Blog</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/web-performance-blog</link>
      <pubDate>Thu, 02 Feb 2012 15:55:00 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2012/02/02/web-performance-blog/</guid>
      <description><![CDATA[This week I launched a new blog that will focus on the performance of Microsoft&rsquo;s Web...]]></description>
      <content:encoded><![CDATA[<p>This week I launched a new blog that will focus on the performance of Microsoft&rsquo;s Web Stack.&nbsp; This includes IIS, ASP.NET, MVC, WCF, WF, Visual Web Developer, WebMatrix and much, much more.&nbsp; Content will be compiled from the performance team under Scott Guthrie that helps to deliver these products.</p>
<p><a href="https://blogs.msdn.com/b/web_performance_blog/">https://blogs.msdn.com/b/web_performance_blog/</a></p>
<p>I hope that our blog becomes a valuable resource for you and I welcome your feedback.&nbsp; Happy reading<em>!</em></p>
<p><em>-Christy Henriksson, ASP.NET Performance Champ</em></p>]]></content:encoded>
    </item>
    <item>
      <title>TypeDescriptor Updates in .NET4</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/typedescriptor-updates-in-net4</link>
      <pubDate>Fri, 19 Nov 2010 13:37:10 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2010/11/19/typedescriptor-updates-in-net4/</guid>
      <description><![CDATA[This is the fifth in my blog series on Visual Studio 2010 Designer Multi-Targeting  A few updates...]]></description>
      <content:encoded><![CDATA[<p>This is the fifth in my blog series on <a href="https://blogs.msdn.com/christy/archive/2010/04/28/visual-studio-2010-designer-multi-targeting.aspx">Visual Studio 2010 Designer Multi-Targeting</a></p>  <p>A few updates were made to the <a href="https://msdn.microsoft.com/en-us/library/ms171819.aspx">TypeDescriptor</a> classes to support multi-targeting:</p>  <p>1. <a href="https://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.interfacetype.aspx">TypeDescriptor.InterfaceType</a></p>  <p>With the different VS project types came slightly different multi-targeting solutions.&#160; Windows and Web Forms attached the TargetFrameworkProvider to control instances on the design surface.&#160; Workflow projects took a more global solution: attaching the provider to all types.&#160; However, this broke down when trying to attach the provider to interfaces since they don’t have a common parent.</p>  <p>The new InterfaceType property allowed us to attach a TypeDescriptionProvider to all interfaces.&#160; This is similar to <a href="https://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.comobjecttype(v=VS.100).aspx">ComObjectType</a> which allows you to attach to all COM types.</p>  <p>2. Performance improvements to <a href="https://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.refresh.aspx">TypeDescriptor.Refresh</a> and <a href="https://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.addprovider.aspx">TypeDescriptor.AddProvider</a></p>  <p>Attaching providers was slow… VERY slow.&#160; Never before had we attached so many TypeDescriptionProviders at design time – it was a true stress test.</p>  <p>When attaching a TypeDescriptionProvider to a type, any derived type or instance of that type also gets the custom provider.&#160; This results in a complex chaining of providers, each of which may have its own cache.&#160; When providers are added or removed, we must ensure that the cache for providers higher in the chain are refreshed.&#160; In .NET4 we optimized TypeDescriptor to avoid some cache refreshes that weren’t necessary.</p>  <p align="left">3. <a href="https://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptionprovider.getruntimetype.aspx">TypeDescriptionProvider.GetRuntimeType</a></p>  <p align="left">Previously, <a href="https://msdn.microsoft.com/en-us/library/bex9hc74.aspx">TypeDescriptionProvider.GetReflectionType</a> always returned types that were compatible with runtime types.&#160; Sometimes they were runtime types; and sometimes they were just imposters which redirected CLR APIs to the real runtime type while modifying certain reflection data.&#160; I’m glossing over things, but you get the idea.</p>  <p align="left">In .NET4, the TargetFrameworkProvider introduced new reflection types which were no longer compatible with runtime types.&#160; Now that there were multiple target frameworks, types no longer fit into a single global “universe”.&#160; Now reflection types came from a 4.0 universe, or a 3.5 universe, etc.&#160; However, since the designer is still just running .NET4 we needed to add this new API to map types back into to the runtime.</p>  <p align="left">4. <a href="https://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptionprovider.issupportedtype.aspx">TypeDescriptionProvider.IsSupportedType</a></p>  <p align="left">The designer is always running the most recent framework, so we know that the target version is always equal or less than the runtime.&#160; Assuming that there are no breaking changes, it means that there is always a runtime type that corresponds to the target reflection type.&#160; However, when targeting a lower version there is not always a reflection type for a given runtime type (if the type was added after the target version).</p>  <p align="left">Ideally TypeDescriptionProvider.GetReflectionType would just return null in this case.&#160; However this allowance was never built into pre-existing code and documentation.&#160; To avoid breaking this legacy contract we added TypeDescriptionProvider.IsSupportedType.&#160; This method returns false if a runtime type does not exist for a given reflection type.</p>]]></content:encoded>
    </item>
    <item>
      <title>Sorting on Dynamic Members at Runtime</title>
      <link>https://docs.microsoft.com/archive/blogs/christy/sorting-on-dynamic-members-at-runtime</link>
      <pubDate>Fri, 19 Nov 2010 11:14:09 GMT</pubDate>
      <dc:creator><![CDATA[Christy Henriksson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/christy/2010/11/19/sorting-on-dynamic-members-at-runtime/</guid>
      <description><![CDATA[Earlier this year I got to play with the DLR a little while working on the WebGrid for ASP.NET Web...]]></description>
      <content:encoded><![CDATA[<p>Earlier this year I got to play with the DLR a little while working on the WebGrid for ASP.NET Web Pages.&#160; I wanted the grid to work with the various LINQ providers, but it also had to support dynamic objects such as those returned by the new simple data APIs.&#160; This began my investigation into using LINQ with dynamics.</p>  <p>With non-dynamic objects, you can order on LINQ’s Expression.Property to reflect against an arbitrary property at runtime:</p>  <pre class="brush: csharp;">static void Main(string[] args) {
    var names = new[] {
        new { Name = &quot;Joe&quot; },
        new { Name = &quot;Bob&quot; },
        new { Name = &quot;Tom&quot; },
        new { Name = &quot;Jack&quot; },
    };
    Print(names);
    Print(Sort(names, &quot;Name&quot;));
}

static void Print(IEnumerable&lt;dynamic&gt; source) {
    foreach (var i in source.Select(s =&gt; s.Name)) Console.WriteLine(i);
    Console.WriteLine();
}

public static T[] Sort&lt;T&gt;(T[] source, string property) {
    var param = Expression.Parameter(typeof(T));
    var getter = Expression.Property(param, property);
    var lambda = Expression.Lambda&lt;Func&lt;T, dynamic&gt;&gt;(getter, param).Compile();
    return source.OrderBy(lambda).ToArray();
}</pre>

<p>Of course, this doesn’t work for dynamic objects.&#160; You need to sort on DynamicObject.TryGetMember with a get member binder that can invoke the property.&#160; My first inclination was to write a helper method for getting the value with a binder, and using Expression.Call to invoke it:</p>

<pre class="brush: csharp;">class DynamicPerson : DynamicObject {
    private string _name;
    public DynamicPerson(string name) {
        _name = name;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        if (binder.Name == &quot;Name&quot;) {
            result = _name;
            return true;
        }
        return base.TryGetMember(binder, out result);
    }
}

class MyBinder : GetMemberBinder {
    public MyBinder(string property) : base(property, ignoreCase:true) { }
    public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) {
        throw new NotImplementedException();
    }
}


static void Main(string[] args) {
    var names = new dynamic[] {
        new DynamicPerson(&quot;Joe&quot;),
        new DynamicPerson(&quot;Bob&quot;),
        new DynamicPerson(&quot;Tom&quot;),
        new DynamicPerson(&quot;Jack&quot;)
    };
    Print(names);
    Print(Sort(names, &quot;Name&quot;));
}

static DynamicObject[] Sort(IEnumerable source, string property) {
    var param = Expression.Parameter(typeof(DynamicObject), &quot;o&quot;);
    var param2 = Expression.Constant(property);
    var getter = Expression.Call(typeof(Example2), &quot;GetDynamicMember&quot;, new Type[0], param, param2);
    var lambda = Expression.Lambda&lt;Func&lt;DynamicObject, dynamic&gt;&gt;(getter, param).Compile();
    return source.Cast&lt;DynamicObject&gt;().OrderBy(lambda).ToArray();
}

static object GetDynamicMember(DynamicObject o, string property) {
    object result = null;
    if (o.TryGetMember(new MyBinder(property), out result)) {
        return result;
    }
    return null;
}</pre>

<p>This looks ugly and also doesn’t work in partial trust since the lambda executed by LINQ is using your internals.&#160; Fortunately there’s a simple fix: Expression.Dynamic.&#160; Using this, LINQ can bind to the dynamic property using the runtime binder.</p>

<pre class="brush: csharp;">using Microsoft.CSharp.RuntimeBinder;</pre>

<pre class="brush: csharp;">static DynamicObject[] Sort(IEnumerable source, string property) {
    var binder = Binder.GetMember(CSharpBinderFlags.None, property, typeof(Example3), new CSharpArgumentInfo[] {
        CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
    var param = Expression.Parameter(typeof(DynamicObject), &quot;o&quot;);
    var getter = Expression.Dynamic(binder, typeof(object), param);
    var lambda = Expression.Lambda&lt;Func&lt;DynamicObject, dynamic&gt;&gt;(getter, param).Compile();
    return source.Cast&lt;DynamicObject&gt;().OrderBy(lambda).ToArray();
}</pre>

<p><strong>UPDATE: There are some considerations you should take into account before </strong><a href="https://blogs.msdn.com/b/cburrows/archive/2010/10/18/on-dynamic-objects-and-dynamicobject.aspx"><strong>extending DynamicObject</strong></a></p>]]></content:encoded>
    </item>
  </channel>
</rss>