{"id":1182,"date":"2011-03-20T12:38:02","date_gmt":"2011-03-20T10:38:02","guid":{"rendered":"https:\/\/alax.info\/blog\/?p=1182"},"modified":"2011-03-20T12:46:09","modified_gmt":"2011-03-20T10:46:09","slug":"obtaining-number-of-thread-context-switched","status":"publish","type":"post","link":"https:\/\/alax.info\/blog\/1182","title":{"rendered":"Obtaining number of thread context switches programmatically"},"content":{"rendered":"<p>Previous post on <a href=\"\/blog\/1177\">thread synchronization and context switches<\/a> used number of thread context switches as one of the performance indicators. One might have hard times getting the number from operating system though.<\/p>\n<p>The only well documented access to amount of context switches seems to be accessing corresponding <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa373083%28VS.85%29.aspx\">performance counters<\/a>. Thread performance counter will list available thread instances and counters &#8220;<em>Thread(&lt;process-name&gt;\/&lt;thread-number&gt;)\/Context Switches\/sec<\/em>&#8221; will provide context switch rate per second.<\/p>\n<p><a href=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image002.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1183\" title=\"Context Switches Performance Counter\" src=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image002-320x238.png\" alt=\"\" width=\"320\" height=\"238\" srcset=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image002-320x238.png 320w, https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image002.png 724w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/a><\/p>\n<p>While access to performance counters is far not the most convenient API, to access data programmatically one would really prefer absolute number of switches rather than rate per second (which is still good for interactive monitoring).<\/p>\n<p>A gate into kernel world to grab the data of interest is provided with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms724509%28VS.85%29.aspx\">NtQuerySystemInformation<\/a> function. Although mentioned in documentation, it is marked as unreliable for use, and Windows SDK static library is missing it so one has to obtain it using <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms683199%28VS.85%29.aspx\">GetModuleHandle<\/a>\/<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms683212%28VS.85%29.aspx\">GetProcAddress<\/a> it explicity.<\/p>\n<pre style=\"color: #000000; background: #ffffff;\"><span style=\"color: #800000; font-weight: bold;\">typedef<\/span> NTSTATUS <span style=\"color: #808030;\">(<\/span><span style=\"color: #603000;\">WINAPI<\/span> <span style=\"color: #808030;\">*<\/span>NTQUERYSYSTEMINFORMATION<span style=\"color: #808030;\">)<\/span><span style=\"color: #808030;\">(<\/span>SYSTEM_INFORMATION_CLASS SystemInformationClass<span style=\"color: #808030;\">,<\/span> <span style=\"color: #603000;\">PVOID<\/span> SystemInformation<span style=\"color: #808030;\">,<\/span> <span style=\"color: #603000;\">ULONG<\/span> SystemInformationLength<span style=\"color: #808030;\">,<\/span> <span style=\"color: #603000;\">PULONG<\/span> ReturnLength<span style=\"color: #808030;\">)<\/span><span style=\"color: #800080;\">;<\/span>\r\nNTQUERYSYSTEMINFORMATION NtQuerySystemInformation <span style=\"color: #808030;\">=<\/span> <span style=\"color: #808030;\">(<\/span>NTQUERYSYSTEMINFORMATION<span style=\"color: #808030;\">)<\/span> <span style=\"color: #400000;\">GetProcAddress<\/span><span style=\"color: #808030;\">(<\/span><span style=\"color: #400000;\">GetModuleHandle<\/span><span style=\"color: #808030;\">(<\/span>_T<span style=\"color: #808030;\">(<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">ntdll.dll<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span><span style=\"color: #808030;\">)<\/span><span style=\"color: #808030;\">,<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">NtQuerySystemInformation<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span><span style=\"color: #800080;\">;<\/span>\r\nATLASSERT<span style=\"color: #808030;\">(<\/span>NtQuerySystemInformation<span style=\"color: #808030;\">)<\/span><span style=\"color: #800080;\">;<\/span>\r\nATLVERIFY<span style=\"color: #808030;\">(<\/span>NtQuerySystemInformation<span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">.<\/span><span style=\"color: #808030;\">.<\/span><span style=\"color: #808030;\">.<\/span><span style=\"color: #808030;\">)<\/span> <span style=\"color: #808030;\">=<\/span><span style=\"color: #808030;\">=<\/span> <span style=\"color: #008c00;\">0<\/span><span style=\"color: #808030;\">)<\/span><span style=\"color: #800080;\">;<\/span><\/pre>\n<p>Having this done, the function is capable of providing SystemProcessInformation\/SYSTEM_PROCESS_INFORMATION data about running processes.<\/p>\n<p><!--more-->MSDN documents only a part of the structure, and the rest of the data contains information of interest. Returned data contains a list of variable length SYSTEM_PROCESS_INFORMATION structures, each of which has a fixed part (partially documented on MSDN), and embeds list of variable length structures for every thread running within the process.<\/p>\n<p>For 32-bit Win32 platform, layout of the structure is documented on Internet, for example, here: <a href=\"http:\/\/undocumented.ntinternals.net\/UserMode\/Undocumented%20Functions\/System%20Information\/Structures\/SYSTEM_THREAD.html\">SYSTEM_THREAD on Undocumented functions of NTDLL<\/a>.<\/p>\n<p>For 64-bit x64 (amd64) platform the access method works too, however I had to fit the structure layout so that it matches actual data:<\/p>\n<pre style=\"color: #000000; background: #ffffff;\"><span style=\"color: #800000; font-weight: bold;\">typedef<\/span> <span style=\"color: #800000; font-weight: bold;\">struct<\/span> _SYSTEM_THREAD_INFORMATION <span style=\"color: #800080;\">{<\/span>\r\n    ULONGLONG KernelTime<span style=\"color: #800080;\">;<\/span>\r\n    ULONGLONG UserTime<span style=\"color: #800080;\">;<\/span>\r\n    ULONGLONG CreateTime<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> WaitTime<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> Reserved1<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">PVOID<\/span> StartAddress<span style=\"color: #800080;\">;<\/span>\r\n    CLIENT_ID ClientId<span style=\"color: #800080;\">;<\/span>\r\n    KPRIORITY Priority<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">LONG<\/span> BasePriority<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> ContextSwitchCount<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> State<span style=\"color: #800080;\">;<\/span>\r\n    KWAIT_REASON WaitReason<span style=\"color: #800080;\">;<\/span>\r\n<span style=\"color: #800080;\">}<\/span> SYSTEM_THREAD_INFORMATION<span style=\"color: #808030;\">,<\/span> <span style=\"color: #808030;\">*<\/span>PSYSTEM_THREAD_INFORMATION<span style=\"color: #800080;\">;<\/span>\r\n\r\n<span style=\"color: #800000; font-weight: bold;\">typedef<\/span> <span style=\"color: #800000; font-weight: bold;\">struct<\/span> _SYSTEM_PROCESS_INFORMATION <span style=\"color: #800080;\">{<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> NextEntryOffset<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> NumberOfThreads<span style=\"color: #800080;\">;<\/span>\r\n    ULONGLONG Reserved<span style=\"color: #808030;\">[<\/span><span style=\"color: #008c00;\">3<\/span><span style=\"color: #808030;\">]<\/span><span style=\"color: #800080;\">;<\/span>\r\n    ULONGLONG CreateTime<span style=\"color: #800080;\">;<\/span>\r\n    ULONGLONG UserTime<span style=\"color: #800080;\">;<\/span>\r\n    ULONGLONG KernelTime<span style=\"color: #800080;\">;<\/span>\r\n    UNICODE_STRING ImageName<span style=\"color: #800080;\">;<\/span>\r\n    KPRIORITY BasePriority<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">HANDLE<\/span> ProcessId<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">HANDLE<\/span> InheritedFromProcessId<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> HandleCount<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> Reserved2<span style=\"color: #808030;\">[<\/span><span style=\"color: #008c00;\">2<\/span><span style=\"color: #808030;\">]<\/span><span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #603000;\">ULONG<\/span> PrivatePageCount<span style=\"color: #800080;\">;<\/span>  <span style=\"color: #696969;\">\/\/ Garbage<\/span>\r\n    VM_COUNTERS VirtualMemoryCounters<span style=\"color: #800080;\">;<\/span>\r\n    IO_COUNTERS IoCounters<span style=\"color: #800080;\">;<\/span>\r\n    SYSTEM_THREAD_INFORMATION Threads<span style=\"color: #808030;\">[<\/span><span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">]<\/span><span style=\"color: #800080;\">;<\/span>\r\n<span style=\"color: #800080;\">}<\/span> SYSTEM_PROCESS_INFORMATION<span style=\"color: #808030;\">,<\/span> <span style=\"color: #808030;\">*<\/span>PSYSTEM_PROCESS_INFORMATION<span style=\"color: #800080;\">;<\/span><\/pre>\n<p>Each structure contains thread identifier and related absolute number of context switches.<\/p>\n<p>Also, the same information is visually available from <a href=\"http:\/\/technet.microsoft.com\/en-us\/sysinternals\/bb896653\">Process Explorer<\/a>:<\/p>\n<p><a href=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image003.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1184\" title=\"Thread Context Switches on Process Explorer\" src=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image003-320x320.png\" alt=\"\" width=\"320\" height=\"320\" srcset=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image003-320x320.png 320w, https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image003-150x150.png 150w, https:\/\/alax.info\/blog\/wp-content\/uploads\/2011\/03\/Image003.png 519w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/a><\/p>\n<p>A more complete code snippet to access the data from x64 code is <a href=\"http:\/\/www.assembla.com\/code\/roatl-utilities\/subversion\/nodes\/trunk\/EventSynchronizationTest01\/EventSynchronizationTest01.cpp#ln18\">here in a small application\/project<\/a>, lines 18-144 within <em>#pragma region<\/em>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previous post on thread synchronization and context switches used number of thread context switches as one of the performance indicators. One might have hard times getting the number from operating system though. The only well documented access to amount of context switches seems to be accessing corresponding performance counters. Thread performance counter will list available&hellip; <\/p>\n<p><a class=\"moretag\" href=\"https:\/\/alax.info\/blog\/1182\">Read the full article<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21,13],"tags":[38,320,326,103,488,327,284],"class_list":["post-1182","post","type-post","status-publish","format-standard","hentry","category-seriously","category-source","tag-c","tag-context-switch","tag-ntdll","tag-performance","tag-source","tag-undocumented","tag-x64"],"_links":{"self":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/1182","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/comments?post=1182"}],"version-history":[{"count":0,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/1182\/revisions"}],"wp:attachment":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/media?parent=1182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/categories?post=1182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/tags?post=1182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}