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.

1377 lines
41 KiB

  1. /*
  2. * Module Name: WSREDUCE.C
  3. *
  4. * Program: WSREDUCE
  5. *
  6. *
  7. * Description:
  8. *
  9. * Performs data reduction on the function reference data collected
  10. * by WST.DLL. Analyzes the WSP file information, and produces
  11. * a suggested list for the ordering of functions within the tuned
  12. * modules. An ASCII version of the reordered function list is written
  13. * to stdout. In addition, a WSR file for each reduced module is
  14. * produced for subsequent use by WSPDUMP /R.
  15. *
  16. * The reduction algorithm employed by WSREDUCE is described in detail
  17. * in WSINSTR.DOC. Briefly, each function monitored by the working set tuner
  18. * is considered to be a vertex in a graph. There is an edge from vertex
  19. * "A" to vertex "B" if the function reference strings for "A" and "B"
  20. * have any overlapping 1 bits. Likewise, there is an edge from vertex "B"
  21. * to vertex "A". The edges between vertices are weighted depending on
  22. * the relative importance of the ending vertex, and the number of
  23. * overlapping bits between the start and end vertices. The relative
  24. * importance of the end vertices, and the weighted edges between
  25. * vertices, is stored in a decision matrix. A greedy algorithm is run on
  26. * the decision matrix to determine a better ordering for the measured
  27. * functions.
  28. *
  29. *
  30. * Microsoft Confidential
  31. *
  32. * Copyright (c) Microsoft Corporation 1992
  33. *
  34. * All Rights Reserved
  35. *
  36. * Modification History:
  37. *
  38. * Modified for NT June 13, 1992 MarkLea.
  39. * 4-23-98: QFE - Performance unacceptable on high function counts DerrickG (mdg):
  40. * - new WSP file format for large symbol counts (ULONG vs. USHORT)
  41. * - support for long file names (LFN) of input/output files
  42. * - removed buggy reference to WSDIR env. variable
  43. * - removed command-line parsing from wsReduceMain()
  44. * - based .TMI & .WSR file names exclusively on .WSP name for consistency
  45. * - removed limit on symbol name lengths - return allocated name from WsTMIReadRec()
  46. * - removed unused code and symbols
  47. * - Analyzed the code blocked off by OPTIMIZE - it doesn't produce the same
  48. * output as non-OPTIMIZEd code, and is buggy (won't build as is) - removed.
  49. * - Removed multiple module capabilities from code (shell sends one at a time)
  50. * - I addressed memory and performance issues by using a smaller allocation
  51. * for WsDecision (USHORT vs. long), using one value to mark a taken vertex
  52. * (as opposed to half the value space by using -1), and an optional
  53. * progress indicator to reassure users. Modified wsRedScaleWsDecision()
  54. * to maximize the scaled values (using some more float math).
  55. * - Added "pnEdges" and "nEdgeCount" to function structure. If the number
  56. * of set functions is < USHRT_MAX (very likely, even for very large
  57. * projects), allocate as needed a sorted index for WsRedReorder(). This
  58. * cuts dramatically the number of passes through the matrix searching for
  59. * the next edge to consider, and permits some other optimizations. The
  60. * optimized algorithm produces identical results for the important high
  61. * usage high overlap functions, but could diverge in the results for low
  62. * usage (2 or 1 hits) low overlap functions. Differences are not
  63. * significant from a results performance perspective - a better algorithm
  64. * would give marginally better results. The original algorithm is in place
  65. * bracketed with "#ifdef SLOWMO".
  66. *
  67. *
  68. */
  69. #include "wstune.h"
  70. /*
  71. * Function prototypes.
  72. */
  73. VOID wsRedInitialization( VOID );
  74. VOID wsRedInitModules( VOID );
  75. VOID wsRedInitFunctions( VOID );
  76. VOID wsRedSetup( VOID );
  77. VOID wsRedSetWsDecision( VOID );
  78. VOID wsRedScaleWsDecision( VOID );
  79. VOID wsRedWeightWsDecision( VOID );
  80. #ifdef SLOWMO
  81. UINT wsRedChooseEdge( UINT );
  82. #else // SLOWMO
  83. UINT wsRedChooseEdgeOpt( UINT ); // mdg 98/4 Alternate optimized edge chooser
  84. INT __cdecl wsRedChooseEdgeOptCmp ( const UINT *, const UINT * );
  85. BOOL wsRedChooseEdgeOptAlloc( UINT uiIndex );
  86. UINT wsRedChooseEdgeOptNextEdge( UINT uiIndex, BOOL bNoSelectOpt );
  87. #endif // SLOWMO
  88. VOID wsRedReorder( VOID );
  89. VOID wsRedOutput( VOID );
  90. VOID wsRedOpenWSR( FILE **);
  91. VOID wsRedExit( UINT, USHORT, UINT, ULONG, PSZ );
  92. VOID wsRedCleanup(VOID);
  93. /*
  94. * Type definitions and structure declarations.
  95. */
  96. /* Data reduction per module information */
  97. struct wsrmod_s {
  98. FILE *wsrmod_hFileWSR; // module's WSR file pointer
  99. FILE *wsrmod_hFileTMI; // module's TMI file pointer
  100. FILE *wsrmod_hFileWSP; // module's WSP file handle
  101. union {
  102. PCHAR wsrmod_pchModName;// pointer to module base name
  103. PCHAR wsrmod_pchModFile;// pointer to WSP file name
  104. } wsrmod_un;
  105. ULONG wsrmod_ulOffWSP; // offset of first function bitstring
  106. };
  107. typedef struct wsrmod_s wsrmod_t;
  108. /* Data reduction per function information */
  109. struct wsrfxn_s {
  110. PCHAR wsrfxn_pchFxnName; // pointer to function name
  111. ULONG wsrfxn_cbFxn; // Size of function in bytes
  112. BOOL wsrfxn_fCandidate; // Candidate flag
  113. #ifndef SLOWMO
  114. UINT nEdgesLeft; // Count of sorted edges left to consider in WsDecision for this function
  115. UINT nEdgesAlloc; // Number of items allocated in pnEdges
  116. UINT * pnEdges; // Allocated array of sorted edges for this function
  117. #endif // SLOWMO
  118. };
  119. typedef struct wsrfxn_s wsrfxn_t;
  120. /*
  121. * Global variable declaration and initialization.
  122. */
  123. static char *szFileWSP = NULL; // WSP file name
  124. static char *szFileTMI = NULL; // TMI file name
  125. static char *szFileWSR = NULL; // WSR file name
  126. static ULONG rc = NO_ERROR; // Return code
  127. static ULONG ulTmp; // Temp variable for Dos API returns
  128. static UINT cTmiFxns = 0; // Number of functions in tmi file
  129. static UINT cFxnsTot = 0; // Total number of functions
  130. static UINT cSnapsTot = 0; // Total number of snapshots
  131. static UINT cbBitStr = 0; // Number of bytes per fxn bitstring
  132. #ifdef DEBUG
  133. static BOOL fVerbose = FALSE; // Flag for verbose mode
  134. #endif /* DEBUG */
  135. #ifndef TMIFILEHACK
  136. static BOOL fFxnSizePresent = FALSE; // Flag for function size availability
  137. #endif /* !TMIFILEHACK */
  138. static wsrmod_t WsrMod; // Module information
  139. static wsrmod_t *pWsrMod = &WsrMod; // Pointer for legacy use
  140. static wsrfxn_t *WsrFxn; // Pointer to function information
  141. static ULONG *FxnBits; // Pointer to dword of bitstring
  142. static ULONG *FxnOrder; // Pointer to ordered list of
  143. // function ordinals
  144. typedef USHORT WsDecision_t;
  145. #define WSDECISION_TAKEN USHRT_MAX // Reserve highest value for special code
  146. #define WsDecision_MAX (WSDECISION_TAKEN-1) // Use fullest spread for decision matrix
  147. static WsDecision_t **WsDecision; // Decision matrix for data reduction; mdg 98/4 use small alloc for large symbol counts
  148. static ULONG ulRefHi1 = 0; // Highest diagonal value (for WsRedScaleWsDecision)
  149. static ULONG ulRefHi2 = 0; // Second highest diagonal value (for WsRedScaleWsDecision)
  150. static UINT uiSelected = 0; // Highest function ordinal selected (for WsRedReorder)
  151. static UINT cFxnOrder = 0; // Count of ordered functions
  152. #ifndef SLOWMO
  153. static UINT nFxnToSort; // To pass static value to wsRedChooseEdgeOptCmp()
  154. #endif // SLOWMO
  155. static FILE *hFileWLK = NULL; // Handle to file containing ordered
  156. HGLOBAL hMem[10];
  157. ULONG ulFxnIndex; // Index of original TMI order of function.
  158. #ifdef TMR
  159. ULONG pqwTime0[2];
  160. #endif /* TMR */
  161. /*
  162. * Procedure wsReduceMain
  163. *
  164. *
  165. ***
  166. * Effects:
  167. *
  168. * Performs data reduction and analysis on the input modules' function reference
  169. * data.
  170. *
  171. * szBaseName Specifies a module WSP file name
  172. */
  173. BOOL wsReduceMain( CHAR *szBaseName )
  174. {
  175. size_t i;
  176. char * pSlash;
  177. szFileWSP = malloc( i = strlen( szBaseName ) + 5 );
  178. if (szFileWSP) {
  179. szFileWSP = strcat( strcpy(szFileWSP , szBaseName ), ".WSP" );
  180. } else {
  181. exit(1);
  182. }
  183. szFileTMI = malloc( i );
  184. if (szFileTMI) {
  185. szFileTMI = strcat( strcpy( szFileTMI, szBaseName ), ".TMI" );
  186. } else {
  187. free(szFileWSP);
  188. exit(1);
  189. }
  190. #ifdef DEBUG
  191. fVerbose = fDbgVerbose;
  192. #endif // DEBUG
  193. // Create output file in current directory
  194. if (NULL != (pSlash = strrchr( szBaseName, '\\' ))
  195. || NULL != (pSlash = strrchr( szBaseName, '/' ))
  196. || NULL != (pSlash = strrchr( szBaseName, ':' )))
  197. {
  198. ++pSlash;
  199. szFileWSR = malloc(strlen( pSlash ) + 5 );
  200. if (szFileWSR) {
  201. szFileWSR = strcat( strcpy(szFileWSR, pSlash ), ".WSR" );
  202. } else {
  203. free(szFileTMI);
  204. free(szFileWSP);
  205. exit(1);
  206. }
  207. } else {
  208. szFileWSR = malloc( i );
  209. if (szFileWSR) {
  210. szFileWSR = strcat( strcpy( szFileWSR, szBaseName ), ".WSR" );
  211. } else {
  212. free(szFileTMI);
  213. free(szFileWSP);
  214. exit(1);
  215. }
  216. }
  217. #ifdef TMR
  218. DosTmrQueryTime((PQWORD)pqwTime0);
  219. printf("Top of Main, 0x%lx:0x%lx\n", pqwTime0[1], pqwTime0[0]);
  220. #endif /* TMR */
  221. pWsrMod->wsrmod_un.wsrmod_pchModFile = szFileWSP;
  222. #ifdef DEBUG
  223. printf("\t%s\n", pWsrMod->wsrmod_un.wsrmod_pchModFile);
  224. #endif /* DEBUG */
  225. // Initialize module and function information structures.
  226. wsRedInitialization();
  227. // Set up weighted decision matrix.
  228. wsRedSetup();
  229. // Perform the function reference data analysis.
  230. wsRedReorder();
  231. // Output the analysis results.
  232. wsRedOutput();
  233. // Cleanup memory allocations.
  234. wsRedCleanup();
  235. free( szFileWSP );
  236. free( szFileWSR );
  237. free( szFileTMI );
  238. return(NO_ERROR);
  239. }
  240. /*
  241. *
  242. ***LP wsRedInitialization
  243. *
  244. *
  245. * Effects:
  246. * - Calls wsRedInitModules to:
  247. * o Open and validate each module's WSP file.
  248. * o Open and validate each module's TMI file.
  249. * - Calls wsRedInitFunctions to:
  250. * o Set up WsrFxn[] with per function information.
  251. * o Allocate FxnBits[].
  252. * - Allocates WsDecision[][].
  253. * - Allocates and initializes DiagonalFxn[].
  254. *
  255. * Returns:
  256. *
  257. * Void. If an error is encountered, exits through wsRedExit()
  258. * with ERROR.
  259. */
  260. VOID
  261. wsRedInitialization()
  262. {
  263. UINT i; // Loop counter
  264. // Setup module information.
  265. wsRedInitModules();
  266. // Setup function information for each module.
  267. wsRedInitFunctions();
  268. // Allocate the decision matrix, WsDecision[cFxnsTot][cFxnsTot].
  269. WsDecision = (WsDecision_t **) AllocAndLockMem((cFxnsTot * cFxnsTot * sizeof(WsDecision_t)) + (cFxnsTot * sizeof(WsDecision_t *)), &hMem[1]);
  270. if (WsDecision == NULL)
  271. wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  272. (cFxnsTot+1)*cFxnsTot*sizeof(WsDecision_t), "WsDecision[][]");
  273. for (i = 0; i < cFxnsTot; i++)
  274. {
  275. WsDecision[i] = (WsDecision_t *) (WsDecision+cFxnsTot)+(i*cFxnsTot);
  276. }
  277. }
  278. /*
  279. *
  280. ***LP wsRedInitModules
  281. *
  282. *
  283. * Effects:
  284. * - Opens and validates each module's WSP file.
  285. * - Opens and validates each module's TMI file.
  286. *
  287. * Returns:
  288. *
  289. * Void. If an error is encountered, exits through wsRedExit()
  290. * with ERROR.
  291. */
  292. VOID
  293. wsRedInitModules()
  294. {
  295. wsphdr_t WspHdr; // WSP file header
  296. UINT cFxns = 0; // Number of functions for this module
  297. ULONG ulTimeStamp = 0; // Time stamp
  298. ULONG ulTDFID = 0; // TDF Identifier
  299. /* Open module's input WSP file. Read and validate
  300. * WSP file header.
  301. */
  302. rc = WsWSPOpen(pWsrMod->wsrmod_un.wsrmod_pchModFile,
  303. &(pWsrMod->wsrmod_hFileWSP), (PFN) wsRedExit,
  304. &WspHdr, ERROR, PRINT_MSG );
  305. if (NULL == (pWsrMod->wsrmod_un.wsrmod_pchModName = malloc( 1 + WspHdr.wsphdr_dtqo.dtqo_cbPathname )))
  306. wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  307. WspHdr.wsphdr_dtqo.dtqo_cbPathname + 1,
  308. pWsrMod->wsrmod_un.wsrmod_pchModFile);
  309. rc = fread( pWsrMod->wsrmod_un.wsrmod_pchModName, WspHdr.wsphdr_dtqo.dtqo_cbPathname,
  310. 1, pWsrMod->wsrmod_hFileWSP );
  311. if (rc != 1)
  312. wsRedExit(ERROR, PRINT_MSG, MSG_FILE_BAD_HDR, (ULONG)-1L,
  313. pWsrMod->wsrmod_un.wsrmod_pchModFile);
  314. pWsrMod->wsrmod_un.wsrmod_pchModName[WspHdr.wsphdr_dtqo.dtqo_cbPathname] = '\0';
  315. ulTimeStamp = WspHdr.wsphdr_ulTimeStamp;
  316. cSnapsTot = WspHdr.wsphdr_ulSnaps;
  317. cbBitStr = cSnapsTot * sizeof(ULONG);
  318. pWsrMod->wsrmod_ulOffWSP = WspHdr.wsphdr_ulOffBits;
  319. /*
  320. * Open associated TMI file. Assume it lives in same directory.
  321. * Read and validate TMI header. Increment cFxnsTot.
  322. */
  323. cTmiFxns = WsTMIOpen(szFileTMI, &(pWsrMod->wsrmod_hFileTMI),
  324. (PFN) wsRedExit,
  325. 0, (PCHAR)0);
  326. cFxns = WspHdr.wsphdr_dtqo.dtqo_SymCnt;
  327. #ifdef DEBUG
  328. printf("%s file header: # fxns = %ld, TDF ID = 0x%x\n", szFileTMI,
  329. cFxns, (UINT) WspHdr.wsphdr_dtqo.dtqo_usID);
  330. #endif /* DEBUG */
  331. cFxnsTot = cFxns;
  332. // If no function data to analyze, just exit without error.
  333. if (cFxnsTot == 0)
  334. wsRedExit(NO_ERROR, NO_MSG, NO_MSG, 0, NULL);
  335. }
  336. /*
  337. *
  338. ***LP wsRedInitFunctions
  339. *
  340. *
  341. * Effects:
  342. * - Sets up WsrFxn[] with per function information.
  343. * - Allocates FxnBits[].
  344. *
  345. * Returns:
  346. *
  347. * Void. If an error is encountered, exits through wsRedExit()
  348. * with ERROR.
  349. */
  350. VOID
  351. wsRedInitFunctions()
  352. {
  353. UINT uiFxn = 0; // Function number
  354. UINT cFxns = 0; // Number of functions for this module
  355. // Allocate memory for per function info, WsrFxn[cFxnsTot].
  356. WsrFxn = (wsrfxn_t *) AllocAndLockMem(cFxnsTot*sizeof(wsrfxn_t), &hMem[3]);
  357. if (WsrFxn == NULL)
  358. wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  359. cFxnsTot * sizeof(wsrfxn_t), "WsrFxn[]");
  360. WsIndicator( WSINDF_NEW, "Load Functions", cFxnsTot );
  361. // Initialize WsrFxn[cFxnsTot].
  362. uiFxn = 0; // loop index init
  363. cFxns = cFxnsTot; // loop invariant
  364. #ifdef DEBUG
  365. if (fVerbose)
  366. {
  367. printf("Initializing WsrFxn[] for %s:\n\tstart/end fxn indices (%d/%d)\n",
  368. pWsrMod->wsrmod_un.wsrmod_pchModName, uiFxn,
  369. cFxns - 1);
  370. printf("TMI file handle: %ld\n",pWsrMod->wsrmod_hFileTMI);
  371. }
  372. #endif /* DEBUG */
  373. for (; uiFxn < cFxns; uiFxn++)
  374. {
  375. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  376. WsrFxn[uiFxn].wsrfxn_cbFxn =
  377. WsTMIReadRec(&(WsrFxn[uiFxn].wsrfxn_pchFxnName),&ulFxnIndex,&ulTmp,pWsrMod->wsrmod_hFileTMI,
  378. (PFN) wsRedExit, (PCHAR)0);
  379. #ifdef DEBUG
  380. if (fVerbose)
  381. printf("\tWsrFxn[%d] %s\n",
  382. uiFxn, WsrFxn[uiFxn].wsrfxn_pchFxnName );
  383. #endif /* DEBUG */
  384. WsrFxn[uiFxn].wsrfxn_fCandidate = TRUE;
  385. }
  386. // Close TMI file.
  387. fclose(pWsrMod->wsrmod_hFileTMI);
  388. WsIndicator( WSINDF_FINISH, NULL, 0 );
  389. // Allocate space to hold 32 snapshots for each function.
  390. FxnBits = (ULONG *) AllocAndLockMem(cFxnsTot*sizeof(ULONG), &hMem[4]);
  391. if (FxnBits == NULL)
  392. wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  393. cFxnsTot * sizeof(ULONG), "FxnBits[]");
  394. }
  395. /*
  396. *
  397. ***LP wsRedSetup
  398. *
  399. *
  400. * Effects:
  401. *
  402. * Initializes the data structures used to analyze the function
  403. * reference bitstrings, including the weighted decision matrix.
  404. *
  405. * Returns:
  406. *
  407. * Void. If an error is encountered, exits through wsRedExit()
  408. * with ERROR.
  409. */
  410. VOID
  411. wsRedSetup()
  412. {
  413. wsRedSetWsDecision(); // set up initial decision matrix
  414. wsRedScaleWsDecision(); // scale the decision matrix
  415. wsRedWeightWsDecision(); // weight the matrix "edge" entries
  416. }
  417. /*
  418. *
  419. ***LP wsRedSetWsDecision
  420. *
  421. *
  422. * Effects:
  423. *
  424. * Initializes and weights the decision matrix, WsDecision[][].
  425. *
  426. * Returns:
  427. *
  428. * Void. If an error is encountered, exits through wsRedExit()
  429. * with ERROR.
  430. */
  431. VOID
  432. wsRedSetWsDecision()
  433. {
  434. UINT i = 0, j = 0; // Temporary loop indexes
  435. UINT uiFxn = 0; // Function number
  436. UINT uiFBits = 0; // Loop index for bitstring dwords
  437. UINT clFBits = 0; // Count of fxn bitstring dwords
  438. ULONG ulResult = 0; // Returned from procedure call
  439. FILE *hFile; // File handle
  440. /* For each dword of snapshot bitstrings...*/
  441. clFBits = (cbBitStr + sizeof(ULONG) - 1) / sizeof(ULONG);
  442. WsIndicator( WSINDF_NEW, "Fill In Matrix", clFBits * cFxnsTot );
  443. for (uiFBits = 0; uiFBits < clFBits; uiFBits++)
  444. {
  445. ULONG ulOffWSP;
  446. WsIndicator( WSINDF_PROGRESS, "Reading Snaps ", 0 );
  447. // Fill in FxnBits for this snapshot
  448. #ifdef DEBUG
  449. if (fVerbose)
  450. printf( "Setting up FxnBits snapshot %lu for %s\n",
  451. uiFBits, pWsrMod->wsrmod_un.wsrmod_pchModName );
  452. #endif /* DEBUG */
  453. hFile = pWsrMod->wsrmod_hFileWSP;
  454. ulOffWSP = uiFBits + pWsrMod->wsrmod_ulOffWSP;
  455. for ( uiFxn = 0; uiFxn < cFxnsTot; uiFxn++, ulOffWSP += cbBitStr) // Loop functions
  456. {
  457. // Seek to next dword of function's bitstring.
  458. if ((rc = fseek( hFile, ulOffWSP, SEEK_SET )) != NO_ERROR)
  459. wsRedExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET,rc,
  460. pWsrMod->wsrmod_un.wsrmod_pchModName);
  461. // Read next dword of function's bitstring.
  462. rc = fread( &(FxnBits[uiFxn]), sizeof(ULONG), 1, hFile );
  463. if(rc != 1)
  464. wsRedExit(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
  465. pWsrMod->wsrmod_un.wsrmod_pchModName);
  466. } // for each function
  467. WsIndicator( WSINDF_PROGRESS, "Fill In Matrix", 0 );
  468. hFile = pWsrMod->wsrmod_hFileWSP;
  469. #ifdef DEBUG
  470. if (fVerbose)
  471. printf("Setting up WsDecision[][] for %s:\n\tstart/end fxn indices (%d/%d)\n",
  472. pWsrMod->wsrmod_un.wsrmod_pchModName,
  473. uiFxn, cFxnsTot - 1);
  474. #endif /* DEBUG */
  475. /* For each function... */
  476. for ( uiFxn = 0; uiFxn < cFxnsTot; uiFxn++ )
  477. {
  478. WsIndicator( WSINDF_PROGRESS, NULL, (uiFBits * cFxnsTot) + uiFxn );
  479. // Get the current snapshot
  480. ulTmp = FxnBits[uiFxn];
  481. #ifdef DEBUG
  482. if (fVerbose)
  483. printf("\tFxnBits[%d] = 0x%lx\n", uiFxn, ulTmp);
  484. #endif /* DEBUG */
  485. /* If there are bits set... */
  486. if (ulTmp != 0)
  487. {
  488. /* Sum the "on" bits and add the result
  489. * to WsDecision[uiFxn][uiFxn].
  490. */
  491. ulResult = 0;
  492. while (ulTmp)
  493. {
  494. ++ulResult;
  495. ulTmp &= ulTmp - 1;
  496. }
  497. ulTmp = WsDecision[uiFxn][uiFxn] += (WsDecision_t)ulResult;
  498. if (ulTmp > ulRefHi2) // Set the highest two diagonal values on the last pass
  499. if (ulTmp > ulRefHi1)
  500. {
  501. ulRefHi2 = ulRefHi1;
  502. ulRefHi1 = ulTmp;
  503. uiSelected = uiFxn; // Remember highest value's index
  504. }
  505. else
  506. ulRefHi2 = ulTmp;
  507. /* Sum the overlapping "on" bits for this
  508. * function's dword with each preceding
  509. * function's dword, and add the results to
  510. * WsDecision[][].
  511. */
  512. for (i = 0; i < uiFxn; i++)
  513. {
  514. ulTmp = FxnBits[i] & FxnBits[uiFxn];
  515. if (ulTmp) // mdg 98/4
  516. {
  517. ulResult = 0;
  518. while (ulTmp)
  519. {
  520. ++ulResult;
  521. ulTmp &= ulTmp - 1;
  522. }
  523. WsDecision[uiFxn][i] += (WsDecision_t)ulResult;
  524. WsDecision[i][uiFxn] += (WsDecision_t)ulResult;
  525. }
  526. } /* End For each previous function's dword */
  527. } /* End If there are bits set...*/
  528. } /* End For each function... */
  529. } /* End For each dword of bitstrings */
  530. WsIndicator( WSINDF_FINISH, NULL, 0 );
  531. #ifdef DEBUG
  532. if (fVerbose)
  533. {
  534. printf("\nRAW MATRIX:\n");
  535. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  536. {
  537. printf("row %4d:\n", uiFxn);
  538. for (i = 0; i < cFxnsTot; i++)
  539. printf("0x%lx ", (LONG)WsDecision[uiFxn][i]);
  540. printf("\n");
  541. }
  542. }
  543. #endif /* DEBUG */
  544. }
  545. /*
  546. *
  547. ***LP wsRedOpenWSR
  548. *
  549. *
  550. * Effects:
  551. * Opens the output WSR files, one per module. If only one module
  552. * is being reduced, also opens a WLK file, setting the WLK file handle
  553. * as a side effect.
  554. *
  555. *
  556. * Returns:
  557. *
  558. * Void. If an error is encountered, exits through wsRedExit()
  559. * with ERROR.
  560. */
  561. VOID
  562. wsRedOpenWSR(FILE **phFileWLK)
  563. {
  564. /* Close WSP file, and open module output file. */
  565. fclose(pWsrMod->wsrmod_hFileWSP);
  566. if ((pWsrMod->wsrmod_hFileWSR = fopen(szFileWSR, "w"))
  567. == NULL)
  568. {
  569. wsRedExit(ERROR, PRINT_MSG,MSG_FILE_OPEN,rc, szFileWSR);
  570. }
  571. /* We're only analyzing ONE module. Also open a WLK
  572. * file. This file will contain the function names in their
  573. * reordered sequence. The linker will use this file to
  574. * automatically reorder functions. Note that we reuse szFileWSR
  575. * here.
  576. */
  577. strcpy(strstr(szFileWSR, ".WSR"), ".PRF");
  578. if ((*phFileWLK = fopen(szFileWSR, "w")) == NULL)
  579. wsRedExit(ERROR, PRINT_MSG,MSG_FILE_OPEN,rc, szFileWSR);
  580. }
  581. /*
  582. *
  583. ***LP wsRedScaleWsDecision
  584. *
  585. *
  586. * Effects:
  587. *
  588. * If necessary, scales the diagonal values of the matrix to avoid overflow
  589. * during calculations of the weighted edges (below). Sets up DiagonalFxn[]
  590. * as a side effect. Note that we go through gyrations to set
  591. * DiagonalFxn up backwards, so that qsort() will handle ties a little better.
  592. *
  593. * Returns:
  594. *
  595. * Void.
  596. */
  597. VOID
  598. wsRedScaleWsDecision()
  599. {
  600. UINT i = 0, j = 0; // Temporary loop indexes
  601. UINT uiFxn = 0; // Function number
  602. double fTmp; // Temporary float variable
  603. WsDecision_t lTmp;
  604. fTmp = (double)ulRefHi1 * (double)ulRefHi2;
  605. if (fTmp > WsDecision_MAX)
  606. {
  607. // Scale down the diagonal. Don't allow rescaled entries
  608. // to be zero if they were non-zero before scaling.
  609. fTmp /= WsDecision_MAX;
  610. printf("%s %s: WARNING -- Scaling back the reduction matrix by %f.\n",
  611. szProgName, pszVersion, fTmp);
  612. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  613. {
  614. lTmp = WsDecision[uiFxn][uiFxn];
  615. if (lTmp)
  616. {
  617. lTmp = (WsDecision_t)(lTmp / fTmp); // Discard any remainders to avoid potential overflows
  618. if (lTmp == 0)
  619. WsDecision[uiFxn][uiFxn] = 1;
  620. else
  621. WsDecision[uiFxn][uiFxn] = lTmp;
  622. }
  623. }
  624. #ifdef DEBUG
  625. if (fVerbose)
  626. {
  627. printf("\nSCALED MATRIX:\n");
  628. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  629. {
  630. printf("row %4d:\n", uiFxn);
  631. for (i = 0; i < cFxnsTot; i++)
  632. printf("0x%lx ", (LONG)WsDecision[uiFxn][i]);
  633. printf("\n");
  634. }
  635. }
  636. #endif /* DEBUG */
  637. }
  638. #ifdef DEBUG
  639. if (fVerbose)
  640. {
  641. printf("Got ulRefHi1 = %ld, ulRefHi2 = %ld\n",
  642. ulRefHi1, ulRefHi2);
  643. }
  644. #endif /* DEBUG */
  645. }
  646. /*
  647. *
  648. ***LP wsRedWeightWsDecision
  649. *
  650. *
  651. * Effects:
  652. *
  653. * Weights the decision matrix edges from start vertex to end vertex,
  654. * depending on the relative importance of the end vertex.
  655. *
  656. * Returns:
  657. *
  658. * Void.
  659. */
  660. VOID
  661. wsRedWeightWsDecision()
  662. {
  663. UINT i = 0, j = 0; // Temporary loop indexes
  664. UINT uiFxn = 0; // Function number
  665. WsIndicator( WSINDF_NEW, "Weight Matrix ", cFxnsTot );
  666. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  667. {
  668. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  669. for (i = 0; i < cFxnsTot; i++)
  670. {
  671. if (uiFxn == i)
  672. continue;
  673. if (WsDecision[uiFxn][i]) // mdg 98/4
  674. WsDecision[uiFxn][i] *= WsDecision[i][i];
  675. }
  676. }
  677. WsIndicator( WSINDF_FINISH, NULL, 0 );
  678. #ifdef DEBUG
  679. if (fVerbose)
  680. {
  681. printf("\nWEIGHTED MATRIX:\n");
  682. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  683. {
  684. printf("row %4d:\n", uiFxn);
  685. for (i = 0; i < cFxnsTot; i++)
  686. printf("0x%lx ", (LONG)WsDecision[uiFxn][i]);
  687. printf("\n");
  688. }
  689. }
  690. #endif /* DEBUG */
  691. }
  692. /*
  693. *
  694. ***LP wsRedReorder
  695. *
  696. * Requires:
  697. *
  698. * Effects:
  699. *
  700. * A greedy algorithm is used to determine a better ordering for the functions
  701. * whose reference patterns are represented in the decision matrix. The
  702. * algorithm is as follows:
  703. *
  704. * o Select the function whose value on the diagonal is greatest.
  705. * The selected function becomes the current starting vertex,
  706. * and is first on the list of ordered functions. Mark that it
  707. * is no longer a candidate function. Note that this does NOT mean
  708. * that its vertex is removed from the graph.
  709. *
  710. * o While there is more than one function remaining as a candidate:
  711. *
  712. * - Choose the edge of greatest weight leading from the current
  713. * starting vertex. Ties are broken as follows: If one of the
  714. * tied ending vertices is in the selected set and the other is
  715. * not, choose the edge whose ending vertex is already selected
  716. * (because we already know that vertex is "important"); further
  717. * ties are broken by choosing the end vertex whose diagonal value
  718. * is greatest.
  719. *
  720. * - If the ending vertex chosen above is still a candidate (i.e., not
  721. * already selected), then select it for the list of ordered
  722. * functions, and mark that it is no longer a candidate.
  723. *
  724. * - Set the matrix entry for the chosen edge to some invalid value,
  725. * so that edge will never be chosen again.
  726. *
  727. * - Set current starting vertex equal to the ending vertex chosen
  728. * above.
  729. *
  730. * o Select the one remaining function for the list of ordered functions.
  731. *
  732. * mdg 98/4: Added "pnEdges" and "nEdgeCount" to function structure. If the number
  733. * of set functions is < USHRT_MAX (very likely, even for very large
  734. * projects), allocate as needed a sorted index for WsRedReorder(). This
  735. * cuts dramatically the number of passes through the matrix searching for
  736. * the next edge to consider.
  737. *
  738. * Returns:
  739. *
  740. * Void.
  741. */
  742. VOID
  743. wsRedReorder()
  744. {
  745. UINT uiFxn = 0; // Function number
  746. UINT i = 0; // Temporary loop index
  747. UINT cCandidates = 0; // Count of candidates remaining
  748. UINT uiEdge = 0; // Function ordinal edge selected
  749. /* Reuse FxnBits[] for the ordered list of functions, FxnOrder[]. */
  750. WsIndicator( WSINDF_NEW, "Reorder Matrix", cFxnsTot );
  751. FxnOrder = FxnBits;
  752. memset((PVOID) FxnOrder, 0, cFxnsTot * sizeof(ULONG));
  753. cCandidates = cFxnsTot;
  754. FxnOrder[cFxnOrder++] = uiSelected;
  755. WsrFxn[uiSelected].wsrfxn_fCandidate = FALSE;
  756. --cCandidates;
  757. while (cCandidates > 1)
  758. {
  759. WsIndicator( WSINDF_PROGRESS, NULL, cFxnsTot - cCandidates );
  760. /* Follow highest weighted edge from selected vertex. */
  761. #ifdef SLOWMO
  762. uiEdge = wsRedChooseEdge(uiSelected);
  763. #else // SLOWMO
  764. uiEdge = wsRedChooseEdgeOpt( uiSelected );
  765. #endif // SLOWMO
  766. #ifdef DEBUG
  767. if (fVerbose)
  768. printf("choose edge (%d->%d)\n", uiSelected, uiEdge);
  769. #endif
  770. uiSelected = uiEdge;
  771. if (WsrFxn[uiEdge].wsrfxn_fCandidate)
  772. {
  773. FxnOrder[cFxnOrder++] = uiSelected;
  774. WsrFxn[uiSelected].wsrfxn_fCandidate = FALSE;
  775. --cCandidates;
  776. }
  777. }
  778. WsIndicator( WSINDF_FINISH, NULL, 0 );
  779. if (cCandidates == 1)
  780. {
  781. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  782. if (WsrFxn[uiFxn].wsrfxn_fCandidate)
  783. {
  784. FxnOrder[cFxnOrder++] = uiFxn;
  785. break;
  786. }
  787. }
  788. }
  789. #ifdef SLOWMO
  790. /*
  791. *
  792. ***LP wsRedChooseEdge
  793. *
  794. *
  795. * Effects:
  796. *
  797. * "Selects" a function from the candidate pool, based on weighted
  798. * edge from 'index' function to a candidate function.
  799. *
  800. *
  801. *
  802. * Returns:
  803. *
  804. * Ordinal number of selected function.
  805. *
  806. */
  807. UINT
  808. wsRedChooseEdge(UINT uiIndex)
  809. {
  810. UINT uiFxn = 0; // Function ordinal number.
  811. WsDecision_t iMaxWt = WSDECISION_TAKEN; // Highest weighted edge encountered.
  812. UINT uiRet = 0; // Return index.
  813. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  814. {
  815. if (uiFxn == uiIndex
  816. || WsDecision[uiIndex][uiFxn] == WSDECISION_TAKEN)
  817. continue;
  818. if (WsDecision[uiIndex][uiFxn] > iMaxWt
  819. || iMaxWt == WSDECISION_TAKEN )
  820. {
  821. iMaxWt = WsDecision[uiIndex][uiFxn];
  822. uiRet = uiFxn;
  823. }
  824. else if (WsDecision[uiIndex][uiFxn] == iMaxWt)
  825. {
  826. /* Need tiebreak. If 'uiFxn' has already been selected,
  827. * we know it is important, so choose it. Otherwise,
  828. * and in the case where more than one of the tied
  829. * functions has already been selected, choose based
  830. * on the diagonal value.
  831. */
  832. if ((WsrFxn[uiFxn].wsrfxn_fCandidate == FALSE) &&
  833. (WsrFxn[uiRet].wsrfxn_fCandidate))
  834. /* Choose 'uiFxn', it's been selected before */
  835. uiRet = uiFxn;
  836. else
  837. if (WsDecision[uiFxn][uiFxn] > WsDecision[uiRet][uiRet])
  838. uiRet = uiFxn;
  839. }
  840. }
  841. WsDecision[uiIndex][uiRet] = WsDecision[uiRet][uiIndex] = WSDECISION_TAKEN;
  842. return(uiRet);
  843. }
  844. #else // SLOWMO
  845. /*
  846. *
  847. ***LP wsRedChooseEdgeOpt
  848. *
  849. *
  850. * Effects:
  851. *
  852. * "Selects" a function from the candidate pool, based on weighted
  853. * edge from 'index' function to a candidate function. Allocates a sorted
  854. * index (highest to lowest) to each function's edges on demand. Uses the
  855. * current highest value (with a few checks) as the selection. This
  856. * optimized algorithm produces identical results for the important high
  857. * usage high overlap functions, but diverges in the results for low usage
  858. * (2 or 1 hits) low overlap functions. Differences are not significant
  859. * from a performance perspective - a better algorithm would give marginally
  860. * better results.
  861. *
  862. *
  863. *
  864. * Returns:
  865. *
  866. * Ordinal number of selected function.
  867. *
  868. */
  869. UINT
  870. wsRedChooseEdgeOpt(UINT uiIndex)
  871. {
  872. UINT uiRet;
  873. wsrfxn_t * pWsrFxn = &WsrFxn[uiIndex];
  874. // Allocate and sort edges list if it doesn't already exist for this function
  875. if (wsRedChooseEdgeOptAlloc( uiIndex ))
  876. {
  877. wsRedExit( ERROR, PRINT_MSG, MSG_NO_MEM,
  878. (cFxnsTot - 1) * sizeof(*pWsrFxn->pnEdges), "WsrFxn[].pnEdges" );
  879. }
  880. // Check remaining edges
  881. uiRet = wsRedChooseEdgeOptNextEdge( uiIndex, FALSE );
  882. if (uiRet == cFxnsTot)
  883. // What should we do here? The algorithm we're copying falls through
  884. // and arbitrarily returns 0. It seems we should pick the most overlapped
  885. // non-Candidate, or the heaviest Candidate and restart from there.
  886. {
  887. WsDecision_t iMaxWt;
  888. static UINT nFxnOrdStart = 0; // Remember last value to restart there
  889. static UINT nFxnTotStart = 0; // Remember last value to restart there
  890. UINT nSelIndex;
  891. UINT nFxn;
  892. // Search for most overlapped non-Candidate that's not uiIndex ('uiIndex' should be empty by now)
  893. iMaxWt = WSDECISION_TAKEN;
  894. for (nFxn = nFxnOrdStart; nFxn < cFxnOrder; ++nFxn)
  895. {
  896. UINT nLocalIndex = FxnOrder[nFxn];
  897. UINT nRetCheck;
  898. if (!WsrFxn[nLocalIndex].nEdgesLeft)
  899. {
  900. if (nFxnOrdStart == nFxn) // Haven't found available edge yet?
  901. ++nFxnOrdStart; // All non-Candidates already have been allocated, so they can be skipped next time
  902. continue;
  903. }
  904. // Get the first available value remaining
  905. nRetCheck = wsRedChooseEdgeOptNextEdge( nLocalIndex, TRUE );
  906. if (nRetCheck != cFxnsTot
  907. && nRetCheck != uiIndex)
  908. {
  909. // See if this one's heavier
  910. if (WsDecision[nLocalIndex][nRetCheck] > iMaxWt
  911. || iMaxWt == WSDECISION_TAKEN)
  912. {
  913. nSelIndex = nLocalIndex;
  914. iMaxWt = WsDecision[nSelIndex][nRetCheck];
  915. uiRet = nRetCheck;
  916. }
  917. else if (WsDecision[nLocalIndex][nRetCheck] == iMaxWt // On tie, use heaviest function
  918. && WsDecision[nRetCheck][nRetCheck] > WsDecision[uiRet][uiRet]) // Assume uiRet != cFxnsTot by now
  919. {
  920. nSelIndex = nLocalIndex;
  921. uiRet = nRetCheck;
  922. }
  923. }
  924. }
  925. if (uiRet != cFxnsTot) // Found an overlapped non-Candidate?
  926. {
  927. WsDecision[nSelIndex][uiRet] = WsDecision[uiRet][nSelIndex] = WSDECISION_TAKEN;
  928. return uiRet;
  929. }
  930. else // Didn't find an overlapped non-Candidate?
  931. {
  932. // Search for heaviest Candidate - assume at least two are left: see wsRedReorder()
  933. iMaxWt = WSDECISION_TAKEN;
  934. for (nFxn = nFxnTotStart; nFxn < cFxnsTot; ++nFxn)
  935. {
  936. if (!WsrFxn[nFxn].wsrfxn_fCandidate)
  937. {
  938. if (nFxnTotStart == nFxn) // Haven't found unused value yet?
  939. ++nFxnTotStart; // If it's not a candidate now, it won't be again either
  940. continue;
  941. }
  942. if (nFxn == uiIndex)
  943. continue;
  944. if (WsDecision[nFxn][nFxn] > iMaxWt
  945. || iMaxWt == WSDECISION_TAKEN)
  946. {
  947. iMaxWt = WsDecision[nFxn][nFxn];
  948. uiRet = nFxn;
  949. }
  950. }
  951. }
  952. }
  953. WsDecision[uiIndex][uiRet] = WsDecision[uiRet][uiIndex] = WSDECISION_TAKEN;
  954. return uiRet;
  955. }
  956. // Comparison function for qsort - uses external nFxnToSort for static index
  957. INT
  958. __cdecl
  959. wsRedChooseEdgeOptCmp ( const UINT *pn1, const UINT *pn2 )
  960. {
  961. WsDecision_t Val1 = WsDecision[nFxnToSort][*pn1],
  962. Val2 = WsDecision[nFxnToSort][*pn2];
  963. return Val1 > Val2 ? -1 // higher values preferred
  964. : Val1 < Val2 ? 1
  965. // If the same, prefer the highest valued diagonal
  966. : (Val1 = WsDecision[*pn1][*pn1]) > (Val2 = WsDecision[*pn2][*pn2]) ? -1
  967. : Val1 < Val2 ? 1
  968. // Prefer prior function if no other differences
  969. : *pn1 < *pn2 ? -1
  970. : 1;
  971. }
  972. // Allocate and sort edges list for a function if not already allocated
  973. // Return TRUE on failure to allocate, FALSE if successful (even if list is empty)
  974. // Creates sorted index list from all non-zero unused WsDecision entries for this row
  975. // except for the diagonal. Sorts from greatest to lowest: see wsRedChooseEdgeOptCmp().
  976. // If no such entries exist, marks the function edges as allocated, but with none
  977. // left to scan; doesn't actually allocate any memory.
  978. BOOL
  979. wsRedChooseEdgeOptAlloc( UINT uiIndex )
  980. {
  981. wsrfxn_t * pWsrFxn = &WsrFxn[uiIndex];
  982. if (pWsrFxn->nEdgesAlloc == 0
  983. && pWsrFxn->pnEdges == NULL)
  984. {
  985. UINT nEdgeTot, nFxn;
  986. // Allocate maximum size initially
  987. pWsrFxn->pnEdges = malloc( (cFxnsTot - 1) * sizeof(*pWsrFxn->pnEdges) );
  988. if (pWsrFxn->pnEdges == NULL) // No more memory?
  989. return TRUE;
  990. // Fill in array
  991. for (nEdgeTot = nFxn = 0; nFxn < cFxnsTot; ++nFxn)
  992. {
  993. if (nFxn == uiIndex) // Skip diagonal
  994. continue;
  995. if (WsDecision[uiIndex][nFxn] > 0 // Edge still available? No point in considering 0
  996. && WsDecision[uiIndex][nFxn] != WSDECISION_TAKEN)
  997. pWsrFxn->pnEdges[nEdgeTot++] = nFxn;
  998. }
  999. if (nEdgeTot > 0) // Edges available?
  1000. {
  1001. if (nEdgeTot != (cFxnsTot - 1)) // Extra space allocated?
  1002. {
  1003. // Make it smaller
  1004. UINT *pNewAlloc = realloc( pWsrFxn->pnEdges, nEdgeTot * sizeof(*pWsrFxn->pnEdges) );
  1005. if (pNewAlloc != NULL)
  1006. pWsrFxn->pnEdges = pNewAlloc;
  1007. }
  1008. // Fill in remaining structure members
  1009. pWsrFxn->nEdgesAlloc = pWsrFxn->nEdgesLeft = nEdgeTot;
  1010. // Sort highest to lowest
  1011. nFxnToSort = uiIndex; // Set static for sort function
  1012. qsort( pWsrFxn->pnEdges, nEdgeTot, sizeof(*pWsrFxn->pnEdges),
  1013. (int (__cdecl *)(const void *, const void *))wsRedChooseEdgeOptCmp );
  1014. }
  1015. else // pWsrFxn->nEdgesAlloc == NULL
  1016. {
  1017. // Set structure members to indicate nothing left
  1018. pWsrFxn->nEdgesAlloc = 1; // non-zero indicates some allocation happened
  1019. pWsrFxn->nEdgesLeft = 0;
  1020. free( pWsrFxn->pnEdges ); // Eliminate allocation - nothing left to check
  1021. pWsrFxn->pnEdges = NULL;
  1022. }
  1023. }
  1024. return FALSE;
  1025. }
  1026. // Get next edge for given function; highest overlap of most-used function
  1027. // Returns "cFxnsTot" if no edge exists; otherwise the function index of next edge
  1028. // Side-effect: optimizes search for next pass; frees edge index if no longer needed
  1029. // Since choosing an edge marks WsDecision entries as used (WSDECISION_TAKEN), we
  1030. // must step over any of these entries. Once these entries and the first unused entry
  1031. // have been selected, we don't need to consider them anymore. However, if
  1032. // 'bNoSelectOpt' is TRUE, only optimize leading skipped entries (not the selected
  1033. // entry, since it may not be taken).
  1034. UINT
  1035. wsRedChooseEdgeOptNextEdge( UINT uiIndex, BOOL bNoSelectOpt )
  1036. {
  1037. wsrfxn_t * pWsrFxn = &WsrFxn[uiIndex];
  1038. UINT uiRet = cFxnsTot;
  1039. if (pWsrFxn->nEdgesLeft > 0)
  1040. {
  1041. UINT nMaxIx,
  1042. nNextIx = pWsrFxn->nEdgesAlloc - pWsrFxn->nEdgesLeft;
  1043. WsDecision_t iMax, iNext;
  1044. UINT nRetCheck;
  1045. // Get the first available value remaining
  1046. while ((iMax = WsDecision[uiIndex][nRetCheck = pWsrFxn->pnEdges[nMaxIx = nNextIx++]])
  1047. == WSDECISION_TAKEN
  1048. && nNextIx < pWsrFxn->nEdgesAlloc);
  1049. // Check next available value for equivalence
  1050. if (iMax != WSDECISION_TAKEN)
  1051. {
  1052. UINT nMaxIxNext = nMaxIx; // Save index of next used entry
  1053. uiRet = nRetCheck;
  1054. for (; nNextIx < pWsrFxn->nEdgesAlloc; ++nNextIx)
  1055. {
  1056. nRetCheck = pWsrFxn->pnEdges[nNextIx];
  1057. iNext = WsDecision[uiIndex][nRetCheck];
  1058. if (iNext != WSDECISION_TAKEN)
  1059. {
  1060. if (iNext != iMax // only need to check for equality since already sorted
  1061. || !WsrFxn[uiRet].wsrfxn_fCandidate) // Already selected - choose this one
  1062. break;
  1063. else
  1064. {
  1065. /* Need tiebreak. If 'nRetCheck' has already been selected,
  1066. * we know it is important, so choose it. Otherwise,
  1067. * and in the case where more than one of the tied
  1068. * functions have already been selected, choose based
  1069. * on the diagonal value (i.e. keep previous choice since
  1070. * sort already accounts for diagonal if equal vertices).
  1071. */
  1072. if (!WsrFxn[nRetCheck].wsrfxn_fCandidate)
  1073. // Choose 'nRetCheck' - it's been selected before
  1074. {
  1075. uiRet = nRetCheck;
  1076. nMaxIxNext = nMaxIx - 1; // First used entry will be checked again; don't skip it
  1077. }
  1078. }
  1079. }
  1080. else if (nMaxIxNext == (nNextIx - 1)) // Skip unavailable values after first used entry only
  1081. ++nMaxIxNext;
  1082. }
  1083. if (!bNoSelectOpt && nMaxIxNext != nMaxIx)
  1084. nMaxIx = nMaxIxNext; // Skip over first used entry and unused entries after it
  1085. }
  1086. else if (bNoSelectOpt) // This is the last one, so step over it anyway
  1087. ++nMaxIx;
  1088. // Adjust the optimization indexes
  1089. pWsrFxn->nEdgesLeft = pWsrFxn->nEdgesAlloc - nMaxIx - (bNoSelectOpt ? 0 : 1);
  1090. if (pWsrFxn->nEdgesLeft == 0)
  1091. {
  1092. free( pWsrFxn->pnEdges ); // Eliminate allocation - nothing left to check
  1093. pWsrFxn->pnEdges = NULL;
  1094. }
  1095. #ifdef YOUVE_REALLY_GOT_MEMORY_PROBLEMS
  1096. else if (pWsrFxn->nEdgesLeft < pWsrFxn->nEdgesAlloc / 2 // Periodically get rid of some unused memory
  1097. && pWsrFxn->nEdgesLeft > 50)
  1098. {
  1099. // Move edges to lower part of allocation and reallocate
  1100. UINT * pNewAlloc;
  1101. nNextIx = pWsrFxn->nEdgesAlloc - pWsrFxn->nEdgesLeft;
  1102. MoveMemory( pWsrFxn->pnEdges, &pWsrFxn->pnEdges[nNextIx], pWsrFxn->nEdgesLeft * sizeof(*pWsrFxn->pnEdges) );
  1103. pNewAlloc = realloc( pWsrFxn->pnEdges, pWsrFxn->nEdgesLeft * sizeof(*pWsrFxn->pnEdges) );
  1104. if (pNewAlloc != NULL)
  1105. pWsrFxn->pnEdges = pNewAlloc;
  1106. pWsrFxn->nEdgesAlloc = pWsrFxn->nEdgesLeft;
  1107. }
  1108. #endif // YOUVE_REALLY_GOT_MEMORY_PROBLEMS
  1109. }
  1110. return uiRet;
  1111. }
  1112. #endif // SLOWMO
  1113. /*
  1114. *
  1115. ***LP wsRedOutput
  1116. *
  1117. *
  1118. * Effects:
  1119. *
  1120. * Prints the reordered list of functions, and writes each module's
  1121. * ordered list of function ordinals to the module's associated WSR file.
  1122. * If only one module is being processed, then we also write the ordered
  1123. * list of function names to a WLK file.
  1124. *
  1125. * Returns:
  1126. *
  1127. * Void. If an error is encountered, exits through wsRedExit()
  1128. * with ERROR.
  1129. */
  1130. VOID
  1131. wsRedOutput()
  1132. {
  1133. UINT uiFxn;
  1134. UINT uiFxnOrd;
  1135. wsrfxn_t *pWsrFxn;
  1136. // fxn names for linker reordering
  1137. // Open one WSR file per module. If only one module is reduced,
  1138. // then also open a WLK file. Handle to WLK file is set in
  1139. // wsRedOpenWSR().
  1140. wsRedOpenWSR(&hFileWLK);
  1141. WsIndicator( WSINDF_NEW, "Saving Results", cTmiFxns );
  1142. for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
  1143. {
  1144. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  1145. pWsrFxn = &(WsrFxn[uiFxnOrd = FxnOrder[uiFxn]]);
  1146. /* Print the function information. */
  1147. #ifdef DEBUG
  1148. if (fVerbose)
  1149. #ifndef TMIFILEHACK
  1150. if (fFxnSizePresent == FALSE)
  1151. printf(" %s: %s\n",
  1152. pWsrMod->wsrmod_un.wsrmod_pchModName,
  1153. pWsrFxn->wsrfxn_pchFxnName);
  1154. else
  1155. #endif /* !TMIFILEHACK */
  1156. printf(" (0x%08lx bytes) %s: %s\n",
  1157. pWsrFxn->wsrfxn_cbFxn,
  1158. pWsrMod->wsrmod_un.wsrmod_pchModName,
  1159. pWsrFxn->wsrfxn_pchFxnName);
  1160. #endif // DEBUG
  1161. /* Write the function's ordinal number to its
  1162. * module's associated WSR output file.
  1163. */
  1164. fprintf(pWsrMod->wsrmod_hFileWSR, "%ld\n",
  1165. uiFxnOrd);
  1166. /* Write the function name to the WLK file, for linker use. */
  1167. if (hFileWLK != NULL &&
  1168. strcmp("???", pWsrFxn->wsrfxn_pchFxnName) &&
  1169. strcmp("_penter", pWsrFxn->wsrfxn_pchFxnName))
  1170. fprintf(hFileWLK, "%s\n", pWsrFxn->wsrfxn_pchFxnName);
  1171. }
  1172. for (uiFxn = cFxnsTot; uiFxn < cTmiFxns; uiFxn++)
  1173. {
  1174. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  1175. pWsrFxn = &(WsrFxn[FxnOrder[0]]);
  1176. /* Write the function's ordinal number to its
  1177. * module's associated WSR output file.
  1178. */
  1179. fprintf(pWsrMod->wsrmod_hFileWSR, "%ld\n",
  1180. uiFxn);
  1181. }
  1182. /* Close the WSR files. */
  1183. fclose(pWsrMod->wsrmod_hFileWSR);
  1184. pWsrMod->wsrmod_hFileWSR = NULL;
  1185. WsIndicator( WSINDF_FINISH, NULL, 0 );
  1186. }
  1187. /*
  1188. *
  1189. ***LP wsRedExit
  1190. *
  1191. ***
  1192. * Requires:
  1193. *
  1194. *
  1195. ***
  1196. *
  1197. * Effects:
  1198. *
  1199. * Frees up resources (as necessary). Exits with the specified
  1200. * exit code, or returns void if exit code is NOEXIT.
  1201. *
  1202. ***
  1203. * Returns:
  1204. *
  1205. * Void, else exits.
  1206. */
  1207. VOID
  1208. wsRedExit(UINT uiExitCode, USHORT fPrintMsg, UINT uiMsgCode, ULONG ulParam1, PSZ pszParam2)
  1209. {
  1210. /* Print message, if necessary. */
  1211. if (fPrintMsg)
  1212. {
  1213. printf(pchMsg[uiMsgCode], szProgName, pszVersion, ulParam1, pszParam2);
  1214. }
  1215. // Special case: do NOT exit if called with NOEXIT.
  1216. if (uiExitCode == NOEXIT)
  1217. return;
  1218. wsRedCleanup(); // mdg 98/4
  1219. exit(uiExitCode);
  1220. }
  1221. VOID wsRedCleanup(VOID)
  1222. {
  1223. UINT x;
  1224. free( pWsrMod->wsrmod_un.wsrmod_pchModName );
  1225. pWsrMod->wsrmod_un.wsrmod_pchModName = NULL;
  1226. for (x = 0; x < cFxnsTot; x++) {
  1227. free( WsrFxn[x].wsrfxn_pchFxnName );
  1228. WsrFxn[x].wsrfxn_pchFxnName = NULL;
  1229. #ifndef SLOWMO
  1230. if (WsrFxn[x].pnEdges != NULL)
  1231. {
  1232. free( WsrFxn[x].pnEdges );
  1233. WsrFxn[x].pnEdges = NULL;
  1234. }
  1235. #endif // SLOWMO
  1236. }
  1237. for (x=0;x < 5 ; x++ ) {
  1238. UnlockAndFreeMem(hMem[x]);
  1239. }
  1240. /* Close the WLK file. */
  1241. if (NULL != hFileWLK)
  1242. fclose(hFileWLK);
  1243. }