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.

466 lines
18 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. physdisk.c
  5. Abstract:
  6. This file implements a Performance Object that presents
  7. Physical Disk 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. #pragma warning ( disable : 4201 )
  19. #include <ntdddisk.h>
  20. #include <windows.h>
  21. #include <ole2.h>
  22. #include <wmium.h>
  23. #pragma warning ( default : 4201 )
  24. #include <assert.h>
  25. #include <winperf.h>
  26. #include <ntprfctr.h>
  27. #define PERF_HEAP hLibHeap
  28. #include <perfutil.h>
  29. #include "perfdisk.h"
  30. #if _DBG_PRINT_INSTANCES
  31. #include <wtypes.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #endif
  35. #include "diskmsg.h"
  36. #include "dataphys.h"
  37. DWORD APIENTRY
  38. CollectPDiskObjectData(
  39. IN OUT LPVOID *lppData,
  40. IN OUT LPDWORD lpcbTotalBytes,
  41. IN OUT LPDWORD lpNumObjectTypes
  42. )
  43. /*++
  44. Routine Description:
  45. This routine will return the data for the logical disk object
  46. Arguments:
  47. IN OUT LPVOID *lppData
  48. IN: pointer to the address of the buffer to receive the completed
  49. PerfDataBlock and subordinate structures. This routine will
  50. append its data to the buffer starting at the point referenced
  51. by *lppData.
  52. OUT: points to the first byte after the data structure added by this
  53. routine. This routine updated the value at lppdata after appending
  54. its data.
  55. IN OUT LPDWORD lpcbTotalBytes
  56. IN: the address of the DWORD that tells the size in bytes of the
  57. buffer referenced by the lppData argument
  58. OUT: the number of bytes added by this routine is writted to the
  59. DWORD pointed to by this argument
  60. IN OUT LPDWORD NumObjectTypes
  61. IN: the address of the DWORD to receive the number of objects added
  62. by this routine
  63. OUT: the number of objects added by this routine is writted to the
  64. DWORD pointed to by this argument
  65. Returns:
  66. 0 if successful, else Win 32 error code of failure
  67. --*/
  68. {
  69. PPDISK_DATA_DEFINITION pPhysicalDiskDataDefinition;
  70. DWORD TotalLen; // Length of the total return block
  71. PDISK_COUNTER_DATA pcdTotal;
  72. DWORD dwStatus = ERROR_SUCCESS;
  73. PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition = NULL;
  74. PWNODE_ALL_DATA WmiDiskInfo;
  75. DISK_PERFORMANCE *pDiskPerformance; // Disk driver returns counters here
  76. PWCHAR wszWmiInstanceName;
  77. WCHAR wszInstanceName[MAX_PATH]; // the numbers shouldn't ever get this big
  78. DWORD dwInstanceNameOffset;
  79. DWORD dwNumPhysicalDisks = 0;
  80. PPDISK_COUNTER_DATA pPCD;
  81. BOOL bMoreEntries;
  82. LONGLONG llTemp;
  83. DWORD dwTemp;
  84. DWORD dwReturn = ERROR_SUCCESS;
  85. WORD wNameLength;
  86. BOOL bSkip;
  87. DWORD dwCurrentWmiObjCount = 0;
  88. DWORD dwRemapCount = 10;
  89. DOUBLE dReadTime, dWriteTime, dTransferTime;
  90. //
  91. // Check for sufficient space for Physical Disk object
  92. // type definition
  93. //
  94. do {
  95. dwNumPhysicalDisks = 0;
  96. // make sure the drive letter map is up-to-date
  97. if (bRemapDriveLetters) {
  98. dwStatus = MapDriveLetters();
  99. // MapDriveLetters clears the remap flag when successful
  100. if (dwStatus != ERROR_SUCCESS) {
  101. *lpcbTotalBytes = (DWORD) 0;
  102. *lpNumObjectTypes = (DWORD) 0;
  103. return dwStatus;
  104. }
  105. }
  106. pPhysicalDiskDataDefinition = (PDISK_DATA_DEFINITION *) *lppData;
  107. // clear the accumulator structure
  108. memset (&pcdTotal, 0, sizeof(pcdTotal));
  109. //
  110. // Define Logical Disk data block
  111. //
  112. TotalLen = sizeof (PDISK_DATA_DEFINITION);
  113. if ( *lpcbTotalBytes < TotalLen ) {
  114. *lpcbTotalBytes = (DWORD) 0;
  115. *lpNumObjectTypes = (DWORD) 0;
  116. return ERROR_MORE_DATA;
  117. }
  118. memmove(pPhysicalDiskDataDefinition,
  119. &PhysicalDiskDataDefinition,
  120. sizeof(PDISK_DATA_DEFINITION));
  121. // read the data from the diskperf driver
  122. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  123. &pPhysicalDiskDataDefinition[1];
  124. WmiDiskInfo = (PWNODE_ALL_DATA)WmiBuffer;
  125. // make sure the structure is valid
  126. if (WmiDiskInfo->WnodeHeader.BufferSize < sizeof(WNODE_ALL_DATA)) {
  127. bMoreEntries = FALSE;
  128. // just to make sure someone notices on a checked build
  129. assert (WmiDiskInfo->WnodeHeader.BufferSize >= sizeof(WNODE_ALL_DATA));
  130. } else {
  131. // make sure there are some entries to return
  132. bMoreEntries =
  133. (WmiDiskInfo->InstanceCount > 0) ? TRUE : FALSE;
  134. }
  135. while (bMoreEntries) {
  136. pDiskPerformance = (PDISK_PERFORMANCE)(
  137. (PUCHAR)WmiDiskInfo + WmiDiskInfo->DataBlockOffset);
  138. dwInstanceNameOffset = *((LPDWORD)(
  139. (LPBYTE)WmiDiskInfo + WmiDiskInfo->OffsetInstanceNameOffsets));
  140. wNameLength = *(WORD *)((LPBYTE)WmiDiskInfo + dwInstanceNameOffset);
  141. if (wNameLength > 0) {
  142. wszWmiInstanceName = (LPWSTR)((LPBYTE)WmiDiskInfo + dwInstanceNameOffset + sizeof(WORD));
  143. if (IsPhysicalDrive(pDiskPerformance)) {
  144. #if _DBG_PRINT_INSTANCES
  145. WCHAR szOutputBuffer[512];
  146. #endif
  147. // then the format is correct AND this is a physical
  148. // partition so set the name string pointer and
  149. // length for use in creating the instance.
  150. memset (wszInstanceName, 0, sizeof(wszInstanceName));
  151. GetPhysicalDriveNameString (
  152. pDiskPerformance->StorageDeviceNumber,
  153. pPhysDiskList,
  154. dwNumPhysDiskListEntries,
  155. wszInstanceName);
  156. #if _DBG_PRINT_INSTANCES
  157. swprintf (szOutputBuffer, (LPCWSTR)L"\nPERFDISK: [%d] PhysDrive [%8.8s,%d] is mapped as: ",
  158. dwNumPhysDiskListEntries,
  159. pDiskPerformance->StorageManagerName,
  160. pDiskPerformance->StorageDeviceNumber);
  161. OutputDebugStringW (szOutputBuffer);
  162. OutputDebugStringW (wszInstanceName);
  163. #endif
  164. bSkip = FALSE;
  165. } else {
  166. bSkip = TRUE;
  167. }
  168. if (!bSkip) {
  169. // first see if there's room for this entry....
  170. TotalLen =
  171. // space already used
  172. (DWORD)((PCHAR) pPerfInstanceDefinition -
  173. (PCHAR) pPhysicalDiskDataDefinition)
  174. // + estimate of this instance
  175. + sizeof(PERF_INSTANCE_DEFINITION)
  176. + (lstrlenW(wszInstanceName) + 1) * sizeof(WCHAR) ;
  177. TotalLen = QWORD_MULTIPLE (TotalLen);
  178. TotalLen += sizeof(PDISK_COUNTER_DATA);
  179. TotalLen = QWORD_MULTIPLE (TotalLen);
  180. if ( *lpcbTotalBytes < TotalLen ) {
  181. *lpcbTotalBytes = (DWORD) 0;
  182. *lpNumObjectTypes = (DWORD) 0;
  183. dwReturn = ERROR_MORE_DATA;
  184. break;
  185. }
  186. MonBuildInstanceDefinition(
  187. pPerfInstanceDefinition,
  188. (PVOID *) &pPCD,
  189. 0, 0, // no parent
  190. (DWORD)-1,// no unique ID
  191. wszInstanceName);
  192. // clear counter data block
  193. pPCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof(PDISK_COUNTER_DATA));
  194. // KdPrint (("PERFDISK: (P) Entry %8.8x for: %ws\n", (DWORD)pPCD, wszWmiInstanceName));
  195. // insure quadword alignment of the data structure
  196. assert (((DWORD)(pPCD) & 0x00000007) == 0);
  197. // Set up pointer for data collection
  198. // the QueueDepth counter is only a byte so clear the unused bytes
  199. pDiskPerformance->QueueDepth &= 0x000000FF;
  200. //
  201. // Format and collect Physical data
  202. //
  203. pcdTotal.DiskCurrentQueueLength += pDiskPerformance->QueueDepth;
  204. pPCD->DiskCurrentQueueLength = pDiskPerformance->QueueDepth;
  205. llTemp = pDiskPerformance->ReadTime.QuadPart +
  206. pDiskPerformance->WriteTime.QuadPart;
  207. // these values are read in 100 NS units but are expected
  208. // to be in sys perf freq (tick) units for the Sec/op ctrs
  209. // so convert them here
  210. dReadTime = (DOUBLE)(pDiskPerformance->ReadTime.QuadPart);
  211. dWriteTime = (DOUBLE)(pDiskPerformance->WriteTime.QuadPart);
  212. dTransferTime = (DOUBLE)(llTemp);
  213. dReadTime *= dSysTickTo100Ns;
  214. dWriteTime *= dSysTickTo100Ns;
  215. dTransferTime *= dSysTickTo100Ns;
  216. pPCD->DiskTime = llTemp;
  217. pPCD->DiskAvgQueueLength = llTemp;
  218. pcdTotal.DiskAvgQueueLength += llTemp;
  219. pcdTotal.DiskTime += llTemp;
  220. pPCD->DiskReadTime = pDiskPerformance->ReadTime.QuadPart;
  221. pPCD->DiskReadQueueLength = pDiskPerformance->ReadTime.QuadPart;
  222. pcdTotal.DiskReadTime += pDiskPerformance->ReadTime.QuadPart;
  223. pcdTotal.DiskReadQueueLength += pDiskPerformance->ReadTime.QuadPart;
  224. pPCD->DiskWriteTime = pDiskPerformance->WriteTime.QuadPart;
  225. pPCD->DiskWriteQueueLength = pDiskPerformance->WriteTime.QuadPart;
  226. pcdTotal.DiskWriteTime += pDiskPerformance->WriteTime.QuadPart;
  227. pcdTotal.DiskWriteQueueLength += pDiskPerformance->WriteTime.QuadPart;
  228. pPCD->DiskAvgTime = (LONGLONG)dTransferTime;
  229. pcdTotal.DiskAvgTime += (LONGLONG)dTransferTime;
  230. dwTemp = pDiskPerformance->ReadCount +
  231. pDiskPerformance->WriteCount;
  232. pcdTotal.DiskTransfersBase1 += dwTemp;
  233. pPCD->DiskTransfersBase1 = dwTemp;
  234. pcdTotal.DiskAvgReadTime += (LONGLONG)dReadTime;
  235. pPCD->DiskAvgReadTime = (LONGLONG)dReadTime;
  236. pcdTotal.DiskReadsBase1 += pDiskPerformance->ReadCount;
  237. pPCD->DiskReadsBase1 = pDiskPerformance->ReadCount;
  238. pcdTotal.DiskAvgWriteTime += (LONGLONG)dWriteTime;
  239. pPCD->DiskAvgWriteTime = (LONGLONG)dWriteTime;
  240. pcdTotal.DiskWritesBase1 += pDiskPerformance->WriteCount;
  241. pPCD->DiskWritesBase1 = pDiskPerformance->WriteCount;
  242. pcdTotal.DiskTransfers += dwTemp;
  243. pPCD->DiskTransfers = dwTemp;
  244. pcdTotal.DiskReads += pDiskPerformance->ReadCount;
  245. pPCD->DiskReads = pDiskPerformance->ReadCount;
  246. pcdTotal.DiskWrites += pDiskPerformance->WriteCount;
  247. pPCD->DiskWrites = pDiskPerformance->WriteCount;
  248. llTemp = pDiskPerformance->BytesRead.QuadPart +
  249. pDiskPerformance->BytesWritten.QuadPart;
  250. pcdTotal.DiskBytes += llTemp;
  251. pPCD->DiskBytes = llTemp;
  252. pcdTotal.DiskReadBytes += pDiskPerformance->BytesRead.QuadPart;
  253. pPCD->DiskReadBytes = pDiskPerformance->BytesRead.QuadPart;
  254. pcdTotal.DiskWriteBytes += pDiskPerformance->BytesWritten.QuadPart;
  255. pPCD->DiskWriteBytes = pDiskPerformance->BytesWritten.QuadPart;
  256. pcdTotal.DiskAvgBytes += llTemp;
  257. pPCD->DiskAvgBytes = llTemp;
  258. pcdTotal.DiskTransfersBase2 += dwTemp;
  259. pPCD->DiskTransfersBase2 = dwTemp;
  260. pcdTotal.DiskAvgReadBytes += pDiskPerformance->BytesRead.QuadPart;
  261. pPCD->DiskAvgReadBytes = pDiskPerformance->BytesRead.QuadPart;
  262. pcdTotal.DiskReadsBase2 += pDiskPerformance->ReadCount;
  263. pPCD->DiskReadsBase2 = pDiskPerformance->ReadCount;
  264. pcdTotal.DiskAvgWriteBytes += pDiskPerformance->BytesWritten.QuadPart;
  265. pPCD->DiskAvgWriteBytes = pDiskPerformance->BytesWritten.QuadPart;
  266. pcdTotal.DiskWritesBase2 += pDiskPerformance->WriteCount;
  267. pPCD->DiskWritesBase2 = pDiskPerformance->WriteCount;
  268. pPCD->IdleTime = pDiskPerformance->IdleTime.QuadPart;
  269. pcdTotal.IdleTime += pDiskPerformance->IdleTime.QuadPart;
  270. pPCD->SplitCount = pDiskPerformance->SplitCount;
  271. pcdTotal.SplitCount += pDiskPerformance->SplitCount;
  272. pPCD->DiskTimeTimeStamp = pDiskPerformance->QueryTime.QuadPart;
  273. pcdTotal.DiskTimeTimeStamp += pDiskPerformance->QueryTime.QuadPart;
  274. // move to the end of the buffer for the next instance
  275. pPerfInstanceDefinition = (PPERF_INSTANCE_DEFINITION)&pPCD[1];
  276. dwNumPhysicalDisks++;
  277. } else {
  278. // KdPrint (("PERFDISK: (P) Skipping Instance: %ws\n", wszWmiInstanceName));
  279. }
  280. // count the number of items returned by WMI
  281. dwCurrentWmiObjCount++;
  282. } else {
  283. // the name has 0 length so skip
  284. }
  285. // bump pointers inside WMI data block
  286. if (WmiDiskInfo->WnodeHeader.Linkage != 0) {
  287. // continue
  288. WmiDiskInfo = (PWNODE_ALL_DATA) (
  289. (LPBYTE)WmiDiskInfo + WmiDiskInfo->WnodeHeader.Linkage);
  290. } else {
  291. // this is the end of the line
  292. bMoreEntries = FALSE;
  293. }
  294. } // end for each volume
  295. // see if number of WMI objects returned is different from
  296. // the last time the instance table was built, if so then
  297. // remap the letters and redo the instances
  298. if (dwCurrentWmiObjCount != dwWmiDriveCount) {
  299. DebugPrint((1, "CollectPDisk: Remap Current %d Drive %d\n",
  300. dwCurrentWmiObjCount, dwWmiDriveCount));
  301. bRemapDriveLetters = TRUE;
  302. dwRemapCount--;
  303. }
  304. } while (bRemapDriveLetters && dwRemapCount);
  305. if (dwNumPhysicalDisks > 0) {
  306. // see if there's room for this entry....
  307. TotalLen =
  308. // space already used
  309. (DWORD)((PCHAR) pPerfInstanceDefinition -
  310. (PCHAR) pPhysicalDiskDataDefinition)
  311. // + estimate of this instance
  312. + sizeof(PERF_INSTANCE_DEFINITION)
  313. + (lstrlenW(wszTotal) + 1) * sizeof(WCHAR) ;
  314. TotalLen = QWORD_MULTIPLE (TotalLen);
  315. TotalLen += sizeof(PDISK_COUNTER_DATA);
  316. TotalLen = QWORD_MULTIPLE (TotalLen);
  317. if ( *lpcbTotalBytes < TotalLen ) {
  318. *lpcbTotalBytes = (DWORD) 0;
  319. *lpNumObjectTypes = (DWORD) 0;
  320. dwReturn = ERROR_MORE_DATA;
  321. } else {
  322. // normalize the total times
  323. pcdTotal.DiskTime /= dwNumPhysicalDisks;
  324. pcdTotal.DiskReadTime /= dwNumPhysicalDisks;
  325. pcdTotal.DiskWriteTime /= dwNumPhysicalDisks;
  326. pcdTotal.IdleTime /= dwNumPhysicalDisks;
  327. pcdTotal.DiskTimeTimeStamp /= dwNumPhysicalDisks;
  328. MonBuildInstanceDefinition(
  329. pPerfInstanceDefinition,
  330. (PVOID *) &pPCD,
  331. 0,
  332. 0,
  333. (DWORD)-1,
  334. wszTotal);
  335. // update the total counters
  336. // insure quadword alignment of the data structure
  337. assert (((DWORD)(pPCD) & 0x00000007) == 0);
  338. memcpy (pPCD, &pcdTotal, sizeof (pcdTotal));
  339. pPCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof(PDISK_COUNTER_DATA));
  340. // and update the "next byte" pointer
  341. pPerfInstanceDefinition = (PPERF_INSTANCE_DEFINITION)&pPCD[1];
  342. // update pointer to next available buffer...
  343. pPhysicalDiskDataDefinition->DiskObjectType.NumInstances =
  344. dwNumPhysicalDisks + 1; // add 1 for "Total" disk
  345. }
  346. } else {
  347. // If we are diskless, then return no instances
  348. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  349. &pPhysicalDiskDataDefinition[1];
  350. pPhysicalDiskDataDefinition->DiskObjectType.NumInstances = 0;
  351. }
  352. if (dwReturn == ERROR_SUCCESS) {
  353. *lpcbTotalBytes =
  354. pPhysicalDiskDataDefinition->DiskObjectType.TotalByteLength =
  355. QWORD_MULTIPLE(
  356. (DWORD)((PCHAR) pPerfInstanceDefinition -
  357. (PCHAR) pPhysicalDiskDataDefinition));
  358. #if DBG
  359. // sanity check on buffer size estimates
  360. if (*lpcbTotalBytes > TotalLen ) {
  361. DbgPrint ("\nPERFDISK: Physical Disk Perf Ctr. Instance Size Underestimated:");
  362. DbgPrint ("\nPERFDISK: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes);
  363. }
  364. #endif
  365. *lppData = (LPVOID) (((LPBYTE) pPhysicalDiskDataDefinition) + (* lpcbTotalBytes));
  366. *lpNumObjectTypes = 1;
  367. }
  368. return dwReturn;
  369. }