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.

389 lines
11 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. perfsys.c
  5. Abstract:
  6. This file implements an Performance Object that presents
  7. System Performance Object information
  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 <winperf.h>
  20. #include <ntprfctr.h>
  21. #include <perfutil.h>
  22. #include "perfos.h"
  23. #include "perfosmc.h"
  24. #include "datasys.h"
  25. static DWORD dwOpenCount = 0; // count of "Open" threads
  26. typedef struct _PERFSYS_THREAD_DATA_BLOCK {
  27. DWORD dwProcessCount;
  28. DWORD dwNullProcessCount;
  29. DWORD dwThreadCount;
  30. DWORD dwReadyThreads; // (1) this is the same as the queue length
  31. DWORD dwTerminatedThreads; // (4)
  32. DWORD dwWaitingThreads; // (5)
  33. DWORD dwTransitionThreads; // (6)
  34. } PERFSYS_THREAD_DATA_BLOCK, * PPERFSYS_THREAD_DATA_BLOCK;
  35. #pragma warning (disable : 4706)
  36. DWORD
  37. GetSystemThreadInfo (
  38. PPERFSYS_THREAD_DATA_BLOCK pTDB
  39. )
  40. {
  41. NTSTATUS status;
  42. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  43. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  44. ULONG ProcessNumber;
  45. ULONG NumThreadInstances;
  46. ULONG ThreadNumber;
  47. ULONG ProcessBufferOffset;
  48. BOOLEAN NullProcess;
  49. UCHAR *pProcessBuffer, *pOldBuffer;
  50. ULONG ProcessBufSize = LARGE_BUFFER_SIZE;
  51. DWORD dwReturnedBufferSize;
  52. // reset the caller's buffer
  53. memset (pTDB, 0, sizeof (PERFSYS_THREAD_DATA_BLOCK));
  54. pProcessBuffer = ALLOCMEM (hLibHeap, 0, ProcessBufSize);
  55. if (pProcessBuffer == NULL) {
  56. status = ERROR_OUTOFMEMORY;
  57. } else {
  58. while( (status = NtQuerySystemInformation(
  59. SystemProcessInformation,
  60. pProcessBuffer,
  61. ProcessBufSize,
  62. &dwReturnedBufferSize)) ==
  63. STATUS_INFO_LENGTH_MISMATCH ) {
  64. ProcessBufSize += INCREMENT_BUFFER_SIZE;
  65. pOldBuffer = pProcessBuffer;
  66. if ( !(pProcessBuffer = REALLOCMEM(hLibHeap, 0,
  67. pProcessBuffer,
  68. ProcessBufSize)) ) {
  69. FREEMEM(hLibHeap, 0, pOldBuffer);
  70. status = ERROR_OUTOFMEMORY;
  71. break;
  72. }
  73. }
  74. }
  75. if ( NT_SUCCESS(status) ) {
  76. // walk processes and threads to count 'ready' threads
  77. ProcessNumber = 0;
  78. NumThreadInstances = 0;
  79. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
  80. ProcessBufferOffset = 0;
  81. while ( ProcessInfo != NULL ) {
  82. if ( ProcessInfo->ImageName.Buffer != NULL ||
  83. ProcessInfo->NumberOfThreads > 0 ) {
  84. NullProcess = FALSE;
  85. pTDB->dwProcessCount++;
  86. } else {
  87. NullProcess = TRUE;
  88. pTDB->dwNullProcessCount++;
  89. }
  90. ThreadNumber = 0; // Thread number of this process
  91. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  92. while ( !NullProcess &&
  93. ThreadNumber < ProcessInfo->NumberOfThreads ) {
  94. //
  95. // Format and collect Thread data
  96. //
  97. pTDB->dwThreadCount++;
  98. // update thread state counters
  99. if (ThreadInfo->ThreadState == 1) {
  100. // then it's READY
  101. pTDB->dwReadyThreads++;
  102. } else if (ThreadInfo->ThreadState == 4) {
  103. // then it's TERMINATED
  104. pTDB->dwTerminatedThreads++;
  105. } else if (ThreadInfo->ThreadState == 5) {
  106. // then it's WAITING
  107. pTDB->dwWaitingThreads++;
  108. } else if (ThreadInfo->ThreadState == 6) {
  109. // then it's in TRANSITION
  110. pTDB->dwTransitionThreads++;
  111. }
  112. ThreadNumber++;
  113. ThreadInfo++;
  114. }
  115. if (ProcessInfo->NextEntryOffset == 0) {
  116. // that was the last process
  117. break;
  118. }
  119. ProcessBufferOffset += ProcessInfo->NextEntryOffset;
  120. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  121. &pProcessBuffer[ProcessBufferOffset];
  122. if ( !NullProcess ) {
  123. ProcessNumber++;
  124. }
  125. }
  126. } else {
  127. ReportEvent (hEventLog,
  128. EVENTLOG_WARNING_TYPE,
  129. 0,
  130. PERFOS_UNABLE_QUERY_PROCESS_INFO,
  131. NULL,
  132. 0,
  133. sizeof(DWORD),
  134. NULL,
  135. (LPVOID)&status);
  136. }
  137. if (pProcessBuffer != NULL) {
  138. FREEMEM (hLibHeap, 0, pProcessBuffer);
  139. }
  140. return ERROR_SUCCESS;
  141. }
  142. #pragma warning (default : 4706)
  143. DWORD APIENTRY
  144. CollectSystemObjectData (
  145. IN OUT LPVOID *lppData,
  146. IN OUT LPDWORD lpcbTotalBytes,
  147. IN OUT LPDWORD lpNumObjectTypes
  148. )
  149. /*++
  150. Routine Description:
  151. This routine will return the data for the System object
  152. Arguments:
  153. QuerySystemData - Get data about system
  154. IN OUT LPVOID *lppData
  155. IN: pointer to the address of the buffer to receive the completed
  156. PerfDataBlock and subordinate structures. This routine will
  157. append its data to the buffer starting at the point referenced
  158. by *lppData.
  159. OUT: points to the first byte after the data structure added by this
  160. routine. This routine updated the value at lppdata after appending
  161. its data.
  162. IN OUT LPDWORD lpcbTotalBytes
  163. IN: the address of the DWORD that tells the size in bytes of the
  164. buffer referenced by the lppData argument
  165. OUT: the number of bytes added by this routine is writted to the
  166. DWORD pointed to by this argument
  167. IN OUT LPDWORD NumObjectTypes
  168. IN: the address of the DWORD to receive the number of objects added
  169. by this routine
  170. OUT: the number of objects added by this routine is writted to the
  171. DWORD pointed to by this argument
  172. Returns:
  173. 0 if successful, else Win 32 error code of failure
  174. --*/
  175. {
  176. DWORD TotalLen; // Length of the total return block
  177. NTSTATUS ntStatus;
  178. PSYSTEM_DATA_DEFINITION pSystemDataDefinition;
  179. PSYSTEM_COUNTER_DATA pSCD;
  180. SYSTEM_EXCEPTION_INFORMATION ExceptionInfo;
  181. SYSTEM_REGISTRY_QUOTA_INFORMATION RegistryInfo;
  182. SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo;
  183. PERFSYS_THREAD_DATA_BLOCK TDB;
  184. DWORD dwReturnedBufferSize;
  185. // Check for sufficient space for system data
  186. //
  187. pSystemDataDefinition = (SYSTEM_DATA_DEFINITION *) *lppData;
  188. TotalLen = sizeof(SYSTEM_DATA_DEFINITION) +
  189. sizeof(SYSTEM_COUNTER_DATA);
  190. TotalLen = QWORD_MULTIPLE (TotalLen);
  191. if ( *lpcbTotalBytes < TotalLen ) {
  192. *lpcbTotalBytes = (DWORD) 0;
  193. *lpNumObjectTypes = (DWORD) 0;
  194. return ERROR_MORE_DATA;
  195. }
  196. //
  197. // Define system data block
  198. //
  199. memcpy (pSystemDataDefinition,
  200. &SystemDataDefinition,
  201. sizeof(SYSTEM_DATA_DEFINITION));
  202. //
  203. // Format and collect system data
  204. //
  205. // get the exception data
  206. ntStatus = NtQuerySystemInformation(
  207. SystemExceptionInformation,
  208. &ExceptionInfo,
  209. sizeof(ExceptionInfo),
  210. NULL
  211. );
  212. if (!NT_SUCCESS(ntStatus)) {
  213. // unable to collect the data from the system so
  214. // clear the return data structure to prevent bogus data from
  215. // being returned
  216. ReportEvent (hEventLog,
  217. EVENTLOG_WARNING_TYPE,
  218. 0,
  219. PERFOS_UNABLE_QUERY_EXCEPTION_INFO,
  220. NULL,
  221. 0,
  222. sizeof(DWORD),
  223. NULL,
  224. (LPVOID)&ntStatus);
  225. memset (&ExceptionInfo, 0, sizeof(ExceptionInfo));
  226. }
  227. // collect registry quota info
  228. memset (&RegistryInfo, 0, sizeof (SYSTEM_REGISTRY_QUOTA_INFORMATION));
  229. ntStatus = NtQuerySystemInformation (
  230. SystemRegistryQuotaInformation,
  231. (PVOID)&RegistryInfo,
  232. sizeof(RegistryInfo),
  233. NULL);
  234. if (ntStatus != STATUS_SUCCESS) {
  235. ReportEvent (hEventLog,
  236. EVENTLOG_WARNING_TYPE,
  237. 0,
  238. PERFOS_UNABLE_QUERY_REGISTRY_QUOTA_INFO,
  239. NULL,
  240. 0,
  241. sizeof(DWORD),
  242. NULL,
  243. (LPVOID)&ntStatus);
  244. // clear the data fields
  245. memset (&RegistryInfo, 0, sizeof (SYSTEM_REGISTRY_QUOTA_INFORMATION));
  246. }
  247. ntStatus = NtQuerySystemInformation(
  248. SystemTimeOfDayInformation,
  249. &SysTimeInfo,
  250. sizeof(SysTimeInfo),
  251. &dwReturnedBufferSize
  252. );
  253. if (!NT_SUCCESS(ntStatus)) {
  254. ReportEvent (hEventLog,
  255. EVENTLOG_WARNING_TYPE,
  256. 0,
  257. PERFOS_UNABLE_QUERY_SYSTEM_TIME_INFO,
  258. NULL,
  259. 0,
  260. sizeof(DWORD),
  261. NULL,
  262. (LPVOID)&ntStatus);
  263. memset (&SysTimeInfo, 0, sizeof(SysTimeInfo));
  264. }
  265. // get thread info
  266. ntStatus = GetSystemThreadInfo (&TDB);
  267. if (!NT_SUCCESS(ntStatus)) {
  268. memset (&TDB, 0, sizeof(TDB));
  269. }
  270. // update the object perf time (freq is constant)
  271. pSystemDataDefinition->SystemObjectType.PerfTime = SysTimeInfo.CurrentTime;
  272. pSCD = (PSYSTEM_COUNTER_DATA)&pSystemDataDefinition[1];
  273. pSCD->CounterBlock.ByteLength = sizeof(SYSTEM_COUNTER_DATA);
  274. pSCD->ReadOperations = SysPerfInfo.IoReadOperationCount;
  275. pSCD->WriteOperations = SysPerfInfo.IoWriteOperationCount;
  276. pSCD->OtherIOOperations = SysPerfInfo.IoOtherOperationCount;
  277. pSCD->ReadBytes = SysPerfInfo.IoReadTransferCount.QuadPart;
  278. pSCD->WriteBytes = SysPerfInfo.IoWriteTransferCount.QuadPart;
  279. pSCD->OtherIOBytes = SysPerfInfo.IoOtherTransferCount.QuadPart;
  280. pSCD->ContextSwitches = SysPerfInfo.ContextSwitches;
  281. pSCD->SystemCalls = SysPerfInfo.SystemCalls;
  282. pSCD->TotalReadWrites = SysPerfInfo.IoReadOperationCount +
  283. SysPerfInfo.IoWriteOperationCount;
  284. pSCD->SystemElapsedTime = SysTimeInfo.BootTime.QuadPart - SysTimeInfo.BootTimeBias;
  285. // leave room for the ProcessorQueueLength data
  286. pSCD->ProcessorQueueLength = TDB.dwReadyThreads;
  287. pSCD->ProcessCount = TDB.dwProcessCount;
  288. pSCD->ThreadCount = TDB.dwThreadCount;
  289. pSCD->AlignmentFixups = ExceptionInfo.AlignmentFixupCount ;
  290. pSCD->ExceptionDispatches = ExceptionInfo.ExceptionDispatchCount ;
  291. pSCD->FloatingPointEmulations = ExceptionInfo.FloatingEmulationCount ;
  292. pSCD->RegistryQuotaUsed = RegistryInfo.RegistryQuotaUsed;
  293. pSCD->RegistryQuotaAllowed = RegistryInfo.RegistryQuotaAllowed;
  294. *lppData = (LPBYTE)&pSCD[1];
  295. // round up buffer to the nearest QUAD WORD
  296. *lppData = ALIGN_ON_QWORD (*lppData);
  297. *lpcbTotalBytes =
  298. pSystemDataDefinition->SystemObjectType.TotalByteLength =
  299. (DWORD)((LPBYTE)*lppData - (LPBYTE)pSystemDataDefinition);
  300. *lpNumObjectTypes = 1;
  301. return ERROR_SUCCESS;
  302. }