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.

1589 lines
52 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. kernprof.c
  5. Abstract:
  6. This module contains the implementation of a kernel profiler.
  7. It uses dbghelp for symbols and image information and
  8. creates profile objects for each modules it finds loaded
  9. when it starts.
  10. Usage:
  11. See below
  12. Author:
  13. Lou Perazzoli (loup) 29-Sep-1990
  14. Envirnoment:
  15. Revision History:
  16. --*/
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <windows.h>
  21. #include <dbghelp.h>
  22. #include <assert.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <memory.h>
  27. #include <ctype.h>
  28. #include <..\pperf\pstat.h>
  29. #define SYM_HANDLE INVALID_HANDLE_VALUE
  30. #define DBG_PROFILE 0
  31. #define MAX_BYTE_PER_LINE 72
  32. #define MAX_PROFILE_COUNT 200
  33. #define MAX_BUCKET_SHIFT 31 // 2GBytes
  34. #define MAX_BUCKET_SIZE 0x80000000U
  35. typedef struct _PROFILE_BLOCK {
  36. HANDLE Handle[MAXIMUM_PROCESSORS];
  37. PVOID ImageBase;
  38. PULONG CodeStart;
  39. SIZE_T CodeLength;
  40. PULONG Buffer[MAXIMUM_PROCESSORS];
  41. ULONG BufferSize;
  42. ULONG BucketSize;
  43. LPSTR ModuleName;
  44. ULONG ModuleHitCount[MAXIMUM_PROCESSORS];
  45. BOOLEAN SymbolsLoaded;
  46. } PROFILE_BLOCK;
  47. //
  48. // This really should go into a header file but....
  49. //
  50. typedef struct _PROFILE_CONTROL_BLOCK {
  51. BOOLEAN Stop;
  52. char FileName[MAX_PATH];
  53. } PROFILE_CONTROL_BLOCK;
  54. typedef PROFILE_CONTROL_BLOCK * PPROFILE_CONTROL_BLOCK;
  55. #define PRFEVENT_START_EVENT "PrfEventStartedEvent"
  56. #define PRFEVENT_STOP_EVENT "PrfEventStopEvent"
  57. #define PRFEVENT_SHARED_MEMORY "PrfEventSharedMemory"
  58. //
  59. // End header file
  60. //
  61. #define MAX_SYMNAME_SIZE 1024
  62. CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
  63. PIMAGEHLP_SYMBOL ThisSymbol = (PIMAGEHLP_SYMBOL) symBuffer;
  64. CHAR LastSymBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
  65. PIMAGEHLP_SYMBOL LastSymbol = (PIMAGEHLP_SYMBOL) LastSymBuffer;
  66. VOID
  67. InitializeProfileSourceMapping (
  68. VOID
  69. );
  70. NTSTATUS
  71. InitializeKernelProfile(
  72. VOID
  73. );
  74. NTSTATUS
  75. RunEventLoop(
  76. VOID
  77. );
  78. NTSTATUS
  79. RunStdProfile(
  80. VOID
  81. );
  82. NTSTATUS
  83. StartProfile(
  84. VOID
  85. );
  86. NTSTATUS
  87. StopProfile(
  88. VOID
  89. );
  90. NTSTATUS
  91. AnalyzeProfile(
  92. ULONG Threshold,
  93. PSYSTEM_CONTEXT_SWITCH_INFORMATION StartContext,
  94. PSYSTEM_CONTEXT_SWITCH_INFORMATION StopContext
  95. );
  96. VOID
  97. OutputSymbolCount(
  98. IN ULONG CountAtSymbol,
  99. IN ULONG TotalCount,
  100. IN PROFILE_BLOCK *ProfileObject,
  101. IN PIMAGEHLP_SYMBOL SymbolInfo,
  102. IN ULONG Threshold,
  103. IN PULONG CounterStart,
  104. IN PULONG CounterStop,
  105. IN ULONG Va,
  106. IN ULONG BytesPerBucket
  107. );
  108. #ifdef _ALPHA_
  109. #define PAGE_SIZE 8192
  110. #else
  111. #define PAGE_SIZE 4096
  112. #endif
  113. FILE *fpOut = NULL;
  114. PROFILE_BLOCK ProfileObject[MAX_PROFILE_COUNT];
  115. DWORD *UserModeBuffer[MAXIMUM_PROCESSORS];
  116. ULONG NumberOfProfileObjects = 0;
  117. ULONG MaxProcessors = 1;
  118. ULONG ProfileInterval = 10000;
  119. CHAR SymbolSearchPathBuf[4096];
  120. LPSTR lpSymbolSearchPath = SymbolSearchPathBuf;
  121. // display flags
  122. BOOLEAN bDisplayAddress=FALSE;
  123. BOOLEAN bDisplayDensity=FALSE;
  124. BOOLEAN bDisplayCounters=FALSE;
  125. BOOLEAN bDisplayContextSwitch=FALSE;
  126. BOOLEAN bPerProcessor = FALSE;
  127. BOOLEAN bWaitForInput = FALSE;
  128. BOOLEAN bEventLoop = FALSE;
  129. BOOLEAN bPrintPercentages = FALSE;
  130. BOOLEAN Verbose = FALSE;
  131. //
  132. // Image name to perform kernel mode analysis upon.
  133. //
  134. #define IMAGE_NAME "\\SystemRoot\\system32\\ntoskrnl.exe"
  135. HANDLE DoneEvent;
  136. HANDLE DelayEvent;
  137. KPROFILE_SOURCE ProfileSource = ProfileTime;
  138. ULONG Seconds = (ULONG)-1;
  139. ULONG Threshold = 100;
  140. ULONG DelaySeconds = (ULONG)-1;
  141. //
  142. // define the mappings between arguments and KPROFILE_SOURCE types
  143. //
  144. typedef struct _PROFILE_SOURCE_MAPPING {
  145. PCHAR ShortName;
  146. PCHAR Description;
  147. KPROFILE_SOURCE Source;
  148. } PROFILE_SOURCE_MAPPING, *PPROFILE_SOURCE_MAPPING;
  149. #if defined(_ALPHA_)
  150. PROFILE_SOURCE_MAPPING ProfileSourceMapping[] = {
  151. {"align", "", ProfileAlignmentFixup},
  152. {"totalissues", "", ProfileTotalIssues},
  153. {"pipelinedry", "", ProfilePipelineDry},
  154. {"loadinstructions", "", ProfileLoadInstructions},
  155. {"pipelinefrozen", "", ProfilePipelineFrozen},
  156. {"branchinstructions", "", ProfileBranchInstructions},
  157. {"totalnonissues", "", ProfileTotalNonissues},
  158. {"dcachemisses", "", ProfileDcacheMisses},
  159. {"icachemisses", "", ProfileIcacheMisses},
  160. {"branchmispredicts", "", ProfileBranchMispredictions},
  161. {"storeinstructions", "", ProfileStoreInstructions},
  162. {NULL,0}
  163. };
  164. #elif defined(_X86_)
  165. PPROFILE_SOURCE_MAPPING ProfileSourceMapping;
  166. #else
  167. PROFILE_SOURCE_MAPPING ProfileSourceMapping[] = {
  168. {NULL,0}
  169. };
  170. #endif
  171. BOOL
  172. CtrlcH(
  173. DWORD dwCtrlType
  174. )
  175. {
  176. if ( dwCtrlType == CTRL_C_EVENT ) {
  177. SetEvent(DoneEvent);
  178. return TRUE;
  179. }
  180. return FALSE;
  181. }
  182. void PrintUsage (void)
  183. {
  184. fputs ("Kernel Profiler Usage:\n\n"
  185. "Kernprof [-acdpnrx] [-w <wait time>] [-s Source] [-t <low threshold>] [<sample time>]\n"
  186. " -a - display function address and length and bucket size\n"
  187. " -c - display individual counters\n"
  188. " -d - compute hit Density for each function\n"
  189. //UNDOC " -e - use special event syncronization for start and stop\n"
  190. " -f filename - output file (Default stdout)\n"
  191. " -i <interval in 100ns> (Default 10000)\n"
  192. " -n - print hit percentages\n"
  193. " -p - Per-processor profile objects\n"
  194. " -r - wait for a <RETURN> before starting collection\n"
  195. " -s Source - use Source instead of clock as profile source\n"
  196. " ? lists Sources\n"
  197. " -t <low threshold> - Minimum number of counts to report.\n"
  198. " Defaults is 100\n"
  199. " -v - Display verbose symbol information\n"
  200. " -w - wait for <wait time> before starting collection\n"
  201. " -x - display context switch counters\n"
  202. " <sample time> - Specify, in seconds, how long to collect\n"
  203. " profile information.\n"
  204. " Default is wait until Ctrl-C\n\n"
  205. #if defined (_ALPHA_)
  206. "Currently supported profile sources are 'align', 'totalissues', 'pipelinedry'\n"
  207. " 'loadinstructions', 'pipelinefrozen', 'branchinstructions', 'totalnonissues',\n"
  208. " 'dcachemisses', 'icachemisses', 'branchmispredicts', 'storeinstructions'\n"
  209. #endif
  210. , stderr);
  211. }
  212. BOOL
  213. SymbolCallbackFunction(
  214. HANDLE hProcess, //currently not used but required
  215. ULONG ActionCode,
  216. #if defined(_WIN64)
  217. ULONG64 CallbackData,
  218. ULONG64 UserContext //currently not used but required
  219. #else
  220. PVOID CallbackData,
  221. PVOID UserContext //currently not used but required
  222. #endif // _WIN64
  223. )
  224. {
  225. PIMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
  226. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
  227. if(Verbose == TRUE){
  228. switch (ActionCode) {
  229. case CBA_DEBUG_INFO:
  230. printf("CBA_DEBUG_INFO: %s\n", (LPSTR)CallbackData);
  231. break;
  232. case CBA_DEFERRED_SYMBOL_LOAD_START:
  233. printf( "CBA_DEFERED: Loading symbols for %16s\n", idsl->FileName);
  234. break;
  235. case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
  236. printf( "*** Error: could not load symbols for %s\n", idsl->FileName );
  237. break;
  238. case CBA_SYMBOLS_UNLOADED:
  239. printf( "Symbols unloaded for %s\n", idsl->FileName);
  240. break;
  241. default:
  242. return FALSE;
  243. }
  244. }
  245. return FALSE;
  246. }
  247. __cdecl
  248. main(
  249. int argc,
  250. char *argv[]
  251. )
  252. {
  253. int j;
  254. NTSTATUS status;
  255. PPROFILE_SOURCE_MAPPING ProfileMapping;
  256. SYSTEM_INFO SystemInfo;
  257. fpOut = stdout;
  258. ThisSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  259. ThisSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  260. LastSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  261. LastSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  262. //
  263. // Parse the input string.
  264. //
  265. DoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  266. if (argc > 1) {
  267. if (((argv[1][0] == '-') || (argv[1][0] == '/')) &&
  268. ((argv[1][1] == '?' ) ||
  269. (argv[1][1] == 'H') ||
  270. (argv[1][1] == 'H'))
  271. ) {
  272. PrintUsage();
  273. return ERROR_SUCCESS;
  274. }
  275. for (j = 1; j < argc; j++) {
  276. BOOLEAN NextArg;
  277. char *p;
  278. if (argv[j][0] == '-') {
  279. NextArg = FALSE;
  280. for (p = &argv[j][1] ; *p && !NextArg ; p++) {
  281. switch (toupper(*p)) {
  282. case 'A':
  283. bDisplayAddress = TRUE;
  284. break;
  285. case 'C':
  286. bDisplayCounters = TRUE;
  287. break;
  288. case 'D':
  289. bDisplayDensity = TRUE;
  290. break;
  291. case 'E':
  292. bEventLoop = TRUE;
  293. break;
  294. case 'F':
  295. NextArg = TRUE;
  296. fpOut = fopen(argv[++j], "w");
  297. break;
  298. case 'I':
  299. NextArg = TRUE;
  300. ProfileInterval = atoi(argv[++j]);
  301. break;
  302. case 'N':
  303. bPrintPercentages = TRUE;
  304. break;
  305. case 'P':
  306. GetSystemInfo(&SystemInfo);
  307. MaxProcessors = SystemInfo.dwNumberOfProcessors;
  308. bPerProcessor = TRUE;
  309. break;
  310. case 'R':
  311. bWaitForInput = TRUE;
  312. break;
  313. case 'S':
  314. NextArg = TRUE;
  315. if (!ProfileSourceMapping) {
  316. InitializeProfileSourceMapping();
  317. }
  318. if (!argv[j+1]) {
  319. break;
  320. }
  321. if (argv[j+1][0] == '?') {
  322. ProfileMapping = ProfileSourceMapping;
  323. if (ProfileMapping) {
  324. fprintf (stderr, "kernprof: profile sources\n");
  325. while (ProfileMapping->ShortName != NULL) {
  326. fprintf (stderr, " %-10s %s\n",
  327. ProfileMapping->ShortName,
  328. ProfileMapping->Description
  329. );
  330. ++ProfileMapping;
  331. }
  332. } else {
  333. fprintf (stderr, "kernprof: no alternative profile sources\n");
  334. }
  335. return 0;
  336. }
  337. ProfileMapping = ProfileSourceMapping;
  338. if (ProfileMapping) {
  339. while (ProfileMapping->ShortName != NULL) {
  340. if (_stricmp(ProfileMapping->ShortName, argv[j+1])==0) {
  341. ProfileSource = ProfileMapping->Source;
  342. fprintf (stderr, "ProfileSource %x\n", ProfileMapping->Source);
  343. ++j;
  344. break;
  345. }
  346. ++ProfileMapping;
  347. }
  348. }
  349. break;
  350. case 'T':
  351. NextArg = TRUE;
  352. Threshold = atoi(argv[++j]);
  353. break;
  354. case 'V':
  355. Verbose = TRUE;
  356. break;
  357. case 'W':
  358. NextArg = TRUE;
  359. DelaySeconds = atoi(argv[++j]);
  360. DelayEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  361. break;
  362. case 'X':
  363. bDisplayContextSwitch = TRUE;
  364. break;
  365. }
  366. }
  367. } else {
  368. Seconds = atoi(argv[j]);
  369. }
  370. }
  371. }
  372. if(Verbose == TRUE){
  373. SymSetOptions( SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_DEBUG);
  374. }else{
  375. SymSetOptions( SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE | SYMOPT_OMAP_FIND_NEAREST);
  376. }
  377. SymInitialize( SYM_HANDLE, NULL, FALSE );
  378. #if defined(_WIN64)
  379. SymRegisterCallback64(SYM_HANDLE, SymbolCallbackFunction, 0);
  380. #else
  381. SymRegisterCallback(SYM_HANDLE, SymbolCallbackFunction, NULL);
  382. #endif
  383. SymGetSearchPath( SYM_HANDLE, SymbolSearchPathBuf, sizeof(SymbolSearchPathBuf) );
  384. // Append Sysroot,System32 etc. to sympath to find the executable images
  385. // (this way the current dir and the sybol dirs will be searched first for privates)
  386. strncat(lpSymbolSearchPath,
  387. ";%SystemRoot%\\System32;%SystemRoot%\\System32\\Drivers;%SystemRoot%",
  388. sizeof(SymbolSearchPathBuf)/sizeof(CHAR) - 1
  389. );
  390. SymSetSearchPath(SYM_HANDLE, lpSymbolSearchPath);
  391. SymGetSearchPath( SYM_HANDLE, SymbolSearchPathBuf, sizeof(SymbolSearchPathBuf) );
  392. printf("Symbol Path = %s\n", SymbolSearchPathBuf);
  393. printf("Loading Symbols, Please Wait...\n");
  394. if (bEventLoop || (DelaySeconds != -1)) {
  395. SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  396. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  397. }
  398. status = InitializeKernelProfile ();
  399. if (!NT_SUCCESS(status)) {
  400. fprintf(stderr, "initialize failed status - %lx\n",status);
  401. return(status);
  402. }
  403. if (bEventLoop)
  404. RunEventLoop();
  405. else
  406. RunStdProfile();
  407. return STATUS_SUCCESS;
  408. }
  409. NTSTATUS
  410. RunEventLoop()
  411. {
  412. NTSTATUS status;
  413. SYSTEM_CONTEXT_SWITCH_INFORMATION StartContext;
  414. SYSTEM_CONTEXT_SWITCH_INFORMATION StopContext;
  415. HANDLE hStartedEvent = NULL;
  416. HANDLE hStopEvent = NULL;
  417. HANDLE hMap = NULL;
  418. PPROFILE_CONTROL_BLOCK pShared = NULL;
  419. // Create the events and shared memory
  420. hStartedEvent = CreateEvent (NULL, FALSE, FALSE, PRFEVENT_START_EVENT);
  421. if (hStartedEvent == NULL) {
  422. fprintf(stderr, "Failed to create started event - 0x%lx\n",
  423. GetLastError());
  424. return(GetLastError());
  425. }
  426. hStopEvent = CreateEvent (NULL, FALSE, FALSE, PRFEVENT_STOP_EVENT);
  427. if (hStopEvent == NULL) {
  428. fprintf(stderr, "Failed to create stop event - 0x%lx\n",
  429. GetLastError());
  430. return(GetLastError());
  431. }
  432. hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT,
  433. 0, sizeof(PROFILE_CONTROL_BLOCK),
  434. PRFEVENT_SHARED_MEMORY);
  435. if (hMap == NULL) {
  436. fprintf(stderr, "Failed to create the file mapping - 0x%lx\n",
  437. GetLastError());
  438. return(GetLastError());
  439. }
  440. pShared = (PPROFILE_CONTROL_BLOCK) MapViewOfFile(hMap, FILE_MAP_WRITE,
  441. 0,0, sizeof(PROFILE_CONTROL_BLOCK));
  442. if (pShared == NULL) {
  443. fprintf(stderr, "Failed to map the shared memory view - 0x%lx\n",
  444. GetLastError());
  445. return(GetLastError());
  446. }
  447. // Wait for start i.e., the stop event
  448. WaitForSingleObject(hStopEvent, INFINITE);
  449. do {
  450. if (bDisplayContextSwitch) {
  451. NtQuerySystemInformation(SystemContextSwitchInformation,
  452. &StartContext,
  453. sizeof(StartContext),
  454. NULL);
  455. }
  456. status = StartProfile ();
  457. if (!NT_SUCCESS(status)) {
  458. fprintf(stderr, "start profile failed status - %lx\n",status);
  459. break;
  460. }
  461. // Signal started
  462. SetEvent(hStartedEvent);
  463. // Wait for stop
  464. WaitForSingleObject(hStopEvent, INFINITE);
  465. status = StopProfile ();
  466. if (!NT_SUCCESS(status)) {
  467. fprintf(stderr, "stop profile failed status - %lx\n",status);
  468. break;
  469. }
  470. if (bDisplayContextSwitch) {
  471. status = NtQuerySystemInformation(SystemContextSwitchInformation,
  472. &StopContext,
  473. sizeof(StopContext),
  474. NULL);
  475. if (!NT_SUCCESS(status)) {
  476. fprintf(stderr, "QuerySystemInformation for context switch information failed %08lx\n",status);
  477. bDisplayContextSwitch = FALSE;
  478. }
  479. }
  480. fpOut = fopen(pShared->FileName, "w");
  481. status = AnalyzeProfile (Threshold, &StartContext, &StopContext);
  482. fclose(fpOut);
  483. if (!NT_SUCCESS(status)) {
  484. fprintf(stderr, "analyze profile failed status - %lx\n",status);
  485. }
  486. }while( pShared->Stop == FALSE );
  487. SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
  488. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  489. UnmapViewOfFile((void*)pShared);
  490. CloseHandle(hMap);
  491. CloseHandle(hStopEvent);
  492. CloseHandle(hStartedEvent);
  493. return(status);
  494. }
  495. NTSTATUS
  496. RunStdProfile()
  497. {
  498. NTSTATUS status;
  499. SYSTEM_CONTEXT_SWITCH_INFORMATION StartContext;
  500. SYSTEM_CONTEXT_SWITCH_INFORMATION StopContext;
  501. SetConsoleCtrlHandler(CtrlcH,TRUE);
  502. if (DelaySeconds != -1) {
  503. fprintf(stderr, "starting profile after %d seconds\n",DelaySeconds);
  504. WaitForSingleObject(DelayEvent, DelaySeconds*1000);
  505. }
  506. if (bDisplayContextSwitch) {
  507. NtQuerySystemInformation(SystemContextSwitchInformation,
  508. &StartContext,
  509. sizeof(StartContext),
  510. NULL);
  511. }
  512. status = StartProfile ();
  513. if (!NT_SUCCESS(status)) {
  514. fprintf(stderr, "start profile failed status - %lx\n",status);
  515. return(status);
  516. }
  517. if ( Seconds == -1 ) {
  518. fprintf(stderr, "delaying until ^C\n");
  519. } else {
  520. fprintf(stderr, "delaying for %ld seconds... "
  521. "report on values with %ld hits\n",
  522. Seconds,
  523. Threshold
  524. );
  525. }
  526. if ( Seconds ) {
  527. if ( Seconds != -1 ) {
  528. Seconds = Seconds * 1000;
  529. }
  530. if ( DoneEvent ) {
  531. WaitForSingleObject(DoneEvent,Seconds);
  532. }
  533. else {
  534. Sleep(Seconds);
  535. }
  536. }
  537. else {
  538. getchar();
  539. }
  540. fprintf (stderr, "end of delay\n");
  541. status = StopProfile ();
  542. if (!NT_SUCCESS(status)) {
  543. fprintf(stderr, "stop profile failed status - %lx\n",status);
  544. return(status);
  545. }
  546. SetConsoleCtrlHandler(CtrlcH,FALSE);
  547. if (bDisplayContextSwitch) {
  548. status = NtQuerySystemInformation(SystemContextSwitchInformation,
  549. &StopContext,
  550. sizeof(StopContext),
  551. NULL);
  552. if (!NT_SUCCESS(status)) {
  553. fprintf(stderr, "QuerySystemInformation for context switch information failed %08lx\n",status);
  554. bDisplayContextSwitch = FALSE;
  555. }
  556. }
  557. if (DelaySeconds != -1) {
  558. SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
  559. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  560. }
  561. status = AnalyzeProfile (Threshold, &StartContext, &StopContext);
  562. if (!NT_SUCCESS(status)) {
  563. fprintf(stderr, "analyze profile failed status - %lx\n",status);
  564. }
  565. return(status);
  566. }
  567. VOID
  568. InitializeProfileSourceMapping (
  569. VOID
  570. )
  571. {
  572. #if defined(_X86_)
  573. UNICODE_STRING DriverName;
  574. NTSTATUS status;
  575. OBJECT_ATTRIBUTES ObjA;
  576. IO_STATUS_BLOCK IOSB;
  577. UCHAR buffer[400];
  578. ULONG i, j, Count;
  579. PEVENTID Event;
  580. HANDLE DriverHandle;
  581. //
  582. // Open PStat driver
  583. //
  584. RtlInitUnicodeString(&DriverName, L"\\Device\\PStat");
  585. InitializeObjectAttributes(
  586. &ObjA,
  587. &DriverName,
  588. OBJ_CASE_INSENSITIVE,
  589. 0,
  590. 0 );
  591. status = NtOpenFile (
  592. &DriverHandle, // return handle
  593. SYNCHRONIZE | FILE_READ_DATA, // desired access
  594. &ObjA, // Object
  595. &IOSB, // io status block
  596. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  597. FILE_SYNCHRONOUS_IO_ALERT // open options
  598. );
  599. if (!NT_SUCCESS(status)) {
  600. fprintf(stderr, "ERROR - Failed OpenFile in InitializeProfileSourceMapping\n");
  601. return ;
  602. }
  603. //
  604. // Initialize possible counters
  605. //
  606. // determine how many events there are
  607. Event = (PEVENTID) buffer;
  608. Count = 0;
  609. do {
  610. *((PULONG) buffer) = Count;
  611. Count += 1;
  612. status = NtDeviceIoControlFile(
  613. DriverHandle,
  614. (HANDLE) NULL, // event
  615. (PIO_APC_ROUTINE) NULL,
  616. (PVOID) NULL,
  617. &IOSB,
  618. PSTAT_QUERY_EVENTS,
  619. buffer, // input buffer
  620. sizeof (buffer),
  621. NULL, // output buffer
  622. 0
  623. );
  624. } while (NT_SUCCESS(status));
  625. ProfileSourceMapping = malloc(sizeof(*ProfileSourceMapping) * Count);
  626. Count -= 1;
  627. for (i=0, j=0; i < Count; i++) {
  628. *((PULONG) buffer) = i;
  629. NtDeviceIoControlFile(
  630. DriverHandle,
  631. (HANDLE) NULL, // event
  632. (PIO_APC_ROUTINE) NULL,
  633. (PVOID) NULL,
  634. &IOSB,
  635. PSTAT_QUERY_EVENTS,
  636. buffer, // input buffer
  637. sizeof (buffer),
  638. NULL, // output buffer
  639. 0
  640. );
  641. if (Event->ProfileSource > ProfileTime) {
  642. ProfileSourceMapping[j].Source = Event->ProfileSource;
  643. ProfileSourceMapping[j].ShortName = _strdup ((PCHAR)Event->Buffer);
  644. ProfileSourceMapping[j].Description = _strdup ((PCHAR)(Event->Buffer + Event->DescriptionOffset));
  645. j++;
  646. }
  647. }
  648. ProfileSourceMapping[j].Source = (KPROFILE_SOURCE) 0;
  649. ProfileSourceMapping[j].ShortName = NULL;
  650. ProfileSourceMapping[j].Description = NULL;
  651. NtClose (DriverHandle);
  652. #endif
  653. }
  654. NTSTATUS
  655. InitializeKernelProfile (
  656. VOID
  657. )
  658. /*++
  659. Routine Description:
  660. This routine initializes profiling for the kernel for the
  661. current process.
  662. Arguments:
  663. None.
  664. Return Value:
  665. Returns the status of the last NtCreateProfile.
  666. --*/
  667. {
  668. ULONG i;
  669. ULONG ModuleNumber;
  670. SIZE_T ViewSize;
  671. PULONG CodeStart;
  672. ULONG CodeLength;
  673. NTSTATUS status;
  674. HANDLE CurrentProcessHandle;
  675. QUOTA_LIMITS QuotaLimits;
  676. PVOID Buffer;
  677. DWORD Cells;
  678. ULONG BucketSize;
  679. WCHAR StringBuf[500];
  680. PCHAR ModuleInfoBuffer;
  681. ULONG ModuleInfoBufferLength;
  682. ULONG ReturnedLength;
  683. PRTL_PROCESS_MODULES Modules;
  684. PRTL_PROCESS_MODULE_INFORMATION Module;
  685. BOOLEAN PreviousProfilePrivState;
  686. BOOLEAN PreviousQuotaPrivState;
  687. CHAR ImageName[256];
  688. HANDLE hFile;
  689. HANDLE hMap;
  690. PVOID MappedBase;
  691. PIMAGE_NT_HEADERS NtHeaders;
  692. CurrentProcessHandle = NtCurrentProcess();
  693. //
  694. // Locate system drivers.
  695. //
  696. ModuleInfoBufferLength = 0;
  697. ModuleInfoBuffer = NULL;
  698. do {
  699. status = NtQuerySystemInformation (SystemModuleInformation,
  700. ModuleInfoBuffer,
  701. ModuleInfoBufferLength,
  702. &ReturnedLength);
  703. if (NT_SUCCESS (status)) {
  704. break;
  705. }
  706. if (ModuleInfoBuffer != NULL) {
  707. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  708. ModuleInfoBuffer = NULL;
  709. }
  710. if (status == STATUS_INFO_LENGTH_MISMATCH && ReturnedLength > ModuleInfoBufferLength) {
  711. ModuleInfoBufferLength = ReturnedLength;
  712. ModuleInfoBuffer = RtlAllocateHeap (RtlProcessHeap(), 0, ModuleInfoBufferLength);
  713. if (ModuleInfoBuffer == NULL) {
  714. return STATUS_INSUFFICIENT_RESOURCES;
  715. }
  716. } else if (!NT_SUCCESS(status)) {
  717. fprintf(stderr, "query system info failed status - %lx\n",status);
  718. return(status);
  719. }
  720. }while( !NT_SUCCESS(status) );
  721. status = RtlAdjustPrivilege(
  722. SE_SYSTEM_PROFILE_PRIVILEGE,
  723. TRUE, //Enable
  724. FALSE, //not impersonating
  725. &PreviousProfilePrivState
  726. );
  727. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  728. fprintf(stderr, "Enable system profile privilege failed - status 0x%lx\n",
  729. status);
  730. }
  731. status = RtlAdjustPrivilege(
  732. SE_INCREASE_QUOTA_PRIVILEGE,
  733. TRUE, //Enable
  734. FALSE, //not impersonating
  735. &PreviousQuotaPrivState
  736. );
  737. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  738. fprintf(stderr, "Unable to increase quota privilege (status=0x%lx)\n",
  739. status);
  740. }
  741. Modules = (PRTL_PROCESS_MODULES)ModuleInfoBuffer;
  742. if(Modules != NULL){
  743. Module = &Modules->Modules[ 0 ];
  744. }else{
  745. fprintf(stderr, "InitializeKernelProfile: ModuleInfoBuffer is NULL\n");
  746. return (STATUS_UNSUCCESSFUL);
  747. }
  748. for (ModuleNumber=0; ModuleNumber < Modules->NumberOfModules; ModuleNumber++,Module++) {
  749. #if DBG_PROFILE
  750. fprintf(stderr, "module base %p\n",Module->ImageBase);
  751. fprintf(stderr, "module full path name: %s (%u)\n",
  752. Module->FullPathName,
  753. Module->OffsetToFileName);
  754. #endif
  755. if (SymLoadModule(
  756. SYM_HANDLE,
  757. NULL,
  758. (PSTR)&Module->FullPathName[Module->OffsetToFileName],
  759. NULL,
  760. (ULONG_PTR)Module->ImageBase,
  761. Module->ImageSize
  762. )) {
  763. ProfileObject[NumberOfProfileObjects].SymbolsLoaded = TRUE;
  764. if (Verbose) {
  765. fprintf(stderr, "Symbols loaded: %p %s\n",
  766. Module->ImageBase,
  767. &Module->FullPathName[Module->OffsetToFileName]
  768. );
  769. }
  770. } else {
  771. ProfileObject[NumberOfProfileObjects].SymbolsLoaded = FALSE;
  772. if (Verbose) {
  773. fprintf(stderr, "*** Could not load symbols: %p %s\n",
  774. Module->ImageBase,
  775. &Module->FullPathName[Module->OffsetToFileName]
  776. );
  777. }
  778. }
  779. hFile = FindExecutableImage(
  780. (PSTR)&Module->FullPathName[Module->OffsetToFileName],
  781. lpSymbolSearchPath,
  782. ImageName
  783. );
  784. if (!hFile) {
  785. fprintf(stderr,
  786. "WARNING - Could not find executable image for %s\n",
  787. &Module->FullPathName[Module->OffsetToFileName]
  788. );
  789. continue;
  790. }
  791. hMap = CreateFileMapping(
  792. hFile,
  793. NULL,
  794. PAGE_READONLY,
  795. 0,
  796. 0,
  797. NULL
  798. );
  799. if (!hMap) {
  800. CloseHandle( hFile );
  801. fprintf(stderr,
  802. "ERROR - Could not Create File Mapping for %s\n",
  803. &Module->FullPathName[Module->OffsetToFileName]
  804. );
  805. continue;
  806. }
  807. MappedBase = MapViewOfFile(
  808. hMap,
  809. FILE_MAP_READ,
  810. 0,
  811. 0,
  812. 0
  813. );
  814. if (!MappedBase) {
  815. CloseHandle( hMap );
  816. CloseHandle( hFile );
  817. fprintf(stderr,
  818. "ERROR - Could not Map View of File for %s\n",
  819. &Module->FullPathName[Module->OffsetToFileName]
  820. );
  821. continue;
  822. }
  823. NtHeaders = ImageNtHeader( MappedBase );
  824. CodeLength = NtHeaders->OptionalHeader.SizeOfImage;
  825. CodeStart = (PULONG)Module->ImageBase;
  826. UnmapViewOfFile( MappedBase );
  827. CloseHandle( hMap );
  828. CloseHandle( hFile );
  829. if (CodeLength > 1024*512) {
  830. //
  831. // Just create a 512K byte buffer.
  832. //
  833. ViewSize = 1024 * 512;
  834. } else {
  835. ViewSize = CodeLength + PAGE_SIZE;
  836. }
  837. ProfileObject[NumberOfProfileObjects].CodeStart = CodeStart;
  838. ProfileObject[NumberOfProfileObjects].CodeLength = CodeLength;
  839. ProfileObject[NumberOfProfileObjects].ImageBase = Module->ImageBase;
  840. ProfileObject[NumberOfProfileObjects].ModuleName = _strdup((PCHAR)&Module->FullPathName[Module->OffsetToFileName]);
  841. for (i=0; i<MaxProcessors; i++) {
  842. Buffer = NULL;
  843. status = NtAllocateVirtualMemory (CurrentProcessHandle,
  844. (PVOID *)&Buffer,
  845. 0,
  846. &ViewSize,
  847. MEM_RESERVE | MEM_COMMIT,
  848. PAGE_READWRITE);
  849. if (!NT_SUCCESS(status)) {
  850. fprintf (stderr, "alloc VM failed %lx\n",status);
  851. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  852. return(status);
  853. }
  854. //
  855. // Calculate the bucket size for the profile.
  856. //
  857. Cells = (DWORD)((CodeLength / (ViewSize >> 2)) >> 2);
  858. BucketSize = 2;
  859. while (Cells != 0) {
  860. Cells = Cells >> 1;
  861. BucketSize += 1;
  862. }
  863. ProfileObject[NumberOfProfileObjects].Buffer[i] = Buffer;
  864. ProfileObject[NumberOfProfileObjects].BufferSize = 1 + (CodeLength >> (BucketSize - 2));
  865. ProfileObject[NumberOfProfileObjects].BucketSize = BucketSize;
  866. //
  867. // Increase the working set to lock down a bigger buffer.
  868. //
  869. status = NtQueryInformationProcess (CurrentProcessHandle,
  870. ProcessQuotaLimits,
  871. &QuotaLimits,
  872. sizeof(QUOTA_LIMITS),
  873. NULL );
  874. if (!NT_SUCCESS(status)) {
  875. fprintf (stderr, "query process info failed %lx\n",status);
  876. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  877. return(status);
  878. }
  879. QuotaLimits.MaximumWorkingSetSize += ViewSize;
  880. QuotaLimits.MinimumWorkingSetSize += ViewSize;
  881. status = NtSetInformationProcess (CurrentProcessHandle,
  882. ProcessQuotaLimits,
  883. &QuotaLimits,
  884. sizeof(QUOTA_LIMITS));
  885. #if DBG_PROFILE
  886. fprintf(stderr, "code start %p len %p, bucksize %lx buffer %p bsize %08x %s ",
  887. ProfileObject[NumberOfProfileObjects].CodeStart,
  888. ProfileObject[NumberOfProfileObjects].CodeLength,
  889. ProfileObject[NumberOfProfileObjects].BucketSize,
  890. ProfileObject[NumberOfProfileObjects].Buffer ,
  891. ProfileObject[NumberOfProfileObjects].BufferSize,
  892. ProfileObject[NumberOfProfileObjects].ModuleName
  893. );
  894. #endif
  895. if (bPerProcessor) {
  896. status = NtCreateProfile (
  897. &ProfileObject[NumberOfProfileObjects].Handle[i],
  898. 0,
  899. ProfileObject[NumberOfProfileObjects].CodeStart,
  900. ProfileObject[NumberOfProfileObjects].CodeLength,
  901. ProfileObject[NumberOfProfileObjects].BucketSize,
  902. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  903. ProfileObject[NumberOfProfileObjects].BufferSize,
  904. ProfileSource,
  905. 1 << i);
  906. } else {
  907. status = NtCreateProfile (
  908. &ProfileObject[NumberOfProfileObjects].Handle[i],
  909. 0,
  910. ProfileObject[NumberOfProfileObjects].CodeStart,
  911. ProfileObject[NumberOfProfileObjects].CodeLength,
  912. ProfileObject[NumberOfProfileObjects].BucketSize,
  913. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  914. ProfileObject[NumberOfProfileObjects].BufferSize,
  915. ProfileSource,
  916. (KAFFINITY)-1);
  917. }
  918. #if DBG_PROFILE
  919. fprintf(stderr, "Handle= 0x%x\n", ProfileObject[NumberOfProfileObjects].Handle[i] );
  920. #endif
  921. if (status != STATUS_SUCCESS) {
  922. fprintf(stderr, "create kernel profile %s failed - status %lx\n",
  923. ProfileObject[NumberOfProfileObjects].ModuleName, status);
  924. }
  925. }
  926. NumberOfProfileObjects += 1;
  927. if (NumberOfProfileObjects == MAX_PROFILE_COUNT) {
  928. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  929. return STATUS_SUCCESS;
  930. }
  931. }
  932. if (NumberOfProfileObjects < MAX_PROFILE_COUNT) {
  933. //
  934. // Add in usermode object
  935. // 0x00000000 -> SystemRangeStart
  936. //
  937. ULONG_PTR SystemRangeStart;
  938. ULONG UserModeBucketCount;
  939. status = NtQuerySystemInformation(SystemRangeStartInformation,
  940. &SystemRangeStart,
  941. sizeof(SystemRangeStart),
  942. NULL);
  943. //
  944. // How many buckets to cover the range
  945. //
  946. UserModeBucketCount = (ULONG)(1 + ((SystemRangeStart - 1) / MAX_BUCKET_SIZE));
  947. if (!NT_SUCCESS(status)) {
  948. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  949. fprintf(stderr,
  950. "ERROR - Add User Mode Object - NtQuerySystemInformation failed - status %lx\n",
  951. status
  952. );
  953. return status;
  954. }
  955. ProfileObject[NumberOfProfileObjects].SymbolsLoaded = FALSE;
  956. ProfileObject[NumberOfProfileObjects].CodeStart = 0;
  957. ProfileObject[NumberOfProfileObjects].CodeLength = SystemRangeStart;
  958. ProfileObject[NumberOfProfileObjects].ImageBase = 0;
  959. ProfileObject[NumberOfProfileObjects].ModuleName = "User Mode";
  960. ProfileObject[NumberOfProfileObjects].BufferSize = UserModeBucketCount * sizeof(DWORD);
  961. ProfileObject[NumberOfProfileObjects].BucketSize = MAX_BUCKET_SHIFT;
  962. for (i=0; i<MaxProcessors; i++) {
  963. UserModeBuffer[i] = HeapAlloc(GetProcessHeap(),
  964. HEAP_ZERO_MEMORY,
  965. ProfileObject[NumberOfProfileObjects].BufferSize);
  966. if (UserModeBuffer[i] == NULL) {
  967. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  968. fprintf (stderr, "ERROR - Add User Mode Object - HeapAlloc failed\n");
  969. return(STATUS_NO_MEMORY);
  970. }
  971. ProfileObject[NumberOfProfileObjects].Buffer[i] = UserModeBuffer[i];
  972. ProfileObject[NumberOfProfileObjects].Handle[i] = NULL;
  973. #if DBG_PROFILE
  974. fprintf(stderr, "code start %p len %lx, bucksize %lx buffer %p bsize %lx\n",
  975. ProfileObject[NumberOfProfileObjects].CodeStart,
  976. ProfileObject[NumberOfProfileObjects].CodeLength,
  977. ProfileObject[NumberOfProfileObjects].BucketSize,
  978. ProfileObject[NumberOfProfileObjects].Buffer ,
  979. ProfileObject[NumberOfProfileObjects].BufferSize);
  980. #endif
  981. if (bPerProcessor) {
  982. status = NtCreateProfile (
  983. &ProfileObject[NumberOfProfileObjects].Handle[i],
  984. 0,
  985. ProfileObject[NumberOfProfileObjects].CodeStart,
  986. ProfileObject[NumberOfProfileObjects].CodeLength,
  987. ProfileObject[NumberOfProfileObjects].BucketSize,
  988. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  989. ProfileObject[NumberOfProfileObjects].BufferSize,
  990. ProfileSource,
  991. 1 << i);
  992. } else {
  993. status = NtCreateProfile (
  994. &ProfileObject[NumberOfProfileObjects].Handle[i],
  995. 0,
  996. ProfileObject[NumberOfProfileObjects].CodeStart,
  997. ProfileObject[NumberOfProfileObjects].CodeLength,
  998. ProfileObject[NumberOfProfileObjects].BucketSize,
  999. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  1000. ProfileObject[NumberOfProfileObjects].BufferSize,
  1001. ProfileSource,
  1002. (KAFFINITY)-1);
  1003. }
  1004. if (status != STATUS_SUCCESS) {
  1005. fprintf(stderr, "ERROR - User Mode Object - NtCreateProfile %s failed - status %lx\n",
  1006. ProfileObject[NumberOfProfileObjects].ModuleName, status);
  1007. }
  1008. }
  1009. NumberOfProfileObjects += 1;
  1010. }
  1011. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  1012. return status;
  1013. }
  1014. NTSTATUS
  1015. StartProfile (
  1016. VOID
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. This routine starts all profile objects which have been initialized.
  1021. Arguments:
  1022. None.
  1023. Return Value:
  1024. Returns the status of the last NtStartProfile.
  1025. --*/
  1026. {
  1027. ULONG Object;
  1028. ULONG Processor;
  1029. NTSTATUS status = STATUS_SUCCESS;
  1030. NtSetIntervalProfile(ProfileInterval, ProfileSource);
  1031. if (bWaitForInput) {
  1032. fprintf(stderr, "Hit return to continue.\n");
  1033. (void) getchar();
  1034. }
  1035. for (Object = 0; Object < NumberOfProfileObjects; Object++) {
  1036. for (Processor = 0;Processor < MaxProcessors; Processor++) {
  1037. status = NtStartProfile (ProfileObject[Object].Handle[Processor]);
  1038. if (!NT_SUCCESS(status)) {
  1039. if (status == STATUS_INVALID_HANDLE) {
  1040. fprintf(stderr, "StartProfile Failed, status= %lx (STATUS_INVALID_HANDLE)\n", status);
  1041. }else{
  1042. fprintf(stderr, "start profile %s failed - status %lx\n",
  1043. ProfileObject[Object].ModuleName, status);
  1044. }
  1045. return status;
  1046. }
  1047. }
  1048. }
  1049. return status;
  1050. }
  1051. NTSTATUS
  1052. StopProfile (
  1053. VOID
  1054. )
  1055. /*++
  1056. Routine Description:
  1057. This routine stops all profile objects which have been initialized.
  1058. Arguments:
  1059. None.
  1060. Return Value:
  1061. Returns the status of the last NtStopProfile.
  1062. --*/
  1063. {
  1064. ULONG i;
  1065. ULONG Processor;
  1066. NTSTATUS status = STATUS_SUCCESS;
  1067. for (i = 0; i < NumberOfProfileObjects; i++) {
  1068. for (Processor=0; Processor < MaxProcessors; Processor++) {
  1069. status = NtStopProfile (ProfileObject[i].Handle[Processor]);
  1070. if (status != STATUS_SUCCESS) {
  1071. fprintf(stderr, "stop profile %s failed - status %lx\n",
  1072. ProfileObject[i].ModuleName,status);
  1073. return status;
  1074. }
  1075. }
  1076. }
  1077. return status;
  1078. }
  1079. NTSTATUS
  1080. AnalyzeProfile (
  1081. ULONG Threshold,
  1082. PSYSTEM_CONTEXT_SWITCH_INFORMATION StartContext,
  1083. PSYSTEM_CONTEXT_SWITCH_INFORMATION StopContext
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. This routine does the analysis of all the profile buffers and
  1088. correlates hits to the appropriate symbol table.
  1089. Arguments:
  1090. None.
  1091. Return Value:
  1092. None.
  1093. --*/
  1094. {
  1095. ULONG CountAtSymbol;
  1096. ULONG_PTR Va;
  1097. int i;
  1098. PULONG Counter;
  1099. ULONG_PTR Displacement;
  1100. ULONG Processor;
  1101. ULONG TotalHits = 0;
  1102. ULONG ProcessorTotalHits[MAXIMUM_PROCESSORS] = {0};
  1103. PULONG BufferEnd;
  1104. PULONG Buffer;
  1105. PULONG pInitialCounter;
  1106. ULONG OffsetVa = 0;
  1107. ULONG BytesPerBucket;
  1108. BOOLEAN UseLastSymbol = FALSE;
  1109. for (i = 0; i < (int)NumberOfProfileObjects; i++) {
  1110. for (Processor=0;Processor < MaxProcessors;Processor++) {
  1111. NtStopProfile (ProfileObject[i].Handle[Processor]);
  1112. }
  1113. }
  1114. if ((NumberOfProfileObjects == 1) &&
  1115. (strstr((char *)&ProfileObject[0].ModuleName, "User Mode"))){
  1116. fprintf(stderr,
  1117. "WARNING - Only User Mode Counts Are Found\n" \
  1118. "Make Sure You Have the latest DBGHELP.DLL and IMAGEHLP.DLL Installed\n"
  1119. );
  1120. }
  1121. for (Processor = 0; Processor < MaxProcessors; Processor++) {
  1122. for (i = 0; i < (int)NumberOfProfileObjects; i++) {
  1123. //
  1124. // Sum the total number of cells written.
  1125. //
  1126. BufferEnd = ProfileObject[i].Buffer[Processor] + (
  1127. ProfileObject[i].BufferSize / sizeof(ULONG));
  1128. Buffer = ProfileObject[i].Buffer[Processor];
  1129. Counter = BufferEnd;
  1130. ProfileObject[i].ModuleHitCount[Processor] = 0;
  1131. while (Counter > Buffer) {
  1132. Counter -= 1;
  1133. ProfileObject[i].ModuleHitCount[Processor] += *Counter;
  1134. }
  1135. ProcessorTotalHits[Processor] += ProfileObject[i].ModuleHitCount[Processor];
  1136. }
  1137. if (bPerProcessor) {
  1138. fprintf(fpOut, "Processor %d: %d Total hits\n",
  1139. Processor, ProcessorTotalHits[Processor]);
  1140. }
  1141. TotalHits += ProcessorTotalHits[Processor];
  1142. }
  1143. fprintf(fpOut, "%d Total hits\n",TotalHits);
  1144. for (Processor = 0; Processor < MaxProcessors; Processor++) {
  1145. if (bPerProcessor) {
  1146. fprintf(fpOut, "\nPROCESSOR %d\n",Processor);
  1147. }
  1148. for (i = 0; i < (int)NumberOfProfileObjects; i++) {
  1149. CountAtSymbol = 0;
  1150. //
  1151. // Sum the total number of cells written.
  1152. //
  1153. BufferEnd = ProfileObject[i].Buffer[Processor] + (
  1154. ProfileObject[i].BufferSize / sizeof(ULONG));
  1155. Buffer = ProfileObject[i].Buffer[Processor];
  1156. Counter = BufferEnd;
  1157. if (ProfileObject[i].ModuleHitCount[Processor] < Threshold) {
  1158. continue;
  1159. }
  1160. fprintf(fpOut, "\n%9d ",
  1161. ProfileObject[i].ModuleHitCount[Processor]);
  1162. if (bPrintPercentages) {
  1163. fprintf(fpOut, "%5.2f ",
  1164. (ProfileObject[i].ModuleHitCount[Processor] /
  1165. (double)ProcessorTotalHits[Processor]) * 100);
  1166. }
  1167. fprintf(fpOut, "%20s --Total Hits-- %s\n",
  1168. ProfileObject[i].ModuleName,
  1169. ((ProfileObject[i].SymbolsLoaded) ? "" :
  1170. "(NO SYMBOLS)")
  1171. );
  1172. if (!ProfileObject[i].SymbolsLoaded) {
  1173. RtlZeroMemory(ProfileObject[i].Buffer[Processor],
  1174. ProfileObject[i].BufferSize);
  1175. continue;
  1176. }
  1177. BytesPerBucket = (1 << ProfileObject[i].BucketSize);
  1178. pInitialCounter = Buffer;
  1179. for ( Counter = Buffer; Counter < BufferEnd; Counter += 1 ) {
  1180. if ( *Counter ) {
  1181. //
  1182. // Calculate the virtual address of the counter
  1183. //
  1184. Va = Counter - Buffer; // Calculate buckets #
  1185. Va = Va * BytesPerBucket; // convert to bytes
  1186. Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart; // add in base address
  1187. if (SymGetSymFromAddr( SYM_HANDLE, Va, &Displacement, ThisSymbol )) {
  1188. if (UseLastSymbol &&
  1189. LastSymbol->Address &&
  1190. (LastSymbol->Address == ThisSymbol->Address))
  1191. {
  1192. CountAtSymbol += *Counter;
  1193. } else {
  1194. OutputSymbolCount(CountAtSymbol,
  1195. ProcessorTotalHits[Processor],
  1196. &ProfileObject[i],
  1197. LastSymbol,
  1198. Threshold,
  1199. pInitialCounter,
  1200. Counter,
  1201. OffsetVa,
  1202. BytesPerBucket);
  1203. pInitialCounter = Counter;
  1204. OffsetVa = (DWORD) Displacement; // Images aren't > 2g so this cast s/b O.K.
  1205. CountAtSymbol = *Counter;
  1206. memcpy( LastSymBuffer, symBuffer, sizeof(symBuffer) );
  1207. UseLastSymbol = TRUE;
  1208. }
  1209. } else {
  1210. OutputSymbolCount(CountAtSymbol,
  1211. ProcessorTotalHits[Processor],
  1212. &ProfileObject[i],
  1213. LastSymbol,
  1214. Threshold,
  1215. pInitialCounter,
  1216. Counter,
  1217. OffsetVa,
  1218. BytesPerBucket);
  1219. } // else !(NT_SUCCESS)
  1220. } // if (*Counter)
  1221. } // for (Counter)
  1222. OutputSymbolCount(CountAtSymbol,
  1223. ProcessorTotalHits[Processor],
  1224. &ProfileObject[i],
  1225. LastSymbol,
  1226. Threshold,
  1227. pInitialCounter,
  1228. Counter,
  1229. OffsetVa,
  1230. BytesPerBucket);
  1231. //
  1232. // Clear after buffer's been checked and displayed
  1233. //
  1234. RtlZeroMemory(ProfileObject[i].Buffer[Processor], ProfileObject[i].BufferSize);
  1235. }
  1236. }
  1237. if (bDisplayContextSwitch) {
  1238. fprintf(fpOut, "\n");
  1239. fprintf(fpOut, "Context Switch Information\n");
  1240. fprintf(fpOut, " Find any processor %6ld\n", StopContext->FindAny - StartContext->FindAny);
  1241. fprintf(fpOut, " Find last processor %6ld\n", StopContext->FindLast - StartContext->FindLast);
  1242. fprintf(fpOut, " Idle any processor %6ld\n", StopContext->IdleAny - StartContext->IdleAny);
  1243. fprintf(fpOut, " Idle current processor %6ld\n", StopContext->IdleCurrent - StartContext->IdleCurrent);
  1244. fprintf(fpOut, " Idle last processor %6ld\n", StopContext->IdleLast - StartContext->IdleLast);
  1245. fprintf(fpOut, " Preempt any processor %6ld\n", StopContext->PreemptAny - StartContext->PreemptAny);
  1246. fprintf(fpOut, " Preempt current processor %6ld\n", StopContext->PreemptCurrent - StartContext->PreemptCurrent);
  1247. fprintf(fpOut, " Preempt last processor %6ld\n", StopContext->PreemptLast - StartContext->PreemptLast);
  1248. fprintf(fpOut, " Switch to idle %6ld\n", StopContext->SwitchToIdle - StartContext->SwitchToIdle);
  1249. fprintf(fpOut, "\n");
  1250. fprintf(fpOut, " Total context switches %6ld\n", StopContext->ContextSwitches - StartContext->ContextSwitches);
  1251. }
  1252. return STATUS_SUCCESS;
  1253. }
  1254. VOID
  1255. OutputSymbolCount(
  1256. IN ULONG CountAtSymbol,
  1257. IN ULONG TotalCount,
  1258. IN PROFILE_BLOCK *ProfileObject,
  1259. IN PIMAGEHLP_SYMBOL SymbolInfo,
  1260. IN ULONG Threshold,
  1261. IN PULONG CounterStart,
  1262. IN PULONG CounterStop,
  1263. IN ULONG Va,
  1264. IN ULONG BytesPerBucket
  1265. )
  1266. {
  1267. ULONG Density;
  1268. ULONG i;
  1269. if (CountAtSymbol < Threshold) {
  1270. return;
  1271. }
  1272. fprintf(fpOut, "%9d ", CountAtSymbol);
  1273. if (bPrintPercentages) {
  1274. fprintf(fpOut, "%5.2f ", (CountAtSymbol / (double) TotalCount) * 100);
  1275. }
  1276. if (bDisplayDensity) {
  1277. //
  1278. // Compute hit density = hits * 100 / function length
  1279. //
  1280. if (!SymbolInfo || !SymbolInfo->Size) {
  1281. Density = 0;
  1282. } else {
  1283. Density = CountAtSymbol * 100 / SymbolInfo->Size;
  1284. }
  1285. fprintf(fpOut, "%5d ",Density);
  1286. }
  1287. if(SymbolInfo !=NULL){
  1288. if (SymbolInfo->MaxNameLength) {
  1289. fprintf(fpOut, "%20s %s",
  1290. ProfileObject->ModuleName,
  1291. SymbolInfo->Name);
  1292. } else {
  1293. fprintf(fpOut, "%20s 0x%x",
  1294. ProfileObject->ModuleName,
  1295. SymbolInfo->Address);
  1296. }
  1297. if (bDisplayAddress) {
  1298. fprintf(fpOut, " 0x0%p %d %d",
  1299. (PVOID)SymbolInfo->Address,
  1300. SymbolInfo->Size,
  1301. ProfileObject->BucketSize);
  1302. }
  1303. }
  1304. if (bDisplayCounters) {
  1305. for (i = 0 ; CounterStart < CounterStop; i++, Va += BytesPerBucket, ++CounterStart) {
  1306. if ((i % 16) == 0) {
  1307. fprintf (fpOut, "\n0x%08x:", Va);
  1308. }
  1309. fprintf(fpOut, " %5d", *CounterStart);
  1310. }
  1311. }
  1312. fprintf (fpOut, "\n");
  1313. }