Leaked source code of windows server 2003
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.

346 lines
10 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. perfthrd.c
  5. Abstract:
  6. This file implements an Performance Object that presents
  7. Thread performance object data
  8. Created:
  9. Bob Watson 22-Oct-1996
  10. Revision History
  11. --*/
  12. //
  13. // Include Files
  14. //
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <assert.h>
  20. #include <winperf.h>
  21. #include <ntprfctr.h>
  22. #define PERF_HEAP hLibHeap
  23. #include <perfutil.h>
  24. #include "perfsprc.h"
  25. #include "perfmsg.h"
  26. #include "datathrd.h"
  27. extern DWORD PerfSprc_dwThreadNameFormat;
  28. DWORD APIENTRY
  29. CollectThreadObjectData (
  30. IN OUT LPVOID *lppData,
  31. IN OUT LPDWORD lpcbTotalBytes,
  32. IN OUT LPDWORD lpNumObjectTypes
  33. )
  34. /*++
  35. Routine Description:
  36. This routine will return the data for the processor object
  37. Arguments:
  38. IN OUT LPVOID *lppData
  39. IN: pointer to the address of the buffer to receive the completed
  40. PerfDataBlock and subordinate structures. This routine will
  41. append its data to the buffer starting at the point referenced
  42. by *lppData.
  43. OUT: points to the first byte after the data structure added by this
  44. routine. This routine updated the value at lppdata after appending
  45. its data.
  46. IN OUT LPDWORD lpcbTotalBytes
  47. IN: the address of the DWORD that tells the size in bytes of the
  48. buffer referenced by the lppData argument
  49. OUT: the number of bytes added by this routine is writted to the
  50. DWORD pointed to by this argument
  51. IN OUT LPDWORD NumObjectTypes
  52. IN: the address of the DWORD to receive the number of objects added
  53. by this routine
  54. OUT: the number of objects added by this routine is writted to the
  55. DWORD pointed to by this argument
  56. Returns:
  57. 0 if successful, else Win 32 error code of failure
  58. --*/
  59. {
  60. LONG lReturn = ERROR_SUCCESS;
  61. DWORD TotalLen; // Length of the total return block
  62. THREAD_DATA_DEFINITION *pThreadDataDefinition;
  63. PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition;
  64. PTHREAD_COUNTER_DATA pTCD;
  65. THREAD_COUNTER_DATA tcdTotal;
  66. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  67. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  68. ULONG ProcessNumber;
  69. ULONG NumThreadInstances;
  70. ULONG ThreadNumber;
  71. ULONG ProcessBufferOffset;
  72. BOOLEAN NullProcess;
  73. BOOL bMoreThreads;
  74. // total thread accumulator variables
  75. UNICODE_STRING ThreadName;
  76. WCHAR ThreadNameBuffer[MAX_THREAD_NAME_LENGTH+1];
  77. pThreadDataDefinition = (THREAD_DATA_DEFINITION *) *lppData;
  78. //
  79. // Check for sufficient space for Thread object type definition
  80. //
  81. TotalLen = sizeof(THREAD_DATA_DEFINITION) +
  82. sizeof(PERF_INSTANCE_DEFINITION) +
  83. sizeof(THREAD_COUNTER_DATA);
  84. if ( *lpcbTotalBytes < TotalLen ) {
  85. *lpcbTotalBytes = (DWORD) 0;
  86. *lpNumObjectTypes = (DWORD) 0;
  87. return ERROR_MORE_DATA;
  88. }
  89. //
  90. // Define Thread data block
  91. //
  92. ThreadName.Length =
  93. ThreadName.MaximumLength = (MAX_THREAD_NAME_LENGTH + 1) * sizeof(WCHAR);
  94. ThreadName.Buffer = ThreadNameBuffer;
  95. RtlZeroMemory(ThreadNameBuffer, ThreadName.MaximumLength);
  96. memcpy(pThreadDataDefinition,
  97. &ThreadDataDefinition,
  98. sizeof(THREAD_DATA_DEFINITION));
  99. pThreadDataDefinition->ThreadObjectType.PerfTime = PerfTime;
  100. ProcessBufferOffset = 0;
  101. // Now collect data for each Thread
  102. ProcessNumber = 0;
  103. NumThreadInstances = 0;
  104. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
  105. pPerfInstanceDefinition =
  106. (PPERF_INSTANCE_DEFINITION)&pThreadDataDefinition[1];
  107. TotalLen = sizeof(THREAD_DATA_DEFINITION);
  108. // clear total accumulator
  109. memset (&tcdTotal, 0, sizeof (tcdTotal));
  110. bMoreThreads = FALSE;
  111. if (ProcessInfo) {
  112. if (ProcessInfo->NextEntryOffset != 0) {
  113. bMoreThreads = TRUE;
  114. }
  115. }
  116. while ( bMoreThreads && (ProcessInfo != NULL)) {
  117. if ( ProcessInfo->ImageName.Buffer != NULL ||
  118. ProcessInfo->NumberOfThreads > 0 ) {
  119. NullProcess = FALSE;
  120. } else {
  121. NullProcess = TRUE;
  122. }
  123. ThreadNumber = 0; // Thread number of this process
  124. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  125. while ( !NullProcess &&
  126. ThreadNumber < ProcessInfo->NumberOfThreads ) {
  127. TotalLen += sizeof(PERF_INSTANCE_DEFINITION) +
  128. (MAX_THREAD_NAME_LENGTH+1+sizeof(DWORD))*
  129. sizeof(WCHAR) +
  130. sizeof (THREAD_COUNTER_DATA);
  131. if ( *lpcbTotalBytes < TotalLen ) {
  132. *lpcbTotalBytes = (DWORD) 0;
  133. *lpNumObjectTypes = (DWORD) 0;
  134. return ERROR_MORE_DATA;
  135. }
  136. if (PerfSprc_dwThreadNameFormat == NAME_FORMAT_ID) {
  137. PerfIntegerToWString(
  138. HandleToUlong(ThreadInfo->ClientId.UniqueThread),
  139. 10,
  140. MAX_THREAD_NAME_LENGTH+1,
  141. ThreadNameBuffer);
  142. }
  143. else {
  144. // The only name we've got is the thread number
  145. if (!NT_SUCCESS(RtlIntegerToUnicodeString(ThreadNumber,
  146. 10,
  147. &ThreadName))) {
  148. ThreadName.Length = 2 * sizeof(WCHAR);
  149. memcpy(ThreadName.Buffer, L"-1", ThreadName.Length);
  150. ThreadName.Buffer[2] = UNICODE_NULL;
  151. }
  152. }
  153. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  154. (PVOID *) &pTCD,
  155. PROCESS_OBJECT_TITLE_INDEX,
  156. ProcessNumber,
  157. (DWORD)-1,
  158. ThreadName.Buffer);
  159. // test structure for Quadword Alignment
  160. assert (((DWORD)(pTCD) & 0x00000007) == 0);
  161. //
  162. //
  163. // Format and collect Thread data
  164. //
  165. pTCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof(THREAD_COUNTER_DATA));
  166. //
  167. // Convert User time from 100 nsec units to counter
  168. // frequency.
  169. //
  170. tcdTotal.ProcessorTime +=
  171. pTCD->ProcessorTime = ThreadInfo->KernelTime.QuadPart +
  172. ThreadInfo->UserTime.QuadPart;
  173. tcdTotal.UserTime +=
  174. pTCD->UserTime = ThreadInfo->UserTime.QuadPart;
  175. tcdTotal.KernelTime +=
  176. pTCD->KernelTime = ThreadInfo->KernelTime.QuadPart;
  177. tcdTotal.ContextSwitches +=
  178. pTCD->ContextSwitches = ThreadInfo->ContextSwitches;
  179. pTCD->ThreadElapsedTime = ThreadInfo->CreateTime.QuadPart;
  180. pTCD->ThreadPriority = (ThreadInfo->ClientId.UniqueProcess == 0) ?
  181. 0 : ThreadInfo->Priority;
  182. pTCD->ThreadBasePriority = ThreadInfo->BasePriority;
  183. pTCD->ThreadStartAddr = ThreadInfo->StartAddress;
  184. pTCD->ThreadState =
  185. (DWORD)((ThreadInfo->ThreadState > 7) ?
  186. 7 : ThreadInfo->ThreadState);
  187. pTCD->WaitReason = (DWORD)ThreadInfo->WaitReason;
  188. // now stuff in the process and thread id's
  189. pTCD->ProcessId = HandleToUlong(ThreadInfo->ClientId.UniqueProcess);
  190. pTCD->ThreadId = HandleToUlong(ThreadInfo->ClientId.UniqueThread);
  191. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pTCD[1];
  192. NumThreadInstances++;
  193. ThreadNumber++;
  194. ThreadInfo++;
  195. }
  196. if ( !NullProcess ) {
  197. ProcessNumber++;
  198. }
  199. if (ProcessInfo->NextEntryOffset == 0) {
  200. bMoreThreads = FALSE;
  201. continue;
  202. }
  203. ProcessBufferOffset += ProcessInfo->NextEntryOffset;
  204. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  205. &pProcessBuffer[ProcessBufferOffset];
  206. }
  207. if (NumThreadInstances > 0) {
  208. // See if the total instance will fit
  209. TotalLen += sizeof(PERF_INSTANCE_DEFINITION) +
  210. (MAX_THREAD_NAME_LENGTH+1+sizeof(DWORD))*
  211. sizeof(WCHAR) +
  212. sizeof (THREAD_COUNTER_DATA);
  213. if ( *lpcbTotalBytes < TotalLen ) {
  214. *lpcbTotalBytes = (DWORD) 0;
  215. *lpNumObjectTypes = (DWORD) 0;
  216. return ERROR_MORE_DATA;
  217. }
  218. // set the Total Elapsed Time to be the current time so that it will
  219. // show up as 0 when displayed.
  220. tcdTotal.ThreadElapsedTime = pThreadDataDefinition->ThreadObjectType.PerfTime.QuadPart;
  221. // use the "total" for this instance
  222. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  223. (PVOID *) &pTCD,
  224. PROCESS_OBJECT_TITLE_INDEX,
  225. ProcessNumber,
  226. (DWORD)-1,
  227. wszTotal);
  228. // test structure for Quadword Alignment
  229. assert (((DWORD)(pTCD) & 0x00000007) == 0);
  230. //
  231. //
  232. // Format and collect Thread data
  233. //
  234. memcpy (pTCD, &tcdTotal, sizeof(tcdTotal));
  235. pTCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof(THREAD_COUNTER_DATA));
  236. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pTCD[1];
  237. NumThreadInstances++;
  238. }
  239. // Note number of Thread instances
  240. pThreadDataDefinition->ThreadObjectType.NumInstances =
  241. NumThreadInstances;
  242. //
  243. // Now we know how large an area we used for the
  244. // Thread definition, so we can update the offset
  245. // to the next object definition
  246. //
  247. *lpcbTotalBytes =
  248. pThreadDataDefinition->ThreadObjectType.TotalByteLength =
  249. QWORD_MULTIPLE(
  250. (DWORD)((PCHAR) pPerfInstanceDefinition -
  251. (PCHAR) pThreadDataDefinition));
  252. #if DBG
  253. if (*lpcbTotalBytes > TotalLen ) {
  254. DbgPrint ("\nPERFPROC: Thread Perf Ctr. Instance Size Underestimated:");
  255. DbgPrint ("\nPERFPROC: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes);
  256. }
  257. #endif
  258. *lppData = (LPVOID) ((PCHAR) pThreadDataDefinition + *lpcbTotalBytes);
  259. *lpNumObjectTypes = 1;
  260. return lReturn;
  261. }