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.

516 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. perf.cxx
  6. Abstract:
  7. Performance counter implementation
  8. // PerfDataBlock // Not created here, but this block
  9. // exists before the real one that
  10. // we create.
  11. _PERF_OBJECT_TYPE // There is one object type in this counter.
  12. 00 Total size // Size of entire returned structure
  13. 04 Definition length // Instance offset
  14. + _PERF_INSTANCE_DEFINITION
  15. | 00 Total size // Offset
  16. | 04
  17. | 08
  18. | 0c Unique ID (-1)
  19. | 10 Offset to Name
  20. | 14 Name Length
  21. | _PERF_COUNTER_BLOCK
  22. | 00 Total size // Offset to next instance definition
  23. | <data> variable // Holds struct of perf data
  24. | // (e.g., LSPL_COUNTER_DATA).
  25. |
  26. +----This entire block repeats, one per printer
  27. Author:
  28. Albert Ting (AlbertT) 17-Dec-1996
  29. Revision History:
  30. --*/
  31. #include "precomp.hxx"
  32. #pragma hdrstop
  33. #include "perf.hxx"
  34. #include "perfp.hxx"
  35. #include "messages.h"
  36. /********************************************************************
  37. Forward prototypes
  38. ********************************************************************/
  39. PM_OPEN_PROC PerfOpen;
  40. PM_COLLECT_PROC PerfCollect;
  41. PM_CLOSE_PROC PerfClose;
  42. GLOBAL_PERF_DATA gpd;
  43. LPCWSTR gszGlobal = TEXT( "Global" );
  44. LPCWSTR gszForeign = TEXT( "Foreign" );
  45. LPCWSTR gszCostly = TEXT( "Costly" );
  46. LPCWSTR gszNULL = TEXT( "" );
  47. LPCTSTR gszLogLevelKeyName = TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib" );
  48. LPCTSTR gszLogLevelValueName = TEXT( "EventLogLevel" );
  49. #define FOREIGN_LENGTH 7
  50. /********************************************************************
  51. Performance interface functions:
  52. PerOpen, PerfCollect, PerfClose
  53. ********************************************************************/
  54. DWORD
  55. APIENTRY
  56. PerfOpen(
  57. LPCWSTR pszDeviceNames
  58. )
  59. {
  60. DWORD Status = ERROR_SUCCESS;
  61. if( !gpd.cOpens )
  62. {
  63. Status = Pf_dwClientOpen( pszDeviceNames, &gpd.ppdd );
  64. HKEY hAppKey;
  65. DWORD dwValueType;
  66. DWORD dwValueSize;
  67. UINT uLogLevel;
  68. LONG lStatus;
  69. gpd.uLogLevel = kUser << kLevelShift;
  70. lStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  71. gszLogLevelKeyName,
  72. 0,
  73. KEY_READ,
  74. &hAppKey );
  75. dwValueSize = sizeof(uLogLevel);
  76. if (lStatus == ERROR_SUCCESS)
  77. {
  78. lStatus = RegQueryValueEx( hAppKey,
  79. gszLogLevelValueName,
  80. (LPDWORD)NULL,
  81. &dwValueType,
  82. (LPBYTE)&uLogLevel,
  83. &dwValueSize );
  84. if (lStatus == ERROR_SUCCESS)
  85. {
  86. gpd.uLogLevel = uLogLevel;
  87. }
  88. RegCloseKey(hAppKey);
  89. }
  90. }
  91. if( Status == ERROR_SUCCESS )
  92. {
  93. ++gpd.cOpens;
  94. }
  95. Pf_vReportEvent( kInformation | kDebug,
  96. MSG_PERF_OPEN_CALLED,
  97. sizeof( Status ),
  98. &Status,
  99. NULL );
  100. return Status;
  101. }
  102. DWORD
  103. APIENTRY
  104. PerfCollect(
  105. LPCWSTR pszValue,
  106. PBYTE *ppData,
  107. PDWORD pcbData,
  108. PDWORD pcObjectTypes
  109. )
  110. {
  111. DWORD Status = ERROR_SUCCESS;
  112. DWORD cbObjectType;
  113. DWORD cbDataLeft;
  114. PBYTE pData = *ppData;
  115. DWORD cNumInstances;
  116. DWORD cbTotalSize;
  117. PPERF_OBJECT_TYPE ppot;
  118. //
  119. // pszValue can be NULL, in this case we consider it gszNULL.
  120. //
  121. pszValue = pszValue == NULL ? gszNULL : pszValue;
  122. //
  123. // We need to punt if we're:
  124. //
  125. // Not initialized
  126. // Foreign
  127. // Costly
  128. //
  129. if( !gpd.cOpens ||
  130. !wcsncmp( pszValue, gszForeign, FOREIGN_LENGTH ) ||
  131. !wcscmp( pszValue, gszCostly ))
  132. {
  133. goto Fail;
  134. }
  135. //
  136. // If we're not global, then see if our title index is requested.
  137. //
  138. if( wcscmp( pszValue, gszGlobal ))
  139. {
  140. if( !Pfp_bNumberInUnicodeList(
  141. gpd.ppdd->ObjectType.ObjectNameTitleIndex,
  142. pszValue ))
  143. {
  144. goto Fail;
  145. }
  146. }
  147. //
  148. // Add the header information to the buffer if there is space.
  149. // First check if we have space.
  150. //
  151. cbObjectType = gpd.ppdd->ObjectType.DefinitionLength;
  152. if( *pcbData < cbObjectType )
  153. {
  154. //
  155. // Out of space; fail.
  156. //
  157. Status = ERROR_MORE_DATA;
  158. goto Fail;
  159. }
  160. //
  161. // Copy the data then update the space used.
  162. //
  163. CopyMemory( pData, &gpd.ppdd->ObjectType, cbObjectType );
  164. pData += cbObjectType;
  165. cbDataLeft = *pcbData - cbObjectType;
  166. //
  167. // Call back to the client to collect instance information.
  168. //
  169. Status = Pf_dwClientCollect( &pData,
  170. &cbDataLeft,
  171. &cNumInstances );
  172. if( Status != ERROR_SUCCESS )
  173. {
  174. goto Fail;
  175. }
  176. //
  177. // Update header information then return.
  178. //
  179. cbTotalSize = *pcbData - cbDataLeft;
  180. ppot = reinterpret_cast<PPERF_OBJECT_TYPE>(*ppData);
  181. ppot->NumInstances = cNumInstances;
  182. ppot->TotalByteLength = cbTotalSize;
  183. *ppData += cbTotalSize;
  184. *pcbData = cbTotalSize;
  185. *pcObjectTypes = 1;
  186. return ERROR_SUCCESS;
  187. Fail:
  188. *pcbData = 0;
  189. *pcObjectTypes = 0;
  190. return Status;
  191. }
  192. DWORD
  193. PerfClose(
  194. VOID
  195. )
  196. {
  197. --gpd.cOpens;
  198. if( !gpd.cOpens )
  199. {
  200. //
  201. // Close everything.
  202. //
  203. Pf_vClientClose();
  204. Pf_vReportEvent( kInformation | kDebug,
  205. MSG_PERF_CLOSE_CALLED,
  206. 0,
  207. NULL,
  208. NULL );
  209. //
  210. // If event log was opened, close it.
  211. //
  212. Pfp_vCloseEventLog();
  213. }
  214. return 0;
  215. }
  216. /********************************************************************
  217. Utility functions
  218. ********************************************************************/
  219. LPCTSTR gszFirstCounter = TEXT( "First Counter" );
  220. LPCTSTR gszFirstHelp = TEXT( "First Help" );
  221. VOID
  222. Pf_vFixIndiciesFromIndex(
  223. DWORD dwFirstCounter,
  224. DWORD dwFirstHelp,
  225. PPERF_DATA_DEFINITION ppdd
  226. )
  227. /*++
  228. Routine Description:
  229. Fix the offsets to the localized strings based on indicies.
  230. Arguments:
  231. dwFirstCounter - Offset for counter text.
  232. dwFirstHelp - Offset for help text.
  233. Return Value:
  234. --*/
  235. {
  236. //
  237. // Update object indicies.
  238. //
  239. ppdd->ObjectType.ObjectNameTitleIndex += dwFirstCounter;
  240. ppdd->ObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  241. //
  242. // Update all counter definitions.
  243. //
  244. UINT i;
  245. UINT cCounters = ppdd->ObjectType.NumCounters;
  246. PPERF_COUNTER_DEFINITION ppcd;
  247. for( i = 0, ppcd = ppdd->aCounterDefinitions;
  248. i < cCounters;
  249. ++i, ++ppcd )
  250. {
  251. ppcd->CounterNameTitleIndex += dwFirstCounter;
  252. ppcd->CounterHelpTitleIndex += dwFirstHelp;
  253. }
  254. }
  255. DWORD
  256. Pf_dwFixIndiciesFromKey(
  257. LPCTSTR szPerformanceKey,
  258. PPERF_DATA_DEFINITION ppdd
  259. )
  260. /*++
  261. Routine Description:
  262. Open the performance key so that we can fix up the offsets
  263. of the localized strings.
  264. Arguments:
  265. szPerformanceKey - Performance registry key.
  266. Return Value:
  267. TRUE - Success
  268. FALSE - Failure
  269. --*/
  270. {
  271. HKEY hkey = NULL;
  272. DWORD dwFirstCounter;
  273. DWORD dwFirstHelp;
  274. DWORD cbSize = 0;
  275. DWORD dwType;
  276. DWORD Error;
  277. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  278. szPerformanceKey,
  279. 0,
  280. KEY_READ,
  281. &hkey );
  282. if( Error == ERROR_SUCCESS )
  283. {
  284. //
  285. // Read the first counter DWORD.
  286. //
  287. cbSize = sizeof(DWORD);
  288. Error = RegQueryValueEx( hkey,
  289. gszFirstCounter,
  290. NULL,
  291. &dwType,
  292. reinterpret_cast<LPBYTE>( &dwFirstCounter ),
  293. &cbSize );
  294. }
  295. if( Error == ERROR_SUCCESS )
  296. {
  297. //
  298. // Read the first counter DWORD.
  299. //
  300. cbSize = sizeof(DWORD);
  301. Error = RegQueryValueEx( hkey,
  302. gszFirstHelp,
  303. NULL,
  304. &dwType,
  305. reinterpret_cast<LPBYTE>( &dwFirstHelp ),
  306. &cbSize );
  307. }
  308. if( Error == ERROR_SUCCESS )
  309. {
  310. Pf_vFixIndiciesFromIndex( dwFirstCounter, dwFirstHelp, ppdd );
  311. }
  312. if ( hkey != NULL)
  313. {
  314. RegCloseKey( hkey );
  315. }
  316. return Error;
  317. }
  318. DWORD
  319. Pf_dwBuildInstance(
  320. IN DWORD dwParentObjectTitleIndex,
  321. IN DWORD dwParentObjectInstance,
  322. IN DWORD dwUniqueID,
  323. IN LPCWSTR pszName,
  324. IN OUT PBYTE* ppData,
  325. IN OUT PDWORD pcbDataLeft
  326. )
  327. /*++
  328. Routine Description:
  329. Builds and initializes the variable structre PERF_INSTANCE_DEFINITION.
  330. Arguments:
  331. dwParentObjectTitleIndex - Index of the parent object in the database.
  332. dwParentObjectInstance - Instance of the parent object (0 or greater).
  333. dwUniqueID - Id of the object. May be PERF_NO_UNIQUE_ID.
  334. pszName - Name of the instance.
  335. ppData - On entry, holds the pointer to the buffer. Should be QUADWORD
  336. aligned. On exit, holds the next free QUADWORD aligned point in the
  337. buffer. If this function fails, this is not modified.
  338. pcbDataLeft - On entry, holds the size of the buffer. On exit, holds
  339. the space remaining (unused) in the buffer. If this function
  340. fails, this is not modified.
  341. Return Value:
  342. ERROR_SUCCESS - Success, else error code.
  343. --*/
  344. {
  345. //
  346. // First calculate if we have enough space. (Assumes that the
  347. // PERF_INSTANCE_DEFINITION size is WORD aligned.)
  348. //
  349. UINT cbName = ( wcslen( pszName ) + 1 ) * sizeof( pszName[0] );
  350. UINT cbInstanceDefinition = sizeof( PERF_INSTANCE_DEFINITION ) + cbName;
  351. cbInstanceDefinition = QuadAlignUp( cbInstanceDefinition );
  352. if( *pcbDataLeft < cbInstanceDefinition )
  353. {
  354. return ERROR_MORE_DATA;
  355. }
  356. //
  357. // Build the structure.
  358. //
  359. PERF_INSTANCE_DEFINITION *pped;
  360. pped = reinterpret_cast<PPERF_INSTANCE_DEFINITION>( *ppData );
  361. pped->ByteLength = cbInstanceDefinition;
  362. pped->ParentObjectTitleIndex = dwParentObjectTitleIndex;
  363. pped->ParentObjectInstance = dwParentObjectInstance;
  364. pped->UniqueID = dwUniqueID;
  365. pped->NameOffset = sizeof( PERF_INSTANCE_DEFINITION );
  366. pped->NameLength = cbName;
  367. //
  368. // Move the pointer past this structure.
  369. //
  370. ++pped;
  371. //
  372. // Copy the name right after this structure. We change all / to , because
  373. // perfmon uses / to denote parent and child instances ( parent/child).
  374. //
  375. LPCWSTR pszSrc = pszName;
  376. for (LPWSTR pszDest = reinterpret_cast<LPWSTR>(pped) ; *pszSrc ; pszSrc++, pszDest++)
  377. {
  378. *pszDest = (*pszSrc == '/') ? ',' : *pszSrc ;
  379. }
  380. *pszDest = L'\0';
  381. //
  382. // Update the pointers.
  383. //
  384. *ppData += cbInstanceDefinition;
  385. *pcbDataLeft -= cbInstanceDefinition;
  386. return ERROR_SUCCESS;
  387. }