<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">Sue Loh's blog</title><subtitle type="html">Random spurts of inspired discussion</subtitle><id>http://blogs.msdn.com/sloh/atom.xml</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/sloh/atom.xml" /><generator uri="http://communityserver.org" version="2.1.61025.2">Community Server</generator><updated>2005-02-28T12:37:00Z</updated><entry><title>Windows Embedded Challenge ROCKS!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/06/19/430535.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/06/19/430535.aspx</id><published>2005-06-19T06:54:00Z</published><updated>2005-06-19T06:54:00Z</updated><content type="html">&lt;P&gt;I know I said I'd be blogging on the ce_base team blog now, but I figured my personal blog is a better place for this one as it's more personal in nature.&amp;nbsp; I just finished two days of serving as a judge for the &lt;A href="http://www.windowschallenge.com/"&gt;Windows Embedded Student Challenge&lt;/A&gt;.&amp;nbsp; I had a most wonderful time.&amp;nbsp; The quality of the work,&amp;nbsp;the innovation, and the energy of the students were simply amazing.&amp;nbsp; What a diversity of projects from a diverse cross-section of the world!&amp;nbsp; How energizing to see people take the work I do and build such impressive systems on top of it!&amp;nbsp; The only disappointing part of the competition was that I didn't have a chance to see all 30 projects.&lt;/P&gt;
&lt;P&gt;I also feel somewhat emotional about the event because it was heartbreaking to&amp;nbsp;give some of these teams such disappointments.&amp;nbsp;&amp;nbsp;Everyone has worked so hard and cares so much.&amp;nbsp; So to those teams out there who might read this, I want to say that just because you weren't chosen doesn't mean we didn't like your projects, or think that they could become successful products.&amp;nbsp; In some cases we had to eliminate teams because their projects just weren't 100% ready, or because we felt&amp;nbsp;they didn't adequately describe important aspects of their project during their presentation.&amp;nbsp; It was clear in many cases that the teams intended to continue working on their projects, in an attempt to build a real commercial product.&amp;nbsp; I would encourage you all to continue following the dream.&amp;nbsp; If you want more feedback please do ask for it; we would be happy to help you understand what parts of the project were weak and how to improve on them for the future.&lt;/P&gt;
&lt;P&gt;I loved meeting everyone.&amp;nbsp; Thank you for your hard work, and for sharing it with us.&amp;nbsp; I wish you all the best of luck, and hope to see you again!&amp;nbsp; (Maybe next year?)&amp;nbsp; Stay in touch, and I will see you online.&amp;nbsp; ;-)&lt;/P&gt;
&lt;P&gt;Sue&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=430535" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Misc. Fun" scheme="http://blogs.msdn.com/sloh/archive/tags/Misc.+Fun/default.aspx" /></entry><entry><title>Windows CE Base Team Blog</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/06/06/425906.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/06/06/425906.aspx</id><published>2005-06-07T03:27:00Z</published><updated>2005-06-07T03:27:00Z</updated><content type="html">&lt;P&gt;We just created a new team blog, the CE base team blog, to cover kernel &amp;amp; file system issues.&lt;/P&gt;
&lt;P&gt;&lt;a href="http://blogs.msdn.com/ce_base/"&gt;http://blogs.msdn.com/ce_base/&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;I'm going to start posting there instead of here.&amp;nbsp; I probably won't have a lot of side-posts on this blog; I don't really have the energy for lots of&amp;nbsp;off-topic personal stuff.&amp;nbsp; So if you are subscribed to this blog, you may want to switch over to that one.&amp;nbsp; We're hoping that the new blog will get more of our team involved in posting, and provide a more consistent stream of information (as I tend to write in bursts).&lt;/P&gt;
&lt;P&gt;Don't worry, I still have a list of&amp;nbsp;things I want to write up "when I get the chance."&amp;nbsp; See you there,&lt;/P&gt;
&lt;P&gt;Sue&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=425906" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Misc. Fun" scheme="http://blogs.msdn.com/sloh/archive/tags/Misc.+Fun/default.aspx" /></entry><entry><title>Lock Convoys and How to Recognize Them</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/05/27/lock-convoys-and-how-to-recognize-them.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/05/27/lock-convoys-and-how-to-recognize-them.aspx</id><published>2005-05-27T18:39:00Z</published><updated>2005-05-27T18:39:00Z</updated><content type="html">&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;The problem:&lt;/B&gt; When using a particular application on one specific device, users noticed very bad UI response for a period of a few seconds.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;After those seconds, UI responsiveness went back to normal.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;The investigation:&lt;/B&gt; I used ActiveSync to drop celog.dll and oscapture.exe onto a standalone device.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I could have hooked the device up to Platform Builder and run Remote Kernel Tracker over KITL, but in this case the device I had was configured to run without KITL.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I just didn’t bother reconfiguring it.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;/o:p&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;I made a .lnk file to start oscapture, and a second .lnk file to trigger it (run a second instance of oscapture with the “-c” parameter).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I dropped these onto the Start menu of the device.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I ran oscapture, and played around with the errant application until the UI slowdown occurred.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;As quickly as I could (due to the UI slowdown it took a few seconds) I brought up the start menu and clicked the link to trigger oscapture.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;OScapture saved its data to a file.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I then hooked up ActiveSync again, and copied the log file off the device.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Actually now that I think of it, I probably could have just connected Remote Kernel Tracker to the device over ActiveSync, but you know I’m not that smart.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Here is what I saw when opening up the file in Remote Kernel Tracker:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;EM&gt;(scroll down if you can't see anything)&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;EM&gt;&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_convoy.png" mce_src="http://cenet.members.winisp.net/sloh_files/kt_convoy.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The main thread of pimg.exe is taking all the CPU time, and a few other threads (notably a couple in telshell.exe, which is responsible for the Smartphone UI) took little blips of time here and there, contending over a critical section.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I know they are contending because CeLog only logs critical section entry and exit events when there is contention.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Critical sections are acquired and released far too often to log uncontended operations. You don’t see any critical section exit events in this screen shot, but they’re there; they happen so close to the entry events that the “exit” icons are hidden underneath the “entry” icons.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If I had zoomed in some more, you’d see them resolve into distinct events.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;All of these threads are at the same priority, 251 (THREAD_PRIORITY_NORMAL).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I know the thread priorities because I hovered over the thread lines and saw the priorities in the resulting tooltips. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;But despite the equal priorities in this case, only one thread, that from pimg.exe, is getting very much CPU time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It is running to the completion of its quantum.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I know that because I set the “time marker 1 &amp;amp; 2” in the time scale bar – you can see them in the screen shot.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In the bottom right of the Remote Kernel Tracker window, where it says “Marker Time Delta,” is the time between the two markers.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;That time is about 100ms, the default thread quantum in Windows CE.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Each time the pimg.exe thread runs for about the same length of time, about 100ms.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;I immediately recognized this as a lock convoy problem.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Let me describe what that means.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;A lock convoy is a situation which occurs when two or more threads at the same priority frequently (several times per quantum) acquire a synchronization object, even if they only hold that object for a very short amount of time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It happens most often with critical sections, but can occur with mutexes, etc as well.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For a while the threads may go along happily without contending over the object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;But eventually some thread’s quantum will expire while it holds the object, and then the problem begins.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The expired thread (let’s call it Thread A) stops running, and the next thread at that priority level begins.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Soon that thread (let’s call it Thread B) gets to a point where it needs to acquire the object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It blocks on the object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The kernel chooses the next thread in the priority-queue.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If there are more threads at that priority which end up trying to acquire the object, they block on the object too.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This continues until the kernel returns to Thread A which owns the object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;That thread begins running again, and soon releases the object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Here are the two important points.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, once Thread A releases the object, the kernel chooses a thread that’s blocked waiting for the object (probably Thread B), makes that thread the next owner of the object, and marks it as “runnable.”&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Second, Thread A hasn’t expired its quantum yet, so it continues running rather than switching to Thread B.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since the threads in this scenario acquire the synchronization object frequently, Thread A soon comes back to a point where it needs to acquire the object again.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This time, however, Thread B owns it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So Thread A blocks on the object, and the kernel again chooses the next thread in the priority-queue to run.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It eventually gets to Thread B, who does its work while owning the object, then releases the object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The next thread blocked on the object receives ownership, and this cycle continues endlessly until eventually the threads stop acquiring so often.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The real performance killer about a lock convoy situation is that every time the threads involved need to acquire the synchronization object, they block and take at least a couple of context switches.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since the premise of this situation is that the threads acquire the object frequently (several times a quantum), they are running for much less than a quantum between each context switch.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The less time they run between acquires, the more context switches involved – and remember that this is all regardless of how long or short of a time they spend owning the object.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The other performance killer in a lock convoy situation is that it dramatically increases the percentage of CPU time non-contending threads at the same priority level get to run.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If all threads at that priority level are contending over the object, what you see is very frequent context switching between them all.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If one or more threads at that level are running continuously without blocking on any objects, those threads get to run for a full quantum each time the contending threads loop on the object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;That is what you see in the screen shot above; the pimg.exe thread is not involved in the lock convoy, but since it’s at the same priority level as all the threads in the convoy, it gets all the CPU time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this case, the UI threads only ran very tiny periods once each quantum of the pimg.exe thread execution, so the UI was very slow to respond to user input.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Eventually the pimg.exe thread completed its work, the UI threads completed their convoy, and the UI response time went back to its snappy old self.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;The solution:&lt;/B&gt; Lock convoys are not always easy to solve.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this case, I don’t know the solution for sure, but I believe they either lowered the priority of the pimg.exe main thread or made it do its work at another time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;While that doesn’t actually get rid of the lock convoy, it speeds it up to the point where it is unnoticeable to the user.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Another work-around might have been to make the pimg.exe thread yield frequently, by calling Sleep(0), to allow the other threads to do their work more frequently than once per quantum.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Note, however, that this isn’t a very ideal work-around, because it’d lead to very frequent thread switching.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Context-switching very often is a problem in itself; you spend all your time making the kernel reschedule threads instead of letting those threads run.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;A different work-around is to reduce contention over the object by allowing it to be shared more often.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, suppose the object is a critical section protecting some data.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;You don’t want threads to read the data while it’s being written, or write concurrently, etc.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If reads are relatively frequent while writes are relatively rare, then a way to reduce contention over the lock is to convert it to a reader / writer lock.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If writes are frequent, the improvement of using a reader/writer lock is minimal, but otherwise such a change can allow threads to read at the same time without serializing over a lock.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Sometimes you can work around the problem by acquiring the lock at some other time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, I note that there’s a thread in filesys.exe involved in the convoy.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So I suspect the critical section that was undergoing contention was inside filesys.exe.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;(While critical sections cannot be shared between processes, the non-filesys.exe threads may have used its critical section during calls into filesys.exe APIs.)&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Maybe the UI threads were reading from files to draw icons, or reading from the registry, or writing to a log file.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In the read case, perhaps the UI could have kept the objects in a cache so as to avoid entering the file system.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In the write case, perhaps it could queue up file system writes to execute at a later time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Either solution amounts to caching data and performing operations asynchronously, instead of during time-critical UI processing.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;While lock convoys are also possible in Windows XP, they’re a little less problematic because of the priority boosting and aging that the Windows XP scheduler does.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If a thread blocks on an object, then when it becomes un-blocked the XP scheduler temporarily boosts its priority a little.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;When a thread runs to the completion of its quantum, the XP scheduler ages its priority a little.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this manner, threads that block often end up at higher priority than threads that run continuously without blocking.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Then the lock convoy isn’t eliminated, but there is less chance of another unrelated thread skunking up the works by running a full quantum each thread switch.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;A better solution, if you can change all the code that acquires the contentious lock, is to use TryEnterCriticalSection to acquire the lock only when it’s uncontended.&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;/o:p&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;retries = 0;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;while(!TryEnterCriticalSection(&amp;amp;CritSec)) {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;if( retries++ &amp;lt; SpinLimit ){&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;Sleep(0);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;continue;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;EnterCriticalSection(&amp;amp;CritSec);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;break;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;}&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;This code will use TryEnterCriticalSection a number of times, yielding the processor on each failure until it reaches the SpinLimit and then uses regular EnterCriticalSection.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The SpinLimit is necessary in case the critical section is owned by a lower-priority thread which would not run and release the critical section while the current thread is looping.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In that case the EnterCriticalSection call is required to make the kernel invert the priority of the owning thread briefly, so that the higher-priority thread can acquire the critical section.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;You may expect this code, which basically polls for the critical section, to hurt performance.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;But believe it or not, it can greatly improve it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The difference between this loop and a regular EnterCriticalSection call is that threads do not enter the queue to acquire the critical section if some other thread owns it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So in the example above, when Thread A releases the critical section, Thread B does not immediately become the owner.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Thread A is free to continue running and even acquire and release the critical section a few more times before Thread B comes back and tries to acquire it again.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Even with a SpinLimit of 2 (= 1 Sleep() call) two threads can recover from critical section contention without creating a convoy.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Alas, this solution is unavailable if you cannot change the code which acquires the critical section.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;To those of you who might ask whether we intend to make changes to Windows CE to eliminate lock convoys, I’m not at liberty to discuss what we may or may not do in future products.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I can only say the standard non-informative spiel: Microsoft is committed to improving the quality of its products and considers all improvements in the context of other improvements we wish to make, to provide our customers the biggest benefits possible in the time available blah blah blah.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;(By the way that spiel, while hokey, really is true.)&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;In the meantime I hope I’ve provided you with some information you can use to identify and escape this problem if you encounter it.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;STRONG&gt;&lt;EM&gt;UPDATE 26 June 06:&lt;/EM&gt;&lt;/STRONG&gt;&amp;nbsp; Discussion of whether the TryEnter/Sleep solution hurts perf.&amp;nbsp; I don’t really think the Sleep() will hurt perf at all.&amp;nbsp; Here is what would happen:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Thread 1 quantum expires while holding the CS (which is what starts a convoy)&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Thread 2 does TryEnter, fails, and sleeps&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Thread 1 runs again, acquires and releases the CS a bunch of times, and quantum expires while not holding the CS&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Thread 2 runs again, does TryEnter again, succeeds.&amp;nbsp; Now it can acquire and release the CS a bunch of times.&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;So the sleep causes a thread switch, but it’s a thread switch you’d have taken anyway if you were using regular EnterCriticalSection.&amp;nbsp; And now that I think more about this, I think your change to hold the CS for a longer period would negatively impact the perf of the TryEnter solution, because it’d increase the chances of expiring your quantum while holding the CS.&amp;nbsp; Though the impact would still not be bad because in general the threads would run to quantum completion.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=422605" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="CE Performance Tools" scheme="http://blogs.msdn.com/sloh/archive/tags/CE+Performance+Tools/default.aspx" /></entry><entry><title>Windows CE eHow-tos and Tutorials!  WOW!!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/05/25/421840.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/05/25/421840.aspx</id><published>2005-05-25T21:49:00Z</published><updated>2005-05-25T21:49:00Z</updated><content type="html">&lt;P&gt;I saw a blip of this at MEDC, and just checked it out myself.&amp;nbsp; How cool!&amp;nbsp; It's like a DevCon for all to share!&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/embedded/getstart/basics/tutorialsce/default.aspx"&gt;http://msdn.microsoft.com/embedded/getstart/basics/tutorialsce/default.aspx&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Most of it is pretty basic stuff,&amp;nbsp;but if you're new to Windows CE, you should check&amp;nbsp;some of these&amp;nbsp;out!&amp;nbsp; (If you are new to performance tools like Remote Kernel Tracker which I've been posting about, take a look at the&amp;nbsp;&lt;A&gt;Microsoft Windows CE 5.0 Advanced Lab&lt;/A&gt;&amp;nbsp;that's on that site.)&lt;/P&gt;
&lt;P&gt;Sue&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=421840" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="CE Performance Tools" scheme="http://blogs.msdn.com/sloh/archive/tags/CE+Performance+Tools/default.aspx" /><category term="Debugging, Kernel &amp; misc. File System issues" scheme="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx" /></entry><entry><title>Using RAM over 512MB</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/05/25/421750.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/05/25/421750.aspx</id><published>2005-05-25T18:23:00Z</published><updated>2005-05-25T18:23:00Z</updated><content type="html">&lt;P&gt;&lt;STRONG&gt;Q:&lt;/STRONG&gt; &lt;FONT size=2&gt;I can use only 512MB of RAM from&amp;nbsp;my device. How can I address the remaining RAM ? &lt;a href="http://blogs.msdn.com/sloh/archive/2004/09/09/227599.aspx"&gt;On one of your posts&lt;/A&gt; you said that there is a way to go with more that 512 MB RAM. Can you help me on this issue?&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;A:&lt;/STRONG&gt;&amp;nbsp;Windows CE can't address more than 512MB.&amp;nbsp; There's no way to make the OS use it the way it uses other RAM.&amp;nbsp; OEMAddressTable, OEMGetExtensionDRAM&amp;nbsp;and OEMEnumExtensionDRAM are all limited to 512MB.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;The only thing you can do is write applications that specifically know about the extra memory.&amp;nbsp; They can use&amp;nbsp;&lt;FONT size=2&gt;VirtualAlloc with address 0 to reserve some virtual address space, and then use VirtualCopy with the PAGE_PHYSICAL to map the physical memory above 512MB into the virtual address space.&amp;nbsp; In this manner the application can use the additional RAM. &lt;/FONT&gt;&amp;nbsp;&lt;FONT size=2&gt;But the memory won't be used by the system the way other memory is.&amp;nbsp; It won't go into the pool that's used for general operation; other applications won't ever get that memory.&amp;nbsp; Your system could use up all of the first 512MB and then "run out of memory" because it can't use the other 512MB.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;If your device&amp;nbsp;needs a lot of resources like this, you might want to look into Windows XP Embedded instead.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;Q:&lt;/STRONG&gt; Are there any plans to address this problem in future releases of Windows CE?&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;A:&lt;/STRONG&gt; I cannot comment on what will or will not be in future releases.&amp;nbsp; I can only say, so far I don't think it is a high priority.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT size=2&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=421750" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Debugging, Kernel &amp; misc. File System issues" scheme="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx" /></entry><entry><title>Recognizing Excessive Thread Switching</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/05/23/421057.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/05/23/421057.aspx</id><published>2005-05-23T17:16:00Z</published><updated>2005-05-23T17:16:00Z</updated><content type="html">&lt;P class=Text&gt;&lt;FONT face=Verdana size=2&gt;Sometimes the source of a performance problem is not that code is too slow, but that threads switch too frequently. When the system switches between threads, the system consumes extra cycles in scheduling activities such as selecting the next thread to run, or switching to the new thread, rather than spending the time executing application code. In general, the less time threads run before switching out, the more total time the system spends scheduling new threads to run.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Text&gt;&lt;FONT face=Verdana size=2&gt;The default amount of time that a thread runs before switching to another thread is called the Default Thread Quantum, &lt;SPAN class=Bold&gt;&lt;I&gt;&lt;SPAN&gt;dwDefaultThreadQuantum&lt;/SPAN&gt;&lt;/I&gt;&lt;/SPAN&gt;. For example, if the default thread quantum is 100 milliseconds, then a thread would run continuously for 100 milliseconds before another thread ran, unless preempted by a higher-priority thread. &lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Text&gt;&lt;FONT face=Verdana size=2&gt;In a system where threads run to the end of a 100-millisecond quantum, there is one thread switch per 100 milliseconds, or 10 thread switches per second. In contrast, in a system where threads run only 50 microseconds before switching, there is one switch per 50 microseconds, or 20,000 thread switches per second. Switching at such an elevated rate has a dramatic performance impact.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Text&gt;&lt;FONT face=Verdana size=2&gt;You can use Remote Kernel Tracker to identify these situations. Remote Kernel Tracker depicts thread switches as vertical green lines.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Text&gt;&lt;FONT face=Verdana size=2&gt;The following screenshot shows an example of an application with excessive thread switching. In this picture, I’ve set two markers in the time scale at the top of the display. The difference in time between the two is displayed in the status bar on the bottom right, so from time marker 1 to time marker 2 is 10 milliseconds. As you can see, there are numerous vertical green lines; each represents a switch from one thread to another.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;(scroll down if you can't see anything)&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_contextswitch1.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;You also can see above that the threads seem to be continuously repeating a pattern. The next picture zooms in on that pattern:&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;EM&gt;(again, scroll down if you can't see anything)&lt;/EM&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_contextswitch2.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal&gt;As you can see in the preceding picture, the “&lt;SPAN class=bold&gt;OpenDeviceKey”&lt;/SPAN&gt; thread runs the longest continuous time, about 0.6 milliseconds. The next longest run-time in this screenshot, “&lt;SPAN class=bold&gt;RndisSendRndisMessage&lt;/SPAN&gt;&lt;STRONG&gt;,”&lt;/STRONG&gt; is 0.16 milliseconds. The greatest switching activity, between “&lt;SPAN class=bold&gt;UsbInterruptThreadStub”&lt;/SPAN&gt; and “&lt;SPAN class=bold&gt;DmacIntrThread&lt;/SPAN&gt;&lt;STRONG&gt;,” &lt;/STRONG&gt;occurs at a rate of one switch approximately every 50 &lt;U&gt;micro&lt;/U&gt;seconds. One thread switch per 50us is a rate of 20,000 thread switches per second. This means that thread switching occurs at a rate that is about 2000 times higher than the ideal.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Let me describe where these screen shots came from:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;B&gt;The problem:&lt;/B&gt; Poor USB throughput.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;On particular hardware we expected to get about 50Mbps throughput, but were getting only about 23Mbps.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;B&gt;The investigation:&lt;/B&gt; We recorded a Monte Carlo profiling trace, with these results:&lt;/P&gt;
&lt;B&gt;HITS PER SYMBOL&lt;/A&gt;&lt;/B&gt;&lt;BR&gt;
&lt;TABLE cellSpacing=4&gt;

&lt;TR&gt;
&lt;TH&gt;Hits&lt;/TH&gt;
&lt;TH&gt;Percent&lt;/TH&gt;
&lt;TH&gt;Address&lt;/TH&gt;
&lt;TH&gt;Module&lt;/TH&gt;
&lt;TH align=left&gt;Routine&lt;/TH&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;6557&lt;/TD&gt;
&lt;TD&gt;7.3&lt;/TD&gt;
&lt;TD&gt;0x8012C8FC&lt;/TD&gt;
&lt;TD&gt;NK.EXE&lt;/TD&gt;
&lt;TD align=left&gt;IDLE_STATE&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;4643&lt;/TD&gt;
&lt;TD&gt;5.2&lt;/TD&gt;
&lt;TD&gt;0x8010E330&lt;/TD&gt;
&lt;TD&gt;NK.EXE&lt;/TD&gt;
&lt;TD align=left&gt;INTERRUPTS_ENABLE&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;2882&lt;/TD&gt;
&lt;TD&gt;3.2&lt;/TD&gt;
&lt;TD&gt;0x02FEA884&lt;/TD&gt;
&lt;TD&gt;tcpstk.dll&lt;/TD&gt;
&lt;TD align=left&gt;tcpxsum&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#008000&gt;&lt;STRONG&gt;2166&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#008000&gt;&lt;STRONG&gt;2.4&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#008000&gt;&lt;STRONG&gt;0x80110894&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#008000&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#008000&gt;&lt;STRONG&gt;ObjectCall&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;2123&lt;/TD&gt;
&lt;TD&gt;2.4&lt;/TD&gt;
&lt;TD&gt;0x03FA37B8&lt;/TD&gt;
&lt;TD&gt;coredll.dll&lt;/TD&gt;
&lt;TD align=left&gt;memcpybigblk&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;2064&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;2.3&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;0x8010DB7C&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;NK.EXE&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;PrefetchAbort&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;1732&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;1.9&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;0x80110EC0&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;NK.EXE&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;STRONG&gt;&lt;FONT color=#008000&gt;ServerCallReturn&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;1518&lt;/TD&gt;
&lt;TD&gt;1.7&lt;/TD&gt;
&lt;TD&gt;0x801491D4&lt;/TD&gt;
&lt;TD&gt;NK.EXE&lt;/TD&gt;
&lt;TD align=left&gt;OEMWriteDebugByte&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1468&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1.6&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;0x8011A094&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;SleepOneMore&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1460&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1.6&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;0x8011BCDC&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;WaitOneMore&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1418&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1.6&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;0x80119360&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;KCNextThread&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1405&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1.6&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;0x8011C154&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;SC_WaitForMultiple&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;1404&lt;/TD&gt;
&lt;TD&gt;1.6&lt;/TD&gt;
&lt;TD&gt;0x8010E00C&lt;/TD&gt;
&lt;TD&gt;NK.EXE&lt;/TD&gt;
&lt;TD align=left&gt;IRQHandler&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1255&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1.4&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;0x8010DEC0&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;SaveAndReschedule&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;1212&lt;/TD&gt;
&lt;TD&gt;1.4&lt;/TD&gt;
&lt;TD&gt;0x03F73CA0&lt;/TD&gt;
&lt;TD&gt;coredll.dll&lt;/TD&gt;
&lt;TD align=left&gt;xxx_CeLogData&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;1145&lt;/TD&gt;
&lt;TD&gt;1.3&lt;/TD&gt;
&lt;TD&gt;0x03F68258&lt;/TD&gt;
&lt;TD&gt;coredll.dll&lt;/TD&gt;
&lt;TD align=left&gt;xxx_GetTickCount&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;979&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1.1&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;0x8010EF34&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;KCALLPROFON&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;908&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;1.0&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;0x8010EFE0&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;NK.EXE&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD align=left&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;KCALLPROFOFF&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR align=right&gt;
&lt;TD&gt;865&lt;/TD&gt;
&lt;TD&gt;1.0&lt;/TD&gt;
&lt;TD&gt;0x017A4544&lt;/TD&gt;
&lt;TD&gt;pxa27x_dma.dll&lt;/TD&gt;
&lt;TD align=left&gt;InterruptDone&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;The lines in&amp;nbsp;green are all related to making API calls.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The ones in&amp;nbsp;blue are all involved with thread rescheduling.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I was a little suspicious about the number of API calls and the amount of thread rescheduling that was going on here.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;KCNextThread is the primary kernel function which selects the next thread to run, and having that show up 1.6 percent of the time is pretty significant.&amp;nbsp; The API call time might also&amp;nbsp;be partly blamed on calling into the kernel to reschedule.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Then we looked at a Kernel Tracker trace for the same scenario, and saw the screen shots above.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I realized how much thread switching was going on, and brought it to the attention of the folks who owned the code involved.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;B&gt;The fix:&lt;/B&gt; They changed the design so that the work done between the two most active threads (UsbInterruptThreadStub and DmacIntrThread) was all on one thread instead of shared between two.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;As a result, the USB throughput jumped from 23Mbps to almost 41Mbps.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=421057" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="CE Performance Tools" scheme="http://blogs.msdn.com/sloh/archive/tags/CE+Performance+Tools/default.aspx" /></entry><entry><title>Remote Kernel Tracker: More things you should recognize</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/05/21/Remote-Kernel-Tracker-2.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/05/21/Remote-Kernel-Tracker-2.aspx</id><published>2005-05-21T08:06:00Z</published><updated>2005-05-21T08:06:00Z</updated><content type="html">&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;I have a few more examples of patterns you can recognize when you’re looking at CeLog threading data in Remote Kernel Tracker.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;I style="mso-bidi-font-style: normal"&gt;Note: these images are wacky heights because I tweaked them to cut off white space that didn’t contain any CeLog data.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/I&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="FONT-SIZE: 14pt"&gt;Thread Migration&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;I realized that in &lt;A href="/sloh/archive/2005/05/17/418739.aspx"&gt;my previous Kernel Tracker post&lt;/A&gt; I meant to add a screen shot of thread migration, and forgot.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is an example of what thread migration looks like in Remote Kernel Tracker.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;There’s a raised dashed line which represents that the thread is still running, but inside a different process.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;EM&gt;(scroll down if you can't see anything)&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_migrate.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 1:&lt;/B&gt; Example of what thread migration looks like.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="FONT-SIZE: 14pt"&gt;KITL / debug messages&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;I like this example which hammers home how much work is involved in heavy KITL traffic.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I run a program called enumfiles.exe which enumerates all of the files in the device file system.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The KITL traffic is due to a few different things: mainly the heavy debug messages, and the enumeration of files inside the release directory via RELFSD.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;(The release directory file system driver, which mounts the release directory from the desktop PC as \Release on the device.)&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this case I also loaded the program over KITL from my release directory, so some of this traffic is the work copying code onto the device.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_kitl.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 2:&lt;/B&gt; For a program that’s just enumerating the file system, that’s a lot of time on the KITL thread.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;As you can see, when the enumfiles.exe program starts, a lot of other activity begins too.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The KITL interrupt (25 on this device) and the KITL IST start working overtime.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I like this example because it shows that your code doesn’t always live in the vacuum you might expect.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The system calls you make, or the pure existence of your program, can fire off other activity in the system.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Does the system &lt;I style="mso-bidi-font-style: normal"&gt;really&lt;/I&gt; behave as you expect?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Tools like CeLog and Remote Kernel Tracker are the way to find out for sure.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;I style="mso-bidi-font-style: normal"&gt;&lt;A href="/mikehall/"&gt;Mike Hall&lt;/A&gt; uses an older version of my enumfiles program (walktree.exe) when he gives labs to teach people how to use Remote Kernel Tracker, so if you’ve taken any labs from Mike at DevCons or other events, you may have played with this same program yourself!&lt;o:p&gt;&lt;/o:p&gt;&lt;/I&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /&gt;&lt;st1:place w:st="on"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="FONT-SIZE: 14pt"&gt;Flushing&lt;/SPAN&gt;&lt;/B&gt;&lt;/st1:place&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="FONT-SIZE: 14pt"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;It’s good to know what activity represents side effects of data gathering itself.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Whether you have Remote Kernel Tracker actively connected to a device and collecting data, or you’re running CeLogFlush.exe to save data on a standalone device, the thread that manages the data impacts the system a little itself.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 3&lt;/B&gt; shows CeLogFlush.exe flushing periodically.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this case I specified that CeLogFlush.exe should flush at 3-second intervals, so that more than one flush would show in the same window.&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_CeLogFlush.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 3:&lt;/B&gt; CeLogFlush data flushing at 3 second intervals when data’s not being logged heavily.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;As you can see above, when there’s not a lot of activity, flushing can be a pretty fast operation.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The vertical lines showing a lot of thread switching aren’t very wide; the flush is over quickly.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;Incidentally, you can see that the switching is between the CeLogFlush.exe thread and the KITL thread – OK now tell me where I was storing the log file?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;That’s right, in \Release which required KITL to transport the file data to the release directory on the PC.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Otherwise there’d be less thread switching because it could write to local storage on the device without switching to the KITL thread.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;In contrast, &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 4&lt;/B&gt; shows how much of a load flushing can be on a busy system.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;There are a lot more events being logged, so there is more data to flush and flushes take longer.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The RAM buffer that the data is temporarily stored in fills more quickly than 3 seconds, so the flushes are more frequent.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_CeLogFlush2.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 4:&lt;/B&gt; CeLogFlush flushing during heavy logging activity.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;For completeness I’m including &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 5&lt;/B&gt; which shows what flushes look like when you’re using Remote Kernel Tracker to transport the data to your PC, instead of using CeLogFlush.exe.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;You can see that RTH.EXE does the flushing, and that it flushes over KITL about once per second.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_RTHFlush.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 5:&lt;/B&gt; Remote Kernel Tracker data flushing.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="FONT-SIZE: 14pt"&gt;Data Loss&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;I wrote up a couple of sections about data loss in our recent newly-released CeLog documentation:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 39pt; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;·&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/wcedebug5/html/wce51conAnalyzingDataLossWithRemoteKernelTracker.asp"&gt;Analyzing Data Loss with Remote Kernel Tracker&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 39pt; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;·&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/wcedebug5/html/wce51conRecognizingDataLossInReadlogexe.asp"&gt;Analyzing Data Loss with Readlog&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;But I could not include screen shots.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Here is a screen shot to show you how to recognize data loss when you’re looking at it in Remote Kernel Tracker.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_dataloss.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 6:&lt;/B&gt; The signs of data loss.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;The three characteristics I describe in the Kernel Tracker article are visible in &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 5&lt;/B&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, it pops up a dialog box telling you how many bytes of data have been lost over time in the log.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Second, the interrupt activity appears to stop completely, and one thread appears to be running for a long period.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this screen shot I didn’t expand explorer.exe to show that thread, but it was a single thread and it had no icons showing events occurring during the thread run-time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Finally, when activity picks up again, the flush thread (RTH.EXE) is busy working.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;All of these characteristics are strong hints that the apparently “inactive” period is really a period of time from which data was lost.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="FONT-SIZE: 14pt"&gt;More Tips&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;While I was poking around building up screen shots for this write-up, I caught one view that surprised me a bit.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Look how much priority inversion is going on here!&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is a database test program spewing lots of debug output.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;KITL isn’t something that actually requires “real” real-time, but perhaps I should get someone to examine why we hit priority inversion so regularly.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_prioinversion2.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 7:&lt;/B&gt; Debug output leading to lots of priority inversion.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;Let it be a lesson that while you’re testing real-time response in your system, you should disable KITL.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;And that while you’re running performance tests, for heaven’s sake don’t write a lot of debug messages.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;Another little exercise.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;On the left and right of &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 7&lt;/B&gt; are some periods where activity drops dramatically.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Do those periods represent data loss?&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;The answer is no, because of two clues.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, SYSINTR 0 is still going strong.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Keep an eye on that whenever you’re running a profiling build.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 'MS Mincho'; mso-ansi-language: EN-US; mso-fareast-language: JA; mso-bidi-language: AR-SA"&gt;(I’d say all the time but only profiling builds record interrupts.)&lt;/SPAN&gt; &lt;/SPAN&gt;SYSINTR 0 occurs frequently enough you should always be able to find it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Second, there are lots of events occurring on the testdb.exe thread during those periods.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;There are so many icons drawn on that thread that they don’t show up clearly in this screen shot.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If it was data loss, there’d be no such activity.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since this particular test program was writing a lot of debug output; the less busy periods probably represent time when the test was doing solid periods of work instead of printing debug messages.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;When you’re not running a profiling build, look for events on the thread that was supposedly executing during the quiet period, to see if that really is a period of data loss.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=420687" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="CE Performance Tools" scheme="http://blogs.msdn.com/sloh/archive/tags/CE+Performance+Tools/default.aspx" /></entry><entry><title>Introduction to Remote Kernel Tracker</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/05/17/Introduction-to-Remote-Kernel-Tracker.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/05/17/Introduction-to-Remote-Kernel-Tracker.aspx</id><published>2005-05-17T17:52:00Z</published><updated>2005-05-17T17:52:00Z</updated><content type="html">&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;When you connect to a device with Remote Kernel Tracker, or when you open a log file that has been collected by one of the other CeLog tools, you’ll see a lot of data you may not understand.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;At MEDC this past week, a few people asked for a better explanation of what they’re seeing.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So let’s go over it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 1&lt;/B&gt; shows a sample of what you might typically see when you connect Remote Kernel Tracker to a device:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;EM&gt;(scroll down if you can't see anything)&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_idle1.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 1:&lt;/B&gt; Typical idle behavior, no processes expanded.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Someone asked me what all the information in the key means.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I’ll go through them a bit at a time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, the thread and process state lines.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_icons_state.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;You can see examples of the process state lines in &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 1&lt;/B&gt; above.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Each process in the system has a horizontal line.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;When one of the threads owned by that process is running, the process line is wide and dark green.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Otherwise the process line is thin and black.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;(In case it’s not clear, only one thread ever runs at a time, so only one process ever runs at a time too.)&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So in the example above, threads owned by kernel (nk.exe) are running almost all the time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The vertical lines you see are due to threads in other processes running for very short periods of time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Remote Kernel Tracker draws vertical lines to represent switches between threads, to make it easier to see which threads ran before and after the thread switch.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Underneath each process are all the threads owned by that process.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Processes can be expanded and collapsed to show and hide the threads, for easy viewing.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;There are no thread lines in &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 1&lt;/B&gt;, because none of the processes have been expanded to display their threads yet.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 2&lt;/B&gt; shows the same log, with some of the process lines expanded and with the key hidden for better viewing.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_idle2.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 2:&lt;/B&gt; Typical idle behavior, interrupts and some processes expanded.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;In &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 2&lt;/B&gt; you can see some thread lines too.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Like the process lines, the thread lines are wide and light green whenever the threads are running, and thin when they are not. Most of the threads, except for “0x00000000,” run for such short times that at the zoom level shown in this screen shot, that you can’t see the horizontal thread-run lines, but you can tell that they ran because you can see the vertical thread-switch lines.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;On the threads you can also see some other icons representing the actions taken by the threads.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;More on these later.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;You can also see that interrupts are represented as lines too, with one line for each SYSINTR value to show when interrupts occur.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;What you’re seeing in these screen shots is typical idle activity on a device.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The thread with handle “0x00000000” is not really a thread, but the placeholder to represent when the CPU is idle.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Most of the other threads that run now and then are interrupt service threads (ISTs).&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Every process will have one thread which has the same name as the process; that is the process’s primary thread, the one which starts running at &lt;SPAN style="FONT-FAMILY: 'Courier New'"&gt;main()&lt;/SPAN&gt; or &lt;SPAN style="FONT-FAMILY: 'Courier New'"&gt;WinMain()&lt;/SPAN&gt; or whatever flavor of entry point the process might use.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;All of the other threads in the process are given the name of the thread’s start routine, such as KITLInterruptThread under the process “NK.EXE” (the kernel).&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;An important detail to note at this point is that some of the features you can see here are due to the fact that you are running a profiling build.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, to minimize the impact of the logging hooks which record this data, interrupt data is only available on profiling builds.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;When the profiler is not present, the “Interrupts” line will not appear.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Second, the thread names are also only available on profiling builds.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Remote Kernel Tracker does not look up thread names from the symbol files in the release directory.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Instead, on profiling builds the CeLog event logging hooks obtain thread names via the special symbol table that is included in ROM for use by the profiler, to represent all the code that is stored in &lt;?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /&gt;&lt;st1:country-region w:st="on"&gt;&lt;st1:place w:st="on"&gt;ROM.&lt;/st1:place&gt;&lt;/st1:country-region&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The profiler uses that symbol table to look up symbols for profiling hits, and the logging hooks take advantage of the symbol table in order to provide thread names.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Threads from processes and DLLs that are not stored in the “modules” section of ROM will not have names, since they will not be listed in the profiler’s symbol table.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;And on non-profiling builds, no threads will have names.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;There is also a trick you can use to make the desktop tool “readlog.exe” look up symbols from the release directory and build a new log file containing the thread names on any build and regardless of where the thread’s code is running from.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I don’t quite have documentation to point you to about that yet, but open up a release directory build window and type “readlog -?” on the command line to find out how to use readlog.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The other thread line I haven’t discussed yet is the Thread Migrate line.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In Windows CE, when a thread calls a system API that is implemented by a different process, the thread moves from its owner process into the system process for the duration of the call.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The Thread Migrate line in Remote Kernel Tracker represents the period of time during which the thread is executing inside a process other than its owner.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;You can hover over the line to learn which process the thread is executing inside.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;In my opinion, this representation of thread migration is not terribly useful.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It helps you see when a thread is running inside a process other than its owner, but it does not help you see the entire set of processes the thread transitions to.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example if your thread calls an API, and that API calls a different API, your thread may actually transition through multiple processes, but it is not easy to see if or when those transitions occur.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Nor does it help you understand why those transitions took place (which APIs the thread was calling).&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Back to the event types in the key.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The main events I pay attention to when I’m looking at a log in Remote Kernel Tracker are a subset of those related to thread scheduling:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_icons_scheduling.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;If you are familiar with the Win32 API set, you probably can guess what these mean.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The critical section events represent when threads call the EnterCriticalSection and LeaveCriticalSection functions, and encounter contention over the critical section object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Critical sections are used so widely that logging every entry and exit would generate too many events and bog down system performance.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So only those calls which block the current thread or unblock another thread are logged.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The Set Event, Reset Event and Pulse Event events represent actions taken on Win32 “event” objects.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Similarly the Release Semaphore and Release Mutex events represent actions on Win32 semaphore and mutex objects.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The wait event represents a call to the Win32 WaitForSingleObject or WaitForMultipleObjects APIs, regardless of whether the thread blocks on those objects or not.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Finally, the Sleep Event event represents when the thread calls the Win32 Sleep API.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In general I am not a big fan of Sleep, at least non-zero Sleep periods.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Often it represents lazy programming, and results in polling that churns CPU time and drains power.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, observe the behavior of the selected thread in &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 3&lt;/B&gt; below.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This thread is polling at 500ms intervals.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_sleep.png"&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 3:&lt;/B&gt; Using Sleep to poll at regular intervals consumes CPU and drains power.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;If you hunt around most logs, you’ll find cases where one thread will call the SetEvent API, then another thread will start running, do some work, and then block again in WaitForMultipleObjects on the same event handle.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_wait.png"&gt;&lt;/P&gt;&lt;SPAN style="mso-spacerun: yes"&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 4:&lt;/B&gt; A waiting thread is awakened when another thread signals an object.&lt;/P&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 'MS Mincho'; mso-fareast-language: JA; mso-ansi-language: EN-US; mso-bidi-language: AR-SA"&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;In &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 4&lt;/B&gt; you can see that the threadsample.exe main thread set an event (the “flag” icon) that the last thread in the same process was waiting for.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this screen shot I double-clicked on the WaitForMultipleObjects event and the Set Event event to show their data.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This often makes it easier to compare handle values between events.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I know these two events are related because they both apply to handle value “0xA3E0FF96” in this case.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;There are a few other events I also look at when I’m examining logs.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_icons_misc.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The interrupt event you’ve already seen above, representing when interrupt service routines (ISRs) execute.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It’s worth mentioning that you can see relationships between interrupt service routines (ISRs) running – the “interrupt” events you see in Kernel Tracker – and their corresponding interrupt service threads (ISTs) waking up to do further interrupt handling.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 5&lt;/B&gt; below, you can see the ISR for SYSINTR 1 (the timer interrupt, I believe?) run, and then two different ISTs follow up.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;You can also see the ISR for SYSINTR 30 (the KITL interrupt) run, and the KITLInterruptThread wake up to do some work.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If you look back at &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 2&lt;/B&gt; above, you can also see this relationship between the KITL interrupt and KITLInterruptThread when scaled back to a larger zoom level.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Note that no IST runs for SYSINTR 0, which is a no-op.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_IST.png"&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 5:&lt;/B&gt; The relationship between ISRs and ISTs.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The Invert Priorities event is shown on a thread when the kernel temporarily changes the thread’s priority because it holds a resource that some other higher-priority thread needs.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, if a low-priority thread holds a critical section that a high-priority thread tries to enter, the kernel temporarily boosts the low-priority thread to a high priority, to execute until it releases the critical section.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Then the low-priority thread returns to its original priority.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For real-time behavior, you never want real-time threads to block on resources owned by lower-priority threads, since those threads may do an undetermined amount of work before releasing the resources.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 6&lt;/B&gt; is an example of a case where a higher-priority thread ends up boosting the priority of another thread over and over again.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_prioinversion.png"&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 6:&lt;/B&gt; Recurring cases of priority inversion.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The icons in &lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 6&lt;/B&gt; are a little&amp;nbsp;hard to see&amp;nbsp;– sorry – but what’s going on is that a high-priority IST in the kernel enters a critical section that is held every time by a low-priority thread from testdb.exe.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The kernel thread logs a priority-inversion event representing the priority-boost given to the testdb.exe thread.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Then the kernel thread blocks on the critical section.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The now-high-priority testdb.exe thread runs until it leaves the critical section, then logs a priority-inversion event representing its return to its regular priority.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The kernel thread then begins running again, now that it owns the critical section and is the highest-priority thread.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;You can see in this log that the inversion happens regularly in this particular case.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The page fault event represents a costly page fault operation occurring on a thread.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In CE 4.2 and earlier, a page fault event was logged at the beginning of a page fault; in CE 5.0 and later, an event is also logged at the end of the page fault so that you can tell how long the page fault took.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I don’t see this event often, but sometimes I see cases like this, where a thread incurs many page faults:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_pagefault.png"&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 7:&lt;/B&gt; A thread incurring many page faults.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This log is from CE 5.0 so the fault markers are in begin/end pairs so that you can tell how long they took.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;When I see many page faults like this, I run the readlog.exe command-line tool to get a summary of the faults, to determine where they are occurring.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In general the important thing to check is whether the fault address is paged more than once.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Code must be paged once in order to execute at all, but if it is paged more than once, that means the kernel’s page pool is not large enough to hold all the executing code.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In that case the page pool may need to be enlarged.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If data such as memory-mapped files is paged more than once, then the data may not have good page locality, or the system may be in a low-memory state.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 'MS Mincho'; mso-fareast-language: JA; mso-ansi-language: EN-US; mso-bidi-language: AR-SA"&gt;You can also log your own events from your code.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since Remote Kernel Tracker does not have the ability to interpret your data blobs, you may find it useful to log your data using a set of event types that Remote Kernel Tracker does understand:&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_icons_user.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;When Remote Kernel Tracker sees one of these event types, it expects the data logged for that event to be an array of the given type.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, for the “Raw ulong” type Remote Kernel Tracker interprets the data as an array of unsigned long integers (DWORDs).&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_raw3.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 'MS Mincho'; mso-fareast-language: JA; mso-ansi-language: EN-US; mso-bidi-language: AR-SA"&gt;For the “Raw wchar” type the data is an array of Unicode characters, and Remote Kernel Tracker will display it as a string.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_raw2.png"&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;To see the data corresponding to one of these event types, hover over the event to see the tooltip, or double-click on the event to get the data in a separate window.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Note also that the data is displayed in the bottom-left status bar when you click on an event.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG src="http://cenet.members.winisp.net/sloh_files/kt_raw.png"&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: center" align=center&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Screen Shot 8:&lt;/B&gt; Viewing “raw” data in Remote Kernel Tracker.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;/o:p&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="FONT-SIZE: 14pt"&gt;In Summary&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;I hope I have helped you understand what the tool is showing you, and see some of the things you can use CeLog and Remote Kernel Tracker for.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is a very versatile tool.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It might take some practice to recognize these relationships between events, but a basic understanding of what thread behavior looks like in Kernel Tracker is the first thing you need when you’re troubleshooting a wide range of performance problems.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Remote &lt;SPAN style="mso-bidi-font-weight: bold"&gt;Kernel Tracker&lt;/SPAN&gt; enables you to track down bugs related to thread interactions that are difficult to track with traditional development tools, including deadlocks, race conditions, excessive context switching or priority problems.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;I have some more posts coming in the near future, about more scenarios you can recognize when you get used to Remote Kernel Tracker.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=418739" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="CE Performance Tools" scheme="http://blogs.msdn.com/sloh/archive/tags/CE+Performance+Tools/default.aspx" /></entry><entry><title>CeLog documentation</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/05/16/417936.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/05/16/417936.aspx</id><published>2005-05-16T16:55:00Z</published><updated>2005-05-16T16:55:00Z</updated><content type="html">&lt;P&gt;At long last, a big chunk of work I did to add documentation of CeLog &amp;amp; Remote Kernel Tracker has finally shown up in a form you can view.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/wcedebug5/html/wce50conEventTracking.asp"&gt;http://msdn.microsoft.com/library/en-us/wcedebug5/html/wce50conEventTracking.asp&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;I did a huge brain dump and tried to get all of my tips &amp;amp; tricks down on paper.&amp;nbsp; There are descriptions of how to use tools to gather data on standalone devices, how to log your own data and how to customize the tools.&amp;nbsp; There is a little bit&amp;nbsp;more work&amp;nbsp;to go -- some information really required Kernel Tracker screen shots, and right now we can't include screen shots in our documentation.&amp;nbsp; We've been discussing other formats to release the information in, but for now I am planning to post a bunch of it on my blog.&amp;nbsp; I have it mostly written up, but am trying to set up a web share to hold the pictures.&amp;nbsp; (I don't have any storage space to use with my blog, so I can only post text at the moment, but that should change soon.)&lt;/P&gt;
&lt;P&gt;So look for more in the coming days!&amp;nbsp; I got to show off Remote Kernel Tracker to a lot of folks&amp;nbsp;at MEDC, and got some good questions.&amp;nbsp; I hope that between the documentation posted above and the material I'll add to my blog soon, you'll get to be as much an expert in using CeLog and Remote Kernel Tracker as I am.&lt;/P&gt;
&lt;P&gt;Happy logging!&lt;/P&gt;
&lt;P&gt;Sue&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=417936" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="CE Performance Tools" scheme="http://blogs.msdn.com/sloh/archive/tags/CE+Performance+Tools/default.aspx" /></entry><entry><title>How does the OS use the registry?</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/04/11/407286.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/04/11/407286.aspx</id><published>2005-04-11T20:07:00Z</published><updated>2005-04-11T20:07:00Z</updated><content type="html">&lt;FONT size=2&gt;
&lt;P&gt;&lt;STRONG&gt;Q: &lt;/STRONG&gt;As an embedded programmer I am new to all windows development. And as such I am ignorant of the registry. It seems to play a crucial part in the initialization of the OS (device drivers, services, etc) Do you know of a good source of information about how the OS (not individual applications) uses the registry?&lt;/P&gt;&lt;FONT size=2&gt;
&lt;P&gt;&lt;STRONG&gt;A: &lt;/STRONG&gt;Sorry, I don't have any good sources of information to point you at. The registry is sort of a cross between a database and a file system -- the data is stored hierarchically like a file system, in small values with different types. The OS mostly uses the registry for reading in configuration information that you (or applications) can change. There isn't one big document for all registry information that is used by the system, but I know our documentation team has been making an effort to document all the settings on an area-by-area basis. For example, &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/wcedata5/html/wce50oriFileSystemsDataStoreRegistrySamples.asp"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;http://msdn.microsoft.com/library/en-us/wcedata5/html/wce50oriFileSystemsDataStoreRegistrySamples.asp&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;&lt;FONT size=2&gt;
&lt;P&gt;Most parts of the OS have default registry settings that they use, some of which may be controlled by relatively high-level flags you can set like PRJ_* and IMG*. &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/wceosdev5/html/wce50conPRJEnvironmentVariables.asp"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;http://msdn.microsoft.com/library/en-us/wceosdev5/html/wce50conPRJEnvironmentVariables.asp&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;&lt;FONT size=2&gt;
&lt;P&gt;The OS should be able to boot and run based on these variables, without you having to tweak many (any?) individual settings. Then you can tweak things to modify OS behavior as needed. The hard question I can't answer is what settings you might want to tweak. I guess you will have to find those out as you go.&lt;/P&gt;
&lt;P&gt;Sorry I'm not more help than that,&lt;/P&gt;
&lt;P&gt;Sue&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=407286" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Debugging, Kernel &amp; misc. File System issues" scheme="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx" /></entry><entry><title>More CE database Q&amp;A</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/04/11/407282.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/04/11/407282.aspx</id><published>2005-04-11T20:00:00Z</published><updated>2005-04-11T20:00:00Z</updated><content type="html">&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;Posting some questions I received from my blog.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;&lt;FONT face=Arial&gt;1. You mentioned the that the maximum size of an object store is 256MB. Which versions of Windows CE does this apply, Windows Mobile 2003, Pocket PC 2002?&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;It applies to all versions of Windows CE.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;&lt;FONT face=Arial&gt;2. Do the limitations of database in the object store apply to databases created in the filesystem?&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;Databases in the object store cannot exceed CEDB_MAXNUMRECORDS (=64K) records.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Database volumes (files containing databases) cannot exceed 16MB and the databases inside those volumes still cannot exceed CEDB_MAXNUMRECORDS records.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;&lt;FONT face=Arial&gt;3. Is there a maximum size of a database record in an Object Store? If yes what is it?&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;&lt;FONT face=Arial&gt;4. Is there a maximum size for a field in a database record? If yes what is it?&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;For both the object store and database volume files, one record cannot have more than CEDB_MAXRECORDSIZE bytes (=128KB), and one property value cannot exceed CEDB_MAXPROPDATASIZE bytes (a little short of 64KB).&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;Be careful of the CEDB terminology difference compared to other database engines: A CEDB "database volume" is a "database" to other engines, and a CEDB "database" is a "table" to other engines.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The database volumes were created to let you store your data in a file instead of in the object store, so you can think of the object store as just a special-case "default" database volume.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face=Arial size=2&gt;&lt;U&gt;If you are running into these size limitations, you are probably far better off with SQL-CE than CEDB.&lt;/U&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Or with a new offering (as of CE 5.0), EDB, which is a trimmed-down version of SQL that presents a programming interface very similar to CEDB for easy porting.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;CEDB has very poor performance once you go over ~1000 records.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=407282" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="CE Databases" scheme="http://blogs.msdn.com/sloh/archive/tags/CE+Databases/default.aspx" /></entry><entry><title>GetTickCount – Truth and Fiction</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/04/05/405724.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/04/05/405724.aspx</id><published>2005-04-06T02:16:00Z</published><updated>2005-04-06T02:16:00Z</updated><content type="html">&lt;P class=MsoNormal&gt;I was surprised and dismayed to read a recent article in Embedded Systems Programming (&lt;A href="http://www.embedded.com/showArticle.jhtml?articleID=159902113"&gt;http://www.embedded.com/showArticle.jhtml?articleID=159902113&lt;/A&gt;) that gets so many things wrong about the GetTickCount API and portrays Windows CE so negatively.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Apparently I’m behind on my reading, since the same author also wrote a previous article on the same subject, to which Mike Hall wrote a rebuttal on his own blog: &lt;a href="http://blogs.msdn.com/mikehall/archive/2005/01/28/362498.aspx"&gt;http://blogs.msdn.com/mikehall/archive/2005/01/28/362498.aspx&lt;/A&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Reading the more recent article makes me want to write my own rebuttal.&lt;/P&gt;
&lt;P class=MsoNormal&gt;GetTickCount is a pretty simple API from the caller’s perspective.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Every millisecond the tick count increments, and you can use GetTickCount to retrieve the number of milliseconds since boot. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Since GetTickCount returns only a 32-bit number, after about 49 days, the counter wraps. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;This is &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecoreos5/html/wce50lrfGetTickCount.asp"&gt;documented behavior&lt;/A&gt;, and to properly use GetTickCount you have to understand that. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Typically GetTickCount is used to time the duration between two events, in which case you’re generally safe if you subtract two values; subtraction is safe in the presence of rollover.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;(eg. If you get a tick count of &lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;0xFFFFFF00&lt;/STRONG&gt;&lt;/FONT&gt; before the rollover, and a tick count of &lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;0x200&lt;/STRONG&gt;&lt;/FONT&gt; after the rollover, subtraction gives you get a difference of &lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;0x300&lt;/STRONG&gt;&lt;/FONT&gt; as expected.)&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The only time subtraction can get you into hot water is if there’s a chance the time delta will exceed 49 days, because you may end up needing a difference that’s larger than you can represent in 32 bits.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;In which case GetTickCount is the wrong API for you.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I guess in that case you would probably need to implement something using GetSystemTime and SystemTimeToFileTime.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Applications that use GetTickCount get into trouble if they are subtracting over such a long time period, or if they are using something besides subtraction with the tick count.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;For example,&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (GetTickCount() &amp;gt; MyTickValue) { ... }&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;will also get you into trouble.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If I were to guess, that’s where I’d say most applications probably go wrong using this API.&lt;/P&gt;
&lt;P class=MsoNormal&gt;To help catch such errors in applications and drivers, Windows CE does a little thing on debug builds – it initializes the tick count such that it rolls over 3 minutes after boot.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The author talks about our 3-minute rollover as if it’s indicative of a problem in the OS, when really it’s just a meager attempt to help catch bugs in applications.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;It’s not much help really, if you ask me, but it might help catch a bug or two.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I’d love to improve on it, but it’s tough to arrange for the timer to roll over at a really useful time for testing your application.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;For example you might think we could create an IOCTL you could call, to set the timer at run-time.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;But making the timer jump at run-time could mess things up.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Suddenly drivers and applications would think 47 days have passed, maybe network drivers time out, all your appointments fire, who knows…&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I’m making things up since I don’t really know how networking or appointments are implemented, but you get the idea.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If you really want to be careful about testing your application or driver that uses GetTickCount, probably the best thing to do is create a wrapper that your code uses to call GetTickCount, and arrange for your wrapper to manipulate the times.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I’d love to see suggestions, and if you can come up with something good we can do in the OS, hey, maybe we will take your advice.&lt;/P&gt;
&lt;P class=MsoNormal&gt;So now I’ll describe how GetTickCount is implemented internally.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;First off, the function is technically owned completely by the OEM, though we provide as many implementations as we can manage, so that OEMs can use those.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The implementation varies per CPU and per OAL, but in general, there’s a 32-bit counter, CurMSec, that is incremented once per millisecond with a timer interrupt.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;That millisecond timer interrupt is also used for other things, like scheduling threads.&lt;/P&gt;
&lt;P class=MsoNormal&gt;To conserve power, when the kernel has no threads to schedule, the system goes into an idle state (implemented by the OEM’s OEMIdle function) where the timer interrupt is extended to a longer period.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;That allows the CPU to spend a longer time in a low-power state.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The idle period is ended when an interrupt fires (the extended timer interrupt or some other interrupt).&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;When the system leaves the idle state, OEMIdle updates CurMSec with the amount of time that the system was idle, using whatever timer the hardware has.&lt;/P&gt;
&lt;P class=MsoNormal&gt;All the magic is really in the OEM’s implementation of OEMIdle.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If you want some code to look at, see &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcehardware5/html/wce50conenablingpowermanagement.asphttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcehardware5/html/wce50conenablingpowermanagement.asp"&gt;the CE 5.0 help article&lt;/A&gt;.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Now, back to the article.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Here are my responses:&lt;/P&gt;
&lt;UL&gt;
&lt;LI class=MsoNormal&gt;One of the things that floors me about this article is that it claims that GetTickCount counts downward, not upward.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;That is just plain wrong. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;I don’t know what gave the author that impression but the counter starts out at 0 and goes up.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If you see any documentation or code that claims otherwise, please tell me and we’ll get it corrected. 
&lt;LI class=MsoNormal&gt;The author also asks whether the counter “sticks” at the same value after rollover, which it doesn’t.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;He seems to imply that it does though. 
&lt;LI class=MsoNormal&gt;GetTickCount also works just fine on 16-bit and 64-bit CPUs, though the author implies that it doesn’t. 
&lt;LI class=MsoNormal&gt;The article brings up cases where counters are non-monotonic, where the counter jumps backwards by a few ticks.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If that happens, it means the timer is not implemented correctly by the OEM.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Most likely something in OEMIdle is not right.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;We do provide documentation of how to implement a timer (&lt;A href="http://msdn.microsoft.com/library/en-us/wcehardware5/html/wce50conImplementationOfVariableTickScheduler.asp"&gt;here’s some&lt;/A&gt;), standard implementations for different CPUs, and &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcedebug5/html/wce50conOALTimerTest.asp"&gt;tests to verify that the timer is implemented correctly&lt;/A&gt;.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;But I’m sure some people would argue that we don’t do enough to help OEMs get this right, and maybe they’re right.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Let’s discuss it.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;What else would you like to see?&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;What trouble have you had? 
&lt;LI class=MsoNormal&gt;All the other examples of badness that the author uses come from desktop Windows as far as I can tell, and they are problems with applications that use GetTickCount improperly, not with Windows itself. 
&lt;LI class=MsoNormal&gt;You could argue that this is too complicated, that GetTickCount should just read the timer hardware straight, and scale to milliseconds.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I think the main reason it was done this way was to standardize between hardware with a count-compare type timer and hardware with a count-down timer.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;It also avoids doing division to convert to milliseconds, especially 64-bit division since 64-bit timers are common. 
&lt;LI class=MsoNormal&gt;The author actually suggests using a stopwatch to measure elapsed time during a performance test.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Even if that was accurate enough, it’s a pain and it’s not automatable.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;How could you run tests regularly to make sure that nothing got worse?&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I fully support the author’s idea that you should loop many times, so that the performance test runs long enough that you &lt;I&gt;could&lt;/I&gt; time it with a stopwatch.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;But that’s for reasons of repeatability, to get rid of variance.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I don’t believe a stopwatch is the right answer.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;For timing code run-times, GetTickCount and QueryPerformanceCounter have satisfied every need I’ve seen so far.&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoNormal&gt;I guess the thing I disliked the most was that the author took a list of implementation complications, application bugs from desktop Windows, incorrect information and “what if’s,” and turned it into a negative portrayal of Windows CE.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Maybe I am just too sensitive about the product I pour so much energy into.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Too many people assume that Microsoft developers don’t care, when the truth is very much the opposite. &lt;/P&gt;
&lt;P class=MsoNormal&gt;Oh man has this discussion gotten long.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Have I ever got just a &lt;I&gt;few&lt;/I&gt; words to say about something?&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Oh well.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Write back if you have opinions to add or if you think I got any technical details wrong.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Sue&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=405724" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Debugging, Kernel &amp; misc. File System issues" scheme="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx" /></entry><entry><title>On the lighter side</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/03/24/401612.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/03/24/401612.aspx</id><published>2005-03-24T18:44:00Z</published><updated>2005-03-24T18:44:00Z</updated><content type="html">&lt;p&gt;It is actually pretty funny to read this page in gizoogle: &lt;a href="http://sites.gizoogle.com/?url=http://blogs.msdn.com/sloh/"&gt;http://sites.gizoogle.com/?url=http://blogs.msdn.com/sloh/&lt;/a&gt;&lt;/p&gt; &lt;p&gt;It's really just an updated version of "jive," but it has been a while since I played with those filters so it's fun again.&amp;nbsp; :-)&lt;/p&gt; &lt;p&gt;Im tha Double O G. and I'm not straight trippin' any raps.&amp;nbsp; Yeay cuz its a pimp thang!&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=401612" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Misc. Fun" scheme="http://blogs.msdn.com/sloh/archive/tags/Misc.+Fun/default.aspx" /></entry><entry><title>DevCon 2005</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/03/16/396788.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/03/16/396788.aspx</id><published>2005-03-16T18:46:00Z</published><updated>2005-03-16T18:46:00Z</updated><content type="html">&lt;p align="left"&gt;Yeay! &amp;nbsp;I'm going to this year's DevCon, which covers both Mobile and Embedded this year (instead of just Embedded as I've gone to in years past).&amp;nbsp; Should be a hoot.&amp;nbsp; I'm signed up as plain staff, not giving any talks (so far!), so I'll be working the booth, Ask the Experts, etc. For more info on DevCon see&amp;nbsp;&lt;a href="http://www.medc2005.com/"&gt;http://www.medc2005.com/&lt;/a&gt;.&lt;/p&gt; &lt;p align="justify"&gt;Sue&lt;/p&gt; &lt;p align="justify"&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=396788" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Misc. Fun" scheme="http://blogs.msdn.com/sloh/archive/tags/Misc.+Fun/default.aspx" /></entry><entry><title>Resolving Symbols Manually on Windows CE (ADDRESS --&gt; SYMBOL)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/sloh/archive/2005/02/28/381706.aspx" /><id>http://blogs.msdn.com/sloh/archive/2005/02/28/381706.aspx</id><published>2005-02-28T19:37:00Z</published><updated>2005-02-28T19:37:00Z</updated><content type="html">&lt;P&gt;You know you've been there.&amp;nbsp; You are looking at a callstack, and the one function you want to know the identity of, failed to resolve symbols or &lt;a href="http://blogs.msdn.com/kitlfirst/archive/2005/02/22/377629.aspx"&gt;has bad symbols&lt;/A&gt;.&amp;nbsp; Dang!&amp;nbsp; If only you knew what function &lt;FONT face="Courier New" color=#a52a2a&gt;0x12345678&lt;/FONT&gt; refers to, you'd find your bug.&lt;/P&gt;
&lt;P&gt;First thing's first: you have to understand the Windows CE virtual memory layout.&amp;nbsp; You have to understand what slots are, and recognize slot 0 &amp;amp; 1 addresses versus addresses from process slots.&amp;nbsp; That’s why &lt;a href="http://blogs.msdn.com/sloh/archive/2005/02/25/380475.aspx"&gt;I blogged about that first&lt;/A&gt;.&amp;nbsp; If you internalized all of those details already, then you’d know that &lt;FONT face="Courier New" color=#a52a2a&gt;0x12345678&lt;/FONT&gt; was inside the process that’s running in the slot starting at &lt;FONT face="Courier New" color=#a52a2a&gt;0x12000000&lt;/FONT&gt;.&amp;nbsp; In fact, it’s at offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x00345678&lt;/FONT&gt; from the start of that .exe.&amp;nbsp; Heck, you’re almost to the symbol already!&lt;/P&gt;
&lt;P&gt;But this shows that the 2 main steps to resolving a symbol are: figuring out what module the address lies within, and figuring out what symbol lies at that offset within the module.&amp;nbsp; If you need to get all the way down to the line of source code involved, you can figure that out too, by figuring out what line of source code is at that offset within the function.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT size=4&gt;Figuring out what module it is&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;To figure out what function or variable is at a particular address, first you need to know what module (DLL or EXE) is loaded into that chunk of RAM.&amp;nbsp; So first you eyeball the address and decide whether it’s a DLL or an EXE.&amp;nbsp; Since EXE code &amp;amp; data starts at the bottom of the slot, and DLL code &amp;amp; data starts at the top, it’s pretty easy to figure out.&amp;nbsp; &lt;FONT face="Courier New" color=#a52a2a&gt;0x12345678&lt;/FONT&gt; is an EXE, &lt;FONT face="Courier New" color=#a52a2a&gt;0x13987654&lt;/FONT&gt; is a DLL.&lt;/P&gt;
&lt;P&gt;Then you look for the DLL or EXE that is the closest match.&amp;nbsp; There are a bunch of ways to do this.&amp;nbsp; You can open up the Modules and Symbols Window, sort by address, and find the module that matches.&amp;nbsp; If you are looking up the symbol for a function, sort by “Image Address Range.”&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;Modules and Symbols Window&lt;BR&gt;Module&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Image Address Range&amp;nbsp;&amp;nbsp;&amp;nbsp; Relocated Data Address Range&lt;/STRONG&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#a52a2a size=2&gt;lmemdebug.dll&amp;nbsp; 0x01AC0000-0x01AC4FFF&lt;BR&gt;kbdmouse.dll&amp;nbsp;&amp;nbsp; 0x01BA0000-0x01BC1FFF&lt;BR&gt;devmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x03EE0000-0x03EE9FFF&amp;nbsp; 0x01FE9000-0x01FE92A4&lt;BR&gt;fsdmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x03F50000-0x03F60FFF&amp;nbsp; 0x01FF7000-0x01FF73F0&lt;BR&gt;coredll.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x03F80000-0x03FD8FFF&amp;nbsp; 0x01FFB000-0x01FFBD64&lt;BR&gt;filesys.exe&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04010000-0x04041FFF&lt;BR&gt;shell.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x06010000-0x06022FFF&lt;BR&gt;device.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x08010000-0x08012FFF&lt;BR&gt;gwes.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x0C010000-0x0C0CBFFF&lt;BR&gt;services.exe&amp;nbsp;&amp;nbsp; 0x12010000-0x12017FFF&lt;BR&gt;nk.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x81200000-0x8123DFFF&amp;nbsp; 0x81FA0000-0x81FFD7BF&lt;BR&gt;hd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x8123E000-0x8123FFFF&amp;nbsp; 0x82002000-0x82002954&lt;BR&gt;osaxst0.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x81240000-0x81246FFF&amp;nbsp; 0x82003000-0x82006328&lt;BR&gt;giisr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x81249000-0x8124AFFF&amp;nbsp; 0x82008000-0x82008504&lt;BR&gt;osaxst1.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x82042000-0x82046FFF&lt;BR&gt;kd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x82047000-0x82060FFF&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;If you’re looking up the symbol for a variable, then for a DLL or EXE with a “Relocated Data Address Range” the variable would fall inside that range; for a DLL or EXE that does not have relocated data, the variable would fall inside the image address range.&amp;nbsp; So you may need to sort on both in order to find the right address range.&lt;/P&gt;
&lt;P&gt;Another option you have is that you can type “gi proc” or “gi mod” in the Target Control Window to get the location where the code is loaded.&amp;nbsp; The exception for this is the kernel, nk.exe, which reports a different value under “gi proc” than where its code is loaded.&amp;nbsp; (These lists don’t show relocated data addresses, so they’re only useful for looking up function symbols.)&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;STRONG&gt;Target Control Window&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Windows CE&amp;gt;gi proc&lt;BR&gt;PROC: Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hProcess: CurAKY :dwVMBase:CurZone&lt;BR&gt;&lt;FONT color=#a52a2a&gt;&amp;nbsp;P00: NK.EXE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 03fb4002 00000001 c2000000 00000000&lt;BR&gt;&amp;nbsp;P01: filesys.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 03f4b69e 00000002 04000000 00000020&lt;BR&gt;&amp;nbsp;P02: shell.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 03dcae86 00000004 06000000 00000000&lt;BR&gt;&amp;nbsp;P03: device.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e3d60f6e 00000008 08000000 00000000&lt;BR&gt;&amp;nbsp;P05: gwes.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4389f8aa 00000020 0c000000 00000000&lt;BR&gt;&amp;nbsp;P08: services.exe&amp;nbsp;&amp;nbsp;&amp;nbsp; 03497182 00000100 12000000 00000000&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&lt;BR&gt;Windows CE&amp;gt;gi mod&lt;BR&gt;&amp;nbsp;MOD: Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pModule :dwInUSE :dwVMBase:CurZone&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#a52a2a size=2&gt;&amp;nbsp;M35: coredll.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb4794 7ffbffff 03f80000 00000000&lt;BR&gt;&amp;nbsp;M45: devmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83d36250 00000008 03ee0000 00000000&lt;BR&gt;&amp;nbsp;M58: fsdmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb1ea0 00000002 03f50000 00000000&lt;BR&gt;&amp;nbsp;M60: giisr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8390c5dc 00000009 81249000 00000000&lt;BR&gt;&amp;nbsp;M65: hd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb425c 00000001 8123e000 00000000&lt;BR&gt;&amp;nbsp;M75: kbdmouse.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 8383be54 00000020 01ba0000 00000000&lt;BR&gt;&amp;nbsp;M76: kd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 82ce7e40 00000001 82047000 00000000&lt;BR&gt;&amp;nbsp;M80: lmemdebug.dll&amp;nbsp;&amp;nbsp; 83d60d30 0000003c 01ac0000 00000000&lt;BR&gt;&amp;nbsp;M98: osaxst0.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb44c0 00000001 81240000 00000000&lt;BR&gt;&amp;nbsp;M99: osaxst1.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83103d6c 00000001 82042000 00000000&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Other possible options – if you have data from a Remote Kernel Tracker / CeLog output file (.clg), that file usually contains a “re-sync” (the output of the CeLogReSync API) where CeLog dumps a list of all the existing threads, processes and modules.&amp;nbsp; (This list doesn’t contain relocated data addresses either.)&amp;nbsp; Here is some sample output from the “readlog” command-line tool which parses CeLog output files, edited a little to fit this web format.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;Readlog.exe Output File&lt;BR&gt;&lt;/STRONG&gt;--:--:--.---.--- : Marker, counter frequency=1193180 Hz, default thread quantum=100&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#a52a2a&gt;&amp;nbsp;0:18:33.578.716 : ProcessCreate, dwVMBase=0x81200000, NK.EXE&lt;BR&gt;&amp;nbsp;0:18:33.578.779 : ProcessCreate, dwVMBase=0x04000000, filesys.exe&lt;BR&gt;&amp;nbsp;0:18:33.578.870 : ProcessCreate, dwVMBase=0x06000000, shell.exe&lt;BR&gt;&amp;nbsp;0:18:33.578.901 : ProcessCreate, dwVMBase=0x08000000, device.exe&lt;BR&gt;&amp;nbsp;0:18:33.579.666 : ProcessCreate, dwVMBase=0x0C000000, gwes.exe&lt;BR&gt;&amp;nbsp;0:18:33.579.979 : ProcessCreate, dwVMBase=0x12000000, services.exe&lt;BR&gt;&amp;nbsp;0:18:33.581.421 : ModuleLoad, dwBase=0x82047000, kd.dll&lt;BR&gt;&amp;nbsp;0:18:33.581.450 : ModuleLoad, dwBase=0x82042000, osaxst1.dll&lt;BR&gt;&amp;nbsp;0:18:33.582.422 : ModuleLoad, dwBase=0x01BA0000, kbdmouse.dll&lt;BR&gt;&amp;nbsp;0:18:33.582.559 : ModuleLoad, dwBase=0x81249000, giisr.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.481 : ModuleLoad, dwBase=0x03EE0000, devmgr.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.494 : ModuleLoad, dwBase=0x01AC0000, lmemdebug.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.673 : ModuleLoad, dwBase=0x03F50000, fsdmgr.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.699 : ModuleLoad, dwBase=0x03F80000, coredll.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.714 : ModuleLoad, dwBase=0x81240000, osaxst0.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.727 : ModuleLoad, dwBase=0x8123E000, hd.dll&lt;BR&gt;&lt;/FONT&gt;--:--:--.---.--- : Sync End Marker&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Another option you have is to use the ToolHelp APIs (CreateToolhelp32Snapshot, etc) to programmatically gather this data.&lt;/P&gt;
&lt;P&gt;It’s relatively straightforward to figure out, given an address, which module that address falls inside.&amp;nbsp; Use the “Price Is Right” matching: whichever module is closest to that address, without going over, is the matching module.&amp;nbsp; [“The Price is Right” is an old US TV game show.]&amp;nbsp; Address &lt;FONT face="Courier New" color=#a52a2a&gt;0x8123FFFF&lt;/FONT&gt; is inside hd.dll; &lt;FONT face="Courier New" color=#a52a2a&gt;0x81240000&lt;/FONT&gt; is inside osaxst0.dll.&lt;/P&gt;
&lt;P&gt;The main thing you have to be careful about is recognizing addresses that are inside process slots, and converting them to slot 0 addresses.&amp;nbsp; Address &lt;FONT face="Courier New" color=#a52a2a&gt;0x09EE5678&lt;/FONT&gt; is inside devmgr.dll, not device.exe.&amp;nbsp; (ERRATA: See comments below for the error in this statement.&amp;nbsp; I've left the text here unchanged so that you know what I was talking about.&amp;nbsp; For the sake of the remainder of this write-up, just pretend devmgr.dll loads at address range &lt;FONT face="Courier New" color=#a52a2a&gt;0x01EE0000-0x01EE9FFF&lt;/FONT&gt; instead of the range I listed in all the examples above.)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT size=4&gt;Figuring out what function or global variable it is&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Once you know what DLL or EXE the address is within, you can simply subtract the DLL or EXE base address from the address in question, to get the offset of the address from the start of the DLL or EXE.&amp;nbsp; So address &lt;FONT face="Courier New" color=#a52a2a&gt;0x09EE5678&lt;/FONT&gt; is at offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005678&lt;/FONT&gt; from the start of devmgr.dll.&lt;/P&gt;
&lt;P&gt;Then you look up the offset from the .map file for the DLL or EXE.&amp;nbsp; You should already have the .map files from most modules you work with, but if you are missing one, it may be because the &lt;STRONG&gt;WINCEMAP&lt;/STRONG&gt; environment variable must be set to 1 when the module is&amp;nbsp; linked, in order to produce the .map file.&lt;/P&gt;
&lt;P&gt;Here’s an excerpt from devmgr.map.&amp;nbsp; The important things in the .map file are the function names and the addresses on the right side (highlighted):&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;Preferred load address is 10000000&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&amp;nbsp;0001:000044b0 &lt;FONT&gt;_ConvertStringToGuid&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 100054b0&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004546 &lt;FONT&gt;_FindDeviceInterface&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 10005546&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:0000456c &lt;FONT&gt;_I_AdvertiseDeviceInterface 1000556c&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004774 &lt;FONT&gt;_PnpAdvertiseInterfaces&amp;nbsp;&amp;nbsp;&amp;nbsp; 10005774&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004a9b &lt;FONT&gt;_PnpDeadvertiseInterfaces&amp;nbsp; 10005a9b&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004ae5 &lt;FONT&gt;_InitializePnPNotifications 10005ae5&lt;/FONT&gt; f devcore:devpnp.obj&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The address on the right is saying where the function would live in RAM if the DLL was loaded at its PreferredLoadAddress – which is stored at the top of the .map file, but is almost always &lt;FONT face="Courier New" color=#a52a2a&gt;0x10000000&lt;/FONT&gt; for a DLL.&amp;nbsp; Which makes it easy, because you just chop off the top part of the address to find out where the function would live if the DLL was loaded starting at 0.&amp;nbsp; So offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005678&lt;/FONT&gt; from the beginning of devmgr.dll is the symbol &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt;.&amp;nbsp; Any offset between &lt;FONT face="Courier New" color=#a52a2a&gt;0x0000556C&lt;/FONT&gt; and &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005773&lt;/FONT&gt; inside devmgr.dll falls inside &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt;.&amp;nbsp; And, since devmgr.dll is loaded at address &lt;FONT face="Courier New" color=#a52a2a&gt;0x03EE0000&lt;/FONT&gt;, any address between &lt;FONT face="Courier New" color=#a52a2a&gt;0x03EE556C&lt;/FONT&gt; and &lt;FONT face="Courier New" color=#a52a2a&gt;0x03EE5773&lt;/FONT&gt; corresponds to &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt;.&amp;nbsp; So again you are basically using “Price is Right” matching.&lt;/P&gt;
&lt;P&gt;EXEs are a little different, but even easier.&amp;nbsp; Most EXEs will be linked with a PreferredLoadAddress of &lt;FONT face="Courier New" color=#a52a2a&gt;0x00010000&lt;/FONT&gt;, but that is the spot the Windows CE kernel always loads an EXE at anyway.&amp;nbsp; So there’s no subtraction involved – just use the address to the right of the symbol.&lt;/P&gt;
&lt;P&gt;Once you get used to doing this stuff, it’s not that hard, just a little manual labor.&amp;nbsp; In general the formula for going from ADDRESS à SYMBOL is:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(.map file offset) = (address) – (module base addr) + (module preferred load addr)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;And remember to use “Price is Right” matching for the module and the symbol: whichever has the closest address without going over is the closest match.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT size=4&gt;Figuring out what source line it is &lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;You can even get down to the source line if you have the COD files to look at.&amp;nbsp; I have rarely had to do this kind of lookup, but it is occasionally useful.&amp;nbsp; The two main uses I’ve had for it are: figuring out exactly which line of source/disassembly a crash or debug break occurred on, and figuring out which instance of a function call is involved in a callstack.&amp;nbsp; For example if function &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; calls function &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt; twice, and I’m looking at a callstack which involves &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; calling &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt;, I may want to know which invocation of &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt; it was inside &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt;.&amp;nbsp; The address given for &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; in the stack is the address where the jump to &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt; occurred, so I can use the address given for &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; in the stack to figure out what line of code the jump occurred on.&lt;/P&gt;
&lt;P&gt;COD files come from compiling the code with the&amp;nbsp;&lt;STRONG&gt;WINCECOD&lt;/STRONG&gt; environment variable set to 1.&amp;nbsp; By default &lt;STRONG&gt;WINCECOD&lt;/STRONG&gt; is not set, so you will not have COD files by default.&amp;nbsp; And COD files are not shipped with the Platform Builder CDs or with the Windows CE source.&amp;nbsp; So unless you have buildable source for the OS, this work is only possible for your own code.&lt;/P&gt;
&lt;P&gt;You may have noticed that the MAP file lists the OBJ file the function came from.&amp;nbsp; For example &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt; came from the devpnp.obj file which was linked into devcore.lib.&amp;nbsp; This means the code was in “devpnp.c” or “devpnp.cpp.”&amp;nbsp; If you know where this source file is, you can go to the right directory, set &lt;STRONG&gt;WINCECOD&lt;/STRONG&gt;=1, build –c, and then open the COD file from &lt;FONT face="Courier New"&gt;obj\%_TGTCPU%\%WINCEDEBUG%&lt;/FONT&gt;.&amp;nbsp; It’ll be named after the C or CPP file – in this case devpnp.cod.&amp;nbsp; The function name will appear several times in the COD file, but in only one case will the function name be followed by the word “PROC,” and this is the beginning of the assembly code for that function.&amp;nbsp; Here’s a sample that’s munged a little from reality.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;FONT&gt;_I_AdvertiseDeviceInterface PROC&lt;/FONT&gt; NEAR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ; COMDAT&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;; 348&amp;nbsp; : {&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&amp;nbsp; &lt;FONT&gt;001e8&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 55&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push ebp&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001e9&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8b ec&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp; ebp, esp&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001eb&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 81 ec 14 02 00&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sub&amp;nbsp; esp, 532&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ; 00000214H&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001f1&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a1 00 00 00 00&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp; eax, DWORD PTR ___cke&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001f6&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 53&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push ebx&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001f7&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 56&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push esi&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;; 349&amp;nbsp; :&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ULONG result = ERROR_SUCCESS;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&amp;nbsp; &lt;FONT color=#a52a2a&gt;001f8&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 33 f6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xor&amp;nbsp; esi, esi&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;As you can see, the source code and line numbers are included in the COD file next to the assembly code that implements the source.&amp;nbsp; Each assembly instruction is labeled with an address.&amp;nbsp; So the COD file provides the mapping from function offset to source line.&amp;nbsp; Sometimes the assembly for the function is labeled starting with 0, and sometimes not.&amp;nbsp; (I believe it may depend on which compiler is being used – meaning it varies by CPU type.)&amp;nbsp; If not, you have to take the function start label into account.&amp;nbsp; So in this example the function starts at label &lt;FONT face="Courier New" color=#a52a2a&gt;0x001E8&lt;/FONT&gt;.&lt;/P&gt;
&lt;P&gt;So the formula for the line of assembly to look for is:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(assembly label) = (.map file offset) – (function start addr from .map) + (function start label from .cod)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;And to complete my example, subtracting the start offset of &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt; &lt;FONT face="Courier New" color=#a52a2a&gt;0x0000556C&lt;/FONT&gt; from the address &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005678&lt;/FONT&gt;, I find that the address I'm interested in is at offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x0000010C&lt;/FONT&gt; from the beginning of the function.&amp;nbsp; Add that to the start label &lt;FONT face="Courier New" color=#a52a2a&gt;0x001E8&lt;/FONT&gt; of &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt; from the COD file, and I am looking for the assembly line labeled &lt;FONT face="Courier New" color=#a52a2a&gt;0x002F4&lt;/FONT&gt;.&amp;nbsp; This line will tell me exactly what assembly code is at that address, and what line of source code that corresponds to.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=381706" width="1" height="1"&gt;</content><author><name>sloh</name><uri>http://blogs.msdn.com/members/sloh.aspx</uri></author><category term="Debugging, Kernel &amp; misc. File System issues" scheme="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx" /></entry></feed>