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.

931 lines
26 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. proflib.c
  5. Abstract:
  6. This module contains the implementation of a rudimentry user-mode
  7. profiler.
  8. Usage:
  9. There are 4 routines, RtlInitializeProfile, RtlStartProfile,
  10. RtlStopProfile, and RtlAnalyzeProfile. To initialize profiling
  11. invoke RtlInitializeProfile, this routine is only called once and
  12. goes through the address space looking for code regions of images
  13. and DLLs. To start profiling call RtlStartProfile. To stop
  14. profiling call RtlStopProfile. Note that RtlStartProfile and
  15. RtlStopProfile can be called repeatedly to profile only key
  16. "hot spots", For example:
  17. RtlStartProfile ();
  18. hot spot...
  19. RtlStopProfile ();
  20. ....
  21. RtlStartProfile ();
  22. hot spot...
  23. RtlStopProfile ();
  24. To analyze the results call RtlAnalyzeProfile. This too can
  25. be called repeatedly (it stops profiling during the analysis
  26. phase and does NOT restart profiling). It also does not
  27. zero out the values after reporting.
  28. Author:
  29. Lou Perazzoli (loup) 4-Oct-1990
  30. Revision History:
  31. --*/
  32. #include <nt.h>
  33. #include <ntrtl.h>
  34. #include <nturtl.h>
  35. #include <string.h>
  36. #include <stdio.h>
  37. #include "..\..\..\..\private\ntos\dll\ldrp.h"
  38. NTSTATUS
  39. InitializeKernelProfile ( VOID );
  40. #define PAGE_SIZE 4096
  41. typedef struct _PROFILE_BLOCK {
  42. HANDLE Handle;
  43. PVOID ImageBase; //actual base in image header
  44. PULONG CodeStart;
  45. ULONG CodeLength;
  46. PULONG Buffer;
  47. ULONG BufferSize;
  48. ULONG TextNumber;
  49. ULONG BucketSize;
  50. PVOID MappedImageBase; //actual base where mapped locally.
  51. PSZ ImageName;
  52. } PROFILE_BLOCK;
  53. #define MAX_PROFILE_COUNT 50
  54. PROFILE_BLOCK ProfileObject[MAX_PROFILE_COUNT];
  55. ULONG NumberOfProfileObjects = 0;
  56. PIMAGE_DEBUG_INFO KernelDebugInfo;
  57. //
  58. // Image name to perform kernel mode analysis upon.
  59. //
  60. #define IMAGE_NAME "\\SystemRoot\\ntoskrnl.exe"
  61. //
  62. // Define map data file if the produced data file should be
  63. // a mapped file (currently named "kernprof.dat").
  64. //
  65. // #define MAP_DATA_FILE
  66. //
  67. // Define map as image if the image to be profiled should be mapped
  68. // as an image rather than as data.
  69. //
  70. // #define MAP_AS_IMAGE
  71. #define MAX_PROFILE_COUNT 50
  72. extern ULONG ProfInt;
  73. NTSTATUS
  74. RtlInitializeProfile (
  75. IN BOOLEAN KernelToo
  76. )
  77. /*++
  78. Routine Description:
  79. This routine initializes profiling for the current process.
  80. Arguments:
  81. KernelToo - Set to TRUE if kernel code should be profiled as
  82. well as user code.
  83. Return Value:
  84. Returns the status of the last NtCreateProfile.
  85. --*/
  86. {
  87. NTSTATUS status, LocalStatus;
  88. HANDLE CurrentProcessHandle;
  89. ULONG BufferSize;
  90. PVOID ImageBase;
  91. ULONG CodeLength;
  92. PULONG Buffer;
  93. PPEB Peb;
  94. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  95. PSZ ImageName;
  96. PLIST_ENTRY Next;
  97. ULONG ExportSize, DebugSize;
  98. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  99. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  100. PIMAGE_DEBUG_INFO DebugInfo;
  101. BOOLEAN PreviousPrivState;
  102. //
  103. // Locate all the executables in the address and create a
  104. // seperate profile object for each one.
  105. //
  106. CurrentProcessHandle = NtCurrentProcess();
  107. Peb = NtCurrentPeb();
  108. Next = Peb->Ldr->InMemoryOrderModuleList.Flink;
  109. while ( Next != &Peb->Ldr->InMemoryOrderModuleList) {
  110. LdrDataTableEntry
  111. = (PLDR_DATA_TABLE_ENTRY) (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks));
  112. ImageBase = LdrDataTableEntry->DllBase;
  113. if ( Peb->ImageBaseAddress == ImageBase ) {
  114. ImageName = "TheApplication";
  115. } else {
  116. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
  117. ImageBase,
  118. TRUE,
  119. IMAGE_DIRECTORY_ENTRY_EXPORT,
  120. &ExportSize);
  121. ImageName = (PSZ)((ULONG)ImageBase + ExportDirectory->Name);
  122. }
  123. if (NumberOfProfileObjects > MAX_PROFILE_COUNT) {
  124. break;
  125. }
  126. ProfileObject[NumberOfProfileObjects].ImageBase = ImageBase;
  127. ProfileObject[NumberOfProfileObjects].ImageName = ImageName;
  128. ProfileObject[NumberOfProfileObjects].MappedImageBase = ImageBase;
  129. //
  130. // Locate the code range and start profiling.
  131. //
  132. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(
  133. ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugSize);
  134. if (!DebugDirectory) {
  135. DbgPrint ("RtlInitializeProfile : No debug directory\n");
  136. return STATUS_INVALID_IMAGE_FORMAT;
  137. }
  138. DebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)ImageBase + DebugDirectory->AddressOfRawData);
  139. ProfileObject[NumberOfProfileObjects].CodeStart = (PULONG)((ULONG)ImageBase + DebugInfo->RvaToFirstByteOfCode);
  140. CodeLength = (DebugInfo->RvaToLastByteOfCode - DebugInfo->RvaToFirstByteOfCode) - 1;
  141. ProfileObject[NumberOfProfileObjects].CodeLength = CodeLength;
  142. ProfileObject[NumberOfProfileObjects].TextNumber = 1;
  143. //
  144. // Analyze the size of the code and create a reasonably sized
  145. // profile object.
  146. //
  147. BufferSize = (CodeLength >> 1) + 4;
  148. Buffer = NULL;
  149. status = NtAllocateVirtualMemory (CurrentProcessHandle,
  150. (PVOID *)&Buffer,
  151. 0,
  152. &BufferSize,
  153. MEM_RESERVE | MEM_COMMIT,
  154. PAGE_READWRITE);
  155. if (!NT_SUCCESS(status)) {
  156. DbgPrint ("alloc VM failed %lx\n",status);
  157. return status;
  158. }
  159. status = RtlAdjustPrivilege(
  160. SE_PROF_SINGLE_PROCESS_PRIVILEGE,
  161. TRUE, //Enable
  162. FALSE, //not impersonating
  163. &PreviousPrivState //Remember if it will need to be cleared
  164. );
  165. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  166. DbgPrint("Enable system profile privilege failed - status 0x%lx\n",
  167. status);
  168. }
  169. ProfileObject[NumberOfProfileObjects].Buffer = Buffer;
  170. ProfileObject[NumberOfProfileObjects].BufferSize = BufferSize;
  171. ProfileObject[NumberOfProfileObjects].BucketSize = 3;
  172. status = NtCreateProfile (
  173. &ProfileObject[NumberOfProfileObjects].Handle,
  174. CurrentProcessHandle,
  175. ProfileObject[NumberOfProfileObjects].CodeStart,
  176. CodeLength,
  177. ProfileObject[NumberOfProfileObjects].BucketSize,
  178. ProfileObject[NumberOfProfileObjects].Buffer ,
  179. ProfileObject[NumberOfProfileObjects].BufferSize,
  180. ProfileTime,
  181. (KAFFINITY)-1);
  182. if (PreviousPrivState == FALSE) {
  183. LocalStatus = RtlAdjustPrivilege(
  184. SE_PROF_SINGLE_PROCESS_PRIVILEGE,
  185. FALSE, //Disable
  186. FALSE, //not impersonating
  187. &PreviousPrivState //Don't care if it was already enabled
  188. );
  189. if (!NT_SUCCESS(LocalStatus) || LocalStatus == STATUS_NOT_ALL_ASSIGNED) {
  190. DbgPrint("Disable system profile privilege failed - status 0x%lx\n",
  191. LocalStatus);
  192. }
  193. }
  194. if (status != STATUS_SUCCESS) {
  195. DbgPrint("create profile %x failed - status %lx\n",
  196. ProfileObject[NumberOfProfileObjects].ImageName,status);
  197. return status;
  198. }
  199. NumberOfProfileObjects += 1;
  200. Next = Next->Flink;
  201. }
  202. if (KernelToo) {
  203. if (NumberOfProfileObjects > MAX_PROFILE_COUNT) {
  204. return status;
  205. }
  206. status = InitializeKernelProfile();
  207. }
  208. return status;
  209. }
  210. NTSTATUS
  211. InitializeKernelProfile (
  212. VOID
  213. )
  214. /*++
  215. Routine Description:
  216. This routine initializes profiling for the kernel for the
  217. current process.
  218. Arguments:
  219. None.
  220. Return Value:
  221. Returns the status of the last NtCreateProfile.
  222. --*/
  223. {
  224. //BUGBUG daveh I think that the new working set size calculation is
  225. // generating the number of pages, when the api expects
  226. // the number of bytes.
  227. STRING Name3;
  228. IO_STATUS_BLOCK IoStatus;
  229. HANDLE FileHandle, KernelSection;
  230. OBJECT_ATTRIBUTES ObjectAttributes;
  231. PVOID ImageBase;
  232. ULONG ViewSize;
  233. ULONG CodeLength;
  234. NTSTATUS status, LocalStatus;
  235. HANDLE CurrentProcessHandle;
  236. QUOTA_LIMITS QuotaLimits;
  237. PVOID Buffer;
  238. ULONG Cells;
  239. ULONG BucketSize;
  240. UNICODE_STRING Unicode;
  241. ULONG DebugSize;
  242. PVOID KernelBase;
  243. PIMAGE_NT_HEADERS KernelNtHeaders;
  244. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  245. BOOLEAN PreviousPrivState;
  246. RtlInitString (&Name3, IMAGE_NAME);
  247. CurrentProcessHandle = NtCurrentProcess();
  248. status = RtlAnsiStringToUnicodeString(&Unicode,(PANSI_STRING)&Name3,TRUE);
  249. ASSERT(NT_SUCCESS(status));
  250. InitializeObjectAttributes( &ObjectAttributes,
  251. &Unicode,
  252. OBJ_CASE_INSENSITIVE,
  253. NULL,
  254. NULL );
  255. //
  256. // Open the file as readable and executable.
  257. //
  258. status = NtOpenFile ( &FileHandle,
  259. FILE_READ_DATA | FILE_EXECUTE,
  260. &ObjectAttributes,
  261. &IoStatus,
  262. FILE_SHARE_READ,
  263. 0L);
  264. RtlFreeUnicodeString(&Unicode);
  265. if (!NT_SUCCESS(status)) {
  266. DbgPrint("open file failed status %lx\n", status);
  267. NtTerminateProcess(NtCurrentProcess(),STATUS_SUCCESS);
  268. }
  269. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
  270. //
  271. // For normal images they would be mapped as an image, but
  272. // the kernel has no debug section (as yet) information, hence it
  273. // must be mapped as a file.
  274. //
  275. status = NtCreateSection (&KernelSection,
  276. SECTION_MAP_EXECUTE,
  277. &ObjectAttributes,
  278. 0,
  279. PAGE_READONLY,
  280. SEC_IMAGE,
  281. FileHandle);
  282. if (!NT_SUCCESS(status)) {
  283. DbgPrint("create image section failed status %lx\n", status);
  284. return(status);
  285. }
  286. ViewSize = 0;
  287. //
  288. // Map a view of the section into the address space.
  289. //
  290. KernelBase = NULL;
  291. status = NtMapViewOfSection (KernelSection,
  292. CurrentProcessHandle,
  293. (PVOID *)&KernelBase,
  294. 0L,
  295. 0,
  296. NULL,
  297. &ViewSize,
  298. ViewUnmap,
  299. 0,
  300. PAGE_EXECUTE);
  301. if (!NT_SUCCESS(status)) {
  302. if (status != STATUS_IMAGE_NOT_AT_BASE) {
  303. DbgPrint("map section status %lx base %lx size %lx\n", status,
  304. KernelBase, ViewSize);
  305. }
  306. }
  307. KernelNtHeaders = (PIMAGE_NT_HEADERS)RtlImageNtHeader(KernelBase);
  308. ImageBase = (PVOID)KernelNtHeaders->OptionalHeader.ImageBase;
  309. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(
  310. KernelBase, TRUE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugSize);
  311. if (!DebugDirectory) {
  312. DbgPrint("InitializeKernelProfile : No debug directory\n");
  313. return STATUS_INVALID_IMAGE_FORMAT;
  314. }
  315. KernelDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)KernelBase + DebugDirectory->AddressOfRawData);
  316. CodeLength = (KernelDebugInfo->RvaToLastByteOfCode - KernelDebugInfo->RvaToFirstByteOfCode) -1;
  317. //
  318. // Just create a 512K byte buffer.
  319. //
  320. ViewSize = 1024 * 512;
  321. Buffer = NULL;
  322. status = NtAllocateVirtualMemory (CurrentProcessHandle,
  323. (PVOID *)&Buffer,
  324. 0,
  325. &ViewSize,
  326. MEM_RESERVE | MEM_COMMIT,
  327. PAGE_READWRITE);
  328. if (!NT_SUCCESS(status)) {
  329. DbgPrint ("alloc VM failed %lx\n",status);
  330. NtTerminateProcess(NtCurrentProcess(),STATUS_SUCCESS);
  331. }
  332. //
  333. // Calculate the bucket size for the profile.
  334. //
  335. Cells = ((CodeLength / (ViewSize >> 2)) >> 2);
  336. BucketSize = 2;
  337. while (Cells != 0) {
  338. Cells = Cells >> 1;
  339. BucketSize += 1;
  340. }
  341. ProfileObject[NumberOfProfileObjects].Buffer = Buffer;
  342. ProfileObject[NumberOfProfileObjects].MappedImageBase = KernelBase;
  343. ProfileObject[NumberOfProfileObjects].BufferSize = 1 + (CodeLength >> (BucketSize - 2));
  344. ProfileObject[NumberOfProfileObjects].CodeStart = (PULONG)((ULONG)ImageBase + KernelDebugInfo->RvaToFirstByteOfCode);
  345. ProfileObject[NumberOfProfileObjects].CodeLength = CodeLength;
  346. ProfileObject[NumberOfProfileObjects].TextNumber = 1;
  347. ProfileObject[NumberOfProfileObjects].ImageBase = ImageBase;
  348. ProfileObject[NumberOfProfileObjects].ImageName = "ntoskrnl";
  349. ProfileObject[NumberOfProfileObjects].BucketSize = BucketSize;
  350. //
  351. // Increase the working set to lock down a bigger buffer.
  352. //
  353. status = NtQueryInformationProcess (CurrentProcessHandle,
  354. ProcessQuotaLimits,
  355. &QuotaLimits,
  356. sizeof(QUOTA_LIMITS),
  357. NULL );
  358. if (!NT_SUCCESS(status)) {
  359. DbgPrint ("query process info failed %lx\n",status);
  360. NtTerminateProcess(NtCurrentProcess(),STATUS_SUCCESS);
  361. }
  362. QuotaLimits.MaximumWorkingSetSize += ViewSize / PAGE_SIZE;
  363. QuotaLimits.MinimumWorkingSetSize += ViewSize / PAGE_SIZE;
  364. status = NtSetInformationProcess (CurrentProcessHandle,
  365. ProcessQuotaLimits,
  366. &QuotaLimits,
  367. sizeof(QUOTA_LIMITS));
  368. if (!NT_SUCCESS(status)) {
  369. DbgPrint ("setting working set failed %lx\n",status);
  370. return status;
  371. }
  372. status = RtlAdjustPrivilege(
  373. SE_PROF_SINGLE_PROCESS_PRIVILEGE,
  374. TRUE, //Enable
  375. FALSE, //not impersonating
  376. &PreviousPrivState //Remember if it will need to be cleared
  377. );
  378. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  379. DbgPrint("Enable process profile privilege failed - status 0x%lx\n",
  380. status);
  381. }
  382. status = NtCreateProfile (
  383. &ProfileObject[NumberOfProfileObjects].Handle,
  384. CurrentProcessHandle,
  385. ProfileObject[NumberOfProfileObjects].CodeStart,
  386. CodeLength,
  387. ProfileObject[NumberOfProfileObjects].BucketSize,
  388. ProfileObject[NumberOfProfileObjects].Buffer ,
  389. ProfileObject[NumberOfProfileObjects].BufferSize,
  390. ProfileTime,
  391. (KAFFINITY)-1);
  392. if (PreviousPrivState == FALSE) {
  393. LocalStatus = RtlAdjustPrivilege(
  394. SE_PROF_SINGLE_PROCESS_PRIVILEGE,
  395. FALSE, //Disable
  396. FALSE, //not impersonating
  397. &PreviousPrivState //Don't care if it was already enabled
  398. );
  399. if (!NT_SUCCESS(LocalStatus) || LocalStatus == STATUS_NOT_ALL_ASSIGNED) {
  400. DbgPrint("Disable system profile privilege failed - status 0x%lx\n",
  401. LocalStatus);
  402. }
  403. }
  404. if (status != STATUS_SUCCESS) {
  405. DbgPrint("create kernel profile %s failed - status %lx\n",
  406. ProfileObject[NumberOfProfileObjects].ImageName,status);
  407. }
  408. NumberOfProfileObjects += 1;
  409. return status;
  410. }
  411. VOID
  412. RtlpWriteProfileLine(
  413. IN HANDLE ProfileHandle,
  414. IN PSZ Line,
  415. IN int nbytes
  416. )
  417. {
  418. IO_STATUS_BLOCK IoStatusBlock;
  419. NtWriteFile(
  420. ProfileHandle,
  421. NULL,
  422. NULL,
  423. NULL,
  424. &IoStatusBlock,
  425. Line,
  426. (ULONG)nbytes,
  427. NULL,
  428. NULL
  429. );
  430. }
  431. HANDLE
  432. RtlpOpenProfileOutputFile()
  433. {
  434. NTSTATUS Status;
  435. OBJECT_ATTRIBUTES Obja;
  436. HANDLE Handle;
  437. UNICODE_STRING FileName;
  438. IO_STATUS_BLOCK IoStatusBlock;
  439. BOOLEAN TranslationStatus;
  440. RTL_RELATIVE_NAME_U RelativeName;
  441. PVOID FreeBuffer;
  442. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  443. L"\\profile.out",
  444. &FileName,
  445. NULL,
  446. &RelativeName
  447. );
  448. if ( !TranslationStatus ) {
  449. return NULL;
  450. }
  451. FreeBuffer = FileName.Buffer;
  452. if ( RelativeName.RelativeName.Length ) {
  453. FileName = RelativeName.RelativeName;
  454. }
  455. else {
  456. RelativeName.ContainingDirectory = NULL;
  457. }
  458. InitializeObjectAttributes(
  459. &Obja,
  460. &FileName,
  461. OBJ_CASE_INSENSITIVE,
  462. RelativeName.ContainingDirectory,
  463. NULL
  464. );
  465. Status = NtCreateFile(
  466. &Handle,
  467. FILE_APPEND_DATA | SYNCHRONIZE,
  468. &Obja,
  469. &IoStatusBlock,
  470. NULL,
  471. FILE_ATTRIBUTE_NORMAL,
  472. FILE_SHARE_READ,
  473. FILE_OPEN_IF,
  474. FILE_SYNCHRONOUS_IO_NONALERT,
  475. NULL,
  476. 0L
  477. );
  478. RtlReleaseRelativeName(&RelativeName);
  479. RtlFreeHeap(RtlProcessHeap(),0,FreeBuffer);
  480. if ( !NT_SUCCESS(Status) ) {
  481. return NULL;
  482. }
  483. return Handle;
  484. }
  485. VOID
  486. RtlpDeleteProfileOutputFile()
  487. {
  488. NTSTATUS Status;
  489. OBJECT_ATTRIBUTES Obja;
  490. HANDLE Handle;
  491. UNICODE_STRING FileName;
  492. IO_STATUS_BLOCK IoStatusBlock;
  493. FILE_DISPOSITION_INFORMATION Disposition;
  494. BOOLEAN TranslationStatus;
  495. RTL_RELATIVE_NAME_U RelativeName;
  496. PVOID FreeBuffer;
  497. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  498. L"\\profile.out",
  499. &FileName,
  500. NULL,
  501. &RelativeName
  502. );
  503. if ( !TranslationStatus ) {
  504. return;
  505. }
  506. FreeBuffer = FileName.Buffer;
  507. if ( RelativeName.RelativeName.Length ) {
  508. FileName = RelativeName.RelativeName;
  509. }
  510. else {
  511. RelativeName.ContainingDirectory = NULL;
  512. }
  513. InitializeObjectAttributes(
  514. &Obja,
  515. &FileName,
  516. OBJ_CASE_INSENSITIVE,
  517. RelativeName.ContainingDirectory,
  518. NULL
  519. );
  520. //
  521. // Open the file for delete access
  522. //
  523. Status = NtOpenFile(
  524. &Handle,
  525. (ACCESS_MASK)DELETE | SYNCHRONIZE,
  526. &Obja,
  527. &IoStatusBlock,
  528. FILE_SHARE_DELETE,
  529. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  530. );
  531. RtlReleaseRelativeName(&RelativeName);
  532. RtlFreeHeap(RtlProcessHeap(),0,FreeBuffer);
  533. if ( !NT_SUCCESS(Status) ) {
  534. return;
  535. }
  536. //
  537. // Delete the file
  538. //
  539. Disposition.DeleteFile = TRUE;
  540. Status = NtSetInformationFile(
  541. Handle,
  542. &IoStatusBlock,
  543. &Disposition,
  544. sizeof(Disposition),
  545. FileDispositionInformation
  546. );
  547. NtClose(Handle);
  548. }
  549. NTSTATUS
  550. RtlStartProfile (
  551. VOID
  552. )
  553. /*++
  554. Routine Description:
  555. This routine starts all profile objects which have been initialized.
  556. Arguments:
  557. None.
  558. Return Value:
  559. Returns the status of the last NtStartProfile.
  560. --*/
  561. {
  562. ULONG i;
  563. NTSTATUS status;
  564. QUOTA_LIMITS QuotaLimits;
  565. NtSetIntervalProfile(ProfInt,ProfileTime);
  566. RtlpDeleteProfileOutputFile();
  567. for (i = 0; i < NumberOfProfileObjects; i++) {
  568. status = NtStartProfile (ProfileObject[i].Handle);
  569. if (status == STATUS_WORKING_SET_QUOTA) {
  570. //
  571. // Increase the working set to lock down a bigger buffer.
  572. //
  573. status = NtQueryInformationProcess (NtCurrentProcess(),
  574. ProcessQuotaLimits,
  575. &QuotaLimits,
  576. sizeof(QUOTA_LIMITS),
  577. NULL );
  578. if (!NT_SUCCESS(status)) {
  579. DbgPrint ("query process info failed %lx\n",status);
  580. return status;
  581. }
  582. QuotaLimits.MaximumWorkingSetSize +=
  583. 10 * PAGE_SIZE + ProfileObject[i].BufferSize;
  584. QuotaLimits.MinimumWorkingSetSize +=
  585. 10 * PAGE_SIZE + ProfileObject[i].BufferSize;
  586. status = NtSetInformationProcess (NtCurrentProcess(),
  587. ProcessQuotaLimits,
  588. &QuotaLimits,
  589. sizeof(QUOTA_LIMITS));
  590. if (!NT_SUCCESS(status)) {
  591. DbgPrint ("setting working set failed %lx\n",status);
  592. return status;
  593. }
  594. status = NtStartProfile (ProfileObject[i].Handle);
  595. }
  596. if (status != STATUS_SUCCESS) {
  597. DbgPrint("start profile %s failed - status %lx\n",
  598. ProfileObject[i].ImageName, status);
  599. return status;
  600. }
  601. }
  602. return status;
  603. }
  604. NTSTATUS
  605. RtlStopProfile (
  606. VOID
  607. )
  608. /*++
  609. Routine Description:
  610. This routine stops all profile objects which have been initialized.
  611. Arguments:
  612. None.
  613. Return Value:
  614. Returns the status of the last NtStopProfile.
  615. --*/
  616. {
  617. ULONG i;
  618. NTSTATUS status;
  619. for (i = 0; i < NumberOfProfileObjects; i++) {
  620. status = NtStopProfile (ProfileObject[i].Handle);
  621. if (status != STATUS_SUCCESS) {
  622. DbgPrint("stop profile %s failed - status %lx\n",
  623. ProfileObject[i].ImageName,status);
  624. return status;
  625. }
  626. }
  627. return status;
  628. }
  629. NTSTATUS
  630. RtlAnalyzeProfile (
  631. VOID
  632. )
  633. /*++
  634. Routine Description:
  635. This routine does the analysis of all the profile buffers and
  636. correlates hits to the appropriate symbol table.
  637. Arguments:
  638. None.
  639. Return Value:
  640. None.
  641. --*/
  642. {
  643. RTL_SYMBOL_INFORMATION ThisSymbol;
  644. RTL_SYMBOL_INFORMATION LastSymbol;
  645. ULONG CountAtSymbol;
  646. NTSTATUS Status;
  647. ULONG Va;
  648. HANDLE ProfileHandle;
  649. CHAR Line[512];
  650. int i,n;
  651. PULONG Buffer, BufferEnd, Counter;
  652. ProfileHandle = RtlpOpenProfileOutputFile();
  653. ASSERT(ProfileHandle);
  654. for (i = 0; i < NumberOfProfileObjects; i++) {
  655. Status = NtStopProfile (ProfileObject[i].Handle);
  656. }
  657. //
  658. // The new profiler
  659. //
  660. for (i = 0; i < NumberOfProfileObjects; i++) {
  661. LastSymbol.Value = 0;
  662. CountAtSymbol = 0;
  663. //
  664. // Sum the total number of cells written.
  665. //
  666. BufferEnd = ProfileObject[i].Buffer + (
  667. ProfileObject[i].BufferSize / sizeof(ULONG));
  668. Buffer = ProfileObject[i].Buffer;
  669. for ( Counter = Buffer; Counter < BufferEnd; Counter += 1 ) {
  670. if ( *Counter ) {
  671. //
  672. // Now we have an an address relative to the buffer
  673. // base.
  674. //
  675. Va = (ULONG)((PUCHAR)Counter - (PUCHAR)Buffer);
  676. Va = Va * ( 1 << (ProfileObject[i].BucketSize - 2));
  677. //
  678. // Add in the image base and the base of the
  679. // code to get the Va in the image
  680. //
  681. Va = Va + (ULONG)ProfileObject[i].CodeStart;
  682. Status = RtlLookupSymbolByAddress(
  683. ProfileObject[i].ImageBase,
  684. NULL,
  685. (PVOID)Va,
  686. 0x4000,
  687. &ThisSymbol,
  688. NULL
  689. );
  690. if ( NT_SUCCESS(Status) ) {
  691. if ( LastSymbol.Value && LastSymbol.Value == ThisSymbol.Value ) {
  692. CountAtSymbol += *Counter;
  693. }
  694. else {
  695. if ( LastSymbol.Value ) {
  696. if ( CountAtSymbol ) {
  697. n= sprintf(Line,"%d,%s,%S\n",
  698. CountAtSymbol,
  699. ProfileObject[i].ImageName,
  700. &LastSymbol.Name
  701. );
  702. RtlpWriteProfileLine(ProfileHandle,Line,n);
  703. }
  704. }
  705. CountAtSymbol = *Counter;
  706. LastSymbol = ThisSymbol;
  707. }
  708. }
  709. }
  710. }
  711. if ( CountAtSymbol ) {
  712. n= sprintf(Line,"%d,%s,%S\n",
  713. CountAtSymbol,
  714. ProfileObject[i].ImageName,
  715. &LastSymbol.Name
  716. );
  717. RtlpWriteProfileLine(ProfileHandle,Line,n);
  718. }
  719. }
  720. for (i = 0; i < NumberOfProfileObjects; i++) {
  721. Buffer = ProfileObject[i].Buffer;
  722. RtlZeroMemory(Buffer,ProfileObject[i].BufferSize);
  723. }
  724. NtClose(ProfileHandle);
  725. return Status;
  726. }