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.

576 lines
17 KiB

  1. //=================================================================
  2. //
  3. // PerfData.CPP -- Performance Data Helper class
  4. //
  5. // Copyright (c) 1996-2001 Microsoft Corporation, All Rights Reserved
  6. //
  7. // Revisions: 11/23/97 a-sanjes Created
  8. //
  9. //=================================================================
  10. #include "precomp.h"
  11. #include <assertbreak.h>
  12. #include "perfdata.h"
  13. #include <cregcls.h>
  14. #include <createmutexasprocess.h>
  15. #ifdef NTONLY
  16. // Static Initialization
  17. bool CPerformanceData::m_fCloseKey = false;
  18. //////////////////////////////////////////////////////////
  19. //
  20. // Function: CPerformanceData::CPerformanceData
  21. //
  22. // Default constructor
  23. //
  24. // Inputs:
  25. // None
  26. //
  27. // Outputs:
  28. // None
  29. //
  30. // Returns:
  31. // None
  32. //
  33. // Comments:
  34. //
  35. //////////////////////////////////////////////////////////
  36. CPerformanceData::CPerformanceData( void )
  37. {
  38. m_pBuff = NULL;
  39. }
  40. //////////////////////////////////////////////////////////
  41. //
  42. // Function: CPerformanceData::~CPerformanceData
  43. //
  44. // Destructor
  45. //
  46. // Inputs:
  47. // None
  48. //
  49. // Outputs:
  50. // None
  51. //
  52. // Returns:
  53. // None
  54. //
  55. // Comments:
  56. //
  57. //////////////////////////////////////////////////////////
  58. CPerformanceData::~CPerformanceData( void )
  59. {
  60. if (m_pBuff != NULL)
  61. {
  62. delete [] m_pBuff;
  63. }
  64. }
  65. //////////////////////////////////////////////////////////
  66. //
  67. // Function: CPerformanceData::RegQueryValueExExEx
  68. //
  69. // Inputs: HKEY hKey handle of key to query
  70. // LPTSTR lpValueName, address of name of value to query
  71. // LPDWORD lpReserved reserved
  72. // LPDWORD lpType, address of buffer for value type
  73. // LPBYTE lpData address of data buffer
  74. // LPDWORD lpcbData address of data buffer size
  75. //
  76. //
  77. // Returns: everything documented by RegQueryValueEx AND ERROR_SEM_TIMEOUT or ERROR_OPEN_FAILED
  78. //
  79. //////////////////////////////////////////////////////////
  80. LONG CPerformanceData::RegQueryValueExExEx( HKEY hKey, LPTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
  81. {
  82. LONG ret = -1;
  83. ret = RegQueryValueEx( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
  84. return ret;
  85. }
  86. //////////////////////////////////////////////////////////
  87. //
  88. // Function: CPerformanceData::Open
  89. //
  90. // Opens and retrieves data from the performance data
  91. // registry key.
  92. //
  93. // Inputs:
  94. // LPCTSTR pszValue - Value to retrieve
  95. //
  96. // Outputs:
  97. // LPDWORD pdwType - Type returned
  98. // LPBYTE lpData - Buffer
  99. // LPDWORD lpcbData - Amount of data returned
  100. //
  101. // Returns:
  102. // ERROR_SUCCESS if successful
  103. //
  104. // Comments:
  105. //
  106. //////////////////////////////////////////////////////////
  107. DWORD CPerformanceData::Open( LPCTSTR pszValue, LPDWORD pdwType, LPBYTE *lppData, LPDWORD lpcbData )
  108. {
  109. DWORD dwReturn = ERROR_OUTOFMEMORY;
  110. BOOL fStackTrashed = FALSE;
  111. LogMessage(_T("CPerformanceData::Open"));
  112. LPCTSTR pszOldValue = pszValue;
  113. LPDWORD pdwOldType = pdwType;
  114. LPBYTE* lppOldData = lppData;
  115. LPDWORD lpcbOldData = lpcbData;
  116. ASSERT_BREAK(*lppData == NULL);
  117. DWORD dwSize = 16384;
  118. *lpcbData = dwSize;
  119. *lppData = new byte [*lpcbData];
  120. if (*lppData == NULL)
  121. {
  122. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  123. }
  124. if ( pszOldValue != pszValue
  125. || pdwOldType != pdwType
  126. || lppOldData != lppData
  127. || lpcbOldData != lpcbData )
  128. {
  129. LogErrorMessage(_T("CPerformanceData::stack trashed after malloc"));
  130. fStackTrashed = TRUE;
  131. ASSERT_BREAK(0);
  132. }
  133. else
  134. {
  135. try
  136. {
  137. while ((*lppData != NULL) &&
  138. // remember precedence & associativity?
  139. ((dwReturn = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
  140. (LPTSTR)pszValue,
  141. NULL,
  142. pdwType,
  143. (LPBYTE) *lppData,
  144. lpcbData )) == ERROR_MORE_DATA)
  145. )
  146. {
  147. if ( pszOldValue != pszValue
  148. || pdwOldType != pdwType
  149. || lppOldData != lppData
  150. || lpcbOldData != lpcbData )
  151. {
  152. LogErrorMessage(_T("CPerformanceData::stack trashed after RegQueryValueEx"));
  153. fStackTrashed = TRUE;
  154. ASSERT_BREAK(0);
  155. break;
  156. }
  157. // Get a buffer that is big enough.
  158. LogMessage(_T("CPerformanceData::realloc"));
  159. dwSize += 16384;
  160. *lpcbData = dwSize ;
  161. if ( pszOldValue != pszValue
  162. || pdwOldType != pdwType
  163. || lppOldData != lppData
  164. || lpcbOldData != lpcbData )
  165. {
  166. LogErrorMessage(_T("CPerformanceData::stack trashed after size reset"));
  167. fStackTrashed = TRUE;
  168. ASSERT_BREAK(0);
  169. break;
  170. }
  171. delete [] *lppData;
  172. *lppData = new BYTE [*lpcbData];
  173. if (*lppData == NULL)
  174. {
  175. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  176. }
  177. if ( pszOldValue != pszValue
  178. || pdwOldType != pdwType
  179. || lppOldData != lppData
  180. || lpcbOldData != lpcbData )
  181. {
  182. LogErrorMessage(_T("CPerformanceData::stack trashed after realloc"));
  183. fStackTrashed = TRUE;
  184. ASSERT_BREAK(0);
  185. break;
  186. }
  187. } // While
  188. }
  189. catch ( ... )
  190. {
  191. if (*lppData != NULL)
  192. {
  193. delete [] *lppData;
  194. }
  195. throw ;
  196. }
  197. }
  198. if ( fStackTrashed )
  199. {
  200. dwReturn = ERROR_INVALID_FUNCTION;
  201. }
  202. else
  203. {
  204. // if we got here in an error condition, try to recoup
  205. if ((dwReturn != ERROR_SUCCESS)
  206. &&
  207. (*lppData != NULL))
  208. {
  209. LogErrorMessage(_T("CPerformanceData::failed to alloc enough memory"));
  210. delete [] *lppData;
  211. *lppData = NULL;
  212. }
  213. if (!m_fCloseKey)
  214. {
  215. m_fCloseKey = ( ERROR_SUCCESS == dwReturn );
  216. if (m_fCloseKey)
  217. LogMessage(_T("Opened perf counters"));
  218. }
  219. if ((dwReturn != ERROR_SUCCESS) && IsErrorLoggingEnabled())
  220. {
  221. CHString sTemp;
  222. sTemp.Format(_T("Performance RegQueryValueEx returned %d\n"), dwReturn);
  223. LogErrorMessage(sTemp);
  224. }
  225. if (*lppData == NULL)
  226. {
  227. dwReturn = ERROR_OUTOFMEMORY;
  228. }
  229. }
  230. return dwReturn;
  231. }
  232. //////////////////////////////////////////////////////////
  233. //
  234. // Function: CPerformanceData::Close
  235. //
  236. // Closes the performance data registry key if the
  237. // static value is TRUE.
  238. //
  239. // Inputs:
  240. // None.
  241. //
  242. // Outputs:
  243. // None.
  244. //
  245. // Returns:
  246. // None.
  247. //
  248. // Comments:
  249. //
  250. // Per the KB, calling RegCloseKey on HKEY_PERFORMANCE_DATA
  251. // causes a memory leak, so you do NOT want to do lots of
  252. // these.
  253. //
  254. //////////////////////////////////////////////////////////
  255. #if 0 // From raid 48395
  256. void CPerformanceData::Close( void )
  257. {
  258. if ( m_fCloseKey )
  259. {
  260. if ( m_fCloseKey )
  261. {
  262. RegCloseKey( HKEY_PERFORMANCE_DATA );
  263. m_fCloseKey = FALSE;
  264. LogMessage(_T("Closed Perf Counters"));
  265. }
  266. }
  267. }
  268. #endif
  269. //////////////////////////////////////////////////////////
  270. //
  271. // Function: CPerformanceData::GetPerfIndex
  272. //
  273. // Given a perf object name, this function returns
  274. // the perf object number.
  275. //
  276. // Inputs:
  277. // Object name
  278. //
  279. // Outputs:
  280. // None
  281. //
  282. // Returns:
  283. // Associated Number or 0 on error.
  284. //
  285. // Comments:
  286. //
  287. //
  288. //////////////////////////////////////////////////////////
  289. DWORD CPerformanceData::GetPerfIndex(LPCTSTR pszName)
  290. {
  291. DWORD dwRetVal = 0;
  292. if (m_pBuff == NULL)
  293. {
  294. LONG lRet = ERROR_SUCCESS;
  295. if (m_pBuff == NULL)
  296. {
  297. CRegistry RegInfo;
  298. // Hardcoding 009 should be ok since according to the docs:
  299. // "The langid is the ASCII representation of the 3-digit hexadecimal language identifier. "
  300. // "For example, the U.S. English langid is 009. In a non-English version of Windows NT, "
  301. // "counters are stored in both the native language of the system and in English. "
  302. if ((lRet = RegInfo.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"), KEY_QUERY_VALUE)) == ERROR_SUCCESS)
  303. {
  304. // Get the size of the key
  305. DWORD dwSize;
  306. lRet = RegInfo.GetCurrentBinaryKeyValue(_T("Counter"), NULL, &dwSize);
  307. if (lRet == ERROR_SUCCESS)
  308. {
  309. // Allocate a buffer to hold it
  310. m_pBuff = new BYTE[dwSize];
  311. if (m_pBuff != NULL)
  312. {
  313. // Get the actual data
  314. if ((lRet = RegInfo.GetCurrentBinaryKeyValue(_T("Counter"), m_pBuff, &dwSize)) != ERROR_SUCCESS)
  315. {
  316. delete [] m_pBuff;
  317. m_pBuff = NULL;
  318. }
  319. }
  320. else
  321. {
  322. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  323. }
  324. }
  325. }
  326. }
  327. if (lRet != ERROR_SUCCESS)
  328. {
  329. LogErrorMessage2(L"Failed to read Perflib key: %x", lRet);
  330. }
  331. }
  332. // If we got the registry key
  333. if (m_pBuff != NULL)
  334. {
  335. const TCHAR *pCounter;
  336. const TCHAR *ptemp;
  337. int stringlength;
  338. pCounter = (TCHAR *)m_pBuff;
  339. stringlength = _tcslen((LPCTSTR)pCounter);
  340. // Exit the loop when we hit the end
  341. while(stringlength)
  342. {
  343. // Strings are stored in the form <counternumber>\0<countername>\0.
  344. // What we want to return is the counter number. ptemp will point to the name
  345. ptemp = pCounter + stringlength+1;
  346. stringlength = _tcslen((LPCTSTR)ptemp);
  347. if (stringlength > 0)
  348. {
  349. // Did we find it
  350. if (_tcscmp((TCHAR *)ptemp, pszName) != 0)
  351. {
  352. // Nope, position to the next pair
  353. pCounter = ptemp + stringlength+1;
  354. stringlength = _tcslen((LPCTSTR)pCounter);
  355. }
  356. else
  357. {
  358. // Yup, calculate the value to return
  359. dwRetVal = _ttoi(pCounter);
  360. break;
  361. }
  362. }
  363. }
  364. }
  365. ASSERT_BREAK(dwRetVal > 0);
  366. return dwRetVal;
  367. }
  368. //////////////////////////////////////////////////////////
  369. //
  370. // Function: CPerformanceData::GetValue
  371. //
  372. // Given a perf object index, counter index, and optional
  373. // instance name, returns the value and the time.
  374. //
  375. // Inputs:
  376. // Value, Time
  377. //
  378. // Outputs:
  379. // Value, Time
  380. //
  381. // Returns:
  382. // True if it finds the value
  383. //
  384. // Comments:
  385. //
  386. //
  387. //////////////////////////////////////////////////////////
  388. bool CPerformanceData::GetValue(DWORD dwObjIndex, DWORD dwCtrIndex, const WCHAR *szInstanceName, PBYTE pbData, unsigned __int64 *pTime)
  389. {
  390. PPERF_DATA_BLOCK PerfData = NULL;
  391. DWORD dwBufferSize = 0;
  392. LONG lReturn = 0;
  393. BOOL fReturn = FALSE;
  394. TCHAR szBuff[MAXITOA];
  395. bool bFound = false;
  396. PPERF_INSTANCE_DEFINITION pInstBlock;
  397. DWORD dwInstances;
  398. unsigned __int64 *pbCounterData;
  399. // The subsequent close happens in our destructor (read comment there).
  400. lReturn = Open( _itot(dwObjIndex, szBuff, 10),
  401. NULL,
  402. (LPBYTE *) (&PerfData),
  403. &dwBufferSize );
  404. if ( NULL != PerfData
  405. && ERROR_SUCCESS == lReturn )
  406. {
  407. try
  408. {
  409. // Surf through the objects returned until we find the one we are looking for.
  410. PPERF_OBJECT_TYPE pPerfObject = (PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength);
  411. for ( DWORD dwObjectCtr = 0;
  412. dwObjectCtr < PerfData->NumObjectTypes
  413. && pPerfObject->ObjectNameTitleIndex != dwObjIndex;
  414. dwObjectCtr++ );
  415. // Did we find the Object?
  416. if ( dwObjectCtr < PerfData->NumObjectTypes )
  417. {
  418. // Now surf through the Counter Definition Data until we locate the
  419. // counter we are hunting for.
  420. PPERF_COUNTER_DEFINITION pPerfCtrDef = (PPERF_COUNTER_DEFINITION)((PBYTE) pPerfObject + pPerfObject->HeaderLength);
  421. for ( DWORD dwCtr = 0;
  422. dwCtr < pPerfObject->NumCounters
  423. && pPerfCtrDef->CounterNameTitleIndex != dwCtrIndex;
  424. dwCtr++,
  425. // Go to the next counter
  426. pPerfCtrDef = (PPERF_COUNTER_DEFINITION)((PBYTE) pPerfCtrDef + pPerfCtrDef->ByteLength )
  427. );
  428. // Did we find the counter?
  429. if ( dwCtr < pPerfObject->NumCounters )
  430. {
  431. // Finally go to the data offset we retrieved from the counter definitions
  432. // and access the data (finally).
  433. DWORD dwCounterOffset = pPerfCtrDef->CounterOffset;
  434. PPERF_COUNTER_BLOCK pPerfCtrBlock = NULL;
  435. // If we are looking for an instance
  436. if ((szInstanceName == NULL) && (pPerfObject->NumInstances == PERF_NO_INSTANCES))
  437. {
  438. pPerfCtrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE) pPerfObject + pPerfObject->DefinitionLength);
  439. bFound = true;
  440. }
  441. else if (pPerfObject->NumInstances != PERF_NO_INSTANCES)
  442. {
  443. // Walk the instances looking for the requested one
  444. pInstBlock = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pPerfObject + pPerfObject->DefinitionLength);
  445. dwInstances = 1;
  446. while ((dwInstances <= pPerfObject->NumInstances) &&
  447. (wcscmp((WCHAR *)((pInstBlock->NameOffset) + (PBYTE)pInstBlock), szInstanceName) != 0))
  448. {
  449. pPerfCtrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE)pInstBlock + pInstBlock->ByteLength);
  450. pInstBlock = (PPERF_INSTANCE_DEFINITION)((PBYTE) pInstBlock + (pInstBlock->ByteLength + pPerfCtrBlock->ByteLength));
  451. dwInstances ++;
  452. }
  453. // Did we find it?
  454. if (dwInstances <= pPerfObject->NumInstances)
  455. {
  456. bFound = true;
  457. pPerfCtrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE)pInstBlock + pInstBlock->ByteLength);
  458. }
  459. }
  460. // Grab the appropriate time field based on the counter definition
  461. if (bFound) {
  462. if (pPerfCtrDef->CounterType & PERF_TIMER_100NS)
  463. {
  464. *pTime = PerfData->PerfTime100nSec.QuadPart;
  465. }
  466. else
  467. {
  468. // Unverified
  469. *pTime = PerfData->PerfTime.QuadPart;
  470. }
  471. // Get a pointer to the data, then copy in the correct number of bytes (based on counter def)
  472. pbCounterData = (unsigned __int64 *)(((PBYTE) pPerfCtrBlock ) + dwCounterOffset);
  473. if (pPerfCtrDef->CounterType & PERF_SIZE_DWORD)
  474. {
  475. memcpy(pbData, pbCounterData, 4);
  476. }
  477. else if (pPerfCtrDef->CounterType & PERF_SIZE_LARGE)
  478. {
  479. memcpy(pbData, pbCounterData, 8);
  480. }
  481. }
  482. } // If Counter Definition found
  483. } // If Object found
  484. } // If memory allocated
  485. catch ( ... )
  486. {
  487. delete [] PerfData ;
  488. throw ;
  489. }
  490. }
  491. // Free up any transient memory
  492. if ( NULL != PerfData )
  493. {
  494. delete [] PerfData ;
  495. }
  496. ASSERT_BREAK(bFound);
  497. return bFound;
  498. }
  499. #endif