Windows NT 4.0 source code leak
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.

561 lines
16 KiB

4 years ago
  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: profile.c
  7. //
  8. // Contents: PROFILER code
  9. //
  10. // History: 22-Nov-93 SethuR created
  11. //
  12. // Notes:
  13. //
  14. //--------------------------------------------------------------------------
  15. // #include <ctype.h>
  16. // #include <sys\types.h>
  17. // #include <sys\stat.h>
  18. // #include "ntsdp.h"
  19. #include <profile.h>
  20. #define MAX_STACK_HEIGHT 2000
  21. #define INVOCATIONS_TO_PRINT 0
  22. // Stack element used by wt profiling
  23. typedef struct _SStackElement
  24. {
  25. unsigned char Symbol[MAX_SYMBOL_LEN];
  26. unsigned long cInstructions;
  27. unsigned long cLevel;
  28. } SStackElement;
  29. typedef SStackElement *PSStackElement;
  30. PSStackElement CallStack;
  31. LONG iStackDepth = -1;
  32. PSProfile ps_ProfileDLL;
  33. PSProfile ps_ProfileTrace;
  34. BOOLEAN fProfilingDLL;
  35. //-----------------------------------------------------------------
  36. //
  37. // Function: InitProfile
  38. //
  39. // Purpose: Initializes the data structure for Profiling.
  40. // The profiling data structure uses a hash table
  41. // to determine where to search/put new entries in
  42. // the entries table.
  43. //
  44. // Input: Profile - pointer to profiler data structure
  45. //
  46. // Output: None
  47. //
  48. //------------------------------------------------------------------
  49. void InitProfile(PSProfile Profile)
  50. {
  51. // Set all the entries in the profiler hash table to NULL
  52. int i;
  53. if (!CallStack) {
  54. CallStack = calloc(MAX_STACK_HEIGHT, sizeof(SStackElement));
  55. ps_ProfileDLL = calloc(1, sizeof(SProfile));
  56. ps_ProfileTrace = calloc(1, sizeof(SProfile));
  57. } else {
  58. for (i = 0;i < MAX_NUM_OF_BUCKETS;i++) {
  59. Profile->Buckets[i] = NULL;
  60. }
  61. // Set the used count
  62. Profile->cUsed = 0;
  63. }
  64. }
  65. //-----------------------------------------------------------------
  66. //
  67. // Function: AllocProfilerEntry
  68. //
  69. // Purpose: Allocates and initialized an entry in the profiler's
  70. // entry table.
  71. //
  72. // Input: Profile - pointer to the profiling data structure
  73. //
  74. // Output: SProfileRecord * - pointer to the new entry in the
  75. // profiler's entry table if one can
  76. // be allocated. Otherwise, NULL is
  77. // returned.
  78. //
  79. //------------------------------------------------------------------
  80. SProfileRecord *AllocProfilerEntry(SProfile *Profile)
  81. {
  82. if (Profile->cUsed < MAX_PROFILE_ENTRIES)
  83. {
  84. SProfileRecord *pRecord = &(Profile->ProfileRecords[Profile->cUsed]);
  85. pRecord->pNext = NULL;
  86. Profile->cUsed++;
  87. // Initialize the record ...
  88. pRecord->cInvocations = 0;
  89. pRecord->cMaxInstructions = 0;
  90. pRecord->cMinInstructions = 0;
  91. pRecord->cCumInstructions = 0;
  92. return (pRecord);
  93. }
  94. else
  95. {
  96. // We need to assert the fact that the statically allocated pool
  97. // has been overrun.
  98. dprintf("Profile Allocation size exceeded, Report to SethuR\n");
  99. return NULL;
  100. }
  101. }
  102. //-----------------------------------------------------------------
  103. //
  104. // Function: SearchStructure
  105. //
  106. // Purpose: Searches the profiler data struture for the function
  107. // name.
  108. //
  109. // Input: Profile - pointer to profiler data structure
  110. // Symbol - pointer to name to search for
  111. //
  112. // Output: SProfileRecord - pointer to the entry that contains
  113. // the name, Symbol, if found. Otherwise
  114. // NULL is returned.
  115. //
  116. //------------------------------------------------------------------
  117. SProfileRecord * SearchStructure (SProfile *Profile, UCHAR *Symbol)
  118. {
  119. unsigned long cHashNumber;
  120. unsigned long iBucket;
  121. SProfileRecord *pProfileRecord;
  122. // Hash on the first + last letters of the symbol
  123. cHashNumber = (unsigned long)Symbol[0] + (unsigned long)Symbol[strlen(Symbol)-1];
  124. iBucket = HASH(cHashNumber);
  125. // Search the bucket for the corresponding entry
  126. pProfileRecord = Profile->Buckets[iBucket];
  127. while (pProfileRecord != NULL)
  128. {
  129. if (!strcmp(pProfileRecord->Symbol, Symbol))
  130. break;
  131. else
  132. pProfileRecord = pProfileRecord->pNext;
  133. }
  134. return (pProfileRecord);
  135. }
  136. //-----------------------------------------------------------------
  137. //
  138. // Function: UpdateProfile
  139. //
  140. // Purpose: Searches the profiler data structure for the name,
  141. // Symbol. If one is found, the information in the
  142. // corresponding entry is updated. Otherwise, a new
  143. // entry is allocated and the information saved.
  144. //
  145. // For wt profiling, cValue contains the instruction
  146. // count for the function. For function profiling,
  147. // cValue contains the breakpoint number of the function.
  148. //
  149. // Input: Profile - pointer to profiling data structure
  150. // Symbol - function name
  151. // cValue - value to update
  152. //
  153. // Output: None
  154. //
  155. //------------------------------------------------------------------
  156. void
  157. UpdateProfile(
  158. PSProfile *pProfile,
  159. unsigned char Symbol[],
  160. unsigned long cValue
  161. )
  162. {
  163. unsigned long iBucket;
  164. SProfileRecord *pProfileRecord;
  165. unsigned long cHashNumber;
  166. PSProfile Profile;
  167. // Initialize the Profiler if not initialized already
  168. if (!*pProfile) {
  169. InitProfile(*pProfile);
  170. }
  171. Profile = *pProfile;
  172. // Search data structure
  173. pProfileRecord = SearchStructure (Profile, Symbol);
  174. // If the search was unsuccessful record the new call Site.
  175. if (pProfileRecord == NULL)
  176. {
  177. pProfileRecord = AllocProfilerEntry(Profile);
  178. // Hash on the first + last letters of the symbol
  179. cHashNumber = (unsigned long)Symbol[0] + (unsigned long)Symbol[strlen(Symbol)-1];
  180. iBucket = HASH(cHashNumber);
  181. if (pProfileRecord != NULL)
  182. {
  183. pProfileRecord->pNext = Profile->Buckets[iBucket];
  184. strcpy (pProfileRecord->Symbol, Symbol);
  185. if (PROFILING)
  186. {
  187. pProfileRecord->cInvocations = 0;
  188. pProfileRecord->cBrkptType = BRKPT_PROFILE;
  189. pProfileRecord->cBrkptNo = cValue;
  190. }
  191. else
  192. {
  193. pProfileRecord->cInvocations = 1;
  194. pProfileRecord->cMinInstructions = cValue;
  195. pProfileRecord->cMaxInstructions = cValue;
  196. pProfileRecord->cCumInstructions = cValue;
  197. }
  198. Profile->Buckets[iBucket] = pProfileRecord;
  199. }
  200. }
  201. else
  202. {
  203. // Augment the invocation count.
  204. pProfileRecord->cInvocations++;
  205. if (!PROFILING)
  206. {
  207. if (pProfileRecord->cMinInstructions > cValue)
  208. pProfileRecord->cMinInstructions = cValue;
  209. if (pProfileRecord->cMaxInstructions < cValue)
  210. pProfileRecord->cMaxInstructions = cValue;
  211. pProfileRecord->cCumInstructions += cValue;
  212. }
  213. }
  214. }
  215. //-----------------------------------------------------------------
  216. //
  217. // Function: DumpProfile
  218. //
  219. // Purpose: Display the information in the profiler data structure.
  220. //
  221. // Input: Profile - pointer to profiler data structure
  222. //
  223. // Output: None
  224. //
  225. //------------------------------------------------------------------
  226. void
  227. DumpProfile(
  228. SProfile *Profile
  229. )
  230. {
  231. unsigned long i;
  232. if (!PROFILING)
  233. dprintf ("\n\n%-30.30s Invocations MinInstr MaxInstr AvgInstr\n\n", "Function Name");
  234. else
  235. dprintf ("\n\n%-60.60s Invocations\n\n", "FunctionName");
  236. for (i = 0; i < Profile->cUsed; i++)
  237. {
  238. if (Profile->ProfileRecords[i].cInvocations > INVOCATIONS_TO_PRINT)
  239. {
  240. if (!PROFILING )
  241. {
  242. dprintf("%-30.30s %8d %8d %8d %8d\n",
  243. Profile->ProfileRecords[i].Symbol,
  244. Profile->ProfileRecords[i].cInvocations,
  245. Profile->ProfileRecords[i].cMinInstructions,
  246. Profile->ProfileRecords[i].cMaxInstructions,
  247. ( Profile->ProfileRecords[i].cCumInstructions /
  248. Profile->ProfileRecords[i].cInvocations));
  249. }
  250. else
  251. {
  252. dprintf("%-60.60s %8d\n", Profile->ProfileRecords[i].Symbol,
  253. Profile->ProfileRecords[i].cInvocations);
  254. }
  255. }
  256. Profile->ProfileRecords[i].cInvocations = 0;
  257. Profile->ProfileRecords[i].pNext = &(Profile->ProfileRecords[i+1]);
  258. }
  259. }
  260. //-----------------------------------------------------------------
  261. //
  262. // Function: Profile
  263. //
  264. // Purpose: Used by wt profiling to keep track of trace information.
  265. // A stack is used to keep track of the call tree. The
  266. // function invocation count is incremented only when
  267. // the function is removed from the stack. A function
  268. // is removed from the stack when another function of
  269. // a lower level is reached.
  270. //
  271. // Input: Profile - pointer to profiling data structure
  272. // Symbol - function name to store in profiler data structure.
  273. // cInstructions - instructions executed by the function
  274. // cLevel - level in the call tree
  275. //
  276. // Output: None
  277. //
  278. //------------------------------------------------------------------
  279. void
  280. Profile(
  281. PSProfile *pProfile,
  282. unsigned char *Symbol,
  283. unsigned long cInstructions,
  284. unsigned long cLevel
  285. )
  286. {
  287. long cNewLevel = -1;
  288. PSProfile Profile;
  289. if (!*pProfile) {
  290. InitProfile(*pProfile);
  291. }
  292. Profile = *pProfile;
  293. if (iStackDepth == -1)
  294. {
  295. iStackDepth = 0;
  296. cNewLevel = 0;
  297. }
  298. else
  299. {
  300. // See if this is a lower level function than the current function on
  301. // the stack. If so, pop the stack until at the same level
  302. if (CallStack[iStackDepth].cLevel > cLevel)
  303. {
  304. for ( ; CallStack[iStackDepth].cLevel > cLevel; iStackDepth -= 1)
  305. {
  306. UpdateProfile(pProfile,
  307. CallStack[iStackDepth].Symbol,
  308. CallStack[iStackDepth].cInstructions);
  309. CallStack[iStackDepth-1].cInstructions += CallStack[iStackDepth].cInstructions;
  310. }
  311. }
  312. if (CallStack[iStackDepth].cLevel == cLevel)
  313. {
  314. if (!strcmp(CallStack[iStackDepth].Symbol, Symbol))
  315. {
  316. // Function hasn't finished executing
  317. CallStack[iStackDepth].cInstructions += cInstructions;
  318. }
  319. else
  320. {
  321. // Function finished executing. Save info in Profile
  322. UpdateProfile(pProfile,
  323. CallStack[iStackDepth].Symbol,
  324. CallStack[iStackDepth].cInstructions);
  325. CallStack[iStackDepth-1].cInstructions += CallStack[iStackDepth].cInstructions;
  326. cNewLevel = iStackDepth;
  327. }
  328. }
  329. else if (CallStack[iStackDepth].cLevel < cLevel)
  330. {
  331. // New symbol at higher level
  332. iStackDepth++;
  333. cNewLevel = iStackDepth;
  334. }
  335. }
  336. if (cNewLevel != -1)
  337. {
  338. // Initialize the new stack element
  339. strcpy(CallStack[cNewLevel].Symbol , Symbol);
  340. CallStack[cNewLevel].cInstructions = cInstructions;
  341. CallStack[cNewLevel].cLevel = cLevel;
  342. }
  343. }
  344. //-----------------------------------------------------------------
  345. //
  346. // Function: ProcDump
  347. //
  348. // Purpose: Called by wt profiling to dump out the information in
  349. // profiling data structre. The stack is cleared of
  350. // functions.
  351. //
  352. // Input: Profile - pointer to profiler data structure
  353. //
  354. // Output: None
  355. //
  356. //------------------------------------------------------------------
  357. void ProcDump (PSProfile *Profile )
  358. {
  359. // Clear the stack of any symbols
  360. for ( ; iStackDepth >= 0; iStackDepth -= 1)
  361. {
  362. UpdateProfile(Profile,
  363. CallStack[iStackDepth].Symbol,
  364. CallStack[iStackDepth].cInstructions);
  365. if (iStackDepth != 0)
  366. {
  367. CallStack[iStackDepth-1].cInstructions += CallStack[iStackDepth].cInstructions;
  368. }
  369. }
  370. DumpProfile (*Profile);
  371. InitProfile (*Profile);
  372. }
  373. //-----------------------------------------------------------------
  374. //
  375. // Function: UpdateBrkpt
  376. //
  377. // Purpose: Update the type of breakpoint to BrkptType.
  378. //
  379. // Input: Profile - pointer to profiling data structure
  380. // BrkptNo - break point number to update
  381. // BrkptType - break point type to update breakpoint to
  382. //
  383. // Output: BOOLEAN - TRUE for successful update
  384. // FALSE for breakpoint breakpoint number not found.
  385. //
  386. //------------------------------------------------------------------
  387. BOOLEAN UpdateBrkpt (SProfile *Profile, ULONG BrkptNo, ULONG BrkptType)
  388. {
  389. ULONG i;
  390. if (Profile == NULL)
  391. {
  392. return (FALSE);
  393. }
  394. //Search data structure for the breakpoint
  395. for (i = 0; i < Profile->cUsed; i ++)
  396. {
  397. if (Profile->ProfileRecords[i].cBrkptNo == BrkptNo)
  398. {
  399. Profile->ProfileRecords[i].cBrkptType = BrkptType;
  400. return (TRUE);
  401. }
  402. }
  403. return (FALSE);
  404. }
  405. //-----------------------------------------------------------------
  406. //
  407. // Function: GetBrkptType
  408. //
  409. // Purpose: Get the type of breakpoint.
  410. //
  411. // Input: Profile - pointer to profiling data structure
  412. // BrkptNo - break point number to look at
  413. //
  414. // Output: BRKPT_PROFILE - breakpoint is a profiling breakpoint
  415. // BRKPT_USER - brkpt is profiling breakpoint but
  416. // it is currently set manually by user.
  417. // BRKPT_NOT_FOUND - brkpt is not a profiling breakpoint
  418. //
  419. //------------------------------------------------------------------
  420. LONG GetBrkptType (SProfile *Profile, ULONG BrkptNo)
  421. {
  422. ULONG i;
  423. for (i = 0; i < Profile->cUsed; i++)
  424. {
  425. if (Profile->ProfileRecords[i].cBrkptNo == BrkptNo)
  426. {
  427. return (Profile->ProfileRecords[i].cBrkptType);
  428. }
  429. }
  430. return (BRKPT_NOT_FOUND);
  431. }
  432. //-----------------------------------------------------------------
  433. //
  434. // Function: fnStartProfilingDLL
  435. //
  436. // Purpose: Set up the breakpoints for profiling. The parseExamine()
  437. // routine is called to find the list of brkpts corresponding
  438. // to the user request. Breakpoints are set as each
  439. // function is found in parseExamine().
  440. //
  441. // Input: Profile - pointer to profiling data structure
  442. //
  443. // Output: TRUE - successful
  444. // FALSE - unsuccessful - function name not entered
  445. //
  446. //------------------------------------------------------------------
  447. BOOLEAN fnStartProfilingDLL (PSProfile *Profile)
  448. {
  449. UCHAR ch;
  450. UCHAR chDLL[50];
  451. // Get the DLL name entered
  452. ch = PeekChar();
  453. if (ch == '\0')
  454. {
  455. dprintf ("A DLL name must be entered with this command.\n");
  456. return (FALSE);
  457. }
  458. // set command to invoke the 'x' functionality
  459. strcpy (chDLL, pchCommand);
  460. pchCommand = &chCommand[0];
  461. strcpy (pchCommand, chDLL);
  462. // call function to parse the 'x' command
  463. parseExamine();
  464. return (TRUE);
  465. }
  466. //-----------------------------------------------------------------
  467. //
  468. // Function: fnStopProfilingDLL
  469. //
  470. // Purpose: Stops profiling functions. Clears all profiling
  471. // breakpoints that are not being used by the user.
  472. // The data in profiling data structure is dumped out.
  473. //
  474. // Input: Profile - pointer to profiling data structure
  475. //
  476. // Output: None
  477. //
  478. //------------------------------------------------------------------
  479. void fnStopProfilingDLL (PSProfile *Profile)
  480. {
  481. ULONG cEntries;
  482. // clear all breakpoints set for profiling
  483. for (cEntries = 0; cEntries < (*Profile)->cUsed; cEntries++)
  484. {
  485. if ((*Profile)->ProfileRecords[cEntries].cBrkptType == BRKPT_PROFILE)
  486. fnChangeBpState ((*Profile)->ProfileRecords[cEntries].cBrkptNo, 'c');
  487. }
  488. DumpProfile(*Profile);
  489. InitProfile(*Profile);
  490. }