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.

420 lines
11 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. perfpage.c
  5. Abstract:
  6. This file implements an Performance Object that presents
  7. system Page file performance 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 <winperf.h>
  20. #include <assert.h>
  21. #include <ntprfctr.h>
  22. #include <perfutil.h>
  23. #include "perfos.h"
  24. #include "perfosmc.h"
  25. #include "datapage.h"
  26. DWORD dwPageOpenCount = 0; // count of "Open" threads
  27. static PSYSTEM_PAGEFILE_INFORMATION pSysPageFileInfo = NULL;
  28. static DWORD dwSysPageFileInfoSize = 0; // size of page file info array
  29. DWORD APIENTRY
  30. OpenPageFileObject (
  31. LPWSTR lpDeviceNames
  32. )
  33. /*++
  34. Routine Description:
  35. This routine will initialize the data structures used to pass
  36. data back to the registry
  37. Arguments:
  38. Pointer to object ID of each device to be opened (PerfGen)
  39. Return Value:
  40. None.
  41. --*/
  42. {
  43. DWORD status = ERROR_SUCCESS;
  44. //
  45. // Since WINLOGON is multi-threaded and will call this routine in
  46. // order to service remote performance queries, this library
  47. // must keep track of how many times it has been opened (i.e.
  48. // how many threads have accessed it). the registry routines will
  49. // limit access to the initialization routine to only one thread
  50. // at a time so synchronization (i.e. reentrancy) should not be
  51. // a problem
  52. //
  53. UNREFERENCED_PARAMETER (lpDeviceNames);
  54. if (!dwPageOpenCount) {
  55. // allocate the memory for the Page file info
  56. dwSysPageFileInfoSize = LARGE_BUFFER_SIZE;
  57. pSysPageFileInfo = ALLOCMEM (
  58. hLibHeap, HEAP_ZERO_MEMORY,
  59. dwSysPageFileInfoSize);
  60. if (pSysPageFileInfo == NULL) {
  61. status = ERROR_OUTOFMEMORY;
  62. goto OpenExitPoint;
  63. }
  64. }
  65. dwPageOpenCount++; // increment OPEN counter
  66. status = ERROR_SUCCESS; // for successful exit
  67. OpenExitPoint:
  68. return status;
  69. }
  70. DWORD APIENTRY
  71. CollectPageFileObjectData (
  72. IN OUT LPVOID *lppData,
  73. IN OUT LPDWORD lpcbTotalBytes,
  74. IN OUT LPDWORD lpNumObjectTypes
  75. )
  76. /*++
  77. Routine Description:
  78. This routine will return the data for the XXX object
  79. Arguments:
  80. IN OUT LPVOID *lppData
  81. IN: pointer to the address of the buffer to receive the completed
  82. PerfDataBlock and subordinate structures. This routine will
  83. append its data to the buffer starting at the point referenced
  84. by *lppData.
  85. OUT: points to the first byte after the data structure added by this
  86. routine. This routine updated the value at lppdata after appending
  87. its data.
  88. IN OUT LPDWORD lpcbTotalBytes
  89. IN: the address of the DWORD that tells the size in bytes of the
  90. buffer referenced by the lppData argument
  91. OUT: the number of bytes added by this routine is writted to the
  92. DWORD pointed to by this argument
  93. IN OUT LPDWORD NumObjectTypes
  94. IN: the address of the DWORD to receive the number of objects added
  95. by this routine
  96. OUT: the number of objects added by this routine is writted to the
  97. DWORD pointed to by this argument
  98. Returns:
  99. 0 if successful, else Win 32 error code of failure
  100. --*/
  101. {
  102. DWORD TotalLen; // Length of the total return block
  103. DWORD PageFileNumber;
  104. DWORD NumPageFileInstances;
  105. DWORD dwReturnedBufferSize;
  106. NTSTATUS status;
  107. PSYSTEM_PAGEFILE_INFORMATION pThisPageFile;
  108. PPAGEFILE_DATA_DEFINITION pPageFileDataDefinition;
  109. PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition;
  110. PPAGEFILE_COUNTER_DATA pPFCD;
  111. PAGEFILE_COUNTER_DATA TotalPFCD;
  112. //
  113. // Check for sufficient space for the Pagefile object
  114. // and counter type definition records, + one instance and
  115. // one set of counter data
  116. //
  117. TotalLen = sizeof(PAGEFILE_DATA_DEFINITION) +
  118. sizeof(PERF_INSTANCE_DEFINITION) +
  119. MAX_PATH * sizeof(WCHAR) +
  120. sizeof(PAGEFILE_COUNTER_DATA);
  121. if ( *lpcbTotalBytes < TotalLen ) {
  122. *lpcbTotalBytes = (DWORD) 0;
  123. *lpNumObjectTypes = (DWORD) 0;
  124. return ERROR_MORE_DATA;
  125. }
  126. status = (NTSTATUS) -1; // so we go throug the loop at least once
  127. while ((status = NtQuerySystemInformation(
  128. SystemPageFileInformation, // item id
  129. pSysPageFileInfo, // address of buffer to get data
  130. dwSysPageFileInfoSize, // size of buffer
  131. &dwReturnedBufferSize)) == STATUS_INFO_LENGTH_MISMATCH) {
  132. dwSysPageFileInfoSize += INCREMENT_BUFFER_SIZE;
  133. pThisPageFile = pSysPageFileInfo;
  134. pSysPageFileInfo = REALLOCMEM (hLibHeap,
  135. 0, pSysPageFileInfo,
  136. dwSysPageFileInfoSize);
  137. if (pSysPageFileInfo == NULL) {
  138. status = ERROR_OUTOFMEMORY;
  139. FREEMEM(hLibHeap, 0, pThisPageFile); // free the original buffer
  140. pThisPageFile = NULL;
  141. break;
  142. }
  143. }
  144. if ( !NT_SUCCESS(status) ) {
  145. ReportEvent (hEventLog,
  146. EVENTLOG_ERROR_TYPE,
  147. 0,
  148. PERFOS_UNABLE_QUERY_PAGEFILE_INFO,
  149. NULL,
  150. 0,
  151. sizeof(DWORD),
  152. NULL,
  153. &status);
  154. *lpcbTotalBytes = (DWORD) 0;
  155. *lpNumObjectTypes = (DWORD) 0;
  156. status = (NTSTATUS)RtlNtStatusToDosError(status);
  157. return status;
  158. }
  159. pPageFileDataDefinition = (PPAGEFILE_DATA_DEFINITION) *lppData;
  160. //
  161. // Define Page File data block
  162. //
  163. memcpy (pPageFileDataDefinition,
  164. &PagefileDataDefinition,
  165. sizeof(PAGEFILE_DATA_DEFINITION));
  166. // Now load data for each PageFile
  167. // clear the total fields
  168. memset (&TotalPFCD, 0, sizeof(TotalPFCD));
  169. TotalPFCD.CounterBlock.ByteLength = sizeof (PAGEFILE_COUNTER_DATA);
  170. PageFileNumber = 0;
  171. NumPageFileInstances = 0;
  172. pThisPageFile = pSysPageFileInfo; // initialize pointer to list of pagefiles
  173. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  174. &pPageFileDataDefinition[1];
  175. // the check for NULL pointer is NOT the exit criteria for this loop,
  176. // merely a check to bail out if the first (or any subsequent) pointer
  177. // is NULL. Normally the loop will exit when the NextEntryOffset == 0
  178. while ( pThisPageFile != NULL ) {
  179. // compute the size required for the next instance record
  180. TotalLen =
  181. // current bytes already used
  182. (DWORD)((LPBYTE)pPerfInstanceDefinition -
  183. (LPBYTE)pPageFileDataDefinition)
  184. // + this instance definition
  185. + sizeof(PERF_INSTANCE_DEFINITION)
  186. // + the file (instance) name
  187. + QWORD_MULTIPLE(pThisPageFile->PageFileName.Length + sizeof(WCHAR))
  188. // + the data block
  189. + sizeof (PAGEFILE_COUNTER_DATA);
  190. TotalLen = QWORD_MULTIPLE(TotalLen+4); // round up to the next quadword
  191. if ( *lpcbTotalBytes < TotalLen ) {
  192. *lpcbTotalBytes = (DWORD) 0;
  193. *lpNumObjectTypes = (DWORD) 0;
  194. return ERROR_MORE_DATA;
  195. }
  196. // Build an Instance
  197. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  198. (PVOID *) &pPFCD,
  199. 0,
  200. 0,
  201. (DWORD)-1,
  202. pThisPageFile->PageFileName.Buffer);
  203. //
  204. // Format the pagefile data
  205. //
  206. pPFCD->CounterBlock.ByteLength = sizeof (PAGEFILE_COUNTER_DATA);
  207. pPFCD->PercentInUse = pThisPageFile->TotalInUse;
  208. pPFCD->PeakUsageBase =
  209. pPFCD->PercentInUseBase = pThisPageFile->TotalSize;
  210. pPFCD->PeakUsage = pThisPageFile->PeakUsage;
  211. // update the total accumulators
  212. TotalPFCD.PeakUsageBase =
  213. TotalPFCD.PercentInUseBase += pThisPageFile->TotalSize;
  214. TotalPFCD.PeakUsage += pThisPageFile->PeakUsage;
  215. TotalPFCD.PercentInUse += pThisPageFile->TotalInUse;
  216. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  217. &pPFCD[1];
  218. NumPageFileInstances++;
  219. PageFileNumber++;
  220. if (pThisPageFile->NextEntryOffset != 0) {
  221. pThisPageFile = (PSYSTEM_PAGEFILE_INFORMATION)\
  222. ((BYTE *)pThisPageFile + pThisPageFile->NextEntryOffset);
  223. } else {
  224. break;
  225. }
  226. }
  227. if (NumPageFileInstances > 0) {
  228. // compute the size required for the next instance record
  229. TotalLen =
  230. // current bytes already used
  231. (DWORD)((LPBYTE)pPerfInstanceDefinition -
  232. (LPBYTE)pPageFileDataDefinition)
  233. // + this instance definition
  234. + sizeof(PERF_INSTANCE_DEFINITION)
  235. // + the file (instance) name
  236. + QWORD_MULTIPLE((lstrlenW (wszTotal) + 1) * sizeof (WCHAR))
  237. // + the data block
  238. + sizeof (PAGEFILE_COUNTER_DATA);
  239. TotalLen = QWORD_MULTIPLE(TotalLen+4); // round up to the next quadword
  240. if ( *lpcbTotalBytes < TotalLen ) {
  241. *lpcbTotalBytes = (DWORD) 0;
  242. *lpNumObjectTypes = (DWORD) 0;
  243. return ERROR_MORE_DATA;
  244. }
  245. // Build the Total Instance
  246. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  247. (PVOID *)&pPFCD,
  248. 0,
  249. 0,
  250. (DWORD)-1,
  251. (LPWSTR)wszTotal);
  252. //
  253. // copy the total data
  254. //
  255. memcpy (pPFCD, &TotalPFCD, sizeof (TotalPFCD));
  256. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  257. &pPFCD[1];
  258. NumPageFileInstances++;
  259. }
  260. // Note number of PageFile instances
  261. pPageFileDataDefinition->PagefileObjectType.NumInstances =
  262. NumPageFileInstances;
  263. //
  264. // update pointers for return
  265. //
  266. *lppData = (LPVOID) pPerfInstanceDefinition;
  267. // round up buffer to the nearest QUAD WORD
  268. *lppData = ALIGN_ON_QWORD (*lppData);
  269. *lpcbTotalBytes =
  270. pPageFileDataDefinition->PagefileObjectType.TotalByteLength =
  271. (DWORD)((PCHAR) *lppData -
  272. (PCHAR) pPageFileDataDefinition);
  273. #if DBG
  274. if (*lpcbTotalBytes > TotalLen ) {
  275. DbgPrint ("\nPERFOS: Paging File Perf Ctr. Instance Size Underestimated:");
  276. DbgPrint ("\nPERFOS: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes);
  277. }
  278. #endif
  279. *lpNumObjectTypes = 1;
  280. return ERROR_SUCCESS;
  281. }
  282. #pragma warning (disable : 4706)
  283. DWORD APIENTRY
  284. ClosePageFileObject (
  285. )
  286. /*++
  287. Routine Description:
  288. This routine closes the open handles to the Signal Gen counters.
  289. Arguments:
  290. None.
  291. Return Value:
  292. ERROR_SUCCESS
  293. --*/
  294. {
  295. if (dwPageOpenCount > 0) {
  296. if (!(--dwPageOpenCount)) { // when this is the last thread...
  297. // close stuff here
  298. if (hLibHeap != NULL) {
  299. if (pSysPageFileInfo != NULL) {
  300. FREEMEM (hLibHeap, 0, pSysPageFileInfo);
  301. pSysPageFileInfo = NULL;
  302. }
  303. }
  304. }
  305. } else {
  306. // if open count == 0, then this should be null
  307. assert (pSysPageFileInfo == NULL);
  308. }
  309. return ERROR_SUCCESS;
  310. }
  311. #pragma warning (default: 4706)