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.

1513 lines
48 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 100
  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. __cdecl
  213. main(
  214. int argc,
  215. char *argv[],
  216. char *envp[]
  217. )
  218. {
  219. int j;
  220. NTSTATUS status;
  221. PPROFILE_SOURCE_MAPPING ProfileMapping;
  222. SYSTEM_INFO SystemInfo;
  223. fpOut = stdout;
  224. ThisSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  225. ThisSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  226. LastSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  227. LastSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  228. SymSetOptions( SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE | SYMOPT_OMAP_FIND_NEAREST );
  229. SymInitialize( SYM_HANDLE, NULL, FALSE );
  230. SymGetSearchPath( SYM_HANDLE, SymbolSearchPathBuf, sizeof(SymbolSearchPathBuf) );
  231. //
  232. // Parse the input string.
  233. //
  234. DoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  235. if (argc > 1) {
  236. if (((argv[1][0] == '-') || (argv[1][0] == '/')) &&
  237. ((argv[1][1] == '?' ) ||
  238. (argv[1][1] == 'H') ||
  239. (argv[1][1] == 'H'))
  240. ) {
  241. PrintUsage();
  242. return ERROR_SUCCESS;
  243. }
  244. for (j = 1; j < argc; j++) {
  245. BOOLEAN NextArg;
  246. char *p;
  247. if (argv[j][0] == '-') {
  248. NextArg = FALSE;
  249. for (p = &argv[j][1] ; *p && !NextArg ; p++) {
  250. switch (toupper(*p)) {
  251. case 'A':
  252. bDisplayAddress = TRUE;
  253. break;
  254. case 'C':
  255. bDisplayCounters = TRUE;
  256. break;
  257. case 'D':
  258. bDisplayDensity = TRUE;
  259. break;
  260. case 'E':
  261. bEventLoop = TRUE;
  262. break;
  263. case 'F':
  264. NextArg = TRUE;
  265. fpOut = fopen(argv[++j], "w");
  266. break;
  267. case 'I':
  268. NextArg = TRUE;
  269. ProfileInterval = atoi(argv[++j]);
  270. break;
  271. case 'N':
  272. bPrintPercentages = TRUE;
  273. break;
  274. case 'P':
  275. GetSystemInfo(&SystemInfo);
  276. MaxProcessors = SystemInfo.dwNumberOfProcessors;
  277. bPerProcessor = TRUE;
  278. break;
  279. case 'R':
  280. bWaitForInput = TRUE;
  281. break;
  282. case 'S':
  283. NextArg = TRUE;
  284. if (!ProfileSourceMapping) {
  285. InitializeProfileSourceMapping();
  286. }
  287. if (!argv[j+1]) {
  288. break;
  289. }
  290. if (argv[j+1][0] == '?') {
  291. ProfileMapping = ProfileSourceMapping;
  292. if (ProfileMapping) {
  293. fprintf (stderr, "kernprof: profile sources\n");
  294. while (ProfileMapping->ShortName != NULL) {
  295. fprintf (stderr, " %-10s %s\n",
  296. ProfileMapping->ShortName,
  297. ProfileMapping->Description
  298. );
  299. ++ProfileMapping;
  300. }
  301. } else {
  302. fprintf (stderr, "kernprof: no alternative profile sources\n");
  303. }
  304. return 0;
  305. }
  306. ProfileMapping = ProfileSourceMapping;
  307. if (ProfileMapping) {
  308. while (ProfileMapping->ShortName != NULL) {
  309. if (_stricmp(ProfileMapping->ShortName, argv[j+1])==0) {
  310. ProfileSource = ProfileMapping->Source;
  311. fprintf (stderr, "ProfileSource %x\n", ProfileMapping->Source);
  312. ++j;
  313. break;
  314. }
  315. ++ProfileMapping;
  316. }
  317. }
  318. break;
  319. case 'T':
  320. NextArg = TRUE;
  321. Threshold = atoi(argv[++j]);
  322. break;
  323. case 'V':
  324. Verbose = TRUE;
  325. break;
  326. case 'W':
  327. NextArg = TRUE;
  328. DelaySeconds = atoi(argv[++j]);
  329. DelayEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  330. break;
  331. case 'X':
  332. bDisplayContextSwitch = TRUE;
  333. break;
  334. }
  335. }
  336. } else {
  337. Seconds = atoi(argv[j]);
  338. }
  339. }
  340. }
  341. if (bEventLoop || (DelaySeconds != -1)) {
  342. SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  343. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  344. }
  345. status = InitializeKernelProfile ();
  346. if (!NT_SUCCESS(status)) {
  347. fprintf(stderr, "initialize failed status - %lx\n",status);
  348. return(status);
  349. }
  350. if (bEventLoop)
  351. RunEventLoop();
  352. else
  353. RunStdProfile();
  354. return STATUS_SUCCESS;
  355. }
  356. NTSTATUS
  357. RunEventLoop()
  358. {
  359. NTSTATUS status;
  360. SYSTEM_CONTEXT_SWITCH_INFORMATION StartContext;
  361. SYSTEM_CONTEXT_SWITCH_INFORMATION StopContext;
  362. HANDLE hStartedEvent = NULL;
  363. HANDLE hStopEvent = NULL;
  364. HANDLE hMap = NULL;
  365. PPROFILE_CONTROL_BLOCK pShared = NULL;
  366. // Create the events and shared memory
  367. hStartedEvent = CreateEvent (NULL, FALSE, FALSE, PRFEVENT_START_EVENT);
  368. if (hStartedEvent == NULL) {
  369. fprintf(stderr, "Failed to create started event - 0x%lx\n",
  370. GetLastError());
  371. return(GetLastError());
  372. }
  373. hStopEvent = CreateEvent (NULL, FALSE, FALSE, PRFEVENT_STOP_EVENT);
  374. if (hStopEvent == NULL) {
  375. fprintf(stderr, "Failed to create stop event - 0x%lx\n",
  376. GetLastError());
  377. return(GetLastError());
  378. }
  379. hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT,
  380. 0, sizeof(PROFILE_CONTROL_BLOCK),
  381. PRFEVENT_SHARED_MEMORY);
  382. if (hMap == NULL) {
  383. fprintf(stderr, "Failed to create the file mapping - 0x%lx\n",
  384. GetLastError());
  385. return(GetLastError());
  386. }
  387. pShared = (PPROFILE_CONTROL_BLOCK) MapViewOfFile(hMap, FILE_MAP_WRITE,
  388. 0,0, sizeof(PROFILE_CONTROL_BLOCK));
  389. if (pShared == NULL) {
  390. fprintf(stderr, "Failed to map the shared memory view - 0x%lx\n",
  391. GetLastError());
  392. return(GetLastError());
  393. }
  394. // Wait for start i.e., the stop event
  395. WaitForSingleObject(hStopEvent, INFINITE);
  396. while (TRUE) {
  397. if (bDisplayContextSwitch) {
  398. NtQuerySystemInformation(SystemContextSwitchInformation,
  399. &StartContext,
  400. sizeof(StartContext),
  401. NULL);
  402. }
  403. status = StartProfile ();
  404. if (!NT_SUCCESS(status)) {
  405. fprintf(stderr, "start profile failed status - %lx\n",status);
  406. break;
  407. }
  408. // Signal started
  409. SetEvent(hStartedEvent);
  410. // Wait for stop
  411. WaitForSingleObject(hStopEvent, INFINITE);
  412. status = StopProfile ();
  413. if (!NT_SUCCESS(status)) {
  414. fprintf(stderr, "stop profile failed status - %lx\n",status);
  415. break;
  416. }
  417. if (bDisplayContextSwitch) {
  418. status = NtQuerySystemInformation(SystemContextSwitchInformation,
  419. &StopContext,
  420. sizeof(StopContext),
  421. NULL);
  422. if (!NT_SUCCESS(status)) {
  423. fprintf(stderr, "QuerySystemInformation for context switch information failed %08lx\n",status);
  424. bDisplayContextSwitch = FALSE;
  425. }
  426. }
  427. fpOut = fopen(pShared->FileName, "w");
  428. status = AnalyzeProfile (Threshold, &StartContext, &StopContext);
  429. fclose(fpOut);
  430. if (!NT_SUCCESS(status)) {
  431. fprintf(stderr, "analyze profile failed status - %lx\n",status);
  432. }
  433. if (pShared->Stop == TRUE)
  434. break;
  435. }
  436. SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
  437. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  438. UnmapViewOfFile((void*)pShared);
  439. CloseHandle(hMap);
  440. CloseHandle(hStopEvent);
  441. CloseHandle(hStartedEvent);
  442. return(status);
  443. }
  444. NTSTATUS
  445. RunStdProfile()
  446. {
  447. NTSTATUS status;
  448. SYSTEM_CONTEXT_SWITCH_INFORMATION StartContext;
  449. SYSTEM_CONTEXT_SWITCH_INFORMATION StopContext;
  450. SetConsoleCtrlHandler(CtrlcH,TRUE);
  451. if (DelaySeconds != -1) {
  452. fprintf(stderr, "starting profile after %d seconds\n",DelaySeconds);
  453. WaitForSingleObject(DelayEvent, DelaySeconds*1000);
  454. }
  455. if (bDisplayContextSwitch) {
  456. NtQuerySystemInformation(SystemContextSwitchInformation,
  457. &StartContext,
  458. sizeof(StartContext),
  459. NULL);
  460. }
  461. status = StartProfile ();
  462. if (!NT_SUCCESS(status)) {
  463. fprintf(stderr, "start profile failed status - %lx\n",status);
  464. return(status);
  465. }
  466. if ( Seconds == -1 ) {
  467. fprintf(stderr, "delaying until ^C\n");
  468. } else {
  469. fprintf(stderr, "delaying for %ld seconds... "
  470. "report on values with %ld hits\n",
  471. Seconds,
  472. Threshold
  473. );
  474. }
  475. if ( Seconds ) {
  476. if ( Seconds != -1 ) {
  477. Seconds = Seconds * 1000;
  478. }
  479. if ( DoneEvent ) {
  480. WaitForSingleObject(DoneEvent,Seconds);
  481. }
  482. else {
  483. Sleep(Seconds);
  484. }
  485. }
  486. else {
  487. getchar();
  488. }
  489. fprintf (stderr, "end of delay\n");
  490. status = StopProfile ();
  491. if (!NT_SUCCESS(status)) {
  492. fprintf(stderr, "stop profile failed status - %lx\n",status);
  493. return(status);
  494. }
  495. SetConsoleCtrlHandler(CtrlcH,FALSE);
  496. if (bDisplayContextSwitch) {
  497. status = NtQuerySystemInformation(SystemContextSwitchInformation,
  498. &StopContext,
  499. sizeof(StopContext),
  500. NULL);
  501. if (!NT_SUCCESS(status)) {
  502. fprintf(stderr, "QuerySystemInformation for context switch information failed %08lx\n",status);
  503. bDisplayContextSwitch = FALSE;
  504. }
  505. }
  506. if (DelaySeconds != -1) {
  507. SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
  508. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  509. }
  510. status = AnalyzeProfile (Threshold, &StartContext, &StopContext);
  511. if (!NT_SUCCESS(status)) {
  512. fprintf(stderr, "analyze profile failed status - %lx\n",status);
  513. }
  514. return(status);
  515. }
  516. VOID
  517. InitializeProfileSourceMapping (
  518. VOID
  519. )
  520. {
  521. #if defined(_X86_)
  522. UNICODE_STRING DriverName;
  523. NTSTATUS status;
  524. OBJECT_ATTRIBUTES ObjA;
  525. IO_STATUS_BLOCK IOSB;
  526. UCHAR buffer[400];
  527. ULONG i, j, Count;
  528. PEVENTID Event;
  529. HANDLE DriverHandle;
  530. //
  531. // Open PStat driver
  532. //
  533. RtlInitUnicodeString(&DriverName, L"\\Device\\PStat");
  534. InitializeObjectAttributes(
  535. &ObjA,
  536. &DriverName,
  537. OBJ_CASE_INSENSITIVE,
  538. 0,
  539. 0 );
  540. status = NtOpenFile (
  541. &DriverHandle, // return handle
  542. SYNCHRONIZE | FILE_READ_DATA, // desired access
  543. &ObjA, // Object
  544. &IOSB, // io status block
  545. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  546. FILE_SYNCHRONOUS_IO_ALERT // open options
  547. );
  548. if (!NT_SUCCESS(status)) {
  549. return ;
  550. }
  551. //
  552. // Initialize possible counters
  553. //
  554. // determine how many events there are
  555. Event = (PEVENTID) buffer;
  556. Count = 0;
  557. do {
  558. *((PULONG) buffer) = Count;
  559. Count += 1;
  560. status = NtDeviceIoControlFile(
  561. DriverHandle,
  562. (HANDLE) NULL, // event
  563. (PIO_APC_ROUTINE) NULL,
  564. (PVOID) NULL,
  565. &IOSB,
  566. PSTAT_QUERY_EVENTS,
  567. buffer, // input buffer
  568. sizeof (buffer),
  569. NULL, // output buffer
  570. 0
  571. );
  572. } while (NT_SUCCESS(status));
  573. ProfileSourceMapping = malloc(sizeof(*ProfileSourceMapping) * Count);
  574. Count -= 1;
  575. for (i=0, j=0; i < Count; i++) {
  576. *((PULONG) buffer) = i;
  577. NtDeviceIoControlFile(
  578. DriverHandle,
  579. (HANDLE) NULL, // event
  580. (PIO_APC_ROUTINE) NULL,
  581. (PVOID) NULL,
  582. &IOSB,
  583. PSTAT_QUERY_EVENTS,
  584. buffer, // input buffer
  585. sizeof (buffer),
  586. NULL, // output buffer
  587. 0
  588. );
  589. if (Event->ProfileSource > ProfileTime) {
  590. ProfileSourceMapping[j].Source = Event->ProfileSource;
  591. ProfileSourceMapping[j].ShortName = _strdup (Event->Buffer);
  592. ProfileSourceMapping[j].Description = _strdup (Event->Buffer + Event->DescriptionOffset);
  593. j++;
  594. }
  595. }
  596. ProfileSourceMapping[j].Source = (KPROFILE_SOURCE) 0;
  597. ProfileSourceMapping[j].ShortName = NULL;
  598. ProfileSourceMapping[j].Description = NULL;
  599. NtClose (DriverHandle);
  600. #endif
  601. }
  602. NTSTATUS
  603. InitializeKernelProfile (
  604. VOID
  605. )
  606. /*++
  607. Routine Description:
  608. This routine initializes profiling for the kernel for the
  609. current process.
  610. Arguments:
  611. None.
  612. Return Value:
  613. Returns the status of the last NtCreateProfile.
  614. --*/
  615. {
  616. ULONG i;
  617. ULONG ModuleNumber;
  618. SIZE_T ViewSize;
  619. PULONG CodeStart;
  620. ULONG CodeLength;
  621. NTSTATUS LocalStatus;
  622. NTSTATUS status;
  623. HANDLE CurrentProcessHandle;
  624. QUOTA_LIMITS QuotaLimits;
  625. PVOID Buffer;
  626. DWORD Cells;
  627. ULONG BucketSize;
  628. WCHAR StringBuf[500];
  629. PCHAR ModuleInfoBuffer;
  630. ULONG ModuleInfoBufferLength;
  631. ULONG ReturnedLength;
  632. PRTL_PROCESS_MODULES Modules;
  633. PRTL_PROCESS_MODULE_INFORMATION Module;
  634. UNICODE_STRING Sysdisk;
  635. UNICODE_STRING Sysroot;
  636. UNICODE_STRING Sysdll;
  637. UNICODE_STRING NameString;
  638. BOOLEAN PreviousProfilePrivState;
  639. BOOLEAN PreviousQuotaPrivState;
  640. CHAR ImageName[256];
  641. HANDLE hFile;
  642. HANDLE hMap;
  643. PVOID MappedBase;
  644. PIMAGE_NT_HEADERS NtHeaders;
  645. CurrentProcessHandle = NtCurrentProcess();
  646. //
  647. // Locate system drivers.
  648. //
  649. ModuleInfoBufferLength = 0;
  650. ModuleInfoBuffer = NULL;
  651. while (1) {
  652. status = NtQuerySystemInformation (SystemModuleInformation,
  653. ModuleInfoBuffer,
  654. ModuleInfoBufferLength,
  655. &ReturnedLength);
  656. if (NT_SUCCESS (status)) {
  657. break;
  658. }
  659. if (ModuleInfoBuffer != NULL) {
  660. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  661. }
  662. if (status == STATUS_INFO_LENGTH_MISMATCH && ReturnedLength > ModuleInfoBufferLength) {
  663. ModuleInfoBufferLength = ReturnedLength;
  664. ModuleInfoBuffer = RtlAllocateHeap (RtlProcessHeap(), 0, ModuleInfoBufferLength);
  665. if (ModuleInfoBuffer == NULL) {
  666. return STATUS_INSUFFICIENT_RESOURCES;
  667. }
  668. } else if (!NT_SUCCESS(status)) {
  669. fprintf(stderr, "query system info failed status - %lx\n",status);
  670. return(status);
  671. }
  672. }
  673. RtlInitUnicodeString (&Sysdisk,L"\\SystemRoot\\");
  674. RtlInitUnicodeString (&Sysroot,L"\\SystemRoot\\System32\\Drivers\\");
  675. RtlInitUnicodeString (&Sysdll, L"\\SystemRoot\\System32\\");
  676. NameString.Buffer = StringBuf;
  677. NameString.Length = 0;
  678. NameString.MaximumLength = sizeof( StringBuf );
  679. status = RtlAdjustPrivilege(
  680. SE_SYSTEM_PROFILE_PRIVILEGE,
  681. TRUE, //Enable
  682. FALSE, //not impersonating
  683. &PreviousProfilePrivState
  684. );
  685. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  686. fprintf(stderr, "Enable system profile privilege failed - status 0x%lx\n",
  687. status);
  688. }
  689. status = RtlAdjustPrivilege(
  690. SE_INCREASE_QUOTA_PRIVILEGE,
  691. TRUE, //Enable
  692. FALSE, //not impersonating
  693. &PreviousQuotaPrivState
  694. );
  695. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  696. fprintf(stderr, "Unable to increase quota privilege (status=0x%lx)\n",
  697. status);
  698. }
  699. Modules = (PRTL_PROCESS_MODULES)ModuleInfoBuffer;
  700. Module = &Modules->Modules[ 0 ];
  701. for (ModuleNumber=0; ModuleNumber < Modules->NumberOfModules; ModuleNumber++,Module++) {
  702. #if DBG_PROFILE
  703. fprintf(stderr, "module base %p\n",Module->ImageBase);
  704. fprintf(stderr, "module full path name: %s (%u)\n",
  705. Module->FullPathName,
  706. Module->OffsetToFileName);
  707. #endif
  708. if (SymLoadModule(
  709. SYM_HANDLE,
  710. NULL,
  711. &Module->FullPathName[Module->OffsetToFileName],
  712. NULL,
  713. (ULONG_PTR)Module->ImageBase,
  714. Module->ImageSize
  715. )) {
  716. ProfileObject[NumberOfProfileObjects].SymbolsLoaded = TRUE;
  717. if (Verbose) {
  718. fprintf(stderr, "Symbols loaded: %p %s\n",
  719. Module->ImageBase,
  720. &Module->FullPathName[Module->OffsetToFileName]
  721. );
  722. }
  723. } else {
  724. ProfileObject[NumberOfProfileObjects].SymbolsLoaded = FALSE;
  725. if (Verbose) {
  726. fprintf(stderr, "*** Could not load symbols: %p %s\n",
  727. Module->ImageBase,
  728. &Module->FullPathName[Module->OffsetToFileName]
  729. );
  730. }
  731. }
  732. hFile = FindExecutableImage(
  733. &Module->FullPathName[Module->OffsetToFileName],
  734. lpSymbolSearchPath,
  735. ImageName
  736. );
  737. if (!hFile) {
  738. continue;
  739. }
  740. hMap = CreateFileMapping(
  741. hFile,
  742. NULL,
  743. PAGE_READONLY,
  744. 0,
  745. 0,
  746. NULL
  747. );
  748. if (!hMap) {
  749. CloseHandle( hFile );
  750. continue;
  751. }
  752. MappedBase = MapViewOfFile(
  753. hMap,
  754. FILE_MAP_READ,
  755. 0,
  756. 0,
  757. 0
  758. );
  759. if (!MappedBase) {
  760. CloseHandle( hMap );
  761. CloseHandle( hFile );
  762. continue;
  763. }
  764. NtHeaders = ImageNtHeader( MappedBase );
  765. CodeLength = NtHeaders->OptionalHeader.SizeOfImage;
  766. CodeStart = (PULONG)Module->ImageBase;
  767. UnmapViewOfFile( MappedBase );
  768. CloseHandle( hMap );
  769. CloseHandle( hFile );
  770. if (CodeLength > 1024*512) {
  771. //
  772. // Just create a 512K byte buffer.
  773. //
  774. ViewSize = 1024 * 512;
  775. } else {
  776. ViewSize = CodeLength + PAGE_SIZE;
  777. }
  778. ProfileObject[NumberOfProfileObjects].CodeStart = CodeStart;
  779. ProfileObject[NumberOfProfileObjects].CodeLength = CodeLength;
  780. ProfileObject[NumberOfProfileObjects].ImageBase = Module->ImageBase;
  781. ProfileObject[NumberOfProfileObjects].ModuleName = _strdup(&Module->FullPathName[Module->OffsetToFileName]);
  782. for (i=0; i<MaxProcessors; i++) {
  783. Buffer = NULL;
  784. status = NtAllocateVirtualMemory (CurrentProcessHandle,
  785. (PVOID *)&Buffer,
  786. 0,
  787. &ViewSize,
  788. MEM_RESERVE | MEM_COMMIT,
  789. PAGE_READWRITE);
  790. if (!NT_SUCCESS(status)) {
  791. fprintf (stderr, "alloc VM failed %lx\n",status);
  792. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  793. return(status);
  794. }
  795. //
  796. // Calculate the bucket size for the profile.
  797. //
  798. Cells = (DWORD)((CodeLength / (ViewSize >> 2)) >> 2);
  799. BucketSize = 2;
  800. while (Cells != 0) {
  801. Cells = Cells >> 1;
  802. BucketSize += 1;
  803. }
  804. ProfileObject[NumberOfProfileObjects].Buffer[i] = Buffer;
  805. ProfileObject[NumberOfProfileObjects].BufferSize = 1 + (CodeLength >> (BucketSize - 2));
  806. ProfileObject[NumberOfProfileObjects].BucketSize = BucketSize;
  807. //
  808. // Increase the working set to lock down a bigger buffer.
  809. //
  810. status = NtQueryInformationProcess (CurrentProcessHandle,
  811. ProcessQuotaLimits,
  812. &QuotaLimits,
  813. sizeof(QUOTA_LIMITS),
  814. NULL );
  815. if (!NT_SUCCESS(status)) {
  816. fprintf (stderr, "query process info failed %lx\n",status);
  817. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  818. return(status);
  819. }
  820. QuotaLimits.MaximumWorkingSetSize += ViewSize;
  821. QuotaLimits.MinimumWorkingSetSize += ViewSize;
  822. status = NtSetInformationProcess (CurrentProcessHandle,
  823. ProcessQuotaLimits,
  824. &QuotaLimits,
  825. sizeof(QUOTA_LIMITS));
  826. #if DBG_PROFILE
  827. fprintf(stderr, "code start %p len %p, bucksize %lx buffer %p bsize %08x\n",
  828. ProfileObject[NumberOfProfileObjects].CodeStart,
  829. ProfileObject[NumberOfProfileObjects].CodeLength,
  830. ProfileObject[NumberOfProfileObjects].BucketSize,
  831. ProfileObject[NumberOfProfileObjects].Buffer ,
  832. ProfileObject[NumberOfProfileObjects].BufferSize);
  833. #endif
  834. if (bPerProcessor) {
  835. status = NtCreateProfile (
  836. &ProfileObject[NumberOfProfileObjects].Handle[i],
  837. 0,
  838. ProfileObject[NumberOfProfileObjects].CodeStart,
  839. ProfileObject[NumberOfProfileObjects].CodeLength,
  840. ProfileObject[NumberOfProfileObjects].BucketSize,
  841. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  842. ProfileObject[NumberOfProfileObjects].BufferSize,
  843. ProfileSource,
  844. 1 << i);
  845. } else {
  846. status = NtCreateProfile (
  847. &ProfileObject[NumberOfProfileObjects].Handle[i],
  848. 0,
  849. ProfileObject[NumberOfProfileObjects].CodeStart,
  850. ProfileObject[NumberOfProfileObjects].CodeLength,
  851. ProfileObject[NumberOfProfileObjects].BucketSize,
  852. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  853. ProfileObject[NumberOfProfileObjects].BufferSize,
  854. ProfileSource,
  855. (KAFFINITY)-1);
  856. }
  857. if (status != STATUS_SUCCESS) {
  858. fprintf(stderr, "create kernel profile %s failed - status %lx\n",
  859. ProfileObject[NumberOfProfileObjects].ModuleName, status);
  860. }
  861. }
  862. NumberOfProfileObjects += 1;
  863. if (NumberOfProfileObjects == MAX_PROFILE_COUNT) {
  864. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  865. return STATUS_SUCCESS;
  866. }
  867. }
  868. if (NumberOfProfileObjects < MAX_PROFILE_COUNT) {
  869. //
  870. // Add in usermode object
  871. // 0x00000000 -> SystemRangeStart
  872. //
  873. ULONG_PTR SystemRangeStart;
  874. ULONG UserModeBucketCount;
  875. status = NtQuerySystemInformation(SystemRangeStartInformation,
  876. &SystemRangeStart,
  877. sizeof(SystemRangeStart),
  878. NULL);
  879. //
  880. // How many buckets to cover the range
  881. //
  882. UserModeBucketCount = (ULONG)(1 + ((SystemRangeStart - 1) / MAX_BUCKET_SIZE));
  883. if (!NT_SUCCESS(status)) {
  884. fprintf(stderr, "NtQuerySystemInformation failed - status %lx\n", status);
  885. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  886. return status;
  887. }
  888. ProfileObject[NumberOfProfileObjects].SymbolsLoaded = FALSE;
  889. ProfileObject[NumberOfProfileObjects].CodeStart = 0;
  890. ProfileObject[NumberOfProfileObjects].CodeLength = SystemRangeStart;
  891. ProfileObject[NumberOfProfileObjects].ImageBase = 0;
  892. ProfileObject[NumberOfProfileObjects].ModuleName = "User Mode";
  893. ProfileObject[NumberOfProfileObjects].BufferSize = UserModeBucketCount * sizeof(DWORD);
  894. ProfileObject[NumberOfProfileObjects].BucketSize = MAX_BUCKET_SHIFT;
  895. for (i=0; i<MaxProcessors; i++) {
  896. UserModeBuffer[i] = HeapAlloc(GetProcessHeap(),
  897. HEAP_ZERO_MEMORY,
  898. ProfileObject[NumberOfProfileObjects].BufferSize);
  899. if (UserModeBuffer[i] == NULL) {
  900. fprintf (stderr, "HeapAlloc failed\n");
  901. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  902. return(STATUS_NO_MEMORY);
  903. }
  904. ProfileObject[NumberOfProfileObjects].Buffer[i] = UserModeBuffer[i];
  905. ProfileObject[NumberOfProfileObjects].Handle[i] = NULL;
  906. #if DBG_PROFILE
  907. fprintf(stderr, "code start %p len %lx, bucksize %lx buffer %p bsize %lx\n",
  908. ProfileObject[NumberOfProfileObjects].CodeStart,
  909. ProfileObject[NumberOfProfileObjects].CodeLength,
  910. ProfileObject[NumberOfProfileObjects].BucketSize,
  911. ProfileObject[NumberOfProfileObjects].Buffer ,
  912. ProfileObject[NumberOfProfileObjects].BufferSize);
  913. #endif
  914. if (bPerProcessor) {
  915. status = NtCreateProfile (
  916. &ProfileObject[NumberOfProfileObjects].Handle[i],
  917. 0,
  918. ProfileObject[NumberOfProfileObjects].CodeStart,
  919. ProfileObject[NumberOfProfileObjects].CodeLength,
  920. ProfileObject[NumberOfProfileObjects].BucketSize,
  921. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  922. ProfileObject[NumberOfProfileObjects].BufferSize,
  923. ProfileSource,
  924. 1 << i);
  925. } else {
  926. status = NtCreateProfile (
  927. &ProfileObject[NumberOfProfileObjects].Handle[i],
  928. 0,
  929. ProfileObject[NumberOfProfileObjects].CodeStart,
  930. ProfileObject[NumberOfProfileObjects].CodeLength,
  931. ProfileObject[NumberOfProfileObjects].BucketSize,
  932. ProfileObject[NumberOfProfileObjects].Buffer[i] ,
  933. ProfileObject[NumberOfProfileObjects].BufferSize,
  934. ProfileSource,
  935. (KAFFINITY)-1);
  936. }
  937. if (status != STATUS_SUCCESS) {
  938. fprintf(stderr, "create kernel profile %s failed - status %lx\n",
  939. ProfileObject[NumberOfProfileObjects].ModuleName, status);
  940. }
  941. }
  942. NumberOfProfileObjects += 1;
  943. }
  944. /*
  945. if (PreviousProfilePrivState == FALSE) {
  946. LocalStatus = RtlAdjustPrivilege(
  947. SE_SYSTEM_PROFILE_PRIVILEGE,
  948. FALSE, //Disable
  949. FALSE, //not impersonating
  950. &PreviousProfilePrivState
  951. );
  952. if (!NT_SUCCESS(LocalStatus) || LocalStatus == STATUS_NOT_ALL_ASSIGNED) {
  953. fprintf(stderr, "Disable system profile privilege failed - status 0x%lx\n",
  954. LocalStatus);
  955. }
  956. }
  957. if (PreviousQuotaPrivState == FALSE) {
  958. LocalStatus = RtlAdjustPrivilege(
  959. SE_SYSTEM_PROFILE_PRIVILEGE,
  960. FALSE, //Disable
  961. FALSE, //not impersonating
  962. &PreviousQuotaPrivState
  963. );
  964. if (!NT_SUCCESS(LocalStatus) || LocalStatus == STATUS_NOT_ALL_ASSIGNED) {
  965. fprintf(stderr, "Disable increate quota privilege failed - status 0x%lx\n",
  966. LocalStatus);
  967. }
  968. }
  969. */
  970. RtlFreeHeap (RtlProcessHeap (), 0, ModuleInfoBuffer);
  971. return status;
  972. }
  973. NTSTATUS
  974. StartProfile (
  975. VOID
  976. )
  977. /*++
  978. Routine Description:
  979. This routine starts all profile objects which have been initialized.
  980. Arguments:
  981. None.
  982. Return Value:
  983. Returns the status of the last NtStartProfile.
  984. --*/
  985. {
  986. ULONG Object;
  987. ULONG Processor;
  988. NTSTATUS status;
  989. QUOTA_LIMITS QuotaLimits;
  990. NtSetIntervalProfile(ProfileInterval,ProfileSource);
  991. if (bWaitForInput) {
  992. fprintf(stderr, "Hit return to continue.\n");
  993. (void) getchar();
  994. }
  995. for (Object = 0; Object < NumberOfProfileObjects; Object++) {
  996. for (Processor = 0;Processor < MaxProcessors; Processor++) {
  997. status = NtStartProfile (ProfileObject[Object].Handle[Processor]);
  998. if (!NT_SUCCESS(status)) {
  999. fprintf(stderr, "start profile %s failed - status %lx\n",
  1000. ProfileObject[Object].ModuleName, status);
  1001. return status;
  1002. }
  1003. }
  1004. }
  1005. return status;
  1006. }
  1007. NTSTATUS
  1008. StopProfile (
  1009. VOID
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. This routine stops all profile objects which have been initialized.
  1014. Arguments:
  1015. None.
  1016. Return Value:
  1017. Returns the status of the last NtStopProfile.
  1018. --*/
  1019. {
  1020. ULONG i;
  1021. ULONG Processor;
  1022. NTSTATUS status;
  1023. for (i = 0; i < NumberOfProfileObjects; i++) {
  1024. for (Processor=0; Processor < MaxProcessors; Processor++) {
  1025. status = NtStopProfile (ProfileObject[i].Handle[Processor]);
  1026. if (status != STATUS_SUCCESS) {
  1027. fprintf(stderr, "stop profile %s failed - status %lx\n",
  1028. ProfileObject[i].ModuleName,status);
  1029. return status;
  1030. }
  1031. }
  1032. }
  1033. return status;
  1034. }
  1035. NTSTATUS
  1036. AnalyzeProfile (
  1037. ULONG Threshold,
  1038. PSYSTEM_CONTEXT_SWITCH_INFORMATION StartContext,
  1039. PSYSTEM_CONTEXT_SWITCH_INFORMATION StopContext
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. This routine does the analysis of all the profile buffers and
  1044. correlates hits to the appropriate symbol table.
  1045. Arguments:
  1046. None.
  1047. Return Value:
  1048. None.
  1049. --*/
  1050. {
  1051. ULONG CountAtSymbol;
  1052. ULONG_PTR Va;
  1053. int i;
  1054. PULONG Counter;
  1055. ULONG_PTR Displacement;
  1056. ULONG Processor;
  1057. ULONG TotalHits = 0;
  1058. ULONG ProcessorTotalHits[MAXIMUM_PROCESSORS] = {0};
  1059. PULONG BufferEnd;
  1060. PULONG Buffer;
  1061. PULONG pInitialCounter;
  1062. ULONG OffsetVa = 0;
  1063. ULONG BytesPerBucket;
  1064. STRING NoSymbolFound = {16,15,"No Symbol Found"};
  1065. BOOLEAN UseLastSymbol = FALSE;
  1066. for (i = 0; i < (int)NumberOfProfileObjects; i++) {
  1067. for (Processor=0;Processor < MaxProcessors;Processor++) {
  1068. NtStopProfile (ProfileObject[i].Handle[Processor]);
  1069. }
  1070. }
  1071. for (Processor = 0; Processor < MaxProcessors; Processor++) {
  1072. for (i = 0; i < (int)NumberOfProfileObjects; i++) {
  1073. //
  1074. // Sum the total number of cells written.
  1075. //
  1076. BufferEnd = ProfileObject[i].Buffer[Processor] + (
  1077. ProfileObject[i].BufferSize / sizeof(ULONG));
  1078. Buffer = ProfileObject[i].Buffer[Processor];
  1079. Counter = BufferEnd;
  1080. ProfileObject[i].ModuleHitCount[Processor] = 0;
  1081. while (Counter > Buffer) {
  1082. Counter -= 1;
  1083. ProfileObject[i].ModuleHitCount[Processor] += *Counter;
  1084. }
  1085. ProcessorTotalHits[Processor] += ProfileObject[i].ModuleHitCount[Processor];
  1086. }
  1087. if (bPerProcessor) {
  1088. fprintf(fpOut, "Processor %d: %d Total hits\n",
  1089. Processor, ProcessorTotalHits[Processor]);
  1090. }
  1091. TotalHits += ProcessorTotalHits[Processor];
  1092. }
  1093. fprintf(fpOut, "%d Total hits\n",TotalHits);
  1094. for (Processor = 0; Processor < MaxProcessors; Processor++) {
  1095. if (bPerProcessor) {
  1096. fprintf(fpOut, "\nPROCESSOR %d\n",Processor);
  1097. }
  1098. for (i = 0; i < (int)NumberOfProfileObjects; i++) {
  1099. CountAtSymbol = 0;
  1100. //
  1101. // Sum the total number of cells written.
  1102. //
  1103. BufferEnd = ProfileObject[i].Buffer[Processor] + (
  1104. ProfileObject[i].BufferSize / sizeof(ULONG));
  1105. Buffer = ProfileObject[i].Buffer[Processor];
  1106. Counter = BufferEnd;
  1107. if (ProfileObject[i].ModuleHitCount[Processor] < Threshold) {
  1108. continue;
  1109. }
  1110. fprintf(fpOut, "\n%9d ",
  1111. ProfileObject[i].ModuleHitCount[Processor]);
  1112. if (bPrintPercentages) {
  1113. fprintf(fpOut, "%5.2f ",
  1114. (ProfileObject[i].ModuleHitCount[Processor] /
  1115. (double)ProcessorTotalHits[Processor]) * 100);
  1116. }
  1117. fprintf(fpOut, "%20s --Total Hits-- %s\n",
  1118. ProfileObject[i].ModuleName,
  1119. ((ProfileObject[i].SymbolsLoaded) ? "" :
  1120. "(NO SYMBOLS)")
  1121. );
  1122. if (!ProfileObject[i].SymbolsLoaded) {
  1123. RtlZeroMemory(ProfileObject[i].Buffer[Processor],
  1124. ProfileObject[i].BufferSize);
  1125. continue;
  1126. }
  1127. BytesPerBucket = (1 << ProfileObject[i].BucketSize);
  1128. pInitialCounter = Buffer;
  1129. for ( Counter = Buffer; Counter < BufferEnd; Counter += 1 ) {
  1130. if ( *Counter ) {
  1131. //
  1132. // Calculate the virtual address of the counter
  1133. //
  1134. Va = Counter - Buffer; // Calculate buckets #
  1135. Va = Va * BytesPerBucket; // convert to bytes
  1136. Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart; // add in base address
  1137. if (SymGetSymFromAddr( SYM_HANDLE, Va, &Displacement, ThisSymbol )) {
  1138. if (UseLastSymbol &&
  1139. LastSymbol->Address &&
  1140. (LastSymbol->Address == ThisSymbol->Address))
  1141. {
  1142. CountAtSymbol += *Counter;
  1143. } else {
  1144. OutputSymbolCount(CountAtSymbol,
  1145. ProcessorTotalHits[Processor],
  1146. &ProfileObject[i],
  1147. LastSymbol,
  1148. Threshold,
  1149. pInitialCounter,
  1150. Counter,
  1151. OffsetVa,
  1152. BytesPerBucket);
  1153. pInitialCounter = Counter;
  1154. OffsetVa = (DWORD) Displacement; // Images aren't > 2g so this cast s/b O.K.
  1155. CountAtSymbol = *Counter;
  1156. memcpy( LastSymBuffer, symBuffer, sizeof(symBuffer) );
  1157. UseLastSymbol = TRUE;
  1158. }
  1159. } else {
  1160. OutputSymbolCount(CountAtSymbol,
  1161. ProcessorTotalHits[Processor],
  1162. &ProfileObject[i],
  1163. LastSymbol,
  1164. Threshold,
  1165. pInitialCounter,
  1166. Counter,
  1167. OffsetVa,
  1168. BytesPerBucket);
  1169. } // else !(NT_SUCCESS)
  1170. } // if (*Counter)
  1171. } // for (Counter)
  1172. OutputSymbolCount(CountAtSymbol,
  1173. ProcessorTotalHits[Processor],
  1174. &ProfileObject[i],
  1175. LastSymbol,
  1176. Threshold,
  1177. pInitialCounter,
  1178. Counter,
  1179. OffsetVa,
  1180. BytesPerBucket);
  1181. //
  1182. // Clear after buffer's been checked and displayed
  1183. //
  1184. RtlZeroMemory(ProfileObject[i].Buffer[Processor], ProfileObject[i].BufferSize);
  1185. }
  1186. }
  1187. if (bDisplayContextSwitch) {
  1188. fprintf(fpOut, "\n");
  1189. fprintf(fpOut, "Context Switch Information\n");
  1190. fprintf(fpOut, " Find any processor %6ld\n", StopContext->FindAny - StartContext->FindAny);
  1191. fprintf(fpOut, " Find last processor %6ld\n", StopContext->FindLast - StartContext->FindLast);
  1192. fprintf(fpOut, " Idle any processor %6ld\n", StopContext->IdleAny - StartContext->IdleAny);
  1193. fprintf(fpOut, " Idle current processor %6ld\n", StopContext->IdleCurrent - StartContext->IdleCurrent);
  1194. fprintf(fpOut, " Idle last processor %6ld\n", StopContext->IdleLast - StartContext->IdleLast);
  1195. fprintf(fpOut, " Preempt any processor %6ld\n", StopContext->PreemptAny - StartContext->PreemptAny);
  1196. fprintf(fpOut, " Preempt current processor %6ld\n", StopContext->PreemptCurrent - StartContext->PreemptCurrent);
  1197. fprintf(fpOut, " Preempt last processor %6ld\n", StopContext->PreemptLast - StartContext->PreemptLast);
  1198. fprintf(fpOut, " Switch to idle %6ld\n", StopContext->SwitchToIdle - StartContext->SwitchToIdle);
  1199. fprintf(fpOut, "\n");
  1200. fprintf(fpOut, " Total context switches %6ld\n", StopContext->ContextSwitches - StartContext->ContextSwitches);
  1201. }
  1202. return STATUS_SUCCESS;
  1203. }
  1204. VOID
  1205. OutputSymbolCount(
  1206. IN ULONG CountAtSymbol,
  1207. IN ULONG TotalCount,
  1208. IN PROFILE_BLOCK *ProfileObject,
  1209. IN PIMAGEHLP_SYMBOL SymbolInfo,
  1210. IN ULONG Threshold,
  1211. IN PULONG CounterStart,
  1212. IN PULONG CounterStop,
  1213. IN ULONG Va,
  1214. IN ULONG BytesPerBucket
  1215. )
  1216. {
  1217. ULONG Density;
  1218. ULONG i;
  1219. if (CountAtSymbol < Threshold) {
  1220. return;
  1221. }
  1222. fprintf(fpOut, "%9d ", CountAtSymbol);
  1223. if (bPrintPercentages) {
  1224. fprintf(fpOut, "%5.2f ", (CountAtSymbol / (double) TotalCount) * 100);
  1225. }
  1226. if (bDisplayDensity) {
  1227. //
  1228. // Compute hit density = hits * 100 / function length
  1229. //
  1230. if (!SymbolInfo || !SymbolInfo->Size) {
  1231. Density = 0;
  1232. } else {
  1233. Density = CountAtSymbol * 100 / SymbolInfo->Size;
  1234. }
  1235. fprintf(fpOut, "%5d ",Density);
  1236. }
  1237. if (SymbolInfo->MaxNameLength) {
  1238. fprintf(fpOut, "%20s %s",
  1239. ProfileObject->ModuleName,
  1240. SymbolInfo->Name);
  1241. } else {
  1242. fprintf(fpOut, "%20s 0x%x",
  1243. ProfileObject->ModuleName,
  1244. SymbolInfo->Address);
  1245. }
  1246. if (bDisplayAddress) {
  1247. fprintf(fpOut, " 0x0%p %d %d",
  1248. SymbolInfo->Address,
  1249. SymbolInfo->Size,
  1250. ProfileObject->BucketSize);
  1251. }
  1252. if (bDisplayCounters) {
  1253. for (i = 0 ; CounterStart < CounterStop; i++, Va += BytesPerBucket, ++CounterStart) {
  1254. if ((i % 16) == 0) {
  1255. fprintf (fpOut, "\n0x%08x:", Va);
  1256. }
  1257. fprintf(fpOut, " %5d", *CounterStart);
  1258. }
  1259. }
  1260. fprintf (fpOut, "\n");
  1261. }