<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Pigs Can Fly : Performance</title><link>http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx</link><description>Tags: Performance</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Stack Walking in Xperf</title><link>http://blogs.msdn.com/pigscanfly/archive/2009/08/06/stack-walking-in-xperf.aspx</link><pubDate>Thu, 06 Aug 2009 20:52:25 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9859435</guid><dc:creator>rgr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/9859435.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=9859435</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=9859435</wfw:comment><description>&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Bruce Dawson is a performance analyst on the client performance team.&amp;#160; He has written this guest post on enabling stack walking using xperf for both 32-bit and 64-bit Windows systems (Vista and Win7).&amp;#160; For more posts on xperf see &lt;a href="http://blogs.msdn.com/pigscanfly/pages/xperf-articles.aspx" target="_blank"&gt;this page&lt;/a&gt;.&lt;/p&gt; &lt;strong&gt;&lt;/strong&gt;  &lt;h1&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h1&gt;  &lt;p&gt;When I first started working with xperf I was confused by the many gotchas and settings surrounding the recording of call stacks. It seemed like there were many bits of crucial information needed in order to successfully record call stacks, and these bits were never gathered in one place. In order to save future generations from this complexity (and to give me a convenient reference to look at) I decided to write up what I have learned, while the lessons are still fresh in my memory. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;Warning: &lt;/font&gt;&lt;/strong&gt;The syntax examples below make use of ‘-‘ characters and the single quote character. Both of these characters are often altered by word processing software to visually similar but actually different characters, which can lead to obscure syntax errors. If the example syntax doesn’t work then try typing in the command manually instead of using copy/paste to eliminate that as a factor. &lt;/p&gt;  &lt;h1&gt;&lt;strong&gt;Recording Stack Walks&lt;/strong&gt;&lt;/h1&gt;  &lt;p&gt;In order to enable call stacks in xperf you need to choose what type of event you want call stacks for, make sure that event is being recorded, and then enable call stacks for that type of event. The sampling profile events from the kernel provider (interrupting the CPU every millisecond and recording what it is doing) are one of the main uses of call stacks. The profile events can be enabled with the “PROFILE” kernel flag, or by using some of the kernel groups such as “Base” or “Latency” which include the PROFILE flag. For a list of all the kernel flags and kernel groups use: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier New"&gt;xperf -providers k&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In addition to enabling the sampling profiler we need to enable stack walking on that event with the -stackwalk command. We also need to make sure that the PROC_THREAD and LOADER kernel flags are enabled – so that the xperf tools can identify what modules the code addresses are in. &lt;/p&gt;  &lt;p&gt;Putting this together, the following example command will tell xperf to record a trace with sampling profiler call stacks and save it to mytrace.etl: &lt;/p&gt;  &lt;blockquote&gt;   &lt;table border="0" cellspacing="0" cellpadding="2" width="400"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" width="400"&gt;&lt;font face="Courier New"&gt;xperf -on PROC_THREAD+LOADER+PROFILE -stackwalk profile&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="400"&gt;&lt;font face="Courier New"&gt;rem Your scenario goes here…&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="400"&gt;&lt;font face="Courier New"&gt;xperf -d mytrace.etl&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p align="left"&gt;Alternately, the following command will also work, because the “Latency” kernel group includes all of the necessary kernel flags.&lt;/p&gt;  &lt;blockquote&gt;   &lt;table border="0" cellspacing="0" cellpadding="2" width="400"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" width="400"&gt;&lt;font face="Courier New"&gt;xperf -on Latency -stackwalk profile&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="400"&gt;&lt;font face="Courier New"&gt;rem Your scenario goes here...&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="400"&gt;&lt;font face="Courier New"&gt;xperf -d mytrace.etl&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;Many events can have stack walking enabled using this basic method, so that if you want call stacks for context switches, registry operations, etc., you can get them. You can see the list of events that can have call stacks enabled for them with: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier New"&gt;xperf -help stackwalk&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;You can also record call stacks for manifest-based ETW (Event Tracing for Windows) events, but the syntax is quite different, and it only works on Windows 7 and above. When you specify your ETW provider to xperf after “-on” you can specify extra parameters after the provider name, separated by colons. These are flags, a level, and, for manifest-based providers, a list of extra data to record, which can include call stacks. You can leave the flags and level fields blank and just specify ‘stack’ (in single quotes) after three colons like this: &lt;/p&gt;  &lt;blockquote&gt;   &lt;table border="0" cellspacing="0" cellpadding="2" width="495"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" width="493"&gt;&lt;font face="Courier New"&gt;xperf -on Latency -stackwalk profile -start browse -on Microsoft-IE:::'stack'&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="493"&gt;&lt;font face="Courier New"&gt;rem Your scenario goes here...&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="493"&gt;&lt;font face="Courier New"&gt;xperf -stop browse -stop -d mytrace.etl&lt;/font&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;The syntax above starts the kernel session with the “Latency” set of kernel flags, enables stack walking on the profile events, starts a user session called “browse”, and enables the “Microsoft-IE” ETW provider for that session, with call stacks recorded for all of those events. Then, when your scenario is finished it stops the user session, stops the kernel session, and merges the kernel and user traces into “mytrace.etl”. It’s a bit of a mouthful, but it works. &lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Operating System Support for XPerf Stack Walks&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;Recording stack walks from xperf is not supported in all variations of Windows and does have some prerequisites. Note also that stack walking for classic ETW events is not supported. Owners of classic ETW providers must upgrade their providers to manifest-based to take advantage of stack walking on their custom events.&lt;/p&gt;  &lt;p&gt;The following chart summarizes the situation for stack walking on kernel and manifest-based events:&lt;/p&gt;  &lt;table border="2" cellspacing="0" cellpadding="2" width="400"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="133"&gt;&amp;#160;&lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;&lt;strong&gt;32-bit&lt;/strong&gt;&lt;/p&gt;       &lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;&lt;strong&gt;64-bit&lt;/strong&gt;&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="133"&gt;&lt;strong&gt;XP and below&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;No&lt;/p&gt;       &lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;No&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="133"&gt;&lt;strong&gt;Vista RTM*&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;Yes&lt;/p&gt;       &lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;No&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="133"&gt;&lt;strong&gt;Vista SP1*&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;Yes&lt;/p&gt;       &lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;Yes**&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="133"&gt;&lt;strong&gt;Windows 7&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;Yes&lt;/p&gt;       &lt;/td&gt;        &lt;td valign="top" width="133"&gt;         &lt;p align="center"&gt;Yes**&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;* Stack walking not supported for manifest-based ETW events.&lt;/p&gt;  &lt;p&gt;** Stack walking on 64-bit requires that the DisablePagingExecutive registry key be set. &lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Disable Paging Executive&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;In order for tracing to work on 64-bit Windows you need to set the DisablePagingExecutive registry key. This tells the operating system not to page kernel mode drivers and system code to disk, which is a prerequisite for getting 64-bit call stacks using xperf, because 64-bit stack walking depends on metadata in the executable images, and in some situations the xperf stack walk code is not allowed to touch paged out pages. Running the following command from an elevated command prompt will set this registry key for you. &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;REG ADD &amp;quot;HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management&amp;quot; -v DisablePagingExecutive -d 0x1 -t REG_DWORD -f &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;After setting this registry key you will need to reboot your system before you can record call stacks. Having this flag set means that the Windows kernel locks more pages into RAM, so this will probably consume about 10 MB of additional physical memory. &lt;/p&gt;  &lt;h1&gt;&lt;strong&gt;Looking at Stack Walks&lt;/strong&gt;&lt;/h1&gt;  &lt;p&gt;The call stacks that result from the stack walks are visible in xperfview. You can run xperfview and load your trace or you can invoke it from the command line with: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier New"&gt;xperf mytrace.etl&lt;/font&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If you enabled the PROFILE kernel flag then you should see one or more CPU Sampling graphs – if they aren’t enabled then use the selector on the left sidebar, or the Graphs menu, to enable one of them. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackWalkinginXperf_12FF9/image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackWalkinginXperf_12FF9/image_thumb.png" width="540" height="247" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;From one of the CPU sampling graphs you can select an area of interest and then right-click and select Summary Table. Use the selector on the left sidebar of the summary table, or the Columns menu, to make sure that the Stack column is enabled and visible – this is where your call stacks will be shown. Xperfview summarizes multiple stack walks together, collapsing them down where they are identical. The Count field shows how many stacks were collapsed together on each row (how many times that partial call stack was hit), the Weight column shows an estimate of how many milliseconds of CPU time were spent in that call stack, and the %Weight column shows that as a percentage of total CPU time available.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackWalkinginXperf_12FF9/image_4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackWalkinginXperf_12FF9/image_thumb_1.png" width="546" height="250" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Sampling Implies Estimation&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;CPU sampling is a statistical profiling process. If the number of samples is small, or if the code execution is correlated with the sampling interval, then the results can be off by a large amount. It is important to be aware of the limits of sampling in order to avoid reading too much meaning into a small number of counts.&lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Symbols&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;If you haven’t loaded symbols then your call stacks will show DLL names followed by question marks, as shown below. You can tell that you’ve recorded a call stack, but the details of what code was executing are still hidden.&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="165"&gt;Stack&lt;/td&gt;        &lt;td width="90"&gt;Count&lt;/td&gt;        &lt;td width="93"&gt;Weight&lt;/td&gt;        &lt;td width="141"&gt;% Weight&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;[Root]&lt;/td&gt;        &lt;td width="90"&gt;4973&lt;/td&gt;        &lt;td width="93"&gt;4972.513&lt;/td&gt;        &lt;td width="141"&gt;93.51&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|- ntdll.dll!?&lt;/td&gt;        &lt;td width="90"&gt;4950&lt;/td&gt;        &lt;td width="93"&gt;4949.49&lt;/td&gt;        &lt;td width="141"&gt;93.08&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;| kernel32.dll!?&lt;/td&gt;        &lt;td width="90"&gt;4950&lt;/td&gt;        &lt;td width="93"&gt;4949.49&lt;/td&gt;        &lt;td width="141"&gt;93.08&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |- MSVCR90.DLL!?&lt;/td&gt;        &lt;td width="90"&gt;4904&lt;/td&gt;        &lt;td width="93"&gt;4903.486&lt;/td&gt;        &lt;td width="141"&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160; MSVCR90.DLL!?&lt;/td&gt;        &lt;td width="90"&gt;4904&lt;/td&gt;        &lt;td width="93"&gt;4903.486&lt;/td&gt;        &lt;td width="141"&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160; MFC90.DLL!?&lt;/td&gt;        &lt;td width="90"&gt;4904&lt;/td&gt;        &lt;td width="93"&gt;4903.486&lt;/td&gt;        &lt;td width="141"&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160; FractalX.EXE!?&lt;/td&gt;        &lt;td width="90"&gt;4904&lt;/td&gt;        &lt;td width="93"&gt;4903.486&lt;/td&gt;        &lt;td width="141"&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160; FractalX.EXE!?&lt;/td&gt;        &lt;td width="90"&gt;4904&lt;/td&gt;        &lt;td width="93"&gt;4903.486&lt;/td&gt;        &lt;td width="141"&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160; FractalX.EXE!?&lt;/td&gt;        &lt;td width="90"&gt;4904&lt;/td&gt;        &lt;td width="93"&gt;4903.486&lt;/td&gt;        &lt;td width="141"&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160; |- FractalX.EXE!?&lt;/td&gt;        &lt;td width="90"&gt;4900&lt;/td&gt;        &lt;td width="93"&gt;4899.485&lt;/td&gt;        &lt;td width="141"&gt;92.14&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160; |- user32.dll!?&lt;/td&gt;        &lt;td width="90"&gt;3&lt;/td&gt;        &lt;td width="93"&gt;3.001464&lt;/td&gt;        &lt;td width="141"&gt;0.06&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |&amp;#160; |- MSVCR90.DLL!?&lt;/td&gt;        &lt;td width="90"&gt;1&lt;/td&gt;        &lt;td width="93"&gt;0.999918&lt;/td&gt;        &lt;td width="141"&gt;0.02&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|&amp;#160; |- FractalX.EXE!?&lt;/td&gt;        &lt;td width="90"&gt;46&lt;/td&gt;        &lt;td width="93"&gt;46.00391&lt;/td&gt;        &lt;td width="141"&gt;0.87&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="165"&gt;|- ntkrnlmp.exe!?&lt;/td&gt;        &lt;td width="90"&gt;23&lt;/td&gt;        &lt;td width="93"&gt;23.0229&lt;/td&gt;        &lt;td width="141"&gt;0.43&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;A single question mark in the stack column means that no call stack is available at all. If “?!?” is displayed then that means that xperf doesn’t know what executable image was at the address. &lt;/p&gt;  &lt;p&gt;If the DLLs are from Microsoft then you should point your symbol path to Microsoft’s symbol servers (using the _NT_SYMBOL_PATH environment variable or Configure Symbol Paths from the Trace menu). You can have multiple symbol paths, separate by semicolons, to that you can point at Microsoft’s symbols and your own simultaneously. Then you need to select Load Symbols from the Trace menu or a graph context menu. &lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Exploring Call Stacks&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;The call stack display is a bit unusual in that the root of the call stack (conveniently labeled as [Root]) is displayed at the top and you expand downwards from there. The layout is also a bit subtle and non-obvious at first. When you see multiple functions above each other at the same indentation with no minus signs in front of them (for example &lt;strong&gt;endthreadex&lt;/strong&gt; and &lt;strong&gt;_AfxThreadEntry&lt;/strong&gt; below) then that means that in that section of the call stack all of the collapsed stacks took the same path – &lt;strong&gt;endthreadex&lt;/strong&gt; called &lt;strong&gt;_AfxThreadEntry&lt;/strong&gt; in all of the samples and these functions have a parent/child relationship. This layout helps to keep the call stack display as compact as possible.&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="297"&gt;Stack&lt;/td&gt;        &lt;td width="64"&gt;Count&lt;/td&gt;        &lt;td width="64"&gt;Weight&lt;/td&gt;        &lt;td width="64"&gt;% Weight&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;[Root]&lt;/td&gt;        &lt;td&gt;4973&lt;/td&gt;        &lt;td&gt;4972.513&lt;/td&gt;        &lt;td&gt;93.51&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|- ntdll.dll!?&lt;/td&gt;        &lt;td&gt;4950&lt;/td&gt;        &lt;td&gt;4949.49&lt;/td&gt;        &lt;td&gt;93.08&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; kernel32.dll!?&lt;/td&gt;        &lt;td&gt;4950&lt;/td&gt;        &lt;td&gt;4949.49&lt;/td&gt;        &lt;td&gt;93.08&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |- MSVCR90.DLL!endthreadex&lt;/td&gt;        &lt;td&gt;4904&lt;/td&gt;        &lt;td&gt;4903.486&lt;/td&gt;        &lt;td&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160;&amp;#160; MSVCR90.DLL!endthreadex&lt;/td&gt;        &lt;td&gt;4904&lt;/td&gt;        &lt;td&gt;4903.486&lt;/td&gt;        &lt;td&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160;&amp;#160; MFC90.DLL!_AfxThreadEntry&lt;/td&gt;        &lt;td&gt;4904&lt;/td&gt;        &lt;td&gt;4903.486&lt;/td&gt;        &lt;td&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160;&amp;#160; FractalX.EXE!PrimaryCalculationProc&lt;/td&gt;        &lt;td&gt;4904&lt;/td&gt;        &lt;td&gt;4903.486&lt;/td&gt;        &lt;td&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160;&amp;#160;&amp;#160;&amp;#160; FractalX.EXE!HomeWork::CalculateNextBit&lt;/td&gt;        &lt;td&gt;4904&lt;/td&gt;        &lt;td&gt;4903.486&lt;/td&gt;        &lt;td&gt;92.21&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160; |- FractalX.EXE!Calculator::Calculate&lt;/td&gt;        &lt;td&gt;4899&lt;/td&gt;        &lt;td&gt;4898.484&lt;/td&gt;        &lt;td&gt;92.12&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160; |&amp;#160; |- FractalX.EXE!Calculator::Calculate&amp;lt;itself&amp;gt;&lt;/td&gt;        &lt;td&gt;2743&lt;/td&gt;        &lt;td&gt;2742.873&lt;/td&gt;        &lt;td&gt;51.58&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160; |&amp;#160; |- FractalX.EXE!Calculator::CalculateHelper&lt;/td&gt;        &lt;td&gt;2156&lt;/td&gt;        &lt;td&gt;2155.611&lt;/td&gt;        &lt;td&gt;40.54&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |&amp;#160; |- FractalX.EXE!IterDataImp&amp;lt;int&amp;gt;::Render&lt;/td&gt;        &lt;td&gt;5&lt;/td&gt;        &lt;td&gt;5.002155&lt;/td&gt;        &lt;td&gt;0.09&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;|&amp;#160; |- FractalX.EXE!__tmainCRTStartup&lt;/td&gt;        &lt;td&gt;46&lt;/td&gt;        &lt;td&gt;46.00391&lt;/td&gt;        &lt;td&gt;0.87&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;When you see multiple functions above each other at the same indentation &lt;i&gt;with&lt;/i&gt; minus signs in front of them (for instance &lt;strong&gt;Calculator::Calculate&lt;/strong&gt; and &lt;strong&gt;IterDataImp&amp;lt;int&amp;gt;::Render&lt;/strong&gt;) it means that all of these functions are called by the function above them. In other words those functions are siblings, all called by &lt;strong&gt;HomeWork::CalculateNextBit&lt;/strong&gt;, and the collapsed call stacks took multiple paths at this point. &lt;/p&gt;  &lt;p&gt;When you see a line that ends with &amp;lt;itself&amp;gt; then than line represents samples that occurred in that function, as opposed to in its descendants. This is often described as the exclusive time, as opposed to inclusive time which includes descendants. The &amp;lt;itself&amp;gt; line for a function, if present, will show up as a child node of the function so that the child nodes’ counts sum up to the parent’s count. In the example above Calculator::Calculate was running for 2743 samples and its child function was running for 2156 samples, for a total of 4899. &lt;/p&gt;  &lt;p&gt;The best way to get the feel for how this works is to play around with it. If you select a call stack and repeatedly press the right arrow key then the call stack will keep expanding down the hottest path and this can be a very effective way to drill down into what is probably the most important call stack. &lt;/p&gt;  &lt;p&gt;To see call stacks for manifest-based ETW events (assuming you enabled them) you need to go to the Generic Events graph and then select Summary Table from its context menu. From there you should make sure that the Stack column is enabled and you can then explore the stacks. The Count column can be very useful to see how many times the various events were hit from various call stacks. When enabled the stacks of manifest-based events are also available in the tooltips of the corresponding event markers in the Generic graph itself. &lt;/p&gt;  &lt;h1&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/h1&gt;  &lt;p&gt;Call stacks can be recorded with: &lt;/p&gt;  &lt;blockquote&gt;   &lt;table border="0" cellspacing="0" cellpadding="2" width="400"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" width="400"&gt;xperf -on Latency -stackwalk profile&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="400"&gt;rem Your scenario goes here...&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="400"&gt;xperf -d mytrace.etl&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;If you are tracing on 64-bit Windows don’t forget to set DisablePagingExecutive and then reboot before recording call stacks. And remember that Windows 7 has better ETW call stack recording support than Windows Vista, and Windows XP has no ETW call stack recording support. &lt;/p&gt;  &lt;p&gt;To analyze call stacks load the trace into xperfview and look in the appropriate summary table in the Stack column. &lt;/p&gt;  &lt;p&gt;Happy tracing! &lt;/p&gt;  &lt;p&gt;Bruce Dawson, Windows Client Performance Team &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9859435" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/xperf/default.aspx">xperf</category></item><item><title>StackOverflow answer – why learn multi-core programming? #2</title><link>http://blogs.msdn.com/pigscanfly/archive/2009/08/06/stackoverflow-answer-why-learn-multi-core-programming-2.aspx</link><pubDate>Thu, 06 Aug 2009 20:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9859413</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/9859413.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=9859413</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=9859413</wfw:comment><description>&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/pigscanfly/archive/2009/03/30/stackoverflow-answer-why-learn-multi-core-programming.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/archive/2009/03/30/stackoverflow-answer-why-learn-multi-core-programming.aspx"&gt;last post&lt;/A&gt; I talked about how multi-threading can be used to improve responsiveness while loading a file.&amp;nbsp;&amp;nbsp;&amp;nbsp; I’ve put together a sample program (source included) that shows how to do this in C# 3.0, .NET 3.5, and WPF using Visual Studio 2008.&amp;nbsp; You can find a zip file with a complete project attached.&lt;/P&gt;
&lt;P&gt;The program has a very simple, but fully functional UI.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_4.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_4.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=BFE1 border=0 alt=BFE1 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_thumb_1.png" width=383 height=186 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The “Open a file…” pops up the standard open file dialog and ask the user to find a file.&amp;nbsp;&amp;nbsp; The cancel button is disabled unless there is a loading operation to cancel.&amp;nbsp; The text box is for messages from the loader thread and the slider is just there to show that the UI is responsive while the background load occurs.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_2.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_2.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=BFE2 border=0 alt=BFE2 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_thumb.png" width=386 height=184 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The progress bar is hidden unless a file is actually being loaded.&amp;nbsp; If the async check box is un-checked, then the file will be loaded synchronously.&amp;nbsp; This illustrates how the UI will ‘freeze’ if a second thread isn’t used.&lt;/P&gt;
&lt;P&gt;The key thing about this program is that the UI stays completely responsive while a file is loaded.&amp;nbsp; Of course, this can be done without threads – many programs are written using a state machine approach.&amp;nbsp; But using threads, and functional programming make this much more simple than previous approaches. &lt;/P&gt;
&lt;P&gt;There are many ways to leverage threads in managed code, but the most straight forward way is using the BackgroundWorker class.&amp;nbsp; IT can be used in two ways, by creating one and attaching functions to its delegates, or by creating a new class derived from BackgroundWorker – this is the approach I took here.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;I created a class called AsyncFileLoader that is derived from BackgroundWorker.&amp;nbsp; We’re using all the features of BackgroundWorker here&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Support for asynchronous progress notifications &lt;/LI&gt;
&lt;LI&gt;Support for cancelation &lt;/LI&gt;
&lt;LI&gt;Handling of errors during the file loading &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Progress and cancelation is enabled by setting their properties in the constructor.&lt;/P&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; AsyncFileLoader()&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     WorkerReportsProgress = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt;     WorkerSupportsCancellation = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum5&gt;   5:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;We also need an event handler that will be connected to the cancel button&lt;/P&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; PerformCancel( &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt; sender,  RoutedEventArgs e )&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.CancelAsync();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;The final element is a function that overrides BackgroundWorker.OnDoWork().&amp;nbsp;&amp;nbsp; This function does all the work of asynchronously loading a text file.&lt;/P&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;protected&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; OnDoWork( DoWorkEventArgs e )&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #008000"&gt;// note: do not catch exceptions here.  The BackgroundWorker will catch exceptions &lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #008000"&gt;// and pass them back to the initiating thread in the RunWorkerCompleted() delegate &lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum5&gt;   5:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #008000"&gt;// using the error member of RunWorkerCompletedEventArgs parameter.&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum6&gt;   6:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum7&gt;   7:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; FileName = e.Argument &lt;SPAN style="COLOR: #0000ff"&gt;as&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum8&gt;   8:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum9&gt;   9:&lt;/SPAN&gt;     ReportProgress( &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.MinValue, String.Format( &lt;SPAN style="COLOR: #006080"&gt;"Opening {0}"&lt;/SPAN&gt;, FileName ) );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum10&gt;  10:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum11&gt;  11:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; ( StreamReader sr = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; StreamReader( FileName, Encoding.UTF8 ) ) &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum12&gt;  12:&lt;/SPAN&gt;     {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum13&gt;  13:&lt;/SPAN&gt;         ReportProgress( &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.MinValue, String.Format( &lt;SPAN style="COLOR: #006080"&gt;"Loading {0}"&lt;/SPAN&gt;, FileName ) );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum14&gt;  14:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum15&gt;  15:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;long&lt;/SPAN&gt; FileLength = sr.BaseStream.Length;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum16&gt;  16:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;long&lt;/SPAN&gt; PercentRead = 0;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum17&gt;  17:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;long&lt;/SPAN&gt; LastPercentRead = 0;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum18&gt;  18:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum19&gt;  19:&lt;/SPAN&gt;         String line;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum20&gt;  20:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum21&gt;  21:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;while&lt;/SPAN&gt; ( (line = sr.ReadLine()) != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt; ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum22&gt;  22:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum23&gt;  23:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( CancellationPending ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum24&gt;  24:&lt;/SPAN&gt;                 e.Cancel = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum25&gt;  25:&lt;/SPAN&gt;                 &lt;SPAN style="COLOR: #0000ff"&gt;break&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum26&gt;  26:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum27&gt;  27:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum28&gt;  28:&lt;/SPAN&gt;             PercentRead = (sr.BaseStream.Position * 100) / FileLength;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum29&gt;  29:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum30&gt;  30:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( PercentRead &amp;gt;= LastPercentRead + 1 ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum31&gt;  31:&lt;/SPAN&gt;                 ReportProgress( (&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;)PercentRead );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum32&gt;  32:&lt;/SPAN&gt;                 LastPercentRead = PercentRead;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum33&gt;  33:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum34&gt;  34:&lt;/SPAN&gt;         }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum35&gt;  35:&lt;/SPAN&gt;     }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum36&gt;  36:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;As you can see – this is really simple, and most important procedural – there isn’t a state machine, or any explicitly state kept at all.&amp;nbsp; This single function loads the file, and sends progress messages and errors asynchronously to the calling thread. &lt;/P&gt;
&lt;P&gt;The initiating thread passes the background thread parameters using the DoWorkEventArgs class.&amp;nbsp; Here, I’ve simply passed the file name as a string, but any class or structure could be passed this way.&lt;/P&gt;
&lt;P&gt;Line 9 is important – it asynchronously passes the first progress message back to the main thread.&amp;nbsp;&amp;nbsp; This includes the progress percentage and the name of the file.&amp;nbsp; Here I’m using &lt;STRONG&gt;int.MinValue&lt;/STRONG&gt; to differentiate the first progress message from subsequent ones.&amp;nbsp; This sentinel value means that the main thread doesn’t have to maintain any state to handle progress messages. &lt;/P&gt;
&lt;P&gt;I mentioned above that this function handles errors, but you don’t see any error handling code!&amp;nbsp; Any errors that occur from opening the file, or reading the data are signaled as exceptions.&amp;nbsp; The BackgroundWorker class will catch these and pass them back tot he main thread.&amp;nbsp; I just love this – it keeps the code here very clean.&lt;/P&gt;
&lt;P&gt;Note the using statement on line 11.&amp;nbsp; It is important to do this when using file I/O objects so the underlying OS objects get cleaned up correctly.&amp;nbsp; See &lt;A href="http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx"&gt;this&lt;/A&gt; for more information.&lt;/P&gt;
&lt;P&gt;The progress percentage value is computed very simply, the code simply keeps track of the file position as a ration to the file size.&amp;nbsp; This is the obvious part.&lt;/P&gt;
&lt;P&gt;Note line 30 – this is very important.&amp;nbsp; It only sends progress messages to the main thread when the value changes – not for every line, which would be quite expensive (give it a try to see).&lt;/P&gt;
&lt;P&gt;The entire AsyncFileLoader.cs file is not very big, only 29 lines of actual code and is very straightforward. &lt;/P&gt;
&lt;P&gt;The code in the main thread to mange the UI is equally straight forward and consists of just a single event handler attached to the open button’s click delegate.&amp;nbsp; This one function does all of the following:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Gets the file name from the user using the open file dialog. &lt;/LI&gt;
&lt;LI&gt;Maintains the UI state, disable buttons,&amp;nbsp; showing/hiding the progress bar, displaying messages, etc. &lt;/LI&gt;
&lt;LI&gt;Creates a the AsyncFileLoader object &lt;/LI&gt;
&lt;LI&gt;Starts the asynchronous file loading operation &lt;/LI&gt;
&lt;LI&gt;Handles progress messages &lt;/LI&gt;
&lt;LI&gt;handles the completion of the operation &lt;/LI&gt;
&lt;LI&gt;Handles errors. &lt;/LI&gt;&lt;/OL&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; OpenAFile_Clicked( &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt; sender, RoutedEventArgs e )&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;try&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt;         OpenFileDialog ofd = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; OpenFileDialog();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum5&gt;   5:&lt;/SPAN&gt;         ofd.CheckFileExists = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum6&gt;   6:&lt;/SPAN&gt;         ofd.DefaultExt = &lt;SPAN style="COLOR: #006080"&gt;"txt"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum7&gt;   7:&lt;/SPAN&gt;         ofd.Title = &lt;SPAN style="COLOR: #006080"&gt;"Open an text File"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum8&gt;   8:&lt;/SPAN&gt;         ofd.Filter = &lt;SPAN style="COLOR: #006080"&gt;"Text|*.txt"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum9&gt;   9:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum10&gt;  10:&lt;/SPAN&gt;         OpenAFile_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum11&gt;  11:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum12&gt;  12:&lt;/SPAN&gt;         ofd.ShowDialog();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum13&gt;  13:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum14&gt;  14:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( ofd.FileName.IsBlank() ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum15&gt;  15:&lt;/SPAN&gt;             OpenAFile_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum16&gt;  16:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum17&gt;  17:&lt;/SPAN&gt;         }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum18&gt;  18:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum19&gt;  19:&lt;/SPAN&gt;         AsyncFileLoader TheLoader = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; AsyncFileLoader();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum20&gt;  20:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum21&gt;  21:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #008000"&gt;//---- Do this when the progress bar is updated&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum22&gt;  22:&lt;/SPAN&gt;         TheLoader.ProgressChanged += ( Sender, ArgsX ) =&amp;gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum23&gt;  23:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum24&gt;  24:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( ArgsX.ProgressPercentage == &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.MinValue ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum25&gt;  25:&lt;/SPAN&gt;                 Cancel_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum26&gt;  26:&lt;/SPAN&gt;                 Cancel_Button.Click += TheLoader.PerformCancel;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum27&gt;  27:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum28&gt;  28:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.Visibility = Visibility.Visible;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum29&gt;  29:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.Value = 0;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum30&gt;  30:&lt;/SPAN&gt;                 Info_TextBox.Text = ArgsX.UserState &lt;SPAN style="COLOR: #0000ff"&gt;as&lt;/SPAN&gt; String;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum31&gt;  31:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum32&gt;  32:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum33&gt;  33:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.Value = ArgsX.ProgressPercentage;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum34&gt;  34:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum35&gt;  35:&lt;/SPAN&gt;         };&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum36&gt;  36:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum37&gt;  37:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #008000"&gt;//---- Do this when the background worker is completed &lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum38&gt;  38:&lt;/SPAN&gt;         TheLoader.RunWorkerCompleted += ( SenderX, ArgsX ) =&amp;gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum39&gt;  39:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum40&gt;  40:&lt;/SPAN&gt;             RunWorkerCompletedEventArgs args = ArgsX &lt;SPAN style="COLOR: #0000ff"&gt;as&lt;/SPAN&gt; RunWorkerCompletedEventArgs;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum41&gt;  41:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum42&gt;  42:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( args.Error != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt; ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum43&gt;  43:&lt;/SPAN&gt;                 PopErrorDialog( args.Error, &lt;SPAN style="COLOR: #006080"&gt;"Cannot process file!"&lt;/SPAN&gt; );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum44&gt;  44:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum45&gt;  45:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum46&gt;  46:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( args.Cancelled ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum47&gt;  47:&lt;/SPAN&gt;                 Info_TextBox.Text = &lt;SPAN style="COLOR: #006080"&gt;"Loading cancled"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum48&gt;  48:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum49&gt;  49:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum50&gt;  50:&lt;/SPAN&gt;                 Info_TextBox.Text = &lt;SPAN style="COLOR: #006080"&gt;"File Loaded"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum51&gt;  51:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum52&gt;  52:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum53&gt;  53:&lt;/SPAN&gt;             Cancel_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum54&gt;  54:&lt;/SPAN&gt;             Cancel_Button.Click -= TheLoader.PerformCancel;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum55&gt;  55:&lt;/SPAN&gt;             OpenProgress_ProgressBar.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum56&gt;  56:&lt;/SPAN&gt;             OpenProgress_ProgressBar.Visibility = Visibility.Hidden;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum57&gt;  57:&lt;/SPAN&gt;             OpenAFile_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum58&gt;  58:&lt;/SPAN&gt;         };&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum59&gt;  59:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum60&gt;  60:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #008000"&gt;//---- Start the ascynrnous file loading operation&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum61&gt;  61:&lt;/SPAN&gt;         TheLoader.RunWorkerAsync( ofd.FileName );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum62&gt;  62:&lt;/SPAN&gt;     }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum63&gt;  63:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;catch&lt;/SPAN&gt; ( Exception Ex ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum64&gt;  64:&lt;/SPAN&gt;         PopErrorDialog( Ex, &lt;SPAN style="COLOR: #006080"&gt;"General Failure!"&lt;/SPAN&gt; );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum65&gt;  65:&lt;/SPAN&gt;     }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum66&gt;  66:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;DIV&gt;Functional programming is key to making this code clean and straight forward.&amp;nbsp;&amp;nbsp; Here we’re using lambda functions connected to the AsyncFileLoader’s progress and completion events.&lt;/DIV&gt;
&lt;P&gt;You can see in the progress changed handler how no state needs to be kept – this lambda function gets all the data it needs from the event.&amp;nbsp;&amp;nbsp; You can see how the sentinel value (int.MinValue) is used to trigger the change in UI state.&lt;/P&gt;
&lt;P&gt;Completion is handles in a similarly manner and resets the UI state.&amp;nbsp;&amp;nbsp; This lambda also handles any errors thrown by the loader by checking the args.Error member which will reference an exception if one was thrown.&lt;/P&gt;
&lt;P&gt;This is a great example of using multi-threaded programming for something other than speeding up a computationally bound algorithm using parallelization.&amp;nbsp;&amp;nbsp; Some may suggest that this isn’t “real multi-core” programming, but it is.&amp;nbsp; Indeed, the developer doesn’t need to know how to implement complex inter thread communication or synchronization, but just because this isn’t hard, doesn’t mean it isn’t real multi-threaded, and multi-core enabled code.&amp;nbsp; It absolutely is and the developer does need to understand asynchronous programming techniques to use it. &lt;/P&gt;
&lt;P&gt;Using the BackgroundWorker class is a very simple straight forward way to enable your programs to be more responsive, and to leverage multi-threaded and multi-core performance.&amp;nbsp;&amp;nbsp; You can use other managed code techniques such as threads and dispatching for more sophisticated work.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ef56a28c-723b-4ae1-8908-a387f076f35d class=wlWriterEditableSmartContent&gt;del.icio.us Tags: &lt;A href="http://del.icio.us/popular/performacne" rel=tag mce_href="http://del.icio.us/popular/performacne"&gt;performacne&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/programming" rel=tag mce_href="http://del.icio.us/popular/programming"&gt;programming&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/C%23" rel=tag mce_href="http://del.icio.us/popular/C%23"&gt;C#&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/multi-core" rel=tag mce_href="http://del.icio.us/popular/multi-core"&gt;multi-core&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/multicore" rel=tag mce_href="http://del.icio.us/popular/multicore"&gt;multicore&lt;/A&gt;&lt;/DIV&gt;
&lt;P&gt;You can find the complete VS 2008 project in the attached ZIP file.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9859413" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/9859413.ashx" length="11021" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category></item><item><title>So just what is in a trace? Using the xperf trace dumper</title><link>http://blogs.msdn.com/pigscanfly/archive/2008/03/16/so-just-what-is-in-a-trace-using-the-xperf-trace-dumper.aspx</link><pubDate>Sun, 16 Mar 2008 19:04:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8261959</guid><dc:creator>rgr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/8261959.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=8261959</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=8261959</wfw:comment><description>&lt;p&gt;There is a lot of information in a typical kernel trace.&amp;#160; While the Performance Analyzer tool is quite powerful and makes it easy to view a trace graphically, sometimes you just need to see what is in the trace directly.&amp;#160; Xperf makes this easy.&lt;/p&gt;  &lt;p&gt;First, its important to understand that a trace file (.ETL) is simply just the buffers produced by trace session written to a file.&amp;#160; The data in an ETL file isn't pre-processed, summarized, or otherwise annotated with meta data as it comes out of the OS.&amp;#160; Its is just the raw data that comes from a ETW session.&amp;#160; This is because ETW is designed for log time efficiency - ETW does the absolutely minimal amount of work needed to get the trace data to a file, or other consumer. &lt;/p&gt;  &lt;p&gt;This means that all the heavy lifting of post processing trace data happens later. With the xperf tools, there are two places where this occurs:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;In the merge step, xperf takes the kernel trace and trace files and merges them into a single trace file.&amp;#160; Xperf will merges (adds) meta data to the trace (I've got another post that provides all the detailed on merging in the works...).&amp;#160; The result of merging is a single trace file that can be analyzed by the tools directly on the target machine, or copied to another system for analysis.&amp;#160;&amp;#160; Note that the merge step &lt;u&gt;must&lt;/u&gt; happen on the system where the trace was taken (the target system).       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;When a trace is processed xperf using actions, or loaded into Performance Analyzer, the core trace processing components do a lot of work on the raw trace data.&amp;#160; This includes things like mapping process IDs (PIDs) to file and process names, mapping addresses to filenames, loading symbols for address, unifying stacks, and handling 64-bit and 32-bit differences. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;As you've seen in the &lt;a href="http://blogs.msdn.com/pigscanfly/pages/xperf-articles.aspx" target="_blank"&gt;other posts&lt;/a&gt;, once a trace is merged it can be viewed in the Performance Analyzer.&amp;#160; But, xperf also allows you to see what is in the trace using the dumper action.&amp;#160; This is easy to do:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier New"&gt;&lt;strong&gt;xperf -i fs.etl -a dmper &amp;gt;fs.csv&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The &lt;strong&gt;&lt;font face="Courier New"&gt;-i fs.etl&lt;/font&gt;&lt;/strong&gt; specified that the input file is FS.ETL.&amp;#160;&amp;#160;&amp;#160; The &lt;font face="Courier New"&gt;&lt;strong&gt;-a dumper&lt;/strong&gt;&lt;/font&gt; parameter tells xperf to execute the dumper action.&amp;#160;&amp;#160; The output goes to the standard output.&lt;/p&gt;  &lt;p&gt;There is a short cut for this as well: the dumper action is the default action so if you only specify an input file then xperf simply dumps it.&amp;#160;&amp;#160; For example, the following command does the same thing as the one above:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier New"&gt;&lt;strong&gt;xperf -i fs.etl&amp;#160; &amp;gt;fs.csv&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The resulting file is an ANSI text file where each line is one record.&amp;#160;&amp;#160; Each record consists of a comma delimited set of fields.&amp;#160; The first field of each line is the name (or type) of the record.&amp;#160; &lt;/p&gt;  &lt;p&gt;There are some special lines and sections at the front of the file.&amp;#160;&amp;#160; Each record type is described by a header line.&amp;#160;&amp;#160; The header lines are delimited by the &lt;strong&gt;'BeginHeader'&lt;/strong&gt; and &lt;strong&gt;'EndHeader'&lt;/strong&gt; lines.&amp;#160;&amp;#160; Note that the line immediately after the 'EndHeader' line is unique, it doesn't have a header line.&amp;#160; This line describes some of the characteristics of the trace such as its duration, and the pointer size.&lt;/p&gt;  &lt;p&gt;The first field of each header line is the name (or type) of the ETW record that the header line describes.&amp;#160; The rest of the fields are the names of each of the fields for the record type.&amp;#160; Here is an example of the process start event header (P-Start) and a P-Start event. &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier New"&gt;P-Start,&amp;#160; TimeStamp, Process Name ( PID),&amp;#160; ParentPID,&amp;#160; SessionID,&amp;#160; UniqueKey, UserSid, Command Line&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Courier New"&gt;P-Start, 1017280, fs.exe (3004), 3608, 1, 0x86661508,        &lt;br /&gt;S-1-5-21-626881126-397955417-188441333-3225678, c:\coding\fs\Release\fs\fs.exe&amp;#160; blflargorg c:\coding\*.cpp *.h -s&lt;/font&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This event describes the start of a process.&amp;#160; There is also a corresponding P-End event. For processes that are already running when he trace is begun, the kernel logger includes a pseudo P-Start event.&amp;#160; &lt;/p&gt;  &lt;p&gt;This means that every PID seen in other events will have a corresponding P-Start event in the trace before it is seen in an event. &lt;/p&gt;  &lt;p&gt;Also note that xperf will dump events that you add to your own applications so long as you include an &lt;a href="http://msdn2.microsoft.com/en-us/library/aa384043(VS.85).aspx" target="_blank"&gt;event manifest&lt;/a&gt; in your app.&amp;#160; So, you can add your own events and use xperf to dump them in the context of all the other events you include in the trace. &lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:14307c8f-2b25-40e1-bae1-3e6d6a7fb480" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/performance" rel="tag"&gt;performance&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/xperf" rel="tag"&gt;xperf&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/windows" rel="tag"&gt;windows&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8261959" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/xperf/default.aspx">xperf</category></item><item><title>Using the Windows Sample Profiler with Xperf</title><link>http://blogs.msdn.com/pigscanfly/archive/2008/03/02/using-the-windows-sample-profiler-with-xperf.aspx</link><pubDate>Sun, 02 Mar 2008 20:06:12 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7991482</guid><dc:creator>rgr</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/7991482.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=7991482</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=7991482</wfw:comment><description>&lt;p&gt;Using the xperf tools, ETW, and the kernel sample profile interrupt all together provides a very effective and easy to use sample profiler for the analysis of both application and system wide performance.&amp;#160; At each sample interrupt, the ETW sub-system captures the instruction pointer and the stack.&amp;#160; This data is lazily and efficiently logged to an ETL file.&amp;#160; Once the data is saved, it can be analyzed with Performance Analyzer.&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;The next article in this series is&amp;#160; &lt;/em&gt;&lt;a href="http://blogs.msdn.com/pigscanfly/archive/2008/03/16/so-just-what-is-in-a-trace-using-the-xperf-trace-dumper.aspx"&gt;So just what is in a trace? Using the xperf trace dumper&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;&lt;u&gt;Note:&lt;/u&gt;&lt;/em&gt; &lt;em&gt;the examples in this post only works on Vista or Server 2008 32-bit;&amp;#160; Prior operating system's do not support taking stack traces.&amp;#160; Taking stack traces on 64-bit platforms will be the topic of another post.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Here is an example of profiling FS.EXE, a grep-like utility I've written.&amp;#160; I use this tool for experimenting with various topics such as efficient I/O, well performing string matching algorithms, and instrumenting applications with ETW. &lt;/p&gt;  &lt;p&gt;For this test, I put the following commands in a CMD file: &lt;/p&gt;  &lt;ul&gt;   &lt;ul&gt;     &lt;li&gt;&lt;font face="Courier New" size="2"&gt;xperf -on PROC_THREAD+LOADER+INTERRUPT+DPC+PROFILE          &lt;br /&gt;-stackwalk profile           &lt;br /&gt;-minbuffers 16 -maxbuffers 1024 -flushtimer 0           &lt;br /&gt;-f e:\tmp.etl           &lt;br /&gt;&lt;/font&gt;&lt;/li&gt;      &lt;li&gt;&lt;font face="Courier New" size="2"&gt;fs.exe farglenorgin c:\coding\*.cpp *.h -s          &lt;br /&gt;&lt;/font&gt;&lt;/li&gt;      &lt;li&gt;&lt;font face="Courier New" size="2"&gt;xperf -d profile.etl&lt;/font&gt; &lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;p&gt;Since the commands are a bit long, I've separated them above and added line breaks to make them readable.&amp;#160; Each command above should be on one line in your command file.&lt;/p&gt;  &lt;p&gt;The first command turns on the kernel logger and enables the following events:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;PROC_THREAD flag enables the &lt;a href="http://msdn2.microsoft.com/en-us/library/aa364092(VS.85).aspx" target="_blank"&gt;process&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/aa364132(VS.85).aspx" target="_blank"&gt;thread&lt;/a&gt; events. These mark the beginning and ending of each process and thread.&amp;#160; The kernel provider guarantees that there will be a begin/end pair for every process and thread during the trace.&amp;#160;&amp;#160; Process and threads that exist before the trace was started or are still running when the trace is stopped also have these events. &lt;/li&gt;    &lt;li&gt;The LOADER flag enables the &lt;a href="http://msdn2.microsoft.com/en-us/library/aa364068(VS.85).aspx" target="_blank"&gt;loader events&lt;/a&gt; that log when the kernel loads an image (an EXE or DLL) &lt;/li&gt;    &lt;li&gt;The INTERRUPT&amp;#160; and DPC flags enable the ETW &lt;a href="http://msdn2.microsoft.com/en-us/library/aa964780(VS.85).aspx" target="_blank"&gt;interrupt&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/aa964748(VS.85).aspx" target="_blank"&gt;DPC&lt;/a&gt; events which mark each interrupt and deferred procedure call which are routines that run at &lt;a href="DISPATCH_LEVEL" target="_blank"&gt;DISPATCH_LEVEL&lt;/a&gt;t &lt;/li&gt;    &lt;li&gt;The PROFILE flag does two things; it turns on the systems sample profile interrupt and it enables the kernel's &lt;a href="http://msdn2.microsoft.com/en-us/library/aa964806(VS.85).aspx" target="_blank"&gt;sample profile ETW event&lt;/a&gt;. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The other flags are important as well.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The &lt;strong&gt;-stackwalk profile&lt;/strong&gt; parameter turns on ETW's stack walking feature for the sample profile event.&amp;#160;&amp;#160; Every time a sample profile event is triggered by the sample profile interrupt, ETW will capture the stack and save the data in the trace buffers.&amp;#160;&amp;#160; &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;-minbuffers 16&lt;/strong&gt; parameter sets the minimum number of buffers that ETW will allocate for storing events.&amp;#160; Note, you need at least two for each processor in you system. &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;-maxbuffers 1024&lt;/strong&gt; parameter sets the maximum number of buffers ETW will allocate to 1024 - a total of 64MB. &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;-flushtimer 0&lt;/strong&gt; parameter tells ETW to never flush the buffers based on&amp;#160; timer, buffer's will only be written to disk when they are full. &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;-f e:\tmp.etl&lt;/strong&gt; parameter tells ETW to lazily write the full ETW buffers to e:\tmp.etl.&amp;#160;&amp;#160; This puts the log file on a different physical drive than the drive on which the experiment is running.&amp;#160; This means that the writes that ETW uses to save the trace data do not occur on the interesting drive. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The second command simply runs the experiment.&amp;#160; It searches for the string '&lt;font face="Courier New"&gt;farglenorgin&lt;/font&gt;' in all my .CPP and .H files.&amp;#160; I'm using a string that doesn't exist so I execute the worst case code paths in the application.&amp;#160; Replace this command with a command to run your experiment, or a pause instruction so you can dork around with a graphical program. &lt;/p&gt;  &lt;p&gt;The third command simply stops the kernel logger, merges the data and saves it in &lt;strong&gt;profile.etl&lt;/strong&gt;. &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;font color="#ff8000"&gt;NOTE: &lt;/font&gt;&lt;/strong&gt;These commands need to be run from an elevated command prompt.&amp;#160;&amp;#160; Controlling ETW tracing requires administrative privileges.&lt;/em&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;There is now one other thing to do before examining the data - setting the symbol path.&amp;#160;&amp;#160; Here is how I set the symbol path for this example:&amp;#160; &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier New"&gt;set _NT_SYMBOL_PATH =        &lt;br /&gt;&lt;/font&gt;&lt;font face="Courier New" size="2"&gt;c:\coding\fs\release\fs;        &lt;br /&gt;&lt;/font&gt;&lt;font face="Courier New" size="2"&gt;SRV*c:\symbols*http://msdl.microsoft.com/download/symbols&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This tells the symbol decoder to look for symbols in the release build directory for FS.EXE and in the Windows public symbol server, caching the served symbols in c:\symbols.&amp;#160; The xperf tools uses the symbol decoding libraries from the &lt;a href="http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx" target="_blank"&gt;debugging tools for Windows&lt;/a&gt;.&amp;#160; You can find more information on using symbols &lt;a href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Once the trace is taken and the symbol path is set, then simply open the trace in Performance Analyzer with the command &amp;quot;&lt;strong&gt;&lt;font face="Courier New" size="2"&gt;xperf profile.etl&lt;/font&gt;&lt;/strong&gt;&amp;quot;.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 5px; border-right-width: 0px" height="112" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_1.png" width="235" align="right" border="0" /&gt;&lt;/a&gt;The CPU Sampling by Process graph is the most interesting graph for this example.&amp;#160; To select the visible graphs, click on the flyout control on the left of the window, then select the CPU Sampling by CPU, and by Process graphs.&lt;/p&gt;  &lt;p&gt;For his experiment, the CPU sampling by Process graph looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_36.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="126" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_17.png" width="538" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;By default, all processes running during the trace are shown except the idle task (as seen above).&amp;#160; You can change which processes are displayed or hidden by by using the check boxes in the legend drop down as shown above.&lt;/p&gt;  &lt;p&gt;This graph illustrates an important concept about the kernel event provider and the xperf tools in general - they are specifically designed to analyze system wide and application performance data and events.&amp;#160; For example, in the legend above, there are many processes listed, but only a few of them actually used any CPU time during the experiment. &lt;/p&gt;  &lt;p&gt;Using the legend, you can eliminate all processes except the interesting one.&amp;#160;&amp;#160; Here is what the graph of CPU utilization for only FS.EXE looks like&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_10.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="209" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_4.png" width="523" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This is pretty cool as it provides a nice overview of the CPU utilization of FS.EXE, but it really doesn't tell us much about where time is being spent in the process it self.&lt;/p&gt;  &lt;p&gt;The real power in Performance Analyzer is in its summary tables.&amp;#160; These are tabular displays of data about a specific chart, or a region in a chart.&amp;#160; For this experiment, I looked at the sample profile data for the entire trace.&amp;#160; To do this, right mouse click on the CPU Sampling by Process chart, make sure that the load symbols option is set, then select the Summary table view. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_12.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="212" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_5.png" width="529" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note, it will take 10 to 20 seconds for the summary table to show up.&amp;#160; Performance Analyzer is loading symbols while this is happening.&amp;#160; (putting symbol loading on a background thread is on our to do list...).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_14.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 5px; border-right-width: 0px" height="103" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_6.png" width="108" align="right" border="0" /&gt;&lt;/a&gt;After the summary table pops up, click on the flyout and select the columns for display.&amp;#160; In this case you will want the process, stack and % Weight columns (feel free to experiment with other columns).&amp;#160; &lt;/p&gt;  &lt;p&gt;Next, arrange the columns as follows.&amp;#160; The columns to the left of the gold column are grouping columns.&amp;#160;&amp;#160; You can change the order of columns and put them to the left or right of the gold column by dragging.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_16.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="72" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_7.png" width="529" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Now, you can expand the stacks for FS.EXE and see where it is spending its time.&amp;#160; Not that this isn't by function as in some profilers but by &lt;u&gt;call stack&lt;/u&gt;.&amp;#160; This is much more powerful than simply knowing the functions where time is spent as it also shows you how the time consuming functions were called.&lt;/p&gt;  &lt;p&gt;Its no surprise that my find string utility spends most of its time in the following stack:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_20.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="361" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_9.png" width="536" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;As with other sample profilers, you can look &amp;quot;up&amp;quot; and &amp;quot;down&amp;quot; the stacks from any particular point. This is commonly called a butterfly view.&amp;#160; Right mouse click on any item in the stack column and experiment with the &lt;em&gt;callers/callees&lt;/em&gt; and &lt;em&gt;inntermost/outermost&lt;/em&gt; options, like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_22.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="206" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_10.png" width="452" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This stack trace has very simple call stacks so it isn't very useful for looking at butterfly views.&amp;#160; But try one of your own programs and look at a butterfly stack view of a function that is called often from multiple places.&amp;#160;&amp;#160; Or, use the butterfly view too look at a intermediate function and see all the functions it calls, and their stacks. &lt;/p&gt;  &lt;p&gt;The above screen shots and summary table views contain the data from the entire trace.&amp;#160;&amp;#160; This works ok for short traces.&amp;#160; But for longer traces, or even short traces with a lot of detail, we often need to look at specific time spans.&amp;#160; &lt;/p&gt;  &lt;p&gt;For example, there are some time spans in my experiment where FS isn't using very little CPU time.&amp;#160; I'd like to see what FS is up to in that time span.&amp;#160; This is easily done by using the left mouse button to select a time span on the X axis and zooming the graph to that view, or look at the summary table for that span, as in this example.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_30.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="228" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_14.png" width="531" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_32.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 5px; border-right-width: 0px" height="118" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_15.png" width="163" align="right" border="0" /&gt;&lt;/a&gt;Once the interesting region is selected, I simply use the right mouse button to pop up the context menu and select summary table.&amp;#160; &lt;/p&gt;  &lt;p&gt;Note that you can open up multiple summary tables, each from different regions of a graph, or even different graphs.&amp;#160; This is great for making comparisons.&lt;/p&gt;  &lt;p&gt;The new summary table window now only shows the data for selected time span in the trace.&amp;#160; Is not surprising that FS is spending the little CPU time it is using in user mode asynchronous procedure calls. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_34.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="288" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UsingWindowsSampleProfilerwithXperf_9E19/image_thumb_16.png" width="536" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This post illustrates some key concepts:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The xperf tools are designed for both system wide and application specific analysis. &lt;/li&gt;    &lt;li&gt;Profiling with ETW is very, very light weight.&amp;#160; While the experiment is running, the xperf tools are not even loaded - the kernel itself is collecting the data.&amp;#160;&amp;#160; All analysis is done as post processing tasks. &lt;/li&gt;    &lt;li&gt;OS based sample profiling collects both user and kernel mode stacks.&amp;#160;&amp;#160; &lt;/li&gt;    &lt;li&gt;So long as you have symbols, production code can be profiled - no special debug or instrumented builds are required. &lt;/li&gt;    &lt;li&gt;In this example, I started and stopped FS.exe (the experiment) between the tracing start and stop.&amp;#160; But, since this is ETW based, sample profiling can be started and stopped at any time, without stopping or restating even a single process.&amp;#160; You can profile anything at any time on any system. &lt;/li&gt;    &lt;li&gt;Stack views provide a very powerful method for analyzing where time is spent in a process. &lt;/li&gt;    &lt;li&gt;The general technique with Performance Analyzer is to use the graphics to identify interesting time spans in the trace, then use the summary tables to look at the data in detail. &lt;/li&gt; &lt;/ul&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0a4849cb-6ab2-401e-8382-df6f25b204c5" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/performance" rel="tag"&gt;performance&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/windows" rel="tag"&gt;windows&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/tools" rel="tag"&gt;tools&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/xperf" rel="tag"&gt;xperf&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7991482" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/xperf/default.aspx">xperf</category></item><item><title>Xperf support for XP</title><link>http://blogs.msdn.com/pigscanfly/archive/2008/02/24/xperf-support-for-xp.aspx</link><pubDate>Sun, 24 Feb 2008 20:56:35 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7880729</guid><dc:creator>rgr</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/7880729.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=7880729</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=7880729</wfw:comment><description>&lt;p&gt;&amp;quot;Do the xperf tools support XP or Windows Server 2003?&amp;quot; is a frequently ask question.&amp;#160; The answer is no mostly, and yes for a few things.&amp;#160; &lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;The next article in this series is &lt;/em&gt;&lt;a href="http://blogs.msdn.com/pigscanfly/archive/2008/03/02/using-the-windows-sample-profiler-with-xperf.aspx"&gt;&lt;em&gt;Using the Windows Sample Profiler with Xperf&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;xperf.exe&lt;/strong&gt; can be used on Windows XP SP2, and Windows Server 2003 for turning tracing on and of, and merge kernel trace data with user mode traces into a single ETL file.&amp;#160;&amp;#160; These operations are simply called &amp;quot;trace control&amp;quot;.&amp;#160;&amp;#160; NOte that the '&lt;strong&gt;&lt;font face="Courier New"&gt;-stackwalk&lt;/font&gt;&lt;/strong&gt;' switch is not supported on XP because its kernel doesn't support capturing the stack on events, this is anew feature in the Vista kernel.&lt;/p&gt;  &lt;p&gt;However, all operations that require trace decoding (and that's almost everything else), must be done on Vista or Windows Server 2008.&amp;#160; This includes viewing traces in the Windows Performance Analyzer tool (&lt;strong&gt;xperfview.exe&lt;/strong&gt;).&lt;/p&gt;  &lt;p&gt;The next question is this &amp;quot;The xperf tool kit installer doesn't install the tools on XP or WS2003; how do I get the tools on those systems?&amp;quot;&lt;/p&gt;  &lt;p&gt;The answer is simple: From a Vista or WS2008 installation copy &lt;strong&gt;&lt;font face="Courier New"&gt;xperf.exe&lt;/font&gt; &lt;/strong&gt;and &lt;strong&gt;&lt;font face="Courier New"&gt;perfctrl.dll&lt;/font&gt;&lt;/strong&gt; to the target system. This is all xperf needs to support trace control&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;After you have generated an ETL file, you can then copy it to a Vista or WS2008 system for trace decoding.&amp;#160; &lt;/p&gt;  &lt;p&gt;For those of you interested in the long story....&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&amp;lt;boooring&amp;gt;      &lt;br /&gt;&lt;/strong&gt;Event Tracing for Windows was first introduced in Windows in 2000.&amp;#160; Back then, the OS only supported a small number of events; very few other Window's components used ETW.&amp;#160;&amp;#160; In those days, event logging with ETW was in its infancy and the people that wrote event consumers generally also wrote the code that produced the events, or worked closely with those that did.&lt;/p&gt;  &lt;p&gt;Back in the day, many event providers and consumer's simply used the same C/C++ data structures to produce and consume events.&amp;#160; While simple, this sometimes broke because people wouldn't version the events correctly when the event structure changed.&amp;#160; In short, if the producer and the consumer code wasn't kept in sync then things were busted.&amp;#160; This got to be a real problem as ETW was used more broadly.&lt;/p&gt;  &lt;p&gt;This problem was solved by using meta to describe events.&amp;#160; This allowed event consumers to decode events without knowledge of the events binary format.&amp;#160; This worked much better; it allowed the event provider author to change an event's binary format without breaking the consumer.&amp;#160; In the XP time frame &lt;a href="http://www.wbemsolutions.com/tutorials/CIM/cim-mof.html" target="_blank"&gt;MOF files&lt;/a&gt; were used to describe events.&amp;#160;&amp;#160; For example, you can find he kernel's context switch event &lt;a href="http://msdn2.microsoft.com/en-us/library/aa964744(VS.85).aspx" target="_blank"&gt;here&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Three things changed for Vista:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The entire Windows build system was updated so that every component was described by an XML based &lt;a href="http://msdn2.microsoft.com/en-us/library/aa375632.aspx" target="_blank"&gt;manifest&lt;/a&gt;.&amp;#160; This included describing ETW events.&amp;#160; We deprecated the MOF format and all new events were authored with XML based descriptions in their manifests using the &lt;a href="http://msdn2.microsoft.com/en-us/library/aa384043(VS.85).aspx" target="_blank"&gt;Event Manifest Schema&lt;/a&gt;.&amp;#160;&amp;#160; &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;The use of ETW became very prevalent - many teams added event providers to their components and used them for &lt;a href="http://msdn2.microsoft.com/en-us/library/aa385780(VS.85).aspx" target="_blank"&gt;Windows Event Logging&lt;/a&gt; (which is ETW based), performance work, diagnostics, and testing.&amp;#160; For example, on my laptop, there are 985 registered ETW event providers.&amp;#160; Use the &amp;quot;xperf -provider&amp;quot; command to see what is registered on your system.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Our team decided to make a major investment in ETW based tools as did other teams around Windows.&amp;#160; This meant that meta information for events was very important as it enabled event providers and the consumers to be more decoupled and cohesive. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;But, this posed one problem for us: do we fully support trace decoding on both Vista and XP?&amp;#160; Or just on Vista?&amp;#160; It was technically possible to keep trace decoding working on XP, but this would require shipping some Vista components with the tools because the required trace decoding infrastructure is only present on Vista.&amp;#160; Unfortunately, this isn't possible for all kinds of business, legal, and some technical reasons.&amp;#160; It would have also doubled our test matrix.&lt;/p&gt;  &lt;p&gt;After much discussion, we decided it was an easily workable compromise to support trace collection on XP, and require Vista or WS2008 for all trace decoding operations.    &lt;br /&gt;&lt;strong&gt;&amp;lt;/boooring&amp;gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:1df2a6b9-40be-4e4d-b9de-cb588180a372" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/xperf" rel="tag"&gt;xperf&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/windows" rel="tag"&gt;windows&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/performance" rel="tag"&gt;performance&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/tools" rel="tag"&gt;tools&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7880729" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/xperf/default.aspx">xperf</category></item><item><title>Using Xperf to take a Trace (updated)</title><link>http://blogs.msdn.com/pigscanfly/archive/2008/02/16/using-xperf-to-take-a-trace.aspx</link><pubDate>Sat, 16 Feb 2008 05:32:20 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7727028</guid><dc:creator>rgr</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/7727028.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=7727028</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=7727028</wfw:comment><description>&lt;p&gt;Lets get to it!&amp;#160; Here is how to take a basic trace then look at CPU and disk utilization.&amp;#160;&amp;#160;&amp;#160; Its really simple, just three commands to turn on tracing, turn it off, and then view the trace. &lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;The next article in this series is &lt;a href="http://blogs.msdn.com/pigscanfly/archive/2008/02/24/xperf-support-for-xp.aspx"&gt;Xperf support for XP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;First, from an elevated command prompt window, enable a basic set of the kernel events using this command:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;&lt;font face="Courier New" size="2"&gt;xperf -on PROC_THREAD+LOADER+DISK_IO+HARD_FAULTS+INTERRUPT+DPC+CSWITCH -maxbuffers 1024&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This command enables a set of events in the kernel and sets the maximum number of buffers to 1024.&amp;#160; The default size for each buffer is 64K.&amp;#160; So for this session, ETW will use up to 64MB of memory for ETW buffers.&amp;#160; As buffers are filled with events, they are written to the log file in the background and then made available again for accepting events.&amp;#160; By default, xperf sets the minimum number of buffers to 64.&amp;#160; ETW will start with this many buffers and only allocate more buffers if needed.&amp;#160; Events will only be lost if ETW cannot allocate more buffers and/or keep up with the event rate by writing data to the disk. By default, the kernel events are written to \kernel.etl on the current drive. &lt;/p&gt;  &lt;p&gt;Next, do something interesting - it can be anything from opening Internet explorer and a web page, or compiling a program with Visual studio, to something more complex like opening three or four Microsoft Office applications and doing some work.&lt;/p&gt;  &lt;p&gt;Run the following command when your interesting thing is done: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;&lt;font face="Courier New" size="2"&gt;xperf -d foo.etl&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;This simple command will take 10 to 30 seconds (or possibly longer) because it merging the raw kernel event data with meta data and doing some other post processing.&amp;#160; We call this 'stop and merge'.&amp;#160; Here is what this command does&lt;/p&gt;  &lt;ol dir="ltr"&gt;   &lt;li&gt;     &lt;p&gt;Performs a 'run down', during which the kernel logs a set of events that describe the state of the system.&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;Turns off the kernel logger&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;Interlaces data from multiple trace files and the kernel trace.&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;Adds some meta info to the trace needed for processing the trace on other systems. This data is saved in the trace as a set of synthetic events.&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;Saves the trace data into the file foo.etl (or the file name of your choice).&lt;/div&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;Finally, load the trace in the Performance Analyzer with the following command&lt;/p&gt;  &lt;blockquote&gt;   &lt;p dir="ltr" style="margin-right: 0px"&gt;&lt;strong&gt;&lt;font face="Courier New" size="2"&gt;xperf foo.etl&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;For this example, I took a trace of using Visual Studio 2008 to compile a program.&amp;#160; Here are screen shots of the CPU Usage by CPU and for disk I/O counts.&lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="167" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_thumb.png" width="494" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="167" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_thumb_1.png" width="493" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_8.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 5px 0px 0px; border-right-width: 0px" height="244" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_thumb_3.png" width="186" align="left" border="0" /&gt;&lt;/a&gt; Those are pretty interesting, but lots of things are running in the system, and I'd like to see just the CPU usage for Visual Studio itself.&lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;The CPU usage by process graph makes this easy, just click on the fly out control on the left of the window and select the &lt;em&gt;CPU Usage by Process &lt;/em&gt;graph.&amp;#160; &lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;The fly out frame lists the graphs available for the events in the trace.&amp;#160; If there trace doesn't contain events that are needed for a particular graph, then the graph is not shown.&lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;Performance Analyzer will automatically save the graphs you have selected.&amp;#160; You can change them at any time. &lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;For my trace, the CPU usage for the DEVENV.EXE process and two CL.EXE processes looked like this.&lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_10.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="180" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_thumb_4.png" width="532" border="0" /&gt;&lt;/a&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/UseXperftotakeaTrace_D92D/image_10.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;DEVENV is the Visual Studio 2008 environment itself.&amp;#160;&amp;#160; The CL.EXE processes are the two compiler sessions it started, one for each CPU on my laptop. &lt;/p&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;This is a simple example that illustrates some key points&lt;/p&gt;  &lt;ol dir="ltr"&gt;   &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;The kernel events can be enabled and disabled at any time.&amp;#160; There is no need to re-boot the system, log-out/log-in, or restart processes to use the kernel events, or any ETW event provider.&amp;#160; ETW events from any source can be dynamically controlled at run time.        &lt;br /&gt;&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;The xperf tools are designed for a post processing model, one where a trace is captured, then later analyzed.&amp;#160;&amp;#160; This is in contrast to an observational model where you watch dynamic charts, graphics, or tabular data as something occurs.&amp;#160; The reason for this model is that ETW and the tools are designed for log time efficiency.        &lt;br /&gt;&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;This model is also specifically designed for taking traces on one machine, then analyzing them on another machine.&amp;#160;&amp;#160; This ability is critical for running performance tests in a lab setting.        &lt;br /&gt;&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div dir="ltr" style="margin-right: 0px"&gt;The tools let you look at both system wide activity and process specific activity.&lt;/div&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b92c3beb-b7c8-494f-ac9d-cfc31033be04" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/tools" rel="tag"&gt;tools&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/xperf" rel="tag"&gt;xperf&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/performance" rel="tag"&gt;performance&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/windows" rel="tag"&gt;windows&lt;/a&gt;&lt;/div&gt;  &lt;p dir="ltr" style="margin-right: 0px"&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7727028" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/xperf/default.aspx">xperf</category></item><item><title>Xperf Tools Landing Page and Update</title><link>http://blogs.msdn.com/pigscanfly/archive/2008/02/11/xperf-tools-landing-page-and-update.aspx</link><pubDate>Mon, 11 Feb 2008 04:26:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7597045</guid><dc:creator>rgr</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/7597045.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=7597045</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=7597045</wfw:comment><description>&lt;p&gt;The &lt;a href="http://www.microsoft.com/whdc/default.mspx" target="_blank" mce_href="http://www.microsoft.com/whdc/default.mspx"&gt;WHDC&lt;/a&gt; folks now have web page setup for the &lt;a class="" href="http://www.microsoft.com/whdc/system/sysperf/perftools.mspx" target="_blank" mce_href="http://www.microsoft.com/whdc/system/sysperf/perftools.mspx"&gt;Windows Performance Toolkit&lt;/a&gt; (aka the 'xperf tools').&amp;#160; The page includes downloads for updates to the versions that ship in the SDK.&amp;#160; In the near future, this page will include pointers to updated documentation, and discussion forums.&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;The next article in this series is &lt;a href="http://blogs.msdn.com/pigscanfly/archive/2008/02/16/using-xperf-to-take-a-trace.aspx"&gt;Using Xperf to take a Trace (updated)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;This page included downloads for V4.1.1 of the Windows Performance Toolkit.&amp;#160; This download is an updated for the SDK version and includes fixes for two small bugs in the version included in the Windows SDK.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The COM plug in that handles the power management events is not named correctly, so the power state transition analysis feature doesn't work. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:835204dc-25be-46e0-9a7b-461a860d4168" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/windows" rel="tag"&gt;windows&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/performance" rel="tag"&gt;performance&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/xperf" rel="tag"&gt;xperf&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/tools" rel="tag"&gt;tools&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7597045" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/xperf/default.aspx">xperf</category></item><item><title>Xperf, a new tool in the Windows SDK</title><link>http://blogs.msdn.com/pigscanfly/archive/2008/02/09/xperf-a-new-tool-in-the-windows-sdk.aspx</link><pubDate>Sat, 09 Feb 2008 04:59:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7550033</guid><dc:creator>rgr</dc:creator><slash:comments>15</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/7550033.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=7550033</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=7550033</wfw:comment><description>&lt;p&gt;The SDK team just &lt;a href="http://blogs.msdn.com/windowssdk/archive/2008/02/07/windows-sdk-rtms.aspx" target="_blank"&gt;shipped the latest version of the Windows SDK&lt;/a&gt; which supports Windows Server 2008 and Vista SP1.&amp;#160; The SDK now includes an important new tool; the &lt;strong&gt;Windows Performance Tool Kit&lt;/strong&gt; from the Windows performance team (we call them the xperf tools for short...)&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;This is the first article in the xperf series, the next one is      &lt;br /&gt;&lt;/em&gt;&lt;a href="http://blogs.msdn.com/pigscanfly/archive/2008/02/11/xperf-tools-landing-page-and-update.aspx"&gt;&lt;em&gt;Xperf Tools Landing Page and Update&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The xperf tools have long been an internal tool used by our team, and widely throughout Windows, for system-wide performance analysis.&amp;#160; Xperf got its start many years ago as a set of command-line tools that produce reports based off the &lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/04/ETW/default.aspx" target="_blank"&gt;ETW&lt;/a&gt; instrumentation in the kernel[1]. Many other components and applications in Windows are instrumented with ETW and xperf can enable these events, dump them, and analyze them. &lt;/p&gt;  &lt;p&gt;Xperf is an important tool for anyone doing system performance work on Windows because it's specifically designed to give you a complete system-wide view of performance over long periods of time (10's of seconds, to minutes)[2].&amp;#160; It's also the only tool that knows how to fully process all the events from the kernel and correlate them into something that makes sense.&amp;#160; &lt;/p&gt;  &lt;p&gt;For example, here is a detail graph of all the disk I/O to the system drive on my laptop for opening this post, editing it a bit, and then closing Live Writer.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/screen-capture%5B5%5D.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="180" alt="screen-capture[5]" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/screen-capture%5B5%5D_thumb.png" width="517" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Here is an example of the CPU and disk utilization for Outlook 2007 launch:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/image_10.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="215" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/image_thumb_4.png" width="516" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Here is the same view, but with the data from all processes visible:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/image_14.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="216" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/image_thumb_6.png" width="522" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 5px; border-right-width: 0px" height="298" alt="image" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/NewPerformanceToolintheWindowsSDKXPerf_11405/image_thumb_1.png" width="137" align="right" border="0" /&gt;&lt;/a&gt;In addition to graphical displays, the tools can also display tabular data (what we call &amp;quot;summary data&amp;quot;). The screen capture to the right is a table of sample profile events during a 6.5 second period during a find string operation over a tree of source code.&amp;#160; For that period, 73.93% of the total CPU time was in the idle thread, 6.78% was in the find string utility and the reset of the time was distributed around services, the system, xperf itself (at 3%) and other processes. As you start playing with the summary tables, try shifting around the columns to get different types of views on the data; for example, grouping IOs per process, IO type (read/write/...), IO size, IO service time, and so forth.&lt;/p&gt;  &lt;p&gt;These simple examples barely scratch the surface of the data that the tools can gather and the richness of the information they can display.&amp;#160; The tools have several other important features including:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Full support for symbol decoding.&amp;#160; This uses the same mechanism as the &lt;a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx" target="_blank"&gt;Debugging Tools for Windows&lt;/a&gt;.&amp;#160; This includes full support for the &lt;a href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx" target="_blank"&gt;public Windows symbols&lt;/a&gt;, and for your own symbols. &lt;/li&gt;    &lt;li&gt;The ability to dump all the events from a trace file to a CSV file.&amp;#160; If the summary tables don't display what you want, then you can write your own trace processing tools on top of the text dump, or the (generally XML-based) output of the command-line actions. &lt;/li&gt;    &lt;li&gt;Windows Vista supports collecting stack traces on all the kernel events.&amp;#160;&amp;#160; One of the most useful things to do is collecting stack traces on the sample profile event. This is an extremely powerful tool for understanding where and why a program is spending time. &lt;/li&gt;    &lt;li&gt;The xperf command-line tool can be used to control all the ETW trace providers in a system, including all the kernel events.      &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2b4f5071-8aea-4a31-9dd3-7cc21515c462" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/tools%20windows%20performance" rel="tag"&gt;tools windows performance&lt;/a&gt;&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;The xperf distribution also contains a quick start guide and basic reference manual.&amp;#160; Just look for the document &lt;strong&gt;Performance.Analyzer.QuickStart.docx&lt;/strong&gt;, its in XPS format as well. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In the coming weeks, I'll blog more about the tools, how to use them, and the kernel ETW events.&amp;#160;&amp;#160; We'll also soon have a web page up for the tools.&amp;#160;&amp;#160; This is where you will soon find updates, additional documentation, and a message forum.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;u&gt;&lt;font color="#008000"&gt;Now!&amp;#160;&amp;#160; Here is how you can get the tools!&lt;/font&gt; &lt;/u&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Install the SDK by &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=F26B1AA4-741A-433A-9BE5-FA919850BDBF&amp;amp;displaylang=en" target="_blank"&gt;downloading the ISO image&lt;/a&gt;, or &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=E6E1C3DF-A74F-4207-8586-711EBE331CDC&amp;amp;displaylang=en" target="_blank"&gt;using the Web based installer&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;Find the xperf MSI in the SDK's &amp;quot;bin&amp;quot; directory.&amp;#160;&amp;#160; It will be named &lt;strong&gt;xperf_x86.msi&lt;/strong&gt;, &lt;strong&gt;xperf_x64.msi&lt;/strong&gt;, or &lt;strong&gt;xperf_ia64.msi&lt;/strong&gt;, depending on the architecture for which you install the SDK.&amp;#160;&amp;#160; &lt;/li&gt;    &lt;li&gt;You can then install the xperf tools from the MSI directly, or copy the xperf MSI file to another location and install it from there.&amp;#160; For example, you could keep the MSI files on a USB key. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;We'll soon have a web page up for the tools on the MSDN site... stay tuned!&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d62ba28f-15e2-4e49-a95d-8eb46afaf6c2" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/windows" rel="tag"&gt;windows&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/perfomance" rel="tag"&gt;perfomance&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/xperf" rel="tag"&gt;xperf&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/tools" rel="tag"&gt;tools&lt;/a&gt;&lt;/div&gt;  &lt;p&gt;[1]&amp;#160; You can see the events supported by the kernel in the docs for the &lt;strong&gt;EnableFlags&lt;/strong&gt; field of the &lt;a href="http://msdn2.microsoft.com/en-us/library/aa363784(VS.85).aspx" target="_blank"&gt;&lt;strong&gt;EVENT_TRACE_PROPERTIES&lt;/strong&gt;&lt;/a&gt; structure.&amp;#160; I'm going to blog more about these...&lt;/p&gt;  &lt;p&gt;[2] The xperf tools from the Windows Performance Toolkit are very complimentarily to the &lt;a href="http://technet.microsoft.com/en-us/sysinternals/default.aspx" target="_blank"&gt;SysInternals tools&lt;/a&gt;. &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7550033" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/xperf/default.aspx">xperf</category></item><item><title>Beyond Hello World - Update 5, TreeMap Control Working, Perf Issues</title><link>http://blogs.msdn.com/pigscanfly/archive/2007/03/24/beyond-hello-world-update-4-treemap-control-working-perf-issues.aspx</link><pubDate>Sat, 24 Mar 2007 21:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1943307</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1943307.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1943307</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1943307</wfw:comment><description>&lt;P&gt;&lt;A title="CLC Data Viewer project" href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx"&gt;CLCV&lt;/A&gt; V5 now has a fully working &lt;A title="TreeMap description" href="http://www.cs.umd.edu/hcil/treemap/" target=_blank mce_href="http://www.cs.umd.edu/hcil/treemap/"&gt;TreeMap&lt;/A&gt; control that zooms, supports mouse over events and looks pretty good.&amp;nbsp; The regions are&amp;nbsp;laid out with the &lt;A title="Squarified TreeMap algorithm" href="http://www.win.tue.nl/~vanwijk/stm.pdf" target=_blank mce_href="http://www.win.tue.nl/~vanwijk/stm.pdf"&gt;Squarified TreeMap algorithm&lt;/A&gt;.&amp;nbsp; Even better, the tree map itself scales to large numbers of nodes - easily 100's of thousands, and on &lt;A title="my lap top" href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx"&gt;my lap top&lt;/A&gt;, it will handle a couple of million nodes relatively well.&amp;nbsp;&amp;nbsp; But there are two major performance problems:&amp;nbsp; 1) WPF rendering seems to be &lt;EM&gt;very&lt;/EM&gt; expensive.&amp;nbsp; 2) Tree Map nodes are relatively expensive in terms of memory size.&amp;nbsp; This limits the number of nodes to a ~2 million.&amp;nbsp; You can find a link to the source code at the end of this post.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap16.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap16.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN: 0px 0px 0px 10px; BORDER-RIGHT-WIDTH: 0px" height=480 alt="Tree Map Sceen Shot" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap1_thumb6.png" width=345 align=right border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap1_thumb6.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Note - all performance numbers (number of objects, times and profile data) are gathered from my &lt;A title="Acer Ferrari 5000" href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx"&gt;new Acer Ferrari 5000 laptop&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;From a memory usage perspective the control performs acceptably for even a few hundred thousand nodes.&amp;nbsp; Tens of thousands of nodes are no problem.&amp;nbsp; But, it does begin to struggle with about a million, with two million being a empirical limit.&amp;nbsp; A future post on this WPF version of CLCV will focus on memory optimizations and usage in detail.&lt;/P&gt;
&lt;P&gt;For this post, I'll focus on WPF rendering performance.&amp;nbsp; In summary, the primary performance issue that limits the scaling of my treemap control isn't memory or CPU time to compute or render the layout - it is actual physical rendering of the rectangles and text by WPF itself.&amp;nbsp; WPF cannot keep up with more than about 750 rectangles and a small number of scaled text items.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;My treemap control is pretty well optimized (there is still some work to do) - but the computational performance of the control itself is not the limiting factor.&amp;nbsp; The most important aspect of my treemap implementation is that it is smart about how much work it does -limiting its computations and rendering to only the nods that are reasonably large.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;When learning about treemaps, I looked at some existing code and read all the web&amp;nbsp; material I could find.&amp;nbsp; It looks like most implementations are pretty basic - they compute the size and location of each rectangle for the entire tree.&amp;nbsp; I thought this was a bit odd.&amp;nbsp; It seemed to me that it would be more efficient to only process the part of the tree that would be visible - e.g. computing and rendering tiny or invisible rectangles didn't seem like a good design decision to me.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects2.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN: 0px 0px 0px 5px; BORDER-RIGHT-WIDTH: 0px" height=87 alt="Tiny Rectanges" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects_thumb2.png" width=122 align=right border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects_thumb2.png"&gt;&lt;/A&gt;My first implementation took the straight forward approach as well.&amp;nbsp;&amp;nbsp; As I suspected, for larger trees - even those with a only a few thousands nodes, computing and rendering tiny rectangles was a waste of computation and rendering time.&amp;nbsp; As you can see in the image to the right, rectangles that are smaller than some limit are too small to effectively&amp;nbsp;mouse over or to meaningfully discern their relative area with respect to their parent. &lt;/P&gt;
&lt;P&gt;So, I modified both the layout code and the rendering code to stop when the area of the rectangles became less than some threshold.&amp;nbsp; This worked very well both from a visual perspective and performance standpoint.&amp;nbsp; It also allows the data tree to become very large as it means that neither the layout and rendering costs grow with the overall tree size as the number of nodes surpasses the number of rectangles that the algorithm decides to actually render.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Experiment:&lt;/STRONG&gt; CLC V5 includes a unit test for the treemap control that allows you to control the size of the three and set the treemap parameters such as the &lt;STRONG&gt;Area Limit.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT1.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT1.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=177 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT_thumb1.png" width=640 border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT_thumb1.png"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;The area limit is the minimum size of the rectangles that will be rendered.&amp;nbsp; Assuming there are enough nodes, the larger this number, the fewer rectangles will be visible.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;From&amp;nbsp;empirical testing I determined that a value of 64 works pretty well.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;For trees over a one or two thousand nodes, there are usually more nodes than can be displayed.&amp;nbsp;&amp;nbsp; In these scenarios, the scaling limitations are inherent to WPF itself, not the layout computations, or rendering in the treemap control.&lt;/P&gt;
&lt;P&gt;Its important to understand how the control works and when WPF actually does the visible rendering.&amp;nbsp; The treemap control has two main steps:&amp;nbsp;&amp;nbsp; the first is the actual layout computations of the tree, and the second is the rendering of the tree.&amp;nbsp;&amp;nbsp; Once the control is rendered, then WPF will take the rendering data generated in the control's OnRender function and actually turn that into DirectX commands that become visible on the screen.&amp;nbsp;&amp;nbsp; Its this third step that is the limiting factor.&lt;/P&gt;
&lt;P&gt;The layout computations are handled by a function called &lt;STRONG&gt;ComputeAllNodeBoundingRects&lt;/STRONG&gt;.&amp;nbsp; This &amp;nbsp;function starts at the root node and recursively&amp;nbsp;computes the size of each visible rectangle for the nodes in the tree.&amp;nbsp;&amp;nbsp;This function stops its recursion when it reaches nodes that have visible areas less than the &lt;STRONG&gt;Area Limit.&amp;nbsp; &lt;/STRONG&gt;You can experiment with area limit values&amp;nbsp;using the unit test (see above).&amp;nbsp; If you set the area limit to zero, then the layout computations will compute a rectangle for every node in the tree.&lt;/P&gt;
&lt;P&gt;Computing the bounding rectangles only needs to happen when the treemap control receives a new data tree (by setting the TreeMapData property), or when the render size changes (handled by the OnRenderSizeChanged event).&lt;/P&gt;
&lt;P&gt;When WPF determines that a control needs to be rendered, it calls the controls OnRender method.&amp;nbsp; This control's OnRender method recursively paints each of the rectangles computed in ComputeAllNodeBoundingRects.&amp;nbsp;&amp;nbsp; It also renders the text for the root nodes and first level nodes. &lt;/P&gt;
&lt;P&gt;Both of these functions are relatively fast - here are some statistics for the initial random tree.&amp;nbsp; LQ means 'lower quartile',&amp;nbsp;UQ means 'upper quartile', IQ range is the inter quartile range divided by the median value.&amp;nbsp;&amp;nbsp; Range is the total range (max-min) divided by the median.&amp;nbsp; Times are in milliseconds.&lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=2 width=524 border=0 unselectable="on"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=right width=78&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=46&gt;&lt;STRONG&gt;Count&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;Min&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;LQ&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;Median&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;Mean&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;UQ&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=40&gt;&lt;STRONG&gt;Max&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=104&gt;&lt;STRONG&gt;IQ Range %&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=82&gt;&lt;STRONG&gt;Range %&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=right width=75&gt;&lt;STRONG&gt;Compute&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=48&gt;100&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;2.6&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;2.8&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;3.0&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;3.4&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;3.4&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=41&gt;7.7&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=104&gt;18.4%&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=82&gt;171.7%&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=right width=76&gt;&lt;STRONG&gt;Render&lt;/STRONG&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=50&gt;100&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;5.8&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;6.2&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;6.7&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;7.3&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;7.7&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=41&gt;19.6&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=104&gt;21.8%&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=82&gt;204.9%&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;These times are for computing and rendering from&amp;nbsp;1,316 to 1,539 visible nodes.&amp;nbsp;&amp;nbsp;&amp;nbsp;As you can see from the times, neither compute nor rendering times in the control itself should inhibit the control from rendering smoothly.&amp;nbsp; This is especially true when the control is rendering due to events other than size changes. &lt;/P&gt;
&lt;P&gt;But, even with the times above, the control still struggles to render - you can see this by just rolling the mouse over the control and watching the lagging mouse-over node changes, or by resizing the control.&amp;nbsp; In both cases, if the control is painting more than 700 rectangles or so, then it can't keep up.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization%5B1%5D.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization%5B1%5D.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; MARGIN: 0px 0px 0px 5px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=124 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization_thumb%5B1%5D.png" width=240 align=right border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization_thumb%5B1%5D.png"&gt;&lt;/A&gt;While relatively anecdotal, the CPU utilization for the control also seems on the high side.&amp;nbsp; Just continually moving the mouse over the control uses considerable CPU, 70 to 80%.&amp;nbsp; This is high,&amp;nbsp;especially considering that my lap top has a dual core AMD Turion processor with has a &lt;A title="Windows Experience Index" href="http://windowsvistablog.com/blogs/windowsvista/pages/458117.aspx" target=_blank mce_href="http://windowsvistablog.com/blogs/windowsvista/pages/458117.aspx"&gt;WinEI&lt;/A&gt; rating of 4.8.&lt;/P&gt;
&lt;P&gt;While there does seem to be some material performance and scaling issues with WPF, there is a lot to like about the programming model.&amp;nbsp;&amp;nbsp; I'll talk about this more in subsequent posts.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Source Code for this post:&amp;nbsp; &lt;/STRONG&gt;CLCV-BLOG-5.ZIP contains the source code to this post.&amp;nbsp;&amp;nbsp; I didn't include the data files in this zip file as they haven't changed - you can simply use the ones from &lt;A href="http://blogs.msdn.com/pigscanfly/attachment/1505442.ashx" mce_href="http://blogs.msdn.com/pigscanfly/attachment/1505442.ashx"&gt;CLCV-BLOG-3.ZIP&lt;/A&gt;.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1943307" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/1943307.ashx" length="81780" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Beyond+Hello+World/default.aspx">Beyond Hello World</category></item><item><title>Beyond Hello World - Update 4, File loading 27 times faster!</title><link>http://blogs.msdn.com/pigscanfly/archive/2007/01/30/beyond-hello-world-update-4-file-loading-27-times-faster.aspx</link><pubDate>Wed, 31 Jan 2007 02:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1559624</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1559624.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1559624</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1559624</wfw:comment><description>&lt;p&gt;&lt;a title="Overview" href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx" target="_blank"&gt;CLCV&lt;/a&gt; V4 now loads files about 27 times faster than &lt;a title="CLCV Version 3" href="http://blogs.msdn.com/pigscanfly/archive/2007/01/22/beyond-hello-world-update-3-control-templates-multithreading-and-more-with-source.aspx" target="_blank"&gt;V3&lt;/a&gt;&amp;nbsp;when running on &lt;a href="http://blogs.msdn.com/pigscanfly/pages/ferrari-4000.aspx"&gt;my laptop&lt;/a&gt;.&amp;nbsp;&amp;nbsp; The tree view is also about 5 times faster.&amp;nbsp; This comes from changing my initial naive implementation to a smarter one where I minimize the inter-thread communication and handle the tree view much more efficiently.&amp;nbsp; More information about the source code is at the bottom of this post.&amp;nbsp; Here is what I learned in working on V4.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Updating WPF UI elements can be expensive for large numbers of items.&amp;nbsp; An effective&amp;nbsp;and simple strategy is to&amp;nbsp;only load data into WPF UI elements that the user actually needs to see - don't use WPF objects as the store for large numbers of objects.&amp;nbsp;&amp;nbsp; &lt;br&gt; &lt;li&gt;Updating pixels on the screen is expensive - even with relatively high performance hardware.&amp;nbsp; Changing pixels (e.g. updating UI controls) at a rate faster than the monitor refresh rate is a waste of system resources, CPU time, GPU time, and memory bandwidth.&amp;nbsp; UI updates that are related to (or driven from) high throughput tasks should be paced to&amp;nbsp;no more than the monitor refresh rate. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;V3 was the first&amp;nbsp;functional version of CLCV and while it worked, it loaded files very slowly - talking 90 seconds or so (on my laptop) to load the largest data file (about 8.75MB in size).&amp;nbsp; Given that the ultimate goal is to handle CSV files that hold data for the entire Windows Vista source code tree, I really needed to improve CLCV's performance.&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00121%5B5%5D.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="331" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00121_thumb%5B2%5D.png" width="499" border="0"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The cause of the performance problem was easy to find using the Visual Studio 2005 profiler.&amp;nbsp; I simply enabled instrumented profiling and the offending code was obvious.&lt;/p&gt; &lt;p&gt;The most time consuming operation in V3 wasn't the actual file read time, it was the overhead of building the tree of tree view items.&amp;nbsp; In V3, the file reading thread sent a message to the UI thread for every new file and directory from the CSV file.&amp;nbsp; The UI thread then added that information to the&amp;nbsp;tree of tree view control items as the file was read.&amp;nbsp; This was very time consuming and took much longer than actualy reading the file. &lt;/p&gt; &lt;p&gt;It turns out that building a tree of tree view items is simply expensive.&amp;nbsp; The most expensive part being setting the string that is displayed as the item's header.&amp;nbsp; This&amp;nbsp;is closely followed by actually making a new item the child of another (ItemCollection.Add).&amp;nbsp; I don't yet know why this is expensive, only that it is.&amp;nbsp; It may be because I'm building the tree bottom up instead of top down - &lt;a title="Kiran Kumar's blog" href="http://blogs.msdn.com/kiranku/" target="_blank"&gt;Kiran Kumar&lt;/a&gt;&amp;nbsp;discusses this as a potential issue &lt;a title="WPF performance white paper" href="http://blogs.msdn.com/kiranku/attachment/904197.ashx" target="_blank"&gt;here&lt;/a&gt;.&amp;nbsp; I need to chat with my friend &lt;a title="Time Cahill's blog on WPF performance" href="http://blogs.msdn.com/timothyc" target="_blank"&gt;Tim Cahill&lt;/a&gt; the WPF performance guy about this a bit more.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;For V4, I took a different approach: I re-factored the code so the&amp;nbsp;file loading thread now does all the work of constructing a tree of objects that represent the original&amp;nbsp;directory structure and its files.&amp;nbsp;&amp;nbsp;I also moved the logic that updates the progress bar from the UI thread to the file loader thread - only sending progress messages to the UI thread every 33 milliseconds (this is configurable).&amp;nbsp;&lt;/p&gt; &lt;p&gt;The results were dramatically better.&amp;nbsp; The file loader thread could read the file and re-construct the directory tree much faster than the previous version.&amp;nbsp; On my laptop, the 8.75MB file could be loaded in about 1.47 seconds&amp;nbsp;- not bad at all.&amp;nbsp; In this version, the file loader thread sends a message to the UI thread to update the progress bar no more frequently than every 33 milliseconds (about 30 times per second).&amp;nbsp;&amp;nbsp;This is more than often enough so that the progress bar is visibily smooth, but not so much&amp;nbsp;that&amp;nbsp;updating the progress bar takes too long.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Experiment: &lt;/strong&gt;Updating the progress bar is expensive - way to expensive to do this for every line read from the file.&amp;nbsp;&lt;strong&gt; &lt;/strong&gt;You can see how expensive this can be by using CLCV V4 and&amp;nbsp;setting the "Progress Update Interval" in the options dialog box to 0.&amp;nbsp;&amp;nbsp; When this is zero, the file reading thread will send a message to the UI thread for every record read from the the CSV file.&amp;nbsp;&amp;nbsp; The messages get queued up in the UI threads dispatcher object and processed as fast as the UI can handle them.&amp;nbsp;&amp;nbsp; Processing all these messages and updating the progress bar takes a much longer time than processing the entire file!&amp;nbsp; The lesson here is that the overall process of updating the UI (chaning pixels on the screen) is simply expensive.&amp;nbsp; There is really no need to update the UI faster than the monitor refresh rate.&amp;nbsp; Often about 1/2 to even 1/3 of the monitor refresh rate is just fine.&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Note that for most things, a UI update rate of 30 or so updates per second will present a smooth animaition to the user.&amp;nbsp;&amp;nbsp; If needed, updating the UI faster -- at or close to the monitor refresh rate -- will work well.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Next, I needed a strategy for minimizing the costs of building the tree of tree view items that display the directory tree and files. Given that the file reader thread builds a tree structure, the solution was simple:&amp;nbsp; CLCV V4 only populates the tree view control when it needs to, and&amp;nbsp;only populates the items the user needs to see.&amp;nbsp; After the file is loaded, the UI code updates the tree view with the top level elements.&amp;nbsp; When the user expands an element, the UI thread then populates the data for that item's children.&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;In this way, CLCV only pays the costs for populating elements the user needs to see; only tree view items that will actually be displayed are created and added to the tree view item tree.&amp;nbsp; This also amortizes the costs of the items displayed over the time the user actualy minipulates the control.&amp;nbsp; So even if the user browses the entire three, he never experiences a sluggish tree view control.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Experiment: &lt;/strong&gt;This works quite well, if you use CLCV version 3 to load the large test file (test-l.clc.csv) the first click on the bottom entry ("GSFD") will take a noticeably, and annoyingly, long time to expand ( about 2.5 seconds on my laptop).&amp;nbsp;&amp;nbsp; With V4, this happens quickly: it takes about 150ms to populate 922 child items (~6,000 items per second, or ~166us).&amp;nbsp; It looks like it takes about anothe r300 milliseconds to draw the new items: its hard to measure this because WPF doesn't have a begin and ending events for item expansion (I just used a stop watch).&lt;/p&gt;&lt;/blockquote&gt; &lt;p style="margin: 0in 0in 0in 0.375in"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00131%5B4%5D.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="333" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00131_thumb%5B1%5D.png" width="609" border="0"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;With V4, the profiler shows a very different picture: The bulk of the CPU time during file loading is spent actually parsing the text data from the file, primarily converting text fields to decimal values using UInt32.TryParse().&lt;/p&gt; &lt;p&gt;This is as expected.&amp;nbsp; It probably isn't worth optimizing the conversion operations&amp;nbsp;by writing a hand crafted text to Uint32 conversion routine as such a routine would need to handle localization and othe rissues.&amp;nbsp; I expect it would only result modest performance improvements.&amp;nbsp; The primary file loading bottleneck in V4 isn't CPU time, but I/O efficiency.&lt;/p&gt; &lt;p&gt;Loading a 8.75MB file in 1.47 seconds is pretty good - its about&amp;nbsp;6 MB/s; and its plenty fast enough for my intended scenario.&amp;nbsp;&amp;nbsp; But, it is still slow compared to other applications.&amp;nbsp; I've developed other tools (such as CLC itself) that are completly I/O bound and use only one thread for the entire application.&amp;nbsp; These tools easily drive the disk at its maximum sequential read rate of about 35 MB/s while handling much more complex string opeations than merely parsing some CSV data.&amp;nbsp; For example, CLC is an order of magnitude faster than CLCV.&amp;nbsp; The reason is the stream reader class&amp;nbsp;- it doesn't do asynchronous or un-buffered I/O and its paying the cost of transcoding ANSI or UTF8 text into UTF16 for storing in .NET string objects.&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p&gt;In contrast, my natively implemented tools read files fully asynchronously in un-buffered mode.&amp;nbsp; This makes I/O operations happen in paralell with data processing - not sequentially.&amp;nbsp; They also parse the text data directly from the buffers populated by the operating system file read operation - no data copies are needed.&amp;nbsp; Next,&amp;nbsp;they handle ANSI and UNICODE directly - they don't transcode all input text to UTF-16.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;Now this isn't to say that the StreamBuffer class is slow - it isn't.&amp;nbsp; Using off the shelf I/O libraries in native C++ results in comparable performance to the .NET StreamBuffer class.&amp;nbsp; The difference comes from using hand crafted I/O routines specificaly designed to for sequntial text line reading and maximizing parallism between disk I/O and computation.&amp;nbsp; &lt;/p&gt; &lt;p&gt;One of my future tasks is writing a COM wrapper for my hand crafted C++ I/O libraries so they can be used efficiently from .NET languages.&amp;nbsp; I expect this will allow CLCV to come very close to the file read performance of my native tools. &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Source Code for this post:&amp;nbsp; &lt;/strong&gt;CLCV-BLOG-4.ZIP contains the source code to this post.&amp;nbsp;&amp;nbsp; I didn't include the data files in this zip file as they haven't changed - you can simpy use the ones from &lt;a title="V3 Zip File" href="http://blogs.msdn.com/pigscanfly/attachment/1505442.ashx" target="_blank"&gt;CLCV-BLOG-3.ZIP&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1559624" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/1559624.ashx" length="47521" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category></item><item><title>Vista System Requirements, Minimum Supported and Minimum Recommended</title><link>http://blogs.msdn.com/pigscanfly/archive/2006/12/21/vista-system-requirements-minimum-supported-and-minimum-recommended.aspx</link><pubDate>Fri, 22 Dec 2006 02:14:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1343275</guid><dc:creator>rgr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1343275.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1343275</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1343275</wfw:comment><description>&lt;p&gt;One of the things I worked on for Vista was the System Requirements.&amp;nbsp;&amp;nbsp; These are widely quoted, but the canonical source is &lt;a title="KB919183" href="http://support.microsoft.com/kb/919183" target="_blank"&gt;Knowledge Base Article 919183.&lt;/a&gt;&lt;/p&gt; &lt;p&gt;There are two sets of system requirements&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;The minimum supported system requirements&lt;/strong&gt;:&amp;nbsp; this is the bare minimum need to run any SKU of vista.&amp;nbsp;&amp;nbsp; If the system doesn't meat these then its literally not supported, even if you can get it to run.&amp;nbsp;&amp;nbsp; &lt;br&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;The minimum recommended system requirements&lt;/strong&gt;: these are the&amp;nbsp;requirements we recommend systems have for the basic and premium SKUs.&amp;nbsp;&amp;nbsp; &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;There is another set of important requirements, these are &lt;a title="Windows Logo Requirements" href="http://www.microsoft.com/whdc/winlogo/hwrequirements.mspx" target="_blank"&gt;V3.08 of the Windows Logo System Requirements&lt;/a&gt;.&amp;nbsp;&amp;nbsp; From a system perspective, the systems requirements govern how OEM's build systems that receive the Windows Vista logo.&amp;nbsp;&amp;nbsp;&amp;nbsp;These requirements&amp;nbsp; go far beyond the simple minimum supported and minimum requirements.&amp;nbsp; For example, requirement SYSFUND-046 specifies the system and graphics features and performance necessary for Aero.&amp;nbsp; You can stay up to date with changes to the logo requirements by subscribing to the &lt;a title="Subscribe to the WHDC news letter" href="http://www.microsoft.com/whdc/newsreq.mspx" target="_blank"&gt;WHDC newsletter.&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1343275" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Windows+Vista/default.aspx">Windows Vista</category></item><item><title>How Vista Enables Windows Aero - New Document Available</title><link>http://blogs.msdn.com/pigscanfly/archive/2006/12/20/how-vista-enables-windows-aero-new-document-available.aspx</link><pubDate>Wed, 20 Dec 2006 06:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1328028</guid><dc:creator>rgr</dc:creator><slash:comments>13</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1328028.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1328028</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1328028</wfw:comment><description>&lt;P&gt;&lt;A href="http://www.microsoft.com/windowsvista/experiences/aero.mspx" mce_href="http://www.microsoft.com/windowsvista/experiences/aero.mspx"&gt;Windows Aero&lt;/A&gt;&amp;nbsp;is Vista's new user interface and is based on &lt;A href="http://msdn2.microsoft.com/en-us/library/aa969540.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa969540.aspx"&gt;desktop composition&lt;/A&gt;&amp;nbsp;which is the process where each window and the desktop background is drawn separately and then composed by using the 3‑D graphics engine to create the desktop image a user sees. 
&lt;P&gt;Vista's process for automatically enabling Aero is relatively involved, and to date, the process hasn't been very clear. But now that Vista is out the door - I've had time to catch up on my to-do list which includes writing a white paper describing the process. I’ve also included a trouble shooting guide.&amp;nbsp; You can find the doc here. 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://www.microsoft.com/whdc/device/display/aero_rules.mspx" mce_href="http://www.microsoft.com/whdc/device/display/aero_rules.mspx"&gt;http://www.microsoft.com/whdc/device/display/aero_rules.mspx&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Feel free to post any question you may have.&amp;nbsp; I'll keep track and update my blog with answers and update the doc as necessary. 
&lt;P&gt;One question&amp;nbsp;I receive frequently is "&lt;EM&gt;Why is this so complex?&amp;nbsp; Why can't Vista simply enable Aero on any system?&lt;/EM&gt;"&amp;nbsp; The short answer is that Aero has some fundamental requirements (see the doc), and some performance requirements.&amp;nbsp; For example, Aero won't run at all without a WDDM driver. 
&lt;P&gt;Here is the long answer - In contrast to XP's GDI based "owner draw" model, Vista uses a retained graphics model to mange windows and the desktop.&amp;nbsp; Vista's model and other composition based features (collectively called ‘Aero’) are considerably more expensive in terms of resource utilization than XP.&amp;nbsp; This includes the use of system and graphics memory for storing textures; CPU time to manage the composition process; video memory bandwidth; and GPU time.&amp;nbsp;&amp;nbsp; 
&lt;P&gt;These costs buy a lot of benefits: smoother screen updates, much fewer windowing artifacts and ‘tears’, ability to easily support high DPI (even for legacy applications), no inter frame tearing with video playback, enablement of attractive new visual effects that please users (flip 3D, transparency, thumbnails, window effects, etc.) 
&lt;P&gt;Originally in 2004, we assumed that Aero was so expensive that it would only be available on systems with higher performing discrete graphics cards.&amp;nbsp; Our first implementations&amp;nbsp;only ran well on mid-range graphics adapters (or better).&amp;nbsp; 
&lt;P&gt;Our challenge was to strike a balance between ensuring a good user experience and enabling Aero broadly.&amp;nbsp; The more broadly enabled, the larger the risk of users being unhappy with the user experience due to the demanding nature of composition. In contrast raising the bar to ensure a good user experience would have meant that fewer people would enjoy the benefits of composition and raise the costs of systems designed to run Aero. 
&lt;P&gt;The Desktop Window Manager team (including &lt;A href="http://blogs.msdn.com/greg_schechter/" mce_href="http://blogs.msdn.com/greg_schechter/"&gt;Greg Schechter&lt;/A&gt;, and many others), the DX team, the video playback team, and the client performance team spent a lot&amp;nbsp;of time optimizing the DWM and other components so that Aero would run well on a broad range of hardware: The big push was for Aero to work well on mid range UMA graphics adapters.&amp;nbsp;&amp;nbsp; 
&lt;P&gt;After a lot of work, we achieved a pretty good balance: Contrary to popular belief, with single monitor, Aero runs well on low cost UMA graphics (especially for day to day computing).&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;P&gt;With more capable graphics (such as those scoring 4 or better in the &lt;A href="http://windowsvistablog.com/blogs/windowsvista/archive/2006/09/22/windows-experience-index-an-in-depth-look.aspx" mce_href="http://windowsvistablog.com/blogs/windowsvista/archive/2006/09/22/windows-experience-index-an-in-depth-look.aspx"&gt;Windows Experience Index&lt;/A&gt; graphics score) Aero is very robust and will handle large dual monitors. With today's high end graphics cards, Aero really sings, nicely handling large dual monitors with heavy workloads. 
&lt;P&gt;We achieved this balance three ways (1) by working diligently with IHV’s to make drivers better (2)&amp;nbsp;by making many performance and efficiently improvements in the DWM and related components (3) and by using user research to gain a good understanding of how users perceive composition performance so we could accurately judge the bar (which had started out very high). 
&lt;P&gt;This has resulted in a relatively complex set of conditions under which Vista will automatically enable Aero.&amp;nbsp; The goal is to enable it when the user experience would be acceptable and when it is better to have it enabled than disabled.&amp;nbsp; This also means that sometimes the DWM will scale back the user experience (turning off transparency, or disabling composition all together) when performance suffers.&amp;nbsp; Of course, this will happen sooner and more often on less capable hardware than on more capable hardware and is greatly dependant on the user scenario.&amp;nbsp;&amp;nbsp; &lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1328028" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Vista+Graphics/default.aspx">Vista Graphics</category></item><item><title>ISRs and DPCs, The Silent Killers</title><link>http://blogs.msdn.com/pigscanfly/archive/2006/10/09/ISRs-and-DPCs_2C00_-The-Silent-Killers.aspx</link><pubDate>Mon, 09 Oct 2006 17:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:808236</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/808236.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=808236</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=808236</wfw:comment><description>&lt;P&gt;Hardware interrupt service routines and deferred procedure calls can be the silent killers of system performance.&amp;nbsp; ISRs and DPCs are the highest priority code that runs in the system - they cannot be pre-empted by the OS and run to completion. ISRs and DPCs that run too long - or too often - can eat up significant amounts of CPU time and cause overall system performance to suffer.&amp;nbsp; They can cause audio and video glitches, mouse freezes, UI hangs, and any number of other system wide problems. 
&lt;P&gt;From a user's standpoint, problems with long or frequent ISRs and DPCs often first show up as audio pops and drops (usually just called 'glitches'). This has long been a problem for PC audio: problematic ISRs or DPCs can cause enough delays in applications or in the audio engine so that audio data simply fails to get to the hardware in time causing audible glitches.&amp;nbsp; Even Vista's new audio sub-system isn't immune to interference from ISR's and DPCs.&amp;nbsp; The human ear is very sensitive to even the slightest problem in the audio stream. Chances are, if you are hearing regular audio glitches, long ISRs or DPCs are the problem. 
&lt;P&gt;We've even seen a few extreme cases of really awful DPC behavior; one bug in a new &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/winvistadisplaydrivermodel.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/winvistadisplaydrivermodel.asp"&gt;&lt;FONT color=#006ff7&gt;WDDM&lt;/FONT&gt;&lt;/A&gt; graphics driver has been particularly persistent. We first noticed it a few months ago when users reported periodic mouse freezes on some laptops.&amp;nbsp; Taking a trace on the problem system quickly helped us find the problem: the graphics driver was periodically waking up to check for an external monitor change. This specific hardware doesn't provide an interrupt when a monitor is attached or removed, so&amp;nbsp;the&amp;nbsp;driver&amp;nbsp;needs to periodically poll the adapter for the monitor state. It did this every few seconds. This would normally be fine, but the driver was spending several hundred milliseconds in a DPC every time it did this. Users saw this as a mouse freeze - in reality, it was a system freeze as the CPU was spending all its time doing nothing but polling for a monitor for a few hundred milliseconds. We worked with the vendor to get this fixed, only to have it show up a couple of more times as the vendor worked on the architecture of their driver. 
&lt;P&gt;Network interface cards (NICs)&amp;nbsp;are a frequent culprit of ISR and DPC problems. Their type and age tend to vary widely – even between the same models of computers. Some NICs are well behaved, only interrupting the OS when absolutely necessary, such as when receive buffers are getting full. This is called interrupt aggregation.&amp;nbsp; This lets the OS handle received packets with as few interrupts as possible.&amp;nbsp; Other NICs are very badly behaved, interrupting the CPU for every packet received.&amp;nbsp; Luckily, newer NICs support interrupt aggregation.&amp;nbsp; The "bad NICs" we see tend to be older, circa 2003, 2004. 
&lt;P&gt;I call ISRs and DPCs problems the 'silent killers' for three reasons 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;The OS has no control over their execution. &lt;/B&gt;ISR's are triggered by physical hardware signals from devices to the CPU.&amp;nbsp; When a device signals the CPU that it needs attention, the CPU immediately jumps to the driver's interrupt service routine.&amp;nbsp;&amp;nbsp;DPCs are scheduled by interrupt handlers and run at a priority only exceed by hardware interrupt service routines. 
&lt;P&gt;&lt;B&gt;ISR and DPC activity usually increases with system activity.&lt;/B&gt; As a system becomes more active, interrupts and DPCs will generally&amp;nbsp;become more frequent, taking up more CPU time.&amp;nbsp; This can get to the point where they visibly (or audibly) affect system performance.&amp;nbsp; In these cases, no single ISR or DPC routine is the problem - it is their cumulative usage of CPU time. 
&lt;P&gt;&lt;B&gt;It is rarely obvious that ISRs and DPCs are causing performance problems&lt;/B&gt;. There is really only one place in the OS where information about them is visible surfaced, in the performance monitor.&amp;nbsp; This UI is really useful, but a little hard to get to. &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;ISR's and DPC's can cause other secondary performance problems as well such as dirtying the processor caches and increasing interrupt and DPC latency.&amp;nbsp;&amp;nbsp; 
&lt;P&gt;Tracking down Interrupt and DPC problems is further complicated because their behavior is highly dependent on hardware configuration and drivers.&amp;nbsp;&amp;nbsp; A problem seen on one system may only be reproducible on that particular system.&amp;nbsp; 
&lt;P&gt;The performance monitor UI is a bit buried, but once found provides a good run-time summary of ISR and DPC execution.&amp;nbsp;&amp;nbsp; My favorite way to get to the performance monitor is by entering 'perfmon' into the system run command dialog.&amp;nbsp; Just press the Win-R key and type 'perfmon'.&amp;nbsp;&amp;nbsp; You can then use the 'performance monitor' tab to monitor ISR and DPC activity using these counters: % Interrupt Time, % DPC Time, Interrupts/Sec, DPC Rate, and DPCs Queued/Sec (&lt;A href="http://technet2.microsoft.com/WindowsServer/en/library/c65acc5a-e7f9-4e21-8726-79a3a8bb34cc1033.mspx?mfr=true" mce_href="http://technet2.microsoft.com/WindowsServer/en/library/c65acc5a-e7f9-4e21-8726-79a3a8bb34cc1033.mspx?mfr=true"&gt;&lt;FONT color=#006ff7&gt;see&lt;/FONT&gt;&lt;/A&gt;).&amp;nbsp;&amp;nbsp; This is quite handy as it is 'in-box' - available on every Windows XP and Vista system.&amp;nbsp;&amp;nbsp; This UI can help spot patently bad ISR and DPC activity relatively easily. 
&lt;P&gt;However, the performance counters only tell part of the story.&amp;nbsp; They don't identify the modules that are generating the ISRs and DPCs, and they can’t be used to look at ISR and DPC execution times.&amp;nbsp; The best way to get a clear picture of the CPU time spent in ISRs and DPCs is to use the kernel's &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/etw/etw/about_event_tracing.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/etw/etw/about_event_tracing.asp"&gt;&lt;FONT color=#006ff7&gt;ETW events&lt;/FONT&gt;&lt;/A&gt;&amp;nbsp;which can be enabled and analyzed using &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracetools_eaafb38e-d0e9-4563-b3c6-91317a2871a2.xml.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracetools_eaafb38e-d0e9-4563-b3c6-91317a2871a2.xml.asp"&gt;&lt;FONT color=#006ff7&gt;ETW based performance tools&lt;/FONT&gt;&lt;/A&gt;. 
&lt;P&gt;Event Tracing for Windows (ETW) is a fundamental operating system feature that provides a very efficient method for logging events, mechanisms for controlling event providers (components that generate events, also often called 'loggers' ) and collecting those events for post processing. ETW is the primary tool we use to measure system performance. Probably the most important logger is the kernel logger itself which can generate events for DPCs, ISRs, context switches, disk I/O, hard and soft faults, process start/stop, thread start/stop, file I/O, disk I/O, TCP/IP and UDP traffic, registry access, and image (executable) loads. All of these can be controlled by the &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracelog_ccd36795-bd4a-46aa-b301-2a101efc7f41.xml.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracelog_ccd36795-bd4a-46aa-b301-2a101efc7f41.xml.asp"&gt;&lt;FONT color=#006ff7&gt;tracelog&lt;/FONT&gt;&lt;/A&gt; tool provided in the Windows Vista WDK. 
&lt;P&gt;Using the kernel logger to look at ISR and DPC execution statistics is very easy - here's how: 
&lt;OL&gt;
&lt;LI&gt;Run the following command from an elevated command prompt window:&lt;BR&gt;tracelog -start "NT Kernel Logger" -f krnl.etl -dpcisr -nodisk -nonet -b 1024 -min 4 -max 16 -ft 10 –UsePerfCounter 
&lt;LI&gt;Start, run then stop your test 
&lt;LI&gt;Run the following command to stop the kernel logger and save the data to 'krnl.etl'&lt;BR&gt;tracelog –stop 
&lt;LI&gt;Use the following trace report command to generate a nicely formatted report of the ISR and DPC activity during your test&lt;BR&gt;trcerpt krnl.etl -report isrdpc.xml&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The &lt;B&gt;isrdpc.xml &lt;/B&gt;report file will contain a nicely formatted report&amp;nbsp;that lists the % utilization, counts,&amp;nbsp;and histograms of the ISR and DPC execution time by module. This data is really helpful in finding problematic ISR and DPC activity.&amp;nbsp; 
&lt;P&gt;Driver developers can take things a step further and add ETW based event logging directly to their driver.&amp;nbsp; This is straight forward to do.&amp;nbsp; Even better, ETW is very light weight and the logging features can be shipped in production (non-debug) drivers. This makes it much easier to debug performance problems as driver tracing can be enabled on any system. Since developers can define their own events, the driver can log additional information such as internal driver or hardware state. 
&lt;P&gt;It may even be appropriate for a driver developer to publish the drivers trace GUID, event flags and event structures so others can independently diagnose problems.&amp;nbsp; 
&lt;P&gt;I’ve included some useful related links and other information below. 
&lt;P&gt;&lt;B&gt;&lt;U&gt;Other Details&lt;/U&gt;&lt;/B&gt; 
&lt;UL&gt;
&lt;LI&gt;The &lt;B&gt;tracelog.exe&lt;/B&gt; tool is available in the Windows Vista driver development kit (The WDK).&amp;nbsp;&amp;nbsp; This article assumes the use of this version, other earlier versions don't support the kernel logger switches. 
&lt;LI&gt;Prior to vista shipping, you can get the WDK by singing up for the WDK Beta program &lt;A href="http://www.microsoft.com/whdc/devtools/wdk/betawdk.mspx" mce_href="http://www.microsoft.com/whdc/devtools/wdk/betawdk.mspx"&gt;&lt;FONT color=#006ff7&gt;here&lt;/FONT&gt;&lt;/A&gt;. 
&lt;LI&gt;The &lt;B&gt;tracerpt.exe&lt;/B&gt; tool is built into Windows.&amp;nbsp; &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;B&gt;&lt;U&gt;Useful Links&lt;/U&gt;&lt;/B&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://www.microsoft.com/whdc/driver/kernel/IRQL.mspx" mce_href="http://www.microsoft.com/whdc/driver/kernel/IRQL.mspx"&gt;&lt;FONT color=#006ff7&gt;Scheduling, Thread Context, and IRQL&lt;/FONT&gt;&lt;/A&gt;: This document describes all the gory detail behind how hardware and software interrupts are scheduled and handled by the operating system. 
&lt;P&gt;&lt;A href="http://www.microsoft.com/whdc/devtools/tools/EventTracing.mspx" mce_href="http://www.microsoft.com/whdc/devtools/tools/EventTracing.mspx"&gt;&lt;FONT color=#006ff7&gt;Event Tracing from the WDK docs&lt;/FONT&gt;&lt;/A&gt;: Here is a good place to start on understanding the fundamental ETW infrastructure in windows. 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracetools_eaafb38e-d0e9-4563-b3c6-91317a2871a2.xml.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracetools_eaafb38e-d0e9-4563-b3c6-91317a2871a2.xml.asp"&gt;&lt;FONT color=#006ff7&gt;Tools for Software Tracing&lt;/FONT&gt;&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://technet2.microsoft.com/WindowsServer/en/library/c65acc5a-e7f9-4e21-8726-79a3a8bb34cc1033.mspx?mfr=true" mce_href="http://technet2.microsoft.com/WindowsServer/en/library/c65acc5a-e7f9-4e21-8726-79a3a8bb34cc1033.mspx?mfr=true"&gt;&lt;FONT color=#006ff7&gt;CPU Performance Counters&lt;/FONT&gt;&lt;/A&gt;&lt;STRONG&gt;: &lt;/STRONG&gt;This page describes the various CPU performance counters in windows. 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracelog_ccd36795-bd4a-46aa-b301-2a101efc7f41.xml.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracelog_ccd36795-bd4a-46aa-b301-2a101efc7f41.xml.asp"&gt;&lt;FONT color=#006ff7&gt;TraceLog Documentation&lt;/FONT&gt;&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracelog_a1af43c3-5c00-48c3-969d-51f348c3e7dc.xml.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracelog_a1af43c3-5c00-48c3-969d-51f348c3e7dc.xml.asp"&gt;&lt;FONT color=#006ff7&gt;Measuring ISR and DPC Time&lt;/FONT&gt;&lt;/A&gt;:&amp;nbsp; A related article. 
&lt;P&gt;&lt;A href="http://www.microsoft.com/whdc/driver/perform/mmdrv.mspx" mce_href="http://www.microsoft.com/whdc/driver/perform/mmdrv.mspx"&gt;&lt;FONT color=#006ff7&gt;Device-Driver Performance Considerations for Multimedia Platforms&lt;/FONT&gt;&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/etw/etw/event_tracing_tools.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/etw/etw/event_tracing_tools.asp"&gt;&lt;FONT color=#006ff7&gt;Event Tracing APIs in the Platform SDK&lt;/FONT&gt;&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnlong/html/winvistadisplaydrivermodel.asp?frame=true" mce_href="http://msdn.microsoft.com/library/en-us/dnlong/html/winvistadisplaydrivermodel.asp?frame=true"&gt;&lt;FONT color=#006ff7&gt;Windows Vista Display Driver Model&lt;/FONT&gt;&lt;/A&gt;: A detailed discussion of the virtues of WDDM. 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/Display_d/hh/Display_d/displaydrivermodel_guideintro_aad1cf9c-2b3d-41a4-acfd-433f0830e415.xml.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/Display_d/hh/Display_d/displaydrivermodel_guideintro_aad1cf9c-2b3d-41a4-acfd-433f0830e415.xml.asp"&gt;&lt;FONT color=#006ff7&gt;WDDM In the WDK&lt;/FONT&gt;&lt;/A&gt;: The WDDM SDK - how to write a WDDM driver. 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/winvistadisplaydrivermodel.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/winvistadisplaydrivermodel.asp"&gt;&lt;FONT color=#006ff7&gt;The virtues of WDDM Drivers&lt;/FONT&gt;&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/Intro_g/hh/Intro_g/ddksplash_d0c992d8-3d64-44cc-ab2c-13bcfa0faffb.xml.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/Intro_g/hh/Intro_g/ddksplash_d0c992d8-3d64-44cc-ab2c-13bcfa0faffb.xml.asp"&gt;&lt;FONT color=#006ff7&gt;Windows Driver Kit (WDK) Introduction&lt;/FONT&gt;&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://www.microsoft.com/whdc/Driver/tips/DPC_ISR.mspx" mce_href="http://www.microsoft.com/whdc/Driver/tips/DPC_ISR.mspx"&gt;&lt;FONT color=#006ff7&gt;WinHEC Presentation on generating your own events&lt;/FONT&gt;&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://www.microsoft.com/whdc/DevTools/tools/RATT.mspx" mce_href="http://www.microsoft.com/whdc/DevTools/tools/RATT.mspx"&gt;&lt;FONT color=#006ff7&gt;RATTV3&lt;/FONT&gt;&lt;/A&gt;&lt;B&gt;:&lt;/B&gt;This is a tool that we provided during WinHEC 2005 that allows 24 x 7 logging of ISR and DPC activity.&amp;nbsp; Note, this currently only works on XP, we need to get this updated for Vista. 
&lt;P&gt;&lt;A href="http://www.microsoft.com/whdc/DevTools/tools/EventTrace_sample.mspx" mce_href="http://www.microsoft.com/whdc/DevTools/tools/EventTrace_sample.mspx"&gt;&lt;FONT color=#006ff7&gt;Sample User Mode ETW based event provider&lt;/FONT&gt;&lt;/A&gt; &lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=808236" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category></item><item><title>Channel9 has a good video of Mike Fortin discussing what our team does.</title><link>http://blogs.msdn.com/pigscanfly/archive/2006/10/09/Channel9-has-a-good-video-of-Mike-Fortin-discussing-what-our-team-does_2E00_.aspx</link><pubDate>Mon, 09 Oct 2006 02:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:807020</guid><dc:creator>rgr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/807020.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=807020</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=807020</wfw:comment><description>&lt;P&gt;Channel9 has a good video interview of Mike Fortin where he dicusses what our team does and goes into good detail on SuperFetch, disk layout and defrag, and other interesting topics.&amp;nbsp; See &lt;A href="http://channel9.msdn.com/showpost.aspx?postid=242429" mce_href="http://channel9.msdn.com/showpost.aspx?postid=242429"&gt;http://channel9.msdn.com/showpost.aspx?postid=242429&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=807020" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category></item></channel></rss>