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.

463 lines
13 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. #define PERF_HEAP hLibHeap
  22. #include <perfutil.h>
  23. #include "perfos.h"
  24. #include "perfosmc.h"
  25. #include "datasys.h"
  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. ULONG ProcessBufSize = LARGE_BUFFER_SIZE;
  36. ULONG dwSysOpenCount = 0;
  37. UCHAR *pProcessBuffer = NULL;
  38. DWORD APIENTRY
  39. OpenSystemObject (
  40. LPWSTR lpDeviceNames
  41. )
  42. {
  43. UNREFERENCED_PARAMETER(lpDeviceNames);
  44. dwSysOpenCount++;
  45. return ERROR_SUCCESS;
  46. }
  47. DWORD
  48. GetSystemThreadInfo (
  49. PPERFSYS_THREAD_DATA_BLOCK pTDB
  50. )
  51. {
  52. NTSTATUS status;
  53. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  54. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  55. ULONG ProcessNumber;
  56. ULONG NumThreadInstances;
  57. ULONG ThreadNumber;
  58. ULONG ProcessBufferOffset;
  59. BOOLEAN NullProcess;
  60. DWORD dwReturnedBufferSize = 0;
  61. #ifdef DBG
  62. DWORD trialcount = 0;
  63. STARTTIMING;
  64. #endif
  65. // reset the caller's buffer
  66. memset (pTDB, 0, sizeof (PERFSYS_THREAD_DATA_BLOCK));
  67. if (pProcessBuffer == NULL) {
  68. ProcessBufSize = LARGE_BUFFER_SIZE;
  69. pProcessBuffer = ALLOCMEM (ProcessBufSize);
  70. #ifdef DBG
  71. trialcount = 1;
  72. #endif
  73. }
  74. if (pProcessBuffer == NULL) {
  75. status = STATUS_NO_MEMORY;
  76. } else {
  77. while( (status = NtQuerySystemInformation(
  78. SystemProcessInformation,
  79. pProcessBuffer,
  80. ProcessBufSize,
  81. &dwReturnedBufferSize)) ==
  82. STATUS_INFO_LENGTH_MISMATCH ) {
  83. if (ProcessBufSize < dwReturnedBufferSize) {
  84. ProcessBufSize = dwReturnedBufferSize;
  85. }
  86. ProcessBufSize = PAGESIZE_MULTIPLE(ProcessBufSize + SMALL_BUFFER_SIZE);
  87. #ifdef DBG
  88. trialcount++;
  89. #endif
  90. FREEMEM(pProcessBuffer);
  91. pProcessBuffer = ALLOCMEM(ProcessBufSize);
  92. if (pProcessBuffer == NULL) {
  93. status = STATUS_NO_MEMORY;
  94. break;
  95. }
  96. }
  97. }
  98. #ifdef DBG
  99. ENDTIMING (("PERFSYS: %d takes %I64u ms size=%d,%d trials=%d\n", __LINE__, diff,
  100. dwReturnedBufferSize, ProcessBufSize, trialcount));
  101. #endif
  102. if ( NT_SUCCESS(status) ) {
  103. // walk processes and threads to count 'ready' threads
  104. ProcessNumber = 0;
  105. NumThreadInstances = 0;
  106. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
  107. ProcessBufferOffset = 0;
  108. while ( ProcessInfo != NULL ) {
  109. if ( ProcessInfo->ImageName.Buffer != NULL ||
  110. ProcessInfo->NumberOfThreads > 0 ) {
  111. NullProcess = FALSE;
  112. pTDB->dwProcessCount++;
  113. } else {
  114. NullProcess = TRUE;
  115. pTDB->dwNullProcessCount++;
  116. }
  117. ThreadNumber = 0; // Thread number of this process
  118. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  119. while ( !NullProcess &&
  120. ThreadNumber < ProcessInfo->NumberOfThreads ) {
  121. //
  122. // Format and collect Thread data
  123. //
  124. pTDB->dwThreadCount++;
  125. // update thread state counters
  126. if (ThreadInfo->ThreadState == 1) {
  127. // then it's READY
  128. pTDB->dwReadyThreads++;
  129. } else if (ThreadInfo->ThreadState == 4) {
  130. // then it's TERMINATED
  131. pTDB->dwTerminatedThreads++;
  132. } else if (ThreadInfo->ThreadState == 5) {
  133. // then it's WAITING
  134. pTDB->dwWaitingThreads++;
  135. } else if (ThreadInfo->ThreadState == 6) {
  136. // then it's in TRANSITION
  137. pTDB->dwTransitionThreads++;
  138. }
  139. ThreadNumber++;
  140. ThreadInfo++;
  141. }
  142. if (ProcessInfo->NextEntryOffset == 0) {
  143. // that was the last process
  144. break;
  145. }
  146. ProcessBufferOffset += ProcessInfo->NextEntryOffset;
  147. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  148. &pProcessBuffer[ProcessBufferOffset];
  149. if ( !NullProcess ) {
  150. ProcessNumber++;
  151. }
  152. }
  153. } else if (hEventLog != NULL) {
  154. ReportEvent (hEventLog,
  155. EVENTLOG_WARNING_TYPE,
  156. 0,
  157. PERFOS_UNABLE_QUERY_PROCESS_INFO,
  158. NULL,
  159. 0,
  160. sizeof(DWORD),
  161. NULL,
  162. (LPVOID)&status);
  163. }
  164. #ifdef DBG
  165. ENDTIMING (("PERFSYS: %d takes %I64u ms total\n", __LINE__, diff));
  166. #endif
  167. return ERROR_SUCCESS;
  168. }
  169. DWORD APIENTRY
  170. CollectSystemObjectData (
  171. IN OUT LPVOID *lppData,
  172. IN OUT LPDWORD lpcbTotalBytes,
  173. IN OUT LPDWORD lpNumObjectTypes
  174. )
  175. /*++
  176. Routine Description:
  177. This routine will return the data for the System object
  178. Arguments:
  179. QuerySystemData - Get data about system
  180. IN OUT LPVOID *lppData
  181. IN: pointer to the address of the buffer to receive the completed
  182. PerfDataBlock and subordinate structures. This routine will
  183. append its data to the buffer starting at the point referenced
  184. by *lppData.
  185. OUT: points to the first byte after the data structure added by this
  186. routine. This routine updated the value at lppdata after appending
  187. its data.
  188. IN OUT LPDWORD lpcbTotalBytes
  189. IN: the address of the DWORD that tells the size in bytes of the
  190. buffer referenced by the lppData argument
  191. OUT: the number of bytes added by this routine is writted to the
  192. DWORD pointed to by this argument
  193. IN OUT LPDWORD NumObjectTypes
  194. IN: the address of the DWORD to receive the number of objects added
  195. by this routine
  196. OUT: the number of objects added by this routine is writted to the
  197. DWORD pointed to by this argument
  198. Returns:
  199. 0 if successful, else Win 32 error code of failure
  200. --*/
  201. {
  202. DWORD TotalLen; // Length of the total return block
  203. NTSTATUS ntStatus;
  204. PSYSTEM_DATA_DEFINITION pSystemDataDefinition;
  205. PSYSTEM_COUNTER_DATA pSCD;
  206. SYSTEM_EXCEPTION_INFORMATION ExceptionInfo;
  207. SYSTEM_REGISTRY_QUOTA_INFORMATION RegistryInfo;
  208. SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo;
  209. PERFSYS_THREAD_DATA_BLOCK TDB;
  210. DWORD dwReturnedBufferSize;
  211. // Check for sufficient space for system data
  212. //
  213. #ifdef DBG
  214. STARTTIMING;
  215. #endif
  216. pSystemDataDefinition = (SYSTEM_DATA_DEFINITION *) *lppData;
  217. TotalLen = sizeof(SYSTEM_DATA_DEFINITION) +
  218. sizeof(SYSTEM_COUNTER_DATA);
  219. TotalLen = QWORD_MULTIPLE (TotalLen);
  220. if ( *lpcbTotalBytes < TotalLen ) {
  221. *lpcbTotalBytes = (DWORD) 0;
  222. *lpNumObjectTypes = (DWORD) 0;
  223. return ERROR_MORE_DATA;
  224. }
  225. //
  226. // Define system data block
  227. //
  228. memcpy (pSystemDataDefinition,
  229. &SystemDataDefinition,
  230. sizeof(SYSTEM_DATA_DEFINITION));
  231. //
  232. // Format and collect system data
  233. //
  234. // get the exception data
  235. ntStatus = NtQuerySystemInformation(
  236. SystemExceptionInformation,
  237. &ExceptionInfo,
  238. sizeof(ExceptionInfo),
  239. NULL
  240. );
  241. if (!NT_SUCCESS(ntStatus)) {
  242. // unable to collect the data from the system so
  243. // clear the return data structure to prevent bogus data from
  244. // being returned
  245. if (hEventLog != NULL) {
  246. ReportEvent (hEventLog,
  247. EVENTLOG_WARNING_TYPE,
  248. 0,
  249. PERFOS_UNABLE_QUERY_EXCEPTION_INFO,
  250. NULL,
  251. 0,
  252. sizeof(DWORD),
  253. NULL,
  254. (LPVOID)&ntStatus);
  255. }
  256. memset (&ExceptionInfo, 0, sizeof(ExceptionInfo));
  257. }
  258. // collect registry quota info
  259. memset (&RegistryInfo, 0, sizeof (SYSTEM_REGISTRY_QUOTA_INFORMATION));
  260. ntStatus = NtQuerySystemInformation (
  261. SystemRegistryQuotaInformation,
  262. (PVOID)&RegistryInfo,
  263. sizeof(RegistryInfo),
  264. NULL);
  265. if (ntStatus != STATUS_SUCCESS) {
  266. if (hEventLog != NULL) {
  267. ReportEvent (hEventLog,
  268. EVENTLOG_WARNING_TYPE,
  269. 0,
  270. PERFOS_UNABLE_QUERY_REGISTRY_QUOTA_INFO,
  271. NULL,
  272. 0,
  273. sizeof(DWORD),
  274. NULL,
  275. (LPVOID)&ntStatus);
  276. }
  277. // clear the data fields
  278. memset (&RegistryInfo, 0, sizeof (SYSTEM_REGISTRY_QUOTA_INFORMATION));
  279. }
  280. ntStatus = NtQuerySystemInformation(
  281. SystemTimeOfDayInformation,
  282. &SysTimeInfo,
  283. sizeof(SysTimeInfo),
  284. &dwReturnedBufferSize
  285. );
  286. if (!NT_SUCCESS(ntStatus)) {
  287. if (hEventLog != NULL) {
  288. ReportEvent (hEventLog,
  289. EVENTLOG_WARNING_TYPE,
  290. 0,
  291. PERFOS_UNABLE_QUERY_SYSTEM_TIME_INFO,
  292. NULL,
  293. 0,
  294. sizeof(DWORD),
  295. NULL,
  296. (LPVOID)&ntStatus);
  297. }
  298. memset (&SysTimeInfo, 0, sizeof(SysTimeInfo));
  299. }
  300. // get thread info
  301. ntStatus = GetSystemThreadInfo (&TDB);
  302. if (!NT_SUCCESS(ntStatus)) {
  303. memset (&TDB, 0, sizeof(TDB));
  304. }
  305. // update the object perf time (freq is constant)
  306. pSystemDataDefinition->SystemObjectType.PerfTime = SysTimeInfo.CurrentTime;
  307. pSCD = (PSYSTEM_COUNTER_DATA)&pSystemDataDefinition[1];
  308. pSCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof(SYSTEM_COUNTER_DATA));
  309. pSCD->ReadOperations = SysPerfInfo.IoReadOperationCount;
  310. pSCD->WriteOperations = SysPerfInfo.IoWriteOperationCount;
  311. pSCD->OtherIOOperations = SysPerfInfo.IoOtherOperationCount;
  312. pSCD->ReadBytes = SysPerfInfo.IoReadTransferCount.QuadPart;
  313. pSCD->WriteBytes = SysPerfInfo.IoWriteTransferCount.QuadPart;
  314. pSCD->OtherIOBytes = SysPerfInfo.IoOtherTransferCount.QuadPart;
  315. pSCD->ContextSwitches = SysPerfInfo.ContextSwitches;
  316. pSCD->SystemCalls = SysPerfInfo.SystemCalls;
  317. pSCD->TotalReadWrites = SysPerfInfo.IoReadOperationCount +
  318. SysPerfInfo.IoWriteOperationCount;
  319. pSCD->SystemElapsedTime = SysTimeInfo.BootTime.QuadPart - SysTimeInfo.BootTimeBias;
  320. // leave room for the ProcessorQueueLength data
  321. pSCD->ProcessorQueueLength = TDB.dwReadyThreads;
  322. pSCD->ProcessCount = TDB.dwProcessCount;
  323. pSCD->ThreadCount = TDB.dwThreadCount;
  324. pSCD->AlignmentFixups = ExceptionInfo.AlignmentFixupCount ;
  325. pSCD->ExceptionDispatches = ExceptionInfo.ExceptionDispatchCount ;
  326. pSCD->FloatingPointEmulations = ExceptionInfo.FloatingEmulationCount ;
  327. pSCD->RegistryQuotaUsed = RegistryInfo.RegistryQuotaUsed;
  328. pSCD->RegistryQuotaAllowed = RegistryInfo.RegistryQuotaAllowed;
  329. *lpcbTotalBytes =
  330. pSystemDataDefinition->SystemObjectType.TotalByteLength =
  331. (DWORD) QWORD_MULTIPLE(((LPBYTE) (& pSCD[1])) - (LPBYTE) pSystemDataDefinition);
  332. * lppData = (LPVOID) (((LPBYTE) pSystemDataDefinition) + * lpcbTotalBytes);
  333. *lpNumObjectTypes = 1;
  334. #ifdef DBG
  335. ENDTIMING (("PERFSYS: %d takes %I64u ms total\n", __LINE__, diff));
  336. #endif
  337. return ERROR_SUCCESS;
  338. }
  339. DWORD APIENTRY
  340. CloseSystemObject (
  341. )
  342. /*++
  343. Routine Description:
  344. This routine closes the open handles to the Signal Gen counters.
  345. Arguments:
  346. None.
  347. Return Value:
  348. ERROR_SUCCESS
  349. --*/
  350. {
  351. UCHAR *pBuffer;
  352. if (dwSysOpenCount > 0) {
  353. if (!(--dwSysOpenCount)) { // when this is the last thread...
  354. // close stuff here
  355. if ((hLibHeap != NULL) && (pProcessBuffer != NULL)) {
  356. pBuffer = pProcessBuffer;
  357. pProcessBuffer = NULL;
  358. FREEMEM (pBuffer);
  359. ProcessBufSize = 0;
  360. }
  361. }
  362. }
  363. return ERROR_SUCCESS;
  364. }