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.

525 lines
17 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 - 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: perfinfo.h
  6. * Content: Performance tracking related code
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * ??-??-???? rodtoll Created
  12. * 12-12-2000 rodtoll Re-organize performance struct to handle data misalignment errors on IA64
  13. *
  14. ***************************************************************************/
  15. #include "dncmni.h"
  16. #include "PerfInfo.h"
  17. #include <initguid.h>
  18. // Name of block
  19. #define PERF_INSTANCE_BLOCK_NAME "{F10932E0-2556-4620-9ADE-F572406CFAEA}"
  20. // GUID of block
  21. DEFINE_GUID(PERF_INSTANCE_BLOCK_GUID,
  22. 0xf10932e0, 0x2556, 0x4620, 0x9a, 0xde, 0xf5, 0x72, 0x40, 0x6c, 0xfa, 0xea);
  23. #define PERF_INSTANCE_BLOCK_MUTEX_NAME "{2997F0C7-F135-405f-ABD4-8BAF491B3DAD}"
  24. DEFINE_GUID(PERF_INSTANCE_BLOCK_MUTEX_GUID,
  25. 0x2997f0c7, 0xf135, 0x405f, 0xab, 0xd4, 0x8b, 0xaf, 0x49, 0x1b, 0x3d, 0xad);
  26. HANDLE g_hMutexInstanceBlock = NULL;
  27. HANDLE g_hFileInstanceBlock = NULL;
  28. BYTE *g_pbInstanceBlock = NULL;
  29. PPERF_HEADER g_pperfHeader = NULL;
  30. LONG *g_plNumEntries = NULL;
  31. PPERF_APPLICATION g_pperfAppEntries = NULL;
  32. #define PERF_INSTANCE_BLOCK_MAXENTRIES 100
  33. #define PERF_INSTANCE_BLOCK_SIZE ((sizeof( PERF_APPLICATION ) * PERF_INSTANCE_BLOCK_MAXENTRIES) + sizeof( PERF_HEADER ))
  34. #define PERF_INFO_NAME_LENGTH 64 // 38 for GUID string + room for Global prefix and mutex suffix
  35. void PERF_Coalesce( DWORD dwProcessID = 0xFFFFFFFF );
  36. #undef DPF_MODNAME
  37. #define DPF_MODNAME "PERF_Initialize"
  38. // PERF_Initialize
  39. //
  40. // Initialize the global "instance" list memory block
  41. //
  42. HRESULT PERF_Initialize( )
  43. {
  44. HRESULT hr = S_OK;
  45. BOOL fAlreadyExists = FALSE;
  46. if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
  47. {
  48. g_hMutexInstanceBlock = CreateMutexA( DNGetNullDacl(), FALSE, "Global\\" PERF_INSTANCE_BLOCK_MUTEX_NAME );
  49. }
  50. else
  51. {
  52. g_hMutexInstanceBlock = CreateMutexA( DNGetNullDacl(), FALSE, PERF_INSTANCE_BLOCK_MUTEX_NAME );
  53. }
  54. if( g_hMutexInstanceBlock == NULL )
  55. {
  56. hr = GetLastError();
  57. DPFX(DPFPREP, 0, "Error initializing instance block hr=0x%x", hr );
  58. goto EXIT_ERROR;
  59. }
  60. if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
  61. {
  62. g_hFileInstanceBlock = CreateFileMappingA(INVALID_HANDLE_VALUE,
  63. DNGetNullDacl(),
  64. PAGE_READWRITE,
  65. 0,
  66. PERF_INSTANCE_BLOCK_SIZE,
  67. "Global\\" PERF_INSTANCE_BLOCK_NAME);
  68. }
  69. else
  70. {
  71. g_hFileInstanceBlock = CreateFileMappingA(INVALID_HANDLE_VALUE,
  72. DNGetNullDacl(),
  73. PAGE_READWRITE,
  74. 0,
  75. PERF_INSTANCE_BLOCK_SIZE,
  76. PERF_INSTANCE_BLOCK_NAME);
  77. }
  78. if (g_hFileInstanceBlock == NULL)
  79. {
  80. hr = GetLastError();
  81. DPFX(DPFPREP, 0, "CreateFileMapping() failed hr=0x%x", hr);
  82. goto EXIT_ERROR;
  83. }
  84. if (GetLastError() == ERROR_ALREADY_EXISTS)
  85. {
  86. fAlreadyExists = TRUE;
  87. }
  88. // Map file
  89. g_pbInstanceBlock = reinterpret_cast<BYTE*>(MapViewOfFile(g_hFileInstanceBlock,FILE_MAP_ALL_ACCESS,0,0,0));
  90. if (g_pbInstanceBlock == NULL)
  91. {
  92. hr = GetLastError();
  93. DPFX(DPFPREP, 0,"MapViewOfFile() failed");
  94. goto EXIT_ERROR;
  95. }
  96. g_pperfHeader = (PPERF_HEADER) g_pbInstanceBlock;
  97. g_plNumEntries = &g_pperfHeader->lNumEntries;
  98. g_pperfAppEntries = (PPERF_APPLICATION) &g_pperfHeader[1];
  99. // Access to entry count is protected by interlocked exchange
  100. if( !fAlreadyExists )
  101. {
  102. // Wait for the mutex to enter the block
  103. WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
  104. *g_plNumEntries = 0;
  105. // Zero the memory in the block
  106. ZeroMemory( g_pbInstanceBlock, PERF_INSTANCE_BLOCK_SIZE );
  107. ReleaseMutex( g_hMutexInstanceBlock );
  108. }
  109. else
  110. {
  111. PERF_Coalesce();
  112. }
  113. return hr;
  114. EXIT_ERROR:
  115. if( g_pbInstanceBlock )
  116. {
  117. UnmapViewOfFile(g_pbInstanceBlock);
  118. g_pbInstanceBlock = NULL;
  119. }
  120. if( g_hFileInstanceBlock )
  121. {
  122. CloseHandle( g_hFileInstanceBlock );
  123. g_hFileInstanceBlock = NULL;
  124. }
  125. if( g_hMutexInstanceBlock )
  126. {
  127. CloseHandle( g_hMutexInstanceBlock );
  128. g_hMutexInstanceBlock = NULL;
  129. }
  130. return hr;
  131. }
  132. #undef DPF_MODNAME
  133. #define DPF_MODNAME "PERF_CleanupEntry"
  134. // PERF_CleanupEntry
  135. //
  136. // Cleanup global memory block for the entry
  137. //
  138. void PERF_CleanupEntry( PPERF_APPLICATION pperfApplication, PPERF_APPLICATION_INFO pperfApplicationInfo )
  139. {
  140. if( pperfApplication->dwFlags & PERF_APPLICATION_VALID )
  141. {
  142. // This entry belongs to this process
  143. if( pperfApplicationInfo )
  144. {
  145. if( pperfApplicationInfo->pbMemoryBlock )
  146. {
  147. UnmapViewOfFile( pperfApplicationInfo->pbMemoryBlock );
  148. }
  149. if( pperfApplicationInfo->hFileMap )
  150. {
  151. CloseHandle( pperfApplicationInfo->hFileMap );
  152. }
  153. }
  154. ZeroMemory( pperfApplication, sizeof( PERF_APPLICATION ) );
  155. (*g_plNumEntries)--;
  156. }
  157. }
  158. #undef DPF_MODNAME
  159. #define DPF_MODNAME "PERF_Coalesce"
  160. // PERF_Coalesce
  161. //
  162. // Several routines run this function, the purpose is to run the list of processes
  163. // and remove dead processes from the list.
  164. //
  165. // WARNING: You must have the mutex when you enter this function
  166. //
  167. // Should be called when adding entries or reading entries.
  168. //
  169. // If called with a valid process ID then all entries for that process are removed
  170. //
  171. void PERF_Coalesce( DWORD dwProcessID )
  172. {
  173. if( !g_pbInstanceBlock )
  174. return;
  175. HANDLE hProcess;
  176. for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
  177. {
  178. if( g_pperfAppEntries[lIndex].dwFlags & PERF_APPLICATION_VALID )
  179. {
  180. if( dwProcessID != 0xFFFFFFFF )
  181. {
  182. if( g_pperfAppEntries[lIndex].dwProcessID == dwProcessID )
  183. PERF_CleanupEntry( &g_pperfAppEntries[lIndex], NULL );
  184. break;
  185. }
  186. else
  187. {
  188. hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, (DWORD) g_pperfAppEntries[lIndex].dwProcessID );
  189. // Check for process existance -- if it exists then leave entry, otherwise leave
  190. if( !hProcess )
  191. PERF_CleanupEntry( &g_pperfAppEntries[lIndex], NULL);
  192. else
  193. CloseHandle( hProcess );
  194. }
  195. }
  196. }
  197. }
  198. #undef DPF_MODNAME
  199. #define DPF_MODNAME "PERF_AddEntry"
  200. // PERF_AddEntry
  201. //
  202. // Requests the application be given a statistics block. If succesful a memory block is allocated of the given size and
  203. // an entry is added to the central memory block. The format of the datablock is application defined.
  204. //
  205. // Parameters for the entry to be created are specified in pperfApplication. All entries in this structure should be
  206. // initialized except for dwProcessID which will be filled in by the system.
  207. //
  208. // This function will fill the specified pperfApplicationInfo structure with information about the entry that was
  209. // created. This structure should be stored because it is needed in the call to PERF_RemoveEntry.
  210. //
  211. HRESULT PERF_AddEntry( PPERF_APPLICATION pperfApplication, PPERF_APPLICATION_INFO pperfApplicationInfo )
  212. {
  213. if( !g_pbInstanceBlock )
  214. return S_OK;
  215. // Zero the pperfApplicationInfo structture so in case of error it can be cleaned up properly
  216. ZeroMemory( pperfApplicationInfo, sizeof( PERF_APPLICATION_INFO ) );
  217. HRESULT hr = S_OK;
  218. // We need the mutex to access the block
  219. WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
  220. // Remove dead entries
  221. PERF_Coalesce();
  222. if( *g_plNumEntries >= PERF_INSTANCE_BLOCK_MAXENTRIES )
  223. {
  224. DPFX(DPFPREP, 0, "Instance block is full!" );
  225. hr = E_FAIL;
  226. ReleaseMutex( g_hMutexInstanceBlock );
  227. return hr;
  228. }
  229. for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
  230. {
  231. // We've found a slot
  232. if( !(g_pperfAppEntries[lIndex].dwFlags & PERF_APPLICATION_VALID) )
  233. {
  234. DPFX(DPFPREP, 0, "Placing entry in index %i, pid=0x%x, flags=0x%x", lIndex, pperfApplication->dwProcessID, pperfApplication->dwFlags );
  235. memcpy( &g_pperfAppEntries[lIndex], pperfApplication, sizeof( PERF_APPLICATION ) );
  236. break;
  237. }
  238. }
  239. // Instance block is full -- wow. Shouldn't happen -- afterall we checked above.
  240. if( lIndex == PERF_INSTANCE_BLOCK_MAXENTRIES )
  241. {
  242. // This should not happen, we have mutex AND checked entry count
  243. DNASSERT( FALSE );
  244. DPFX(DPFPREP, 0, "Unable to find an entry in the list" );
  245. hr = E_FAIL;
  246. ReleaseMutex( g_hMutexInstanceBlock );
  247. return hr;
  248. }
  249. char szNameBuffer[PERF_INFO_NAME_LENGTH];
  250. // Build name for shared memory block
  251. if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
  252. {
  253. wsprintfA( szNameBuffer, "Global\\{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
  254. g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
  255. g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
  256. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
  257. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
  258. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
  259. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
  260. }
  261. else
  262. {
  263. wsprintfA( szNameBuffer, "{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
  264. g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
  265. g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
  266. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
  267. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
  268. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
  269. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
  270. }
  271. // Create file mapping for memory block
  272. pperfApplicationInfo->hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE,
  273. DNGetNullDacl(),
  274. PAGE_READWRITE,
  275. 0,
  276. pperfApplication->dwMemoryBlockSize,
  277. szNameBuffer);
  278. if (pperfApplicationInfo->hFileMap == NULL)
  279. {
  280. hr = GetLastError();
  281. DPFX(DPFPREP, 0, "CreateFileMapping() failed hr=0x%x", hr);
  282. goto EXIT_ERROR;
  283. }
  284. // Create the shared memory block
  285. pperfApplicationInfo->pbMemoryBlock = reinterpret_cast<BYTE*>(MapViewOfFile(pperfApplicationInfo->hFileMap,FILE_MAP_ALL_ACCESS,0,0,0));
  286. if (pperfApplicationInfo->pbMemoryBlock == NULL)
  287. {
  288. hr = GetLastError();
  289. DPFX(DPFPREP, 0,"MapViewOfFile() failed hr=0x%x", hr);
  290. goto EXIT_ERROR;
  291. }
  292. strcat( szNameBuffer, "_M" );
  293. // Create mutex to protect the mutex.
  294. pperfApplicationInfo->hMutex = CreateMutexA( DNGetNullDacl(), FALSE, szNameBuffer );
  295. if( !pperfApplicationInfo->hMutex )
  296. {
  297. hr = GetLastError();
  298. DPFX(DPFPREP, 0,"MapViewOfFile() failed hr=0x%x", hr);
  299. goto EXIT_ERROR;
  300. }
  301. // Copy all the settings back to the app specified structure
  302. memcpy( pperfApplication, &g_pperfAppEntries[lIndex], sizeof( PERF_APPLICATION ) );
  303. (*g_plNumEntries)++;
  304. ReleaseMutex( g_hMutexInstanceBlock );
  305. return S_OK;
  306. EXIT_ERROR:
  307. PERF_CleanupEntry( &g_pperfAppEntries[lIndex], pperfApplicationInfo );
  308. ReleaseMutex( g_hMutexInstanceBlock );
  309. return hr;
  310. }
  311. #undef DPF_MODNAME
  312. #define DPF_MODNAME "PERF_RemoveEntry"
  313. // PERF_RemoveENtry
  314. //
  315. // When an entity no longer requires the statistics block they MUST call this function to free up the
  316. // resources and to allow their slot in the central memory block to be used by other applications.
  317. //
  318. void PERF_RemoveEntry( GUID &guidInternalInstance, PPERF_APPLICATION_INFO pperfApplicationInfo )
  319. {
  320. if( !g_pbInstanceBlock )
  321. return;
  322. HRESULT hr = S_OK;
  323. DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Shutting down perf info" );
  324. // We need the mutex to access the block
  325. WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
  326. DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Removing dead entries" );
  327. // Remove dead entries
  328. PERF_Coalesce();
  329. for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
  330. {
  331. // We've found the entry, mark it as empty
  332. if( g_pperfAppEntries[lIndex].guidInternalInstance == guidInternalInstance )
  333. {
  334. DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Removing our entry" );
  335. PERF_CleanupEntry( &g_pperfAppEntries[lIndex], pperfApplicationInfo );
  336. break;
  337. }
  338. }
  339. ReleaseMutex( g_hMutexInstanceBlock );
  340. DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Exiting" );
  341. }
  342. #undef DPF_MODNAME
  343. #define DPF_MODNAME "PERF_DeInitialize"
  344. // PERF_DeInitialize
  345. //
  346. // Free up the global memory map. Must be called when process exits to cleanup
  347. //
  348. void PERF_DeInitialize()
  349. {
  350. if( g_hMutexInstanceBlock )
  351. {
  352. // We need the mutex to access the block
  353. WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
  354. PERF_Coalesce( GetCurrentProcessId() );
  355. ReleaseMutex( g_hMutexInstanceBlock );
  356. CloseHandle( g_hMutexInstanceBlock );
  357. g_hMutexInstanceBlock = NULL;
  358. }
  359. if( g_pbInstanceBlock )
  360. {
  361. UnmapViewOfFile(g_pbInstanceBlock);
  362. g_pbInstanceBlock = NULL;
  363. }
  364. if( g_hFileInstanceBlock )
  365. {
  366. CloseHandle( g_hFileInstanceBlock );
  367. g_hFileInstanceBlock = NULL;
  368. }
  369. }
  370. #undef DPF_MODNAME
  371. #define DPF_MODNAME "PERF_DumpTable"
  372. // PERF_DumpTable
  373. //
  374. // Helper function that calls the specified callback function once for each entry in the central performance
  375. // table.
  376. void PERF_DumpTable( BOOL fGrabMutex, PVOID pvContext, PFNDUMPPERFTABLE pperfAppEntry )
  377. {
  378. BOOL fSelfInitialized = FALSE;
  379. HANDLE hMapInstance = NULL;
  380. char szNameBuffer[PERF_INFO_NAME_LENGTH];
  381. PBYTE pbDataBlob = NULL;
  382. if( !g_pbInstanceBlock )
  383. {
  384. PERF_Initialize();
  385. fSelfInitialized = TRUE;
  386. }
  387. if( fGrabMutex )
  388. WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
  389. for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
  390. {
  391. // Build name for shared memory block
  392. if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
  393. {
  394. wsprintfA( szNameBuffer, "Global\\{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
  395. g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
  396. g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
  397. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
  398. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
  399. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
  400. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
  401. }
  402. else
  403. {
  404. wsprintfA( szNameBuffer, "{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
  405. g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
  406. g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
  407. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
  408. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
  409. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
  410. g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
  411. }
  412. // Create file mapping for memory block
  413. hMapInstance = OpenFileMappingA(PAGE_READWRITE,FALSE,szNameBuffer);
  414. if( hMapInstance )
  415. {
  416. pbDataBlob = reinterpret_cast<BYTE*>(MapViewOfFile(hMapInstance,FILE_MAP_READ,0,0,0));
  417. HRESULT hr = GetLastError();
  418. }
  419. if( FAILED( (*pperfAppEntry)( pvContext, &g_pperfAppEntries[lIndex], pbDataBlob ) ) )
  420. break;
  421. if( pbDataBlob )
  422. {
  423. UnmapViewOfFile( pbDataBlob );
  424. pbDataBlob = NULL;
  425. }
  426. if( hMapInstance )
  427. {
  428. CloseHandle( hMapInstance );
  429. hMapInstance = NULL;
  430. }
  431. }
  432. if( fGrabMutex )
  433. ReleaseMutex( g_hMutexInstanceBlock );
  434. if( fSelfInitialized )
  435. PERF_DeInitialize();
  436. }