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.

1805 lines
45 KiB

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