Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
6.9 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. ntsdexts.c
  5. Abstract:
  6. This function contains the default ntsd debugger extensions
  7. Author:
  8. Revision History:
  9. --*/
  10. //
  11. // Lists threads sorted by CPU time consumed, in order to
  12. // track runaway threads
  13. //
  14. typedef struct _INTERESTING_THREAD_INFO {
  15. ULONG_PTR ThreadId ;
  16. ULONG_PTR Flags ;
  17. LARGE_INTEGER UserTime ;
  18. LARGE_INTEGER KernelTime ;
  19. LARGE_INTEGER ElapsedTime ;
  20. } INTERESTING_THREAD_INFO, * PINTERESTING_THREAD_INFO ;
  21. #define ITI_USER_DONE 0x00000001
  22. #define ITI_KERNEL_DONE 0x00000002
  23. #define ITI_ELAPSED_DONE 0x00000004
  24. DECLARE_API( runaway )
  25. {
  26. PROCESS_BASIC_INFORMATION ProcessInfo ;
  27. PSYSTEM_PROCESS_INFORMATION SystemInfo ;
  28. PSYSTEM_PROCESS_INFORMATION Walk ;
  29. PSYSTEM_THREAD_INFORMATION ThreadInfo ;
  30. PINTERESTING_THREAD_INFO Threads ;
  31. NTSTATUS Status ;
  32. ULONG Flags = 1 ;
  33. ULONG i, j, Found ;
  34. LARGE_INTEGER Now ;
  35. LARGE_INTEGER Compare ;
  36. TIME_FIELDS Time ;
  37. INIT_API();
  38. if (sscanf( args, "%x", &Flags ) == 0) {
  39. goto Exit;
  40. }
  41. Status = NtQueryInformationProcess(
  42. g_hCurrentProcess,
  43. ProcessBasicInformation,
  44. &ProcessInfo,
  45. sizeof( ProcessInfo ),
  46. NULL );
  47. if ( !NT_SUCCESS( Status ) )
  48. {
  49. dprintf( "could not get process information, %d\n",
  50. RtlNtStatusToDosError( Status ) );
  51. goto Exit;
  52. }
  53. SystemInfo = RtlAllocateHeap(
  54. RtlProcessHeap(),
  55. 0,
  56. 1024 * sizeof( SYSTEM_PROCESS_INFORMATION ) );
  57. if ( !SystemInfo )
  58. {
  59. dprintf( "not enough memory\n" );
  60. goto Exit;
  61. }
  62. Status = NtQuerySystemInformation(
  63. SystemProcessInformation,
  64. SystemInfo,
  65. 1024 * sizeof( SYSTEM_PROCESS_INFORMATION ),
  66. NULL );
  67. if ( !NT_SUCCESS( Status ) )
  68. {
  69. dprintf( "unable to get system information\n" );
  70. RtlFreeHeap(
  71. RtlProcessHeap(),
  72. 0,
  73. SystemInfo );
  74. goto Exit;
  75. }
  76. //
  77. // First, find the process:
  78. //
  79. Walk = SystemInfo ;
  80. while ( HandleToUlong( Walk->UniqueProcessId ) != ProcessInfo.UniqueProcessId )
  81. {
  82. if ( Walk->NextEntryOffset == 0 )
  83. {
  84. Walk = NULL ;
  85. break;
  86. }
  87. Walk = (PSYSTEM_PROCESS_INFORMATION) ((PUCHAR) Walk + Walk->NextEntryOffset );
  88. }
  89. if ( !Walk )
  90. {
  91. dprintf( "unable to find process\n" );
  92. RtlFreeHeap( RtlProcessHeap(), 0, SystemInfo );
  93. goto Exit;
  94. }
  95. //
  96. // Now, walk the threads
  97. //
  98. ThreadInfo = (PSYSTEM_THREAD_INFORMATION) (Walk + 1);
  99. Threads = RtlAllocateHeap(
  100. RtlProcessHeap(),
  101. 0,
  102. sizeof( INTERESTING_THREAD_INFO ) * Walk->NumberOfThreads );
  103. if ( !Threads )
  104. {
  105. dprintf( "not enough memory\n" );
  106. RtlFreeHeap(
  107. RtlProcessHeap(),
  108. 0,
  109. SystemInfo );
  110. goto Exit;
  111. }
  112. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  113. for ( i = 0 ; i < Walk->NumberOfThreads ; i++ )
  114. {
  115. Threads[ i ].Flags = 0 ;
  116. Threads[ i ].ThreadId = HandleToUlong( ThreadInfo[ i ].ClientId.UniqueThread );
  117. Threads[ i ].ElapsedTime.QuadPart = Now.QuadPart - ThreadInfo[ i ].CreateTime.QuadPart ;
  118. Threads[ i ].KernelTime = ThreadInfo[ i ].KernelTime ;
  119. Threads[ i ].UserTime = ThreadInfo[ i ].UserTime ;
  120. }
  121. //
  122. // Scan through the list of threads (in an ugly, bubble-ish sort
  123. // of way), and display the threads in order of time, once per time
  124. // field, by way of the flags:
  125. //
  126. if ( Flags & ITI_USER_DONE )
  127. {
  128. j = Walk->NumberOfThreads ;
  129. Found = 0 ;
  130. dprintf( " User Mode Time\n" );
  131. dprintf( " Thread Time\n" );
  132. while ( j-- )
  133. {
  134. Compare.QuadPart = 0 ;
  135. for ( i = 0 ; i < Walk->NumberOfThreads ; i++ )
  136. {
  137. if ( ( ( Threads[ i ].Flags & ITI_USER_DONE ) == 0 ) &&
  138. ( Threads[ i ].UserTime.QuadPart >= Compare.QuadPart ) )
  139. {
  140. Compare.QuadPart = Threads[ i ].UserTime.QuadPart ;
  141. Found = i ;
  142. }
  143. }
  144. Threads[ Found ].Flags |= ITI_USER_DONE ;
  145. RtlTimeToElapsedTimeFields( &Compare, &Time );
  146. dprintf( " %-3x %3ld:%02ld:%02ld.%04ld\n",
  147. Threads[ Found ].ThreadId,
  148. Time.Hour,
  149. Time.Minute,
  150. Time.Second,
  151. Time.Milliseconds );
  152. }
  153. }
  154. if ( Flags & ITI_KERNEL_DONE )
  155. {
  156. j = Walk->NumberOfThreads ;
  157. Found = 0 ;
  158. dprintf( " Kernel Mode Time\n" );
  159. dprintf( " Thread Time\n" );
  160. while ( j-- )
  161. {
  162. Compare.QuadPart = 0 ;
  163. for ( i = 0 ; i < Walk->NumberOfThreads ; i++ )
  164. {
  165. if ( ( ( Threads[ i ].Flags & ITI_KERNEL_DONE ) == 0 ) &&
  166. ( Threads[ i ].KernelTime.QuadPart >= Compare.QuadPart ) )
  167. {
  168. Compare.QuadPart = Threads[ i ].KernelTime.QuadPart ;
  169. Found = i ;
  170. }
  171. }
  172. Threads[ Found ].Flags |= ITI_KERNEL_DONE ;
  173. RtlTimeToElapsedTimeFields( &Compare, &Time );
  174. dprintf( " %-3x %3ld:%02ld:%02ld.%04ld\n",
  175. Threads[ Found ].ThreadId,
  176. Time.Hour,
  177. Time.Minute,
  178. Time.Second,
  179. Time.Milliseconds );
  180. }
  181. }
  182. if ( Flags & ITI_ELAPSED_DONE )
  183. {
  184. j = Walk->NumberOfThreads ;
  185. Found = 0 ;
  186. dprintf( " Elapsed Time\n" );
  187. dprintf( " Thread Time\n" );
  188. while ( j-- )
  189. {
  190. Compare.QuadPart = 0 ;
  191. for ( i = 0 ; i < Walk->NumberOfThreads ; i++ )
  192. {
  193. if ( ( ( Threads[ i ].Flags & ITI_ELAPSED_DONE ) == 0 ) &&
  194. ( Threads[ i ].ElapsedTime.QuadPart >= Compare.QuadPart ) )
  195. {
  196. Compare.QuadPart = Threads[ i ].ElapsedTime.QuadPart ;
  197. Found = i ;
  198. }
  199. }
  200. Threads[ Found ].Flags |= ITI_ELAPSED_DONE ;
  201. RtlTimeToElapsedTimeFields( &Compare, &Time );
  202. dprintf( " %-3x %3ld:%02ld:%02ld.%04ld\n",
  203. Threads[ Found ].ThreadId,
  204. Time.Hour,
  205. Time.Minute,
  206. Time.Second,
  207. Time.Milliseconds );
  208. }
  209. }
  210. if ( SystemInfo )
  211. {
  212. RtlFreeHeap( RtlProcessHeap(), 0, SystemInfo );
  213. }
  214. Exit:
  215. EXIT_API();
  216. }