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.

1804 lines
45 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. order.c
  5. Abstract:
  6. This module contains the order tool which reads a call graph output
  7. by the linker and the performance data from the kernel profile and
  8. produces a .prf file subsequent input to the linker.
  9. Author:
  10. David N. Cutler (davec) 24-Feb-1995
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. #include "stdlib.h"
  16. #include "stdio.h"
  17. #include "string.h"
  18. #include "nt.h"
  19. #include "ntrtl.h"
  20. #include "nturtl.h"
  21. //
  22. // Define maximum values for table sizes.
  23. //
  24. #define MAXIMUM_CALLED 75 // maximum number of called functions
  25. #define MAXIMUM_FUNCTION 5000 // maximum number of program functions
  26. #define MAXIMUM_TOKEN 100 // maximum character in input token
  27. #define MAXIMUM_SECTION 20 // maximum number of allocation sections
  28. #define MAXIMUM_SYNONYM 10 // maximum number of synonym symbols
  29. //
  30. // Define file numbers.
  31. //
  32. #define CALLTREE_FILE 0 // call tree file produced by linker
  33. #define PROFILE_FILE 1 // profile file produced by kernprof
  34. #define ORDER_FILE 2 // order file produced by this program
  35. //
  36. // Define back edge node sttucture.
  37. //
  38. // Back edge nodes are used to represent back edges in the call graph and
  39. // are constructed after the function list has been defined.
  40. //
  41. //
  42. typedef struct _BACK_EDGE_NODE {
  43. LIST_ENTRY Entry;
  44. struct _FUNCTION_NODE *Node;
  45. } BACK_EDGE_NODE, *PBACK_EDGE_NODE;
  46. //
  47. // Define called node structure.
  48. //
  49. // Called nodes are used to represent forward edges in the call graph and
  50. // are constructed when the function list is being defined.
  51. //
  52. #define REFERENCE_NODE 0 // called entry is reference to node
  53. #define REFERENCE_NAME 1 // called entry is reference to name
  54. struct _FUNCTION_NODE;
  55. typedef struct _CALLED_NODE {
  56. union {
  57. struct _FUNCTION_NODE *Node;
  58. PCHAR Name;
  59. } u;
  60. ULONG Type;
  61. } CALLED_NODE, *PCALLED_NODE;
  62. //
  63. // Define section node structure.
  64. //
  65. // Section nodes collect allocation information and contain the list of
  66. // function nodes in the section.
  67. //
  68. typedef struct _SECTION_NODE {
  69. LIST_ENTRY SectionListHead;
  70. LIST_ENTRY OrderListHead;
  71. PCHAR Name;
  72. ULONG Base;
  73. ULONG Size;
  74. ULONG Offset;
  75. ULONG Number;
  76. ULONG Threshold;
  77. } SECTION_NODE, *PSECTION_NODE;
  78. //
  79. // Define symbol node structure.
  80. //
  81. // Symbol nodes are associated with function nodes and store synonym names
  82. // for the functions and their type of allocation.
  83. //
  84. typedef struct _SYMBOL_NODE {
  85. PCHAR Name;
  86. LONG Type;
  87. } SYMBOL_NODE, *PSYMBOL_NODE;
  88. //
  89. // Define function node structure.
  90. //
  91. // Function nodes contain information about a paritcular function and its
  92. // edges in the call graph.
  93. //
  94. typedef struct _FUNCTION_NODE {
  95. SYMBOL_NODE SynonymList[MAXIMUM_SYNONYM];
  96. CALLED_NODE CalledList[MAXIMUM_CALLED];
  97. LIST_ENTRY CallerListHead;
  98. LIST_ENTRY OrderListEntry;
  99. LIST_ENTRY SectionListEntry;
  100. PSECTION_NODE SectionNode;
  101. ULONG NumberSynonyms;
  102. ULONG NumberCalled;
  103. ULONG Rva;
  104. ULONG Size;
  105. ULONG HitCount;
  106. ULONG HitDensity;
  107. ULONG Offset;
  108. ULONG Placed;
  109. ULONG Ordered;
  110. } FUNCTION_NODE, *PFUNCTION_NODE;
  111. //
  112. // Define forward referenced functions.
  113. //
  114. VOID
  115. CheckForConflict (
  116. PFUNCTION_NODE FunctionNode,
  117. PFUNCTION_NODE ConflictNode,
  118. ULONG Depth
  119. );
  120. VOID
  121. DumpInternalTables (
  122. VOID
  123. );
  124. PFUNCTION_NODE
  125. FindHighestDensityFunction (
  126. PFUNCTION_NODE CallerNode
  127. );
  128. LONG
  129. GetNextToken (
  130. IN FILE *InputFile,
  131. OUT PCHAR TokenBuffer
  132. );
  133. PFUNCTION_NODE
  134. LookupFunctionNode (
  135. IN PCHAR Name,
  136. IN ULONG Rva,
  137. IN ULONG Size,
  138. IN LONG Type
  139. );
  140. PSECTION_NODE
  141. LookupSectionNode (
  142. IN PCHAR Name
  143. );
  144. VOID
  145. OrderFunctionList (
  146. VOID
  147. );
  148. ULONG
  149. ParseCallTreeFile (
  150. IN FILE *InputFile
  151. );
  152. ULONG
  153. ParseProfileFile (
  154. IN FILE *InputFile
  155. );
  156. VOID
  157. PlaceCallerList (
  158. IN PFUNCTION_NODE FunctionNode,
  159. IN ULONG Depth
  160. );
  161. VOID
  162. SortFunctionList (
  163. VOID
  164. );
  165. VOID
  166. WriteOrderFile (
  167. IN FILE *OutputFile
  168. );
  169. //
  170. // Define function list data.
  171. //
  172. ULONG NumberFunctions = 0;
  173. PFUNCTION_NODE FunctionList[MAXIMUM_FUNCTION];
  174. //
  175. // Define section list data.
  176. //
  177. ULONG NumberSections = 0;
  178. PSECTION_NODE SectionList[MAXIMUM_SECTION];
  179. //
  180. // Define input and output file name defaults.
  181. //
  182. PCHAR FileName[3] = {"calltree.out", "profile.out", "order.prf"};
  183. //
  184. // Define dump flags.
  185. //
  186. ULONG DumpBackEdges = 0;
  187. ULONG DumpFunctionList = 0;
  188. ULONG DumpGoodnessValue = 0;
  189. ULONG DumpSectionList = 0;
  190. ULONG TraceAllocation = 0;
  191. //
  192. // Define primary cache mask parameter.
  193. //
  194. ULONG CacheMask = 8192 - 1;
  195. ULONG CacheSize = 8192;
  196. VOID
  197. main (
  198. int argc,
  199. char *argv[]
  200. )
  201. /*++
  202. Routine Description:
  203. Arguments:
  204. Return Value:
  205. --*/
  206. {
  207. FILE *InputFile;
  208. ULONG Index;
  209. FILE *OutputFile;
  210. ULONG Shift;
  211. ULONG Status;
  212. PCHAR Switch;
  213. //
  214. // Parse the command parameters.
  215. //
  216. for (Index = 1; Index < (ULONG)argc; Index += 1) {
  217. Switch = argv[Index];
  218. if (*Switch++ == '-') {
  219. if (*Switch == 'b') {
  220. DumpBackEdges = 1;
  221. } else if (*Switch == 'c') {
  222. Switch += 1;
  223. if (sscanf(Switch, "%d", &Shift) != 1) {
  224. fprintf(stderr, "ORDER: Conversion of the shift failed\n");
  225. exit(1);
  226. }
  227. CacheMask = (1024 << Shift) - 1;
  228. CacheSize = (1024 << Shift);
  229. } else if (*Switch == 'f') {
  230. DumpFunctionList = 1;
  231. } else if (*Switch == 'g') {
  232. Switch += 1;
  233. FileName[CALLTREE_FILE] = Switch;
  234. } else if (*Switch == 'k') {
  235. Switch += 1;
  236. FileName[PROFILE_FILE] = Switch;
  237. } else if (*Switch == 's') {
  238. DumpSectionList = 1;
  239. } else if (*Switch == 't') {
  240. TraceAllocation = 1;
  241. } else if (*Switch == 'v') {
  242. DumpGoodnessValue = 1;
  243. } else {
  244. if (*Switch != '?') {
  245. fprintf(stderr, "ORDER: Invalid switch %s\n", argv[Index]);
  246. }
  247. fprintf(stderr, "ORDER: Usage order [switch] [output-file]\n");
  248. fprintf(stderr, " -b = print graph backedges\n");
  249. fprintf(stderr, " -cn = primary cache size 1024*2**n\n");
  250. fprintf(stderr, " -f = print function list\n");
  251. fprintf(stderr, " -gfile = specify graph input file, default calltree.out\n");
  252. fprintf(stderr, " -kfile = specify profile input file, default profile.out\n");
  253. fprintf(stderr, " -s = print section list\n");
  254. fprintf(stderr, " -t = trace allocation\n");
  255. fprintf(stderr, " -v = print graph placement value\n");
  256. fprintf(stderr, " -? - print usage\n");
  257. exit(1);
  258. }
  259. } else {
  260. FileName[ORDER_FILE] = argv[Index];
  261. }
  262. }
  263. //
  264. // Open and parse the call tree file.
  265. //
  266. InputFile = fopen(FileName[CALLTREE_FILE], "r");
  267. if (InputFile == NULL) {
  268. fprintf(stderr,
  269. "ORDER: Open of call tree file %s failed\n",
  270. FileName[CALLTREE_FILE]);
  271. exit(1);
  272. }
  273. Status = ParseCallTreeFile(InputFile);
  274. fclose(InputFile);
  275. if (Status != 0) {
  276. exit(1);
  277. }
  278. //
  279. // Open and parse the profile file.
  280. //
  281. InputFile = fopen(FileName[PROFILE_FILE], "r");
  282. if (InputFile == NULL) {
  283. fprintf(stderr,
  284. "ORDER: Open of profile file %s failed\n",
  285. FileName[PROFILE_FILE]);
  286. exit(1);
  287. }
  288. Status = ParseProfileFile(InputFile);
  289. fclose(InputFile);
  290. if (Status != 0) {
  291. exit(1);
  292. }
  293. //
  294. // Sort the function list and create the section lists.
  295. //
  296. SortFunctionList();
  297. //
  298. // Order function list.
  299. //
  300. OrderFunctionList();
  301. //
  302. // Open the output file and write the ordered function list.
  303. //
  304. OutputFile = fopen(FileName[ORDER_FILE], "w");
  305. if (OutputFile == NULL) {
  306. fprintf(stderr,
  307. "ORDER: Open of order file %s failed\n",
  308. FileName[ORDER_FILE]);
  309. exit(1);
  310. }
  311. WriteOrderFile(OutputFile);
  312. fclose(OutputFile);
  313. if (Status != 0) {
  314. exit(1);
  315. }
  316. //
  317. // Dump internal tables as appropriate.
  318. //
  319. DumpInternalTables();
  320. return;
  321. }
  322. VOID
  323. CheckForConflict (
  324. PFUNCTION_NODE FunctionNode,
  325. PFUNCTION_NODE ConflictNode,
  326. ULONG Depth
  327. )
  328. /*++
  329. Routine Description:
  330. This function checks for an allocation conflict .
  331. Arguments:
  332. FunctionNode - Supplies a pointer to a function node that has been
  333. placed.
  334. ConflictNode - Supplies a pointer to a function node that has not
  335. been placed.
  336. Depth - Supplies the current allocation depth.
  337. Return Value:
  338. None.
  339. --*/
  340. {
  341. ULONG Base;
  342. ULONG Bound;
  343. ULONG Index;
  344. PLIST_ENTRY ListEntry;
  345. PLIST_ENTRY ListHead;
  346. ULONG Offset;
  347. PFUNCTION_NODE PadNode;
  348. PSECTION_NODE SectionNode;
  349. ULONG Wrap;
  350. //
  351. // Compute the cache size truncated offset and bound of the placed
  352. // function.
  353. //
  354. Offset = FunctionNode->Offset & CacheMask;
  355. Bound = Offset + FunctionNode->Size;
  356. SectionNode = FunctionNode->SectionNode;
  357. //
  358. // If the section offset conflicts with the placed function,
  359. // then attempt to allocate a function from the end of the
  360. // section list that will pad the memory allocation so the
  361. // conflict function does not overlap with the placed function.
  362. //
  363. Base = SectionNode->Offset & CacheMask;
  364. Wrap = (Base + ConflictNode->Size) & CacheMask;
  365. while (((Base >= Offset) && (Base < Bound)) ||
  366. ((Base < Offset) && (Wrap >= Bound)) ||
  367. ((Wrap >= Offset) && (Wrap < Base))) {
  368. ListHead = &SectionNode->SectionListHead;
  369. ListEntry = ListHead->Blink;
  370. while (ListEntry != ListHead) {
  371. PadNode = CONTAINING_RECORD(ListEntry,
  372. FUNCTION_NODE,
  373. SectionListEntry);
  374. if ((PadNode->Ordered == 0) &&
  375. (PadNode->SynonymList[0].Type == 'C')) {
  376. PadNode->Ordered = 1;
  377. PadNode->Placed = 1;
  378. InsertTailList(&SectionNode->OrderListHead,
  379. &PadNode->OrderListEntry);
  380. PadNode->Offset = SectionNode->Offset;
  381. SectionNode->Offset += PadNode->Size;
  382. //
  383. // If allocation is being trace, then output the
  384. // allocation and depth information.
  385. //
  386. if (TraceAllocation != 0) {
  387. fprintf(stdout,
  388. "pp %6lx %4lx %-8s",
  389. PadNode->Offset,
  390. PadNode->Size,
  391. SectionNode->Name);
  392. for (Index = 0; Index < Depth; Index += 1) {
  393. fprintf(stdout, " ");
  394. }
  395. fprintf(stdout, "%s\n",
  396. PadNode->SynonymList[0].Name);
  397. }
  398. Base = SectionNode->Offset & CacheMask;
  399. Wrap = (Base + ConflictNode->Size) & CacheMask;
  400. break;
  401. }
  402. ListEntry = ListEntry->Blink;
  403. }
  404. if (ListEntry == ListHead) {
  405. break;
  406. }
  407. }
  408. return;
  409. }
  410. VOID
  411. DumpInternalTables (
  412. VOID
  413. )
  414. /*++
  415. Routine Description:
  416. This function dumps various internal tables.
  417. Arguments:
  418. None.
  419. Return Value:
  420. None.
  421. --*/
  422. {
  423. ULONG Base;
  424. ULONG Bound;
  425. PFUNCTION_NODE CalledNode;
  426. PFUNCTION_NODE CallerNode;
  427. PFUNCTION_NODE FunctionNode;
  428. ULONG Index;
  429. PLIST_ENTRY ListEntry;
  430. PLIST_ENTRY ListHead;
  431. ULONG Loop;
  432. PCHAR Name;
  433. ULONG Number;
  434. ULONG Offset;
  435. PSECTION_NODE SectionNode;
  436. ULONG Sum;
  437. ULONG Total;
  438. ULONG Wrap;
  439. //
  440. // Scan the function list and dump each function entry.
  441. //
  442. if (DumpFunctionList != 0) {
  443. fprintf(stdout, "Dump of function list with attributes\n\n");
  444. for (Index = 0; Index < NumberFunctions; Index += 1) {
  445. //
  446. // Dump the function node.
  447. //
  448. FunctionNode = FunctionList[Index];
  449. fprintf(stdout,
  450. "%7d %-36s %c %-8s %6lx %4lx %7d\n",
  451. FunctionNode->HitDensity,
  452. FunctionNode->SynonymList[0].Name,
  453. FunctionNode->SynonymList[0].Type,
  454. FunctionNode->SectionNode->Name,
  455. FunctionNode->Rva,
  456. FunctionNode->Size,
  457. FunctionNode->HitCount);
  458. //
  459. // Dump the synonym names.
  460. //
  461. for (Loop = 1; Loop < FunctionNode->NumberSynonyms; Loop += 1) {
  462. fprintf(stdout,
  463. " syno: %-34s %c\n",
  464. FunctionNode->SynonymList[Loop].Name,
  465. FunctionNode->SynonymList[Loop].Type);
  466. }
  467. //
  468. // Dump the called references.
  469. //
  470. for (Loop = 0; Loop < FunctionNode->NumberCalled; Loop += 1) {
  471. CalledNode = FunctionNode->CalledList[Loop].u.Node;
  472. Name = CalledNode->SynonymList[0].Name;
  473. fprintf(stdout," calls: %-s\n", Name);
  474. }
  475. }
  476. fprintf(stdout, "\n\n");
  477. }
  478. //
  479. // Scan the function list and dump the back edges of each function
  480. // entry.
  481. //
  482. if (DumpBackEdges != 0) {
  483. fprintf(stdout, "Dump of function list back edges\n\n");
  484. for (Index = 0; Index < NumberFunctions; Index += 1) {
  485. FunctionNode = FunctionList[Index];
  486. fprintf(stdout, "%s\n", FunctionNode->SynonymList[0].Name);
  487. ListHead = &FunctionNode->CallerListHead;
  488. ListEntry = ListHead->Flink;
  489. while (ListEntry != ListHead) {
  490. CallerNode = CONTAINING_RECORD(ListEntry, BACK_EDGE_NODE, Entry)->Node;
  491. fprintf(stdout, " %s\n", CallerNode->SynonymList[0].Name);
  492. ListEntry = ListEntry->Flink;
  493. }
  494. }
  495. fprintf(stdout, "\n\n");
  496. }
  497. //
  498. // Scan the section list and dump each entry.
  499. //
  500. if (DumpSectionList != 0) {
  501. fprintf(stdout, "Dump of section list\n\n");
  502. for (Index = 0; Index < NumberSections; Index += 1) {
  503. SectionNode = SectionList[Index];
  504. fprintf(stdout,
  505. "%-8s %6lx, %6lx, %6lx, %4d %7d\n",
  506. SectionNode->Name,
  507. SectionNode->Base,
  508. SectionNode->Size,
  509. SectionNode->Offset,
  510. SectionNode->Number,
  511. SectionNode->Threshold);
  512. }
  513. fprintf(stdout, "\n\n");
  514. }
  515. //
  516. // Compute the graph goodness value as the summation of the hit
  517. // count of all functions whose allocation does not conflict with
  518. // the functions that call it and whose hit density is great than
  519. // the section threshold.
  520. //
  521. if (DumpGoodnessValue != 0) {
  522. Number = 0;
  523. Sum = 0;
  524. Total = 0;
  525. for (Index = 0; Index < NumberFunctions; Index += 1) {
  526. FunctionNode = FunctionList[Index];
  527. SectionNode = FunctionNode->SectionNode;
  528. Total += FunctionNode->Size;
  529. if ((FunctionNode->HitDensity > SectionNode->Threshold) &&
  530. (FunctionNode->SynonymList[0].Type == 'C')) {
  531. Offset = FunctionNode->Offset & CacheMask;
  532. Bound = (Offset + FunctionNode->Size) & CacheMask;
  533. Sum += FunctionNode->Size;
  534. ListHead = &FunctionNode->CallerListHead;
  535. ListEntry = ListHead->Flink;
  536. while (ListEntry != ListHead) {
  537. CallerNode = CONTAINING_RECORD(ListEntry, BACK_EDGE_NODE, Entry)->Node;
  538. Base = CallerNode->Offset & CacheMask;
  539. Wrap = (Base + CallerNode->Size) & CacheMask;
  540. if ((((Base >= Offset) && (Base < Bound)) ||
  541. ((Base < Offset) && (Wrap >= Bound)) ||
  542. ((Wrap >= Offset) && (Wrap < Base))) &&
  543. (CallerNode != FunctionNode) &&
  544. (CallerNode->HitDensity > SectionNode->Threshold)) {
  545. Number += 1;
  546. fprintf(stdout,
  547. "%-36s %6lx %4lx conflicts with\n %-36s %6lx %4lx\n",
  548. FunctionNode->SynonymList[0].Name,
  549. FunctionNode->Offset,
  550. FunctionNode->Size,
  551. CallerNode->SynonymList[0].Name,
  552. CallerNode->Offset,
  553. CallerNode->Size);
  554. } else {
  555. Sum += CallerNode->Size;
  556. }
  557. ListEntry = ListEntry->Flink;
  558. }
  559. }
  560. }
  561. Sum = Sum * 100 / Total;
  562. fprintf(stdout, "Graph goodness value is %d\n", Sum);
  563. fprintf(stdout, "%d conflicts out of %d functions\n", Number, NumberFunctions);
  564. }
  565. }
  566. PFUNCTION_NODE
  567. FindHighestDensityFunction (
  568. PFUNCTION_NODE CallerNode
  569. )
  570. /*++
  571. Routine Description:
  572. This function finds the function node that has the highest hit density
  573. of all the functions called by the caller node.
  574. Arguments:
  575. CallerNode - Supplies a pointer to a function node whose highest
  576. hit density called function is to be found.
  577. Return Value:
  578. The address of the function node for the highest hit density called
  579. function is returned as the function value.
  580. --*/
  581. {
  582. PFUNCTION_NODE CheckNode;
  583. PFUNCTION_NODE FoundNode;
  584. ULONG Index;
  585. //
  586. // Scan all the functions called by the specified function and
  587. // compute the address of the highest hit density called function.
  588. //
  589. FoundNode = NULL;
  590. for (Index = 0; Index < CallerNode->NumberCalled; Index += 1) {
  591. if (CallerNode->CalledList[Index].Type == REFERENCE_NODE) {
  592. CheckNode = CallerNode->CalledList[Index].u.Node;
  593. if ((FoundNode == NULL) ||
  594. (CheckNode->HitDensity > FoundNode->HitDensity)) {
  595. FoundNode = CheckNode;
  596. }
  597. }
  598. }
  599. return FoundNode;
  600. }
  601. LONG
  602. GetNextToken (
  603. IN FILE *InputFile,
  604. OUT PCHAR TokenBuffer
  605. )
  606. /*++
  607. Routine Description:
  608. This function reads the next token from the specified input file,
  609. copies it to the token buffer, zero terminates the token, and
  610. returns the delimiter character.
  611. Arguments:
  612. InputFile - Supplies a pointer to the input file descripor.
  613. TokenBuffer - Supplies a pointer to the output token buffer.
  614. Return Value:
  615. The token delimiter character is returned as the function value.
  616. --*/
  617. {
  618. CHAR Character;
  619. //
  620. // Read characters from the input stream and copy them to the token
  621. // buffer until an EOF or token delimiter is encountered. Terminate
  622. // the token will a null and return the token delimiter character.
  623. //
  624. do {
  625. Character = fgetc(InputFile);
  626. if ((Character != ' ') &&
  627. (Character != '\t')) {
  628. break;
  629. }
  630. } while(TRUE);
  631. do {
  632. if ((Character == EOF) ||
  633. (Character == ' ') ||
  634. (Character == '\n') ||
  635. (Character == '\t')) {
  636. break;
  637. }
  638. *TokenBuffer++ = Character;
  639. Character = fgetc(InputFile);
  640. } while(TRUE);
  641. *TokenBuffer = '\0';
  642. return Character;
  643. }
  644. PFUNCTION_NODE
  645. LookupFunctionNode (
  646. IN PCHAR Name,
  647. IN ULONG Rva,
  648. IN ULONG Size,
  649. IN LONG Type
  650. )
  651. /*++
  652. Routine Description:
  653. This function searches the function list for a matching entry.
  654. Arguments:
  655. Name - Supplies a pointer to the name of the function.
  656. Rva - Supplies the revlative virtual address of the function.
  657. Size - Supplies the size of the function.
  658. Type - specified the type of the function (0, N, or C).
  659. Return Value:
  660. If a matching entry is found, then the function node address is
  661. returned as the function value. Otherwise, NULL is returned.
  662. --*/
  663. {
  664. ULONG Index;
  665. ULONG Loop;
  666. PFUNCTION_NODE Node;
  667. ULONG Number;
  668. //
  669. // Search the function list for a matching function.
  670. //
  671. for (Index = 0; Index < NumberFunctions; Index += 1) {
  672. Node = FunctionList[Index];
  673. //
  674. // Search the synonym list for the specified function name.
  675. //
  676. for (Loop = 0; Loop < Node->NumberSynonyms; Loop += 1) {
  677. if (strcmp(Name, Node->SynonymList[Loop].Name) == 0) {
  678. if (Type != 0) {
  679. fprintf(stderr,
  680. "ORDER: Warning - duplicate function name %s\n",
  681. Name);
  682. }
  683. return Node;
  684. }
  685. }
  686. //
  687. // If the type is nonzero, then a function definition is being
  688. // looked up and the RVA/size must be checked for a synonym. If
  689. // the RVA and size of the entry are equal to the RVA and size
  690. // of the reference, then the function name is added to the node
  691. // as a synonym.
  692. //
  693. if (Type != 0) {
  694. if ((Node->Rva == Rva) && (Node->Size == Size)) {
  695. Number = Node->NumberSynonyms;
  696. if (Number >= MAXIMUM_SYNONYM) {
  697. fprintf(stderr,
  698. "ORDER: Warning - Too many synonyms %s\n",
  699. Name);
  700. } else {
  701. if (Type == 'C') {
  702. Node->SynonymList[Number].Name = Node->SynonymList[0].Name;
  703. Node->SynonymList[Number].Type = Node->SynonymList[0].Type;
  704. Number = 0;
  705. }
  706. Node->SynonymList[Number].Name = Name;
  707. Node->SynonymList[Number].Type = Type;
  708. Node->NumberSynonyms += 1;
  709. }
  710. return Node;
  711. }
  712. }
  713. }
  714. return NULL;
  715. }
  716. PSECTION_NODE
  717. LookupSectionNode (
  718. IN PCHAR Name
  719. )
  720. /*++
  721. Routine Description:
  722. This function searches the section list for a matching entry.
  723. Arguments:
  724. Name - Supplies a pointer to the name of the section.
  725. Return Value:
  726. If a matching entry is found, then the section node address is
  727. returned as the function value. Otherwise, NULL is returned.
  728. --*/
  729. {
  730. ULONG Index;
  731. PSECTION_NODE SectionNode;
  732. //
  733. // Search the function list for a matching function.
  734. //
  735. for (Index = 0; Index < NumberSections; Index += 1) {
  736. SectionNode = SectionList[Index];
  737. if (strcmp(Name, SectionNode->Name) == 0) {
  738. return SectionNode;
  739. }
  740. }
  741. return NULL;
  742. }
  743. VOID
  744. PlaceCallerList (
  745. IN PFUNCTION_NODE FunctionNode,
  746. ULONG Depth
  747. )
  748. /*++
  749. Routine Description:
  750. This function recursively places all the functions in the caller list
  751. for the specified function.
  752. Arguments:
  753. FunctionNode - Supplies a pointer to a function node.
  754. Depth - Supplies the depth of the function in the caller tree.
  755. Return Value:
  756. None.
  757. --*/
  758. {
  759. PFUNCTION_NODE CallerNode;
  760. ULONG Index;
  761. PLIST_ENTRY ListEntry;
  762. PLIST_ENTRY ListHead;
  763. PFUNCTION_NODE PadNode;
  764. PSECTION_NODE SectionNode;
  765. //
  766. // Scan the caller list and process each function that has not been
  767. // placed.
  768. //
  769. //
  770. Depth += 1;
  771. SectionNode = FunctionNode->SectionNode;
  772. ListHead = &FunctionNode->CallerListHead;
  773. ListEntry = ListHead->Flink;
  774. while (ListHead != ListEntry) {
  775. CallerNode = CONTAINING_RECORD(ListEntry, BACK_EDGE_NODE, Entry)->Node;
  776. //
  777. // If the caller is in the same section, has not been placed, is
  778. // placeable, has a hit density above the section threshold, has
  779. // not been placed, and the current function is the highest density
  780. // called function of the caller, then insert the function in the
  781. // section order list and compute it's offset and bound.
  782. //
  783. if ((SectionNode == CallerNode->SectionNode) &&
  784. (CallerNode->Placed == 0) &&
  785. (CallerNode->Ordered == 0) &&
  786. (CallerNode->SynonymList[0].Type == 'C') &&
  787. (CallerNode->HitDensity > SectionNode->Threshold) &&
  788. (FindHighestDensityFunction(CallerNode) == FunctionNode)) {
  789. CallerNode->Placed = 1;
  790. CallerNode->Ordered = 1;
  791. //
  792. // Resolve any allocation conflict, insert function in the
  793. // section order list, and place the fucntion.
  794. //
  795. CheckForConflict(FunctionNode, CallerNode, Depth);
  796. InsertTailList(&SectionNode->OrderListHead,
  797. &CallerNode->OrderListEntry);
  798. CallerNode->Offset = SectionNode->Offset;
  799. SectionNode->Offset += CallerNode->Size;
  800. //
  801. // If allocation is being trace, then output the allocation and
  802. // depth information.
  803. //
  804. if (TraceAllocation != 0) {
  805. fprintf(stdout,
  806. "%2d %6lx %4lx %-8s",
  807. Depth,
  808. CallerNode->Offset,
  809. CallerNode->Size,
  810. SectionNode->Name);
  811. for (Index = 0; Index < Depth; Index += 1) {
  812. fprintf(stdout, " ");
  813. }
  814. fprintf(stdout, "%s\n",
  815. CallerNode->SynonymList[0].Name);
  816. }
  817. PlaceCallerList(CallerNode, Depth);
  818. }
  819. ListEntry = ListEntry->Flink;
  820. }
  821. return;
  822. }
  823. VOID
  824. OrderFunctionList (
  825. VOID
  826. )
  827. /*++
  828. Routine Description:
  829. This function computes the link order for based on the information
  830. in the function list.
  831. Arguments:
  832. None.
  833. Return Value:
  834. None.
  835. --*/
  836. {
  837. ULONG Base;
  838. ULONG Bound;
  839. PFUNCTION_NODE CallerNode;
  840. FUNCTION_NODE DummyNode;
  841. PFUNCTION_NODE FunctionNode;
  842. ULONG High;
  843. ULONG Index;
  844. ULONG Limit;
  845. PLIST_ENTRY ListEntry;
  846. PLIST_ENTRY ListHead;
  847. ULONG Low;
  848. ULONG Offset;
  849. PFUNCTION_NODE PadNode;
  850. PSECTION_NODE SectionNode;
  851. ULONG Span;
  852. //
  853. // Scan forward through the function list and compute the link order.
  854. //
  855. for (Index = 0; Index < NumberFunctions; Index += 1) {
  856. FunctionNode = FunctionList[Index];
  857. //
  858. // If the function has not been placed, then place the function.
  859. //
  860. if ((FunctionNode->Placed == 0) &&
  861. (FunctionNode->SynonymList[0].Type == 'C')) {
  862. FunctionNode->Ordered = 1;
  863. FunctionNode->Placed = 1;
  864. SectionNode = FunctionNode->SectionNode;
  865. //
  866. // Attempt to find the highest hit density caller than has
  867. // already been placed and compute the total bounds for all
  868. // placed caller functions.
  869. //
  870. Bound = 0;
  871. Offset = CacheMask;
  872. ListHead = &FunctionNode->CallerListHead;
  873. ListEntry = ListHead->Flink;
  874. while (ListEntry != ListHead) {
  875. CallerNode = CONTAINING_RECORD(ListEntry, BACK_EDGE_NODE, Entry)->Node;
  876. if ((SectionNode == CallerNode->SectionNode) &&
  877. (CallerNode->Placed != 0) &&
  878. (CallerNode->Ordered != 0) &&
  879. (CallerNode->SynonymList[0].Type == 'C') &&
  880. (CallerNode->HitDensity > SectionNode->Threshold)) {
  881. Base = CallerNode->Offset & CacheMask;
  882. Limit = Base + CallerNode->Size;
  883. Low = min(Offset, Base);
  884. High = max(Bound, Limit);
  885. Span = High - Low;
  886. if ((Span < CacheSize) &&
  887. ((CacheSize - Span) > FunctionNode->Size)) {
  888. Offset = Low;
  889. Bound = High;
  890. }
  891. }
  892. ListEntry = ListEntry->Flink;
  893. }
  894. //
  895. // If a caller has already been placed and the hit density is
  896. // above the section threshold, then resolve any allocation
  897. // conflict before inserting the function in the section order
  898. // list and placing it in memory.
  899. //
  900. if (Bound != 0) {
  901. Span = Bound - Offset;
  902. if ((Span < CacheSize) &&
  903. ((CacheSize - Span) > FunctionNode->Size)) {
  904. DummyNode.SectionNode = SectionNode;
  905. DummyNode.Offset = Offset;
  906. DummyNode.Size = Span;
  907. CheckForConflict(&DummyNode, FunctionNode, 1);
  908. }
  909. }
  910. InsertTailList(&SectionNode->OrderListHead,
  911. &FunctionNode->OrderListEntry);
  912. FunctionNode->Offset = SectionNode->Offset;
  913. SectionNode->Offset += FunctionNode->Size;
  914. //
  915. // If allocation is being trace, then output the allocation and
  916. // depth information.
  917. //
  918. if (TraceAllocation != 0) {
  919. fprintf(stdout,
  920. "%2d %6lx %4lx %-8s %s\n",
  921. 1,
  922. FunctionNode->Offset,
  923. FunctionNode->Size,
  924. SectionNode->Name,
  925. FunctionNode->SynonymList[0].Name);
  926. }
  927. PlaceCallerList(FunctionNode, 1);
  928. }
  929. }
  930. return;
  931. }
  932. ULONG
  933. ParseCallTreeFile (
  934. IN FILE *InputFile
  935. )
  936. /*++
  937. Routine Description:
  938. This function reads the call tree data and produces the initial call
  939. graph.
  940. Arguments:
  941. InputFile - Supplies a pointer to the input file stream.
  942. Return Value:
  943. A value of zero is returned if the call tree is successfully parsed.
  944. Otherwise, a nonzero value is returned.
  945. --*/
  946. {
  947. PCHAR Buffer;
  948. PFUNCTION_NODE CalledNode;
  949. PBACK_EDGE_NODE CallerNode;
  950. LONG Delimiter;
  951. ULONG HitCount;
  952. ULONG Index;
  953. ULONG Loop;
  954. PCHAR Name;
  955. PFUNCTION_NODE Node;
  956. ULONG Number;
  957. ULONG Rva;
  958. PSECTION_NODE SectionNode;
  959. ULONG Size;
  960. CHAR TokenBuffer[MAXIMUM_TOKEN];
  961. LONG Type;
  962. //
  963. // Process the call tree file.
  964. //
  965. Buffer = &TokenBuffer[0];
  966. do {
  967. //
  968. // Get the relative virtual address of the next function.
  969. //
  970. Delimiter = GetNextToken(InputFile, Buffer);
  971. if (Delimiter == EOF) {
  972. break;
  973. }
  974. if (sscanf(Buffer, "%lx", &Rva) != 1) {
  975. fprintf(stderr, "ORDER: Conversion of the RVA failed\n");
  976. return 1;
  977. }
  978. //
  979. // Get the function type.
  980. //
  981. Delimiter = GetNextToken(InputFile, Buffer);
  982. if (Delimiter == EOF) {
  983. fprintf(stderr, "ORDER: Premature end of file at function type\n");
  984. return 1;
  985. }
  986. Type = *Buffer;
  987. //
  988. // Get the section name.
  989. //
  990. Delimiter = GetNextToken(InputFile, Buffer);
  991. if (Delimiter == EOF) {
  992. fprintf(stderr, "ORDER: Premature end of file at section name\n");
  993. return 1;
  994. }
  995. //
  996. // If the specfied section is not already in the section list, then
  997. // allocate and initialize a new section list entry.
  998. //
  999. SectionNode = LookupSectionNode(Buffer);
  1000. if (SectionNode == NULL) {
  1001. //
  1002. // Allocate a section node and zero.
  1003. //
  1004. if (NumberSections >= MAXIMUM_SECTION) {
  1005. fprintf(stderr, "ORDER: Maximum number of sections exceeded\n");
  1006. return 1;
  1007. }
  1008. SectionNode = (PSECTION_NODE)malloc(sizeof(SECTION_NODE));
  1009. if (SectionNode == NULL) {
  1010. fprintf(stderr, "ORDER: Failed to allocate section node\n");
  1011. return 1;
  1012. }
  1013. memset((PCHAR)SectionNode, 0, sizeof(SECTION_NODE));
  1014. SectionList[NumberSections] = SectionNode;
  1015. NumberSections += 1;
  1016. //
  1017. // Initialize section node.
  1018. //
  1019. InitializeListHead(&SectionNode->OrderListHead);
  1020. InitializeListHead(&SectionNode->SectionListHead);
  1021. Name = (PCHAR)malloc(strlen(Buffer) + 1);
  1022. if (Name == NULL) {
  1023. fprintf(stderr, "ORDER: Failed to allocate section name\n");
  1024. return 1;
  1025. }
  1026. strcpy(Name, Buffer);
  1027. SectionNode->Name = Name;
  1028. }
  1029. //
  1030. // Get the function size.
  1031. //
  1032. Delimiter = GetNextToken(InputFile, Buffer);
  1033. if (Delimiter == EOF) {
  1034. fprintf(stderr, "ORDER: Premature end of file at function size\n");
  1035. return 1;
  1036. }
  1037. if (sscanf(Buffer, "%lx", &Size) != 1) {
  1038. fprintf(stderr, "ORDER: Conversion of the function size failed\n");
  1039. return 1;
  1040. }
  1041. //
  1042. // Get the function name.
  1043. //
  1044. Delimiter = GetNextToken(InputFile, Buffer);
  1045. if (Delimiter == EOF) {
  1046. fprintf(stderr, "ORDER: Premature end of file at function name\n");
  1047. return 1;
  1048. }
  1049. Name = (PCHAR)malloc(strlen(Buffer) + 1);
  1050. if (Name == NULL) {
  1051. fprintf(stderr, "ORDER: Failed to allocate function name\n");
  1052. return 1;
  1053. }
  1054. strcpy(Name, Buffer);
  1055. //
  1056. // If the specified function is not already in the function list,
  1057. // then allocate and initialize a new function list entry.
  1058. //
  1059. Node = LookupFunctionNode(Name, Rva, Size, Type);
  1060. if (Node == NULL) {
  1061. //
  1062. // Allocate a function node and zero.
  1063. //
  1064. if (NumberFunctions >= MAXIMUM_FUNCTION) {
  1065. fprintf(stderr, "ORDER: Maximum number of functions exceeded\n");
  1066. return 1;
  1067. }
  1068. Node = (PFUNCTION_NODE)malloc(sizeof(FUNCTION_NODE));
  1069. if (Node == NULL) {
  1070. fprintf(stderr, "ORDER: Failed to allocate function node\n");
  1071. return 1;
  1072. }
  1073. memset((PCHAR)Node, 0, sizeof(FUNCTION_NODE));
  1074. FunctionList[NumberFunctions] = Node;
  1075. NumberFunctions += 1;
  1076. //
  1077. // Initialize function node.
  1078. //
  1079. InitializeListHead(&Node->CallerListHead);
  1080. Node->SynonymList[0].Name = Name;
  1081. Node->SynonymList[0].Type = Type;
  1082. Node->NumberSynonyms = 1;
  1083. Node->SectionNode = SectionNode;
  1084. //
  1085. // Initialize relative virtual address and function size.
  1086. //
  1087. Node->Rva = Rva;
  1088. if (Size == 0) {
  1089. Size = 4;
  1090. }
  1091. Node->Size = Size;
  1092. }
  1093. //
  1094. // Parse the called forward edges and add them to the current node.
  1095. //
  1096. if (Delimiter != '\n') {
  1097. do {
  1098. //
  1099. // Get next function reference.
  1100. //
  1101. Delimiter = GetNextToken(InputFile, Buffer);
  1102. if (Delimiter == EOF) {
  1103. fprintf(stderr, "ORDER: Premature end of file called scan\n");
  1104. return 1;
  1105. }
  1106. Number = Node->NumberCalled;
  1107. if (Number >= MAXIMUM_CALLED) {
  1108. fprintf(stderr,
  1109. "ORDER: Too many called references %s\n",
  1110. Buffer);
  1111. return 1;
  1112. }
  1113. //
  1114. // Lookup the specified function in the function list. If the
  1115. // specified function is found, then store the address of the
  1116. // function node in the called list. Otherwise, allocate a name
  1117. // buffer, copy the function name to the buffer, and store the
  1118. // address of the name buffer in the called list.
  1119. //
  1120. CalledNode = LookupFunctionNode(Buffer, 0, 0, 0);
  1121. if (CalledNode == NULL) {
  1122. Name = (PCHAR)malloc(strlen(Buffer) + 1);
  1123. if (Name == NULL) {
  1124. fprintf(stderr, "ORDER: Failed to allocate reference name\n");
  1125. return 1;
  1126. }
  1127. strcpy(Name, Buffer);
  1128. Node->CalledList[Number].u.Name = Name;
  1129. Node->CalledList[Number].Type = REFERENCE_NAME;
  1130. } else {
  1131. Node->CalledList[Number].u.Node = CalledNode;
  1132. Node->CalledList[Number].Type = REFERENCE_NODE;
  1133. }
  1134. Node->NumberCalled += 1;
  1135. } while (Delimiter != '\n');
  1136. }
  1137. } while(TRUE);
  1138. //
  1139. // Scan the function table and do the final resolution for all called
  1140. // functions names that were unresolved when the individual functions
  1141. // were defined.
  1142. //
  1143. for (Index = 0; Index < NumberFunctions; Index += 1) {
  1144. Node = FunctionList[Index];
  1145. for (Loop = 0; Loop < Node->NumberCalled; Loop += 1) {
  1146. if (Node->CalledList[Loop].Type == REFERENCE_NAME) {
  1147. CalledNode =
  1148. LookupFunctionNode(Node->CalledList[Loop].u.Name,
  1149. 0,
  1150. 0,
  1151. 0);
  1152. if (CalledNode == NULL) {
  1153. fprintf(stderr,
  1154. "ORDER: Unresolved reference name %s\n",
  1155. Node->CalledList[Loop].u.Name);
  1156. return 1;
  1157. } else {
  1158. Node->CalledList[Loop].Type == REFERENCE_NODE;
  1159. Node->CalledList[Loop].u.Node = CalledNode;
  1160. }
  1161. } else {
  1162. CalledNode = Node->CalledList[Loop].u.Node;
  1163. }
  1164. //
  1165. // Allocate a back edge node and place the node in the caller
  1166. // list of called function.
  1167. //
  1168. CallerNode = (PBACK_EDGE_NODE)malloc(sizeof(BACK_EDGE_NODE));
  1169. if (CallerNode == NULL) {
  1170. fprintf(stderr, "ORDER: Failed to allocate caller node\n");
  1171. return 1;
  1172. }
  1173. CallerNode->Node = Node;
  1174. InsertTailList(&CalledNode->CallerListHead, &CallerNode->Entry);
  1175. }
  1176. }
  1177. return 0;
  1178. }
  1179. ULONG
  1180. ParseProfileFile (
  1181. IN FILE *InputFile
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. This function reads the profile data and computes the hit density
  1186. for each funtion.
  1187. Arguments:
  1188. InputFile - Supplies a pointer to the input file stream.
  1189. Return Value:
  1190. A value of zero is returned if the call tree is successfully parsed.
  1191. Otherwise, a nonzero value is returned.
  1192. --*/
  1193. {
  1194. PCHAR Buffer;
  1195. ULONG HitCount;
  1196. LONG Delimiter;
  1197. PFUNCTION_NODE FunctionNode;
  1198. CHAR TokenBuffer[MAXIMUM_TOKEN];
  1199. //
  1200. // Process the profile file.
  1201. //
  1202. Buffer = &TokenBuffer[0];
  1203. do {
  1204. //
  1205. // Get the bucket hit count.
  1206. //
  1207. Delimiter = GetNextToken(InputFile, Buffer);
  1208. if (Delimiter == EOF) {
  1209. break;
  1210. }
  1211. if (sscanf(Buffer, "%d", &HitCount) != 1) {
  1212. fprintf(stderr, "ORDER: Conversion of bucket hit failed\n");
  1213. return 1;
  1214. }
  1215. //
  1216. // Get the function name.
  1217. //
  1218. Delimiter = GetNextToken(InputFile, Buffer);
  1219. if (Delimiter == EOF) {
  1220. fprintf(stderr, "ORDER: Premature end of file at profile name\n");
  1221. return 1;
  1222. }
  1223. //
  1224. // Lookup the function name in the function table and update the
  1225. // hit count.
  1226. //
  1227. FunctionNode = LookupFunctionNode(Buffer, 0, 0, 0);
  1228. if (FunctionNode == NULL) {
  1229. fprintf(stderr, "ORDER: Warning function name %s undefined\n", Buffer);
  1230. } else {
  1231. FunctionNode->HitCount += HitCount;
  1232. // FunctionNode->HitDensity = FunctionNode->HitCount;
  1233. FunctionNode->HitDensity =
  1234. (FunctionNode->HitCount * 100) / FunctionNode->Size;
  1235. }
  1236. } while (TRUE);
  1237. return 0;
  1238. }
  1239. VOID
  1240. SortFunctionList (
  1241. VOID
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. This function sorts the function list by hit density and creates
  1246. the section list ordered by hit density.
  1247. Arguments:
  1248. None.
  1249. Return Value:
  1250. None.
  1251. --*/
  1252. {
  1253. PFUNCTION_NODE CallerList[MAXIMUM_FUNCTION];
  1254. PFUNCTION_NODE CallerNode;
  1255. PFUNCTION_NODE FunctionNode;
  1256. LONG i;
  1257. LONG j;
  1258. LONG k;
  1259. PSECTION_NODE InitNode;
  1260. PLIST_ENTRY ListEntry;
  1261. PLIST_ENTRY ListHead;
  1262. ULONG NumberCallers;
  1263. PSECTION_NODE SectionNode;
  1264. //
  1265. // All functions that are in the INIT section or cannot be placed are
  1266. // forced to have a hit density of zero.
  1267. //
  1268. InitNode = LookupSectionNode("INIT");
  1269. if (InitNode == NULL) {
  1270. fprintf(stderr, "ORDER: Warning - unable to find INIT section\n");
  1271. }
  1272. for (i = 0; i < (LONG)NumberFunctions; i += 1) {
  1273. FunctionNode = FunctionList[i];
  1274. SectionNode = FunctionNode->SectionNode;
  1275. if ((SectionNode == InitNode) ||
  1276. (FunctionNode->SynonymList[0].Type != 'C')) {
  1277. FunctionNode->HitDensity = 0;
  1278. }
  1279. }
  1280. //
  1281. // Perform a bubble sort on the function list hit density.
  1282. //
  1283. if (NumberFunctions > 1) {
  1284. i = 0;
  1285. do {
  1286. for (j = i; j >= 0; j -= 1) {
  1287. if (FunctionList[j]->HitDensity >= FunctionList[j + 1]->HitDensity) {
  1288. if (FunctionList[j]->HitDensity > FunctionList[j + 1]->HitDensity) {
  1289. break;
  1290. } else if (FunctionList[j]->Size >= FunctionList[j + 1]->Size) {
  1291. break;
  1292. }
  1293. }
  1294. FunctionNode = FunctionList[j];
  1295. FunctionList[j] = FunctionList[j + 1];
  1296. FunctionList[j + 1] = FunctionNode;
  1297. }
  1298. i += 1;
  1299. } while (i < (LONG)(NumberFunctions - 1));
  1300. }
  1301. //
  1302. // Perform a bubble sort on the caller list of each function.
  1303. //
  1304. for (k = 0; k < (LONG)NumberFunctions; k += 1) {
  1305. FunctionNode = FunctionList[i];
  1306. ListHead = &FunctionNode->CallerListHead;
  1307. ListEntry = ListHead->Flink;
  1308. i = 0;
  1309. while (ListEntry != ListHead) {
  1310. CallerList[i] = CONTAINING_RECORD(ListEntry, BACK_EDGE_NODE, Entry)->Node;
  1311. i += 1;
  1312. ListEntry = ListEntry->Flink;
  1313. }
  1314. if (i > 1) {
  1315. NumberCallers = i;
  1316. i = 0;
  1317. do {
  1318. for (j = i; j >= 0; j -= 1) {
  1319. if (CallerList[j]->HitDensity >= CallerList[j + 1]->HitDensity) {
  1320. if (CallerList[j]->HitDensity > CallerList[j + 1]->HitDensity) {
  1321. break;
  1322. } else if (CallerList[j]->Size >= CallerList[j + 1]->Size) {
  1323. break;
  1324. }
  1325. }
  1326. CallerNode = CallerList[j];
  1327. CallerList[j] = CallerList[j + 1];
  1328. CallerList[j + 1] = CallerNode;
  1329. }
  1330. i += 1;
  1331. } while (i < (LONG)(NumberCallers - 1));
  1332. ListEntry = FunctionNode->CallerListHead.Flink;
  1333. for (i = 0; i < (LONG)NumberCallers; i += 1) {
  1334. CONTAINING_RECORD(ListEntry, BACK_EDGE_NODE, Entry)->Node = CallerList[i];
  1335. ListEntry = ListEntry->Flink;
  1336. }
  1337. }
  1338. }
  1339. //
  1340. // Compute the size of each section and create the section lists ordered
  1341. // by hit density.
  1342. //
  1343. for (i = 0; i < (LONG)NumberFunctions; i += 1) {
  1344. FunctionNode = FunctionList[i];
  1345. SectionNode = FunctionNode->SectionNode;
  1346. SectionNode->Size += FunctionNode->Size;
  1347. SectionNode->Number += 1;
  1348. InsertTailList(&SectionNode->SectionListHead,
  1349. &FunctionNode->SectionListEntry);
  1350. }
  1351. //
  1352. // Set the hit density threshold to zero.
  1353. //
  1354. for (i = 0; i < (LONG)NumberSections; i += 1) {
  1355. SectionList[i]->Threshold = 0;
  1356. }
  1357. }
  1358. VOID
  1359. WriteOrderFile (
  1360. IN FILE *OutputFile
  1361. )
  1362. /*++
  1363. Routine Description:
  1364. This function scans the section list and writes the link order file.
  1365. Arguments:
  1366. None.
  1367. Return Value:
  1368. None.
  1369. --*/
  1370. {
  1371. ULONG Index;
  1372. PFUNCTION_NODE FunctionNode;
  1373. PLIST_ENTRY ListEntry;
  1374. PLIST_ENTRY ListHead;
  1375. PSECTION_NODE SectionNode;
  1376. //
  1377. // Scan the section list and write the link order list.
  1378. //
  1379. for (Index = 0; Index < NumberSections; Index += 1) {
  1380. SectionNode = SectionList[Index];
  1381. ListHead = &SectionNode->OrderListHead;
  1382. ListEntry = ListHead->Flink;
  1383. while (ListHead != ListEntry) {
  1384. FunctionNode = CONTAINING_RECORD(ListEntry,
  1385. FUNCTION_NODE,
  1386. OrderListEntry);
  1387. fprintf(OutputFile, "%s\n", FunctionNode->SynonymList[0].Name);
  1388. ListEntry = ListEntry->Flink;
  1389. }
  1390. }
  1391. return;
  1392. }