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.

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