mirror of https://github.com/lianthony/NT4.0
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.
1707 lines
41 KiB
1707 lines
41 KiB
/*
|
|
* Module Name: WSREDUCE.C
|
|
*
|
|
* Program: WSREDUCE
|
|
*
|
|
*
|
|
* Description:
|
|
*
|
|
* Performs data reduction on the function reference data collected
|
|
* by WST.DLL. Analyzes the WSP file information, and produces
|
|
* a suggested list for the ordering of functions within the tuned
|
|
* modules. An ASCII version of the reordered function list is written
|
|
* to stdout. In addition, a WSR file for each reduced module is
|
|
* produced for subsequent use by WSPDUMP /R.
|
|
*
|
|
* The reduction algorithm employed by WSREDUCE is described in detail
|
|
* in WSINSTR.DOC. Briefly, each function monitored by the working set tuner
|
|
* is considered to be a vertex in a graph. There is an edge from vertex
|
|
* "A" to vertex "B" if the function reference strings for "A" and "B"
|
|
* have any overlapping 1 bits. Likewise, there is an edge from vertex "B"
|
|
* to vertex "A". The edges between vertices are weighted depending on
|
|
* the relative importance of the ending vertex, and the number of
|
|
* overlapping bits between the start and end vertices. The relative
|
|
* importance of the end vertices, and the weighted edges between
|
|
* vertices, is stored in a decision matrix. A greedy algorithm is run on
|
|
* the decision matrix to determine a better ordering for the measured
|
|
* functions.
|
|
*
|
|
*
|
|
* Microsoft Confidential
|
|
*
|
|
* Copyright (c) Microsoft Corporation 1992
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* Modification History:
|
|
*
|
|
* Modified for NT June 13, 1992 MarkLea.
|
|
*
|
|
*/
|
|
|
|
#include "wstune.h"
|
|
/*
|
|
* Function prototypes.
|
|
*/
|
|
|
|
VOID wsRedUsage( VOID );
|
|
VOID wsRedInitialization( VOID );
|
|
VOID wsRedInitModules( VOID );
|
|
VOID wsRedInitFunctions( VOID );
|
|
VOID wsRedSetup( VOID );
|
|
VOID wsRedSetWsDecision( VOID );
|
|
VOID wsRedScaleWsDecision( VOID );
|
|
VOID wsRedWeightWsDecision( VOID );
|
|
#ifdef OPTIMIZE
|
|
VOID wsRedSortDiagonal( VOID );
|
|
INT wsRedDiagCmp ( INT *, INT * );
|
|
VOID wsRedSetupEdges( VOID );
|
|
VOID wsRedSortEdges( VOID );
|
|
INT wsRedEdgeCmp ( INT *, INT * );
|
|
#else /* !OPTIMIZE */
|
|
UINT wsRedChooseEdge( UINT );
|
|
#endif /* OPTIMIZE */
|
|
VOID wsRedReorder( VOID );
|
|
VOID wsRedOutput( VOID );
|
|
VOID wsRedOpenWSR( FILE **);
|
|
VOID wsRedExit( UINT, USHORT, UINT, ULONG, PSZ );
|
|
VOID wsRedCleanup(VOID);
|
|
VOID wsRedWriteWlk(VOID);
|
|
|
|
/*
|
|
* Type definitions and structure declarations.
|
|
*/
|
|
|
|
/* Data reduction per module information */
|
|
struct wsrmod_s {
|
|
FILE *wsrmod_hFileWSR; // module's WSR file pointer
|
|
FILE *wsrmod_hFileTMI; // module's TMI file pointer
|
|
FILE *wsrmod_hFileWSP; // module's WSP file handle
|
|
union {
|
|
PCHAR wsrmod_pchModName;// pointer to module base name
|
|
PCHAR wsrmod_pchModFile;// pointer to WSP file name
|
|
} wsrmod_un;
|
|
ULONG wsrmod_ulOffWSP; // offset of first function bitstring
|
|
ULONG wsrmod_ulFxn; // module's first fnx index
|
|
ULONG wsrmod_clFxns; // number of functions in this module
|
|
};
|
|
|
|
typedef struct wsrmod_s wsrmod_t;
|
|
|
|
/* Data reduction per function information */
|
|
struct wsrfxn_s {
|
|
ULONG wsrfxn_ulFxnIndex; // original index in symbol table
|
|
ULONG wsrfxn_ulMod; // function's index into module array
|
|
ULONG wsrfxn_ulFxn; // function number within module
|
|
ULONG wsrfxn_ulOffWSP; // offset into WSP file
|
|
PCHAR wsrfxn_pchFxnName; // pointer to function name
|
|
ULONG wsrfxn_cbFxn; // Size of function in bytes
|
|
BOOL wsrfxn_fCandidate; // Candidate flag
|
|
};
|
|
|
|
typedef struct wsrfxn_s wsrfxn_t;
|
|
|
|
|
|
|
|
/*
|
|
* Global variable declaration and initialization.
|
|
*/
|
|
|
|
static CHAR szFileTMI[CCHMAXPATHCOMP]; // TMI file name
|
|
static CHAR *pszVersion = "V2.0"; // Current program version number
|
|
static CHAR szProgName[20]; // Program name (initialized in Main)
|
|
// WSDIR pathname from environment
|
|
static CHAR szWSDIRPath[CCHMAXPATHCOMP] = "";
|
|
|
|
static ULONG rc = NO_ERROR; // Return code
|
|
static ULONG ulTmp; // Temp variable for Dos API returns
|
|
static wsphdr_t WspHdr; // Input WSP file header
|
|
static tmihdr_t TmiHdr; // Input TMI file header
|
|
static tmirec_t TmiRec; // Input TMI file record
|
|
static ULONG cbWritten; // Byte cnt returned from DosWrite
|
|
static ULONG cbRead; // Byte cnt returned from DosRead
|
|
static UINT cModsTot = 0; // Count of modules
|
|
static UINT cTmiFxns = 0; // Number of functions in tmi file
|
|
static UINT cFxnsTot = 0; // Total number of functions
|
|
static UINT cSnapsTot = 0; // Total number of snapshots
|
|
static UINT cbBitStr = 0; // Number of bytes per fxn bitstring
|
|
#ifdef DEBUG
|
|
static BOOL fVerbose = FALSE; // Flag for verbose mode
|
|
#endif /* DEBUG */
|
|
#ifndef TMIFILEHACK
|
|
static BOOL fFxnSizePresent = FALSE; // Flag for function size availability
|
|
#endif /* !TMIFILEHACK */
|
|
|
|
static wsrmod_t *WsrMod; // Pointer to module information
|
|
static wsrfxn_t *WsrFxn; // Pointer to function information
|
|
static ULONG *FxnBits; // Pointer to dword of bitstring
|
|
static ULONG *FxnOrder; // Pointer to ordered list of
|
|
// function ordinals
|
|
#ifdef OPTIMIZE
|
|
static ULONG *FxnXlat; // Pointer to function translation list
|
|
static ULONG *DiagonalFxn; // Pointer to list of diagonal indexes
|
|
static LONG *NextEdge; // Pointer to index into edge indexes
|
|
static ULONG *MaxEdge; // Pointer to max index into edge list
|
|
static ULONG *Edges; // Edge list, contains function indexes
|
|
static UINT cEdgesTot = 0; // Total number of non-zero edges
|
|
static UINT uiEdgeCmpRow = 0;// WsDecision row for current edge sort
|
|
static LONG lFirstZero = -1;// Index of 1st DiagonalFxn with ref = 0
|
|
#endif /* OPTIMIZE */
|
|
|
|
static LONG **WsDecision; // Decision matrix for data reduction
|
|
static CHAR szDrive[_MAX_DRIVE]; // Drive name
|
|
static CHAR szDir[_MAX_DIR]; // Directory name
|
|
static CHAR szExt[_MAX_EXT]; // Module extension
|
|
|
|
static FILE *hFileWLK = NULL; // Handle to file containing ordered
|
|
HGLOBAL hMem[10];
|
|
ULONG ulFxnIndex; // Index of original TMI order of function.
|
|
|
|
#ifdef TMR
|
|
ULONG pqwTime0[2];
|
|
#endif /* TMR */
|
|
|
|
/*
|
|
* Procedure MAIN
|
|
*
|
|
*
|
|
***
|
|
* Effects:
|
|
*
|
|
* Parses the WSREDUCE command line for module WSP file names. Performs
|
|
* data reduction and analysis on the combined modules' function reference
|
|
* data.
|
|
*
|
|
* The command line interface to WSREDUCE is
|
|
*
|
|
* [d:][path]WSREDUCE File.wsp [File.wsp ...]
|
|
*
|
|
* where:
|
|
*
|
|
* File.wsp Specifies a module WSP file name
|
|
*/
|
|
|
|
BOOL wsReduceMain(INT vargc, CHAR **vargv)
|
|
{
|
|
|
|
ULONG i;
|
|
UINT uiArgvWsp = 1; // Index into vargv[] of 1st WSP name
|
|
|
|
/* Initialize global variable containing name of program. */
|
|
strcpy(szProgName, vargv[0]);
|
|
_strupr(szProgName);
|
|
|
|
#ifdef TMR
|
|
DosTmrQueryTime((PQWORD)pqwTime0);
|
|
printf("Top of Main, 0x%lx:0x%lx\n", pqwTime0[1], pqwTime0[0]);
|
|
#endif /* TMR */
|
|
|
|
/*
|
|
* Parse command line.
|
|
*/
|
|
|
|
if (vargc < 2)
|
|
wsRedUsage();
|
|
else
|
|
if (vargc > 1)
|
|
{
|
|
|
|
/* If the first argument looks like it might be a switch... */
|
|
|
|
if (vargv[uiArgvWsp][0] == '/' || vargv[uiArgvWsp][0] == '-')
|
|
{
|
|
|
|
/* Validate switch. */
|
|
switch (vargv[uiArgvWsp][1])
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
case 'V': /* Verbose (undocumented) */
|
|
case 'v':
|
|
fVerbose = TRUE;
|
|
uiArgvWsp++;
|
|
break;
|
|
#endif /* DEBUG */
|
|
|
|
case '?': /* Help */
|
|
case 'H':
|
|
case 'h':
|
|
wsRedUsage();
|
|
break;
|
|
|
|
default: /* Invalid switch specified */
|
|
printf("%s %s: Invalid switch: '%s'\n", szProgName,
|
|
pszVersion, vargv[uiArgvWsp]);
|
|
wsRedUsage();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Assume rest of the args are WSP file names (1 per module).
|
|
* Allocate and initialize WsrMod[cModsTot].
|
|
*/
|
|
|
|
cModsTot = vargc - uiArgvWsp;
|
|
WsrMod = (wsrmod_t *) AllocAndLockMem((cModsTot*sizeof(wsrmod_t)), &hMem[0]);
|
|
if (WsrMod == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,cModsTot * sizeof(wsrmod_t),
|
|
vargv[uiArgvWsp]);
|
|
|
|
#ifdef DEBUG
|
|
printf("%s %s: Module WSP files:\n", szProgName, pszVersion);
|
|
#endif /* DEBUG */
|
|
|
|
for (i = 0; uiArgvWsp < (UINT)vargc; i++, uiArgvWsp++)
|
|
{
|
|
WsrMod[i].wsrmod_un.wsrmod_pchModFile = vargv[uiArgvWsp];
|
|
#ifdef DEBUG
|
|
printf("\t%s\n", WsrMod[i].wsrmod_un.wsrmod_pchModFile);
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
// Get environment variable WSDIR for default path.
|
|
rc = WsGetWSDIR(szWSDIRPath);
|
|
|
|
// Initialize module and function information structures.
|
|
wsRedInitialization();
|
|
|
|
// Set up weighted decision matrix.
|
|
wsRedSetup();
|
|
|
|
|
|
// Perform the function reference data analysis.
|
|
wsRedReorder();
|
|
|
|
|
|
// Output the analysis results.
|
|
wsRedOutput();
|
|
|
|
// Output "un-touched" functions to PRF file.
|
|
// Commented out because we do not want "un-touched" functions in prf file.
|
|
// wsRedWriteWlk();
|
|
|
|
// Cleanup memory allocations.
|
|
wsRedCleanup();
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedInitialization
|
|
*
|
|
*
|
|
* Effects:
|
|
* - Calls wsRedInitModules to:
|
|
* o Open and validate each module's WSP file.
|
|
* o Open and validate each module's TMI file.
|
|
* o Set up WsrMod[] with per module information.
|
|
* - Calls wsRedInitFunctions to:
|
|
* o Set up WsrFxn[] with per function information.
|
|
* o Allocate FxnBits[].
|
|
* - Allocates WsDecision[][].
|
|
* - Allocates and initializes DiagonalFxn[].
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void. If an error is encountered, exits through wsRedExit()
|
|
* with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedInitialization()
|
|
{
|
|
UINT i; // Loop counter
|
|
|
|
|
|
// Setup module information.
|
|
wsRedInitModules();
|
|
|
|
// Setup function information for each module.
|
|
wsRedInitFunctions();
|
|
|
|
// Allocate the decision matrix, WsDecision[cFxnsTot][cFxnsTot].
|
|
WsDecision = (LONG **) AllocAndLockMem(((cFxnsTot+1) * cFxnsTot * sizeof(LONG)), &hMem[1]);
|
|
if (WsDecision == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
|
|
(cFxnsTot+1)*cFxnsTot*sizeof(LONG), "WsDecision[][]");
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
{
|
|
WsDecision[i] = (LONG *) WsDecision+cFxnsTot+(i*cFxnsTot);
|
|
if (WsDecision[i] == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
|
|
cFxnsTot * sizeof(LONG), "WsDecision[][]");
|
|
}
|
|
|
|
#ifdef OPTIMIZE
|
|
// Allocate the diagonal entries list, DiagonalFxn[cFxnsTot].
|
|
DiagonalFxn = (ULONG *) malloc(cFxnsTot * sizeof(ULONG));
|
|
//Added
|
|
memset((PVOID)DiagonalFxn, 0x00, (cFxnsTot * sizeof(ULONG));
|
|
#endif /* OPTIMIZE */
|
|
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedInitModules
|
|
*
|
|
*
|
|
* Effects:
|
|
* - Opens and validates each module's WSP file.
|
|
* - Opens and validates each module's TMI file.
|
|
* - Sets up WsrMod[] with per module information.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void. If an error is encountered, exits through wsRedExit()
|
|
* with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedInitModules()
|
|
{
|
|
wsrmod_t *pWsrMod; // Pointer to wsrmod struct
|
|
wsphdr_t WspHdr; // WSP file header
|
|
// Module path name
|
|
static CHAR szModPath[CCHMAXPATHCOMP] = "";
|
|
UINT uiMod = 0; // Index of module into WsrMod[]
|
|
UINT cFxns = 0; // Number of functions for this module
|
|
ULONG ulTimeStamp = 0; // Time stamp
|
|
CHAR szFileTmp[CCHMAXPATHCOMP]; // Temporary file name
|
|
ULONG ulTDFID = 0; // TDF Identifier
|
|
wsphdr_t wsHDR;
|
|
|
|
|
|
for (uiMod = 0; uiMod < cModsTot; uiMod++)
|
|
{
|
|
pWsrMod = &WsrMod[uiMod];
|
|
|
|
/* Open module's input WSP file. Read and validate
|
|
* WSP file header.
|
|
*/
|
|
|
|
|
|
rc = WsWSPOpen(pWsrMod->wsrmod_un.wsrmod_pchModFile,
|
|
&(pWsrMod->wsrmod_hFileWSP), (PFN) wsRedExit,
|
|
&WspHdr, ERROR);
|
|
|
|
strcpy(szFileTMI, pWsrMod->wsrmod_un.wsrmod_pchModFile);
|
|
_strupr(szFileTMI);
|
|
strcpy(strstr(szFileTMI,".WSP"),".TMI");
|
|
|
|
|
|
if (ulTimeStamp == 0)
|
|
{
|
|
/* Time stamp and number of snapshots do not
|
|
* vary across modules, so grab them from
|
|
* the first module's WSP header.
|
|
*/
|
|
ulTimeStamp = WspHdr.wsphdr_ulTimeStamp;
|
|
cSnapsTot = WspHdr.wsphdr_ulSnaps;
|
|
cbBitStr = cSnapsTot * sizeof(ULONG);
|
|
}
|
|
else
|
|
if (WspHdr.wsphdr_ulTimeStamp != ulTimeStamp)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_FILE_BAD_HDR, (ULONG)-1L,
|
|
pWsrMod->wsrmod_un.wsrmod_pchModFile);
|
|
|
|
/* Keep module name in memory. */
|
|
if ((pWsrMod->wsrmod_un.wsrmod_pchModName =
|
|
_strdup(szModPath)) == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
|
|
WspHdr.wsphdr_dtqo.dtqo_cbPathname,
|
|
szModPath);
|
|
|
|
/* Keep track of module's first function slot. */
|
|
pWsrMod->wsrmod_ulFxn = cFxnsTot;
|
|
pWsrMod->wsrmod_ulOffWSP = WspHdr.wsphdr_ulOffBits;
|
|
|
|
/*
|
|
* Open associated TMI file. Assume it lives in WSDIR.
|
|
* Read and validate TMI header. Increment cFxnsTot.
|
|
*/
|
|
fseek(pWsrMod->wsrmod_hFileWSP,0L,SEEK_SET);
|
|
fread(&wsHDR,sizeof(wsphdr_t),1,pWsrMod->wsrmod_hFileWSP);
|
|
fseek(pWsrMod->wsrmod_hFileWSP,sizeof(wsphdr_t),SEEK_SET);
|
|
fread(szFileTmp,wsHDR.wsphdr_dtqo.dtqo_cbPathname,1, pWsrMod->wsrmod_hFileWSP);
|
|
szFileTmp[wsHDR.wsphdr_dtqo.dtqo_cbPathname] = '\0';
|
|
|
|
szFileTMI[0] = '\0';
|
|
strcat(szFileTMI,szFileTmp);
|
|
strcat(szFileTMI, ".TMI");
|
|
|
|
cTmiFxns = WsTMIOpen(szFileTMI, &(pWsrMod->wsrmod_hFileTMI),
|
|
(PFN) wsRedExit,
|
|
0, (PCHAR)0);
|
|
cFxns = WspHdr.wsphdr_dtqo.dtqo_SymCnt;
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
printf("%s file header: # fxns = %ld, TDF ID = 0x%x\n", szFileTMI,
|
|
cFxns, (UINT) WspHdr.wsphdr_dtqo.dtqo_usID);
|
|
#endif /* DEBUG */
|
|
|
|
pWsrMod->wsrmod_clFxns = cFxns;
|
|
cFxnsTot += cFxns;
|
|
|
|
|
|
} /* End For */
|
|
|
|
// If no function data to analyze, just exit without error.
|
|
if (cFxnsTot == 0)
|
|
wsRedExit(NO_ERROR, NO_MSG, NO_MSG, 0, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***LP wsRedInitFunctions
|
|
*
|
|
*
|
|
* Effects:
|
|
* - Sets up WsrFxn[] with per function information.
|
|
* - Allocates FxnBits[].
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void. If an error is encountered, exits through wsRedExit()
|
|
* with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedInitFunctions()
|
|
{
|
|
wsrmod_t *pWsrMod; // Pointer to wsrmod struct
|
|
UINT uiMod = 0; // Index of module into WsrMod[]
|
|
UINT uiFxn = 0; // Function number
|
|
UINT cFxns = 0; // Number of functions for this module
|
|
ULONG ulOff = 0; // File offset
|
|
UINT uiFxnOrd = 0; // Order of function within module
|
|
//ULONG ulFxnBit; // function's bit reference position
|
|
//UINT uiFxnAddrObj; // object portion of function address
|
|
//ULONG ulFxnAddrOff; // offset portion of function address
|
|
//ULONG cbFxnName; // size in bytes of function name
|
|
//ULONG cbFxn; // size of function (in bytes)
|
|
// function name
|
|
static CHAR szFxnName[CCHMAXPATHCOMP] = "";
|
|
|
|
|
|
// Allocate memory for per function info, WsrFxn[cFxnsTot].
|
|
WsrFxn = (wsrfxn_t *) AllocAndLockMem(cFxnsTot*sizeof(wsrfxn_t), &hMem[3]);
|
|
if (WsrFxn == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
|
|
cFxnsTot * sizeof(wsrfxn_t), "WsrFxn[]");
|
|
|
|
// Initialize WsrFxn[cFxnsTot].
|
|
for (uiMod = 0; uiMod < cModsTot; uiMod++)
|
|
{
|
|
pWsrMod = &WsrMod[uiMod];
|
|
ulOff = pWsrMod->wsrmod_ulOffWSP;
|
|
uiFxn = pWsrMod->wsrmod_ulFxn; // loop index init
|
|
cFxns = uiFxn + pWsrMod->wsrmod_clFxns; // loop invariant
|
|
#ifdef DEBUG
|
|
printf("Initializing WsrFxn[] for %s (Mod %d):\n\tstart/end fxn indices (%d/%d)\n",
|
|
pWsrMod->wsrmod_un.wsrmod_pchModName, uiMod, uiFxn,
|
|
cFxns - 1);
|
|
|
|
printf("TMI file handle: %ld\n",pWsrMod->wsrmod_hFileTMI);
|
|
#endif /* DEBUG */
|
|
for (uiFxnOrd = 0; uiFxn < cFxns; uiFxnOrd++, uiFxn++)
|
|
{
|
|
WsrFxn[uiFxn].wsrfxn_ulMod = uiMod;
|
|
WsrFxn[uiFxn].wsrfxn_ulFxn = uiFxnOrd;
|
|
WsrFxn[uiFxn].wsrfxn_ulOffWSP = ulOff;
|
|
WsrFxn[uiFxn].wsrfxn_cbFxn =
|
|
WsTMIReadRec(szFxnName,&ulFxnIndex,&ulTmp,pWsrMod->wsrmod_hFileTMI,
|
|
(PFN) wsRedExit, (PCHAR)0);
|
|
if ((WsrFxn[uiFxn].wsrfxn_pchFxnName
|
|
= _strdup(szFxnName)) == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
|
|
strlen(szFxnName) + 1,
|
|
szFxnName);
|
|
WsrFxn[uiFxn].wsrfxn_ulFxnIndex = ulFxnIndex;
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
printf("\tWsrFxn[%d] %s: Fxn Ordinal (%d), Off (0x%lx)\n",
|
|
uiFxn, WsrFxn[uiFxn].wsrfxn_pchFxnName,
|
|
uiFxnOrd, ulOff);
|
|
#endif /* DEBUG */
|
|
ulOff += cbBitStr;
|
|
WsrFxn[uiFxn].wsrfxn_fCandidate = TRUE;
|
|
|
|
|
|
}
|
|
|
|
// Close TMI file.
|
|
fclose(pWsrMod->wsrmod_hFileTMI);
|
|
|
|
} /* End For */
|
|
|
|
// Allocate space to hold 32 snapshots for each function.
|
|
FxnBits = (ULONG *) AllocAndLockMem(cFxnsTot*sizeof(ULONG), &hMem[4]);
|
|
if (FxnBits == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_NO_MEM,
|
|
cFxnsTot * sizeof(ULONG), "FxnBits[]");
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedSetup
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Initializes the data structures used to analyze the function
|
|
* reference bitstrings, including the weighted decision matrix.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void. If an error is encountered, exits through wsRedExit()
|
|
* with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedSetup()
|
|
{
|
|
#ifdef OPTIMIZE
|
|
UINT i;
|
|
#endif /* OPTIMIZE */
|
|
|
|
wsRedSetWsDecision(); // set up initial decision matrix
|
|
wsRedScaleWsDecision(); // scale the decision matrix
|
|
wsRedWeightWsDecision(); // weight the matrix "edge" entries
|
|
|
|
#ifdef OPTIMIZE
|
|
/* Reuse FxnBits[] for the function translation table, FxnXlat[]. */
|
|
FxnXlat = FxnBits;
|
|
memset((PVOID) FxnXlat, 0, cFxnsTot * sizeof(ULONG));
|
|
|
|
wsRedSortDiagonal(); // Get optimal diagonal ordering
|
|
wsRedSetupEdges(); // Set up NextEdge and MaxEdge
|
|
wsRedSortEdges(); // Get optimal edge ordering
|
|
|
|
/* Free memory that is no longer needed, including WsDecision[][]. */
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
free(WsDecision[i]);
|
|
free(WsDecision);
|
|
|
|
|
|
#endif /* OPTIMIZE */
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedSetWsDecision
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Initializes and weights the decision matrix, WsDecision[][].
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void. If an error is encountered, exits through wsRedExit()
|
|
* with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedSetWsDecision()
|
|
{
|
|
wsrmod_t *pWsrMod; // Pointer to wsrmod struct
|
|
UINT i = 0, j = 0; // Temporary loop indexes
|
|
UINT uiMod = 0; // Index of module into WsrMod[]
|
|
UINT uiFxn = 0; // Function number
|
|
UINT cFxns = 0; // Number of functions for this module
|
|
UINT uiFBits = 0; // Loop index for bitstring dwords
|
|
UINT clFBits = 0; // Count of fxn bitstring dwords
|
|
ULONG ulResult = 0; // Returned from procedure call
|
|
FILE *hFile; // File handle
|
|
|
|
/* For each dword of snapshot bitstrings...*/
|
|
clFBits = (cbBitStr + sizeof(ULONG) - 1) / sizeof(ULONG);
|
|
for (uiFBits = 0; uiFBits < clFBits; uiFBits++)
|
|
{
|
|
/* For each module... */
|
|
for (uiMod = 0; uiMod < cModsTot; uiMod++)
|
|
{
|
|
pWsrMod = &WsrMod[uiMod];
|
|
hFile = pWsrMod->wsrmod_hFileWSP;
|
|
uiFxn = pWsrMod->wsrmod_ulFxn; // loop index init
|
|
cFxns = uiFxn + pWsrMod->wsrmod_clFxns; //loop invariant
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
printf("Setting up WsDecision[][] and FxnBits[] for %s (Mod %d):\n\tstart/end fxn indices (%d/%d)\n",
|
|
pWsrMod->wsrmod_un.wsrmod_pchModName, uiMod,
|
|
uiFxn, cFxns - 1);
|
|
#endif /* DEBUG */
|
|
/* For each function... */
|
|
for ( ; uiFxn < cFxns; uiFxn++)
|
|
{
|
|
/* Seek to next dword of function's bitstring. */
|
|
if ((rc = fseek(hFile,(WsrFxn[uiFxn].wsrfxn_ulOffWSP),SEEK_SET))!=NO_ERROR)
|
|
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET,rc,
|
|
pWsrMod->wsrmod_un.wsrmod_pchModName);
|
|
|
|
/* Read next dword of function's bitstring. */
|
|
rc = fread((PVOID) &(FxnBits[uiFxn]),
|
|
(ULONG) sizeof(ULONG),1, hFile);
|
|
if(rc == 1)
|
|
rc = NO_ERROR;
|
|
else
|
|
rc = 2;
|
|
|
|
if (rc != NO_ERROR)
|
|
|
|
wsRedExit(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pWsrMod->wsrmod_un.wsrmod_pchModName);
|
|
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
printf("\tFxnBits[%d] = 0x%lx\n", uiFxn,
|
|
FxnBits[uiFxn]);
|
|
#endif /* DEBUG */
|
|
|
|
/* Increment WSP file offset for next time. */
|
|
WsrFxn[uiFxn].wsrfxn_ulOffWSP += sizeof(ULONG);
|
|
|
|
ulTmp = FxnBits[uiFxn];
|
|
/* If there are bits set... */
|
|
if (ulTmp != 0)
|
|
{
|
|
/* Sum the "on" bits and add the result
|
|
* to WsDecision[uiFxn][uiFxn].
|
|
*/
|
|
ulResult = 0;
|
|
for (j = 0; j < NUM_VAR_BITS; j++)
|
|
{
|
|
ulResult += (ulTmp & 1);
|
|
ulTmp = ulTmp >> 1;
|
|
}
|
|
WsDecision[uiFxn][uiFxn] += ulResult;
|
|
|
|
/* Sum the overlapping "on" bits for this
|
|
* function's dword with each preceding
|
|
* function's dword, and add the results to
|
|
* WsDecision[][].
|
|
*/
|
|
|
|
for (i = 0; i < uiFxn; i++)
|
|
{
|
|
if (i == uiFxn)
|
|
continue;
|
|
ulTmp = (ULONG) ((ULONG)(FxnBits[i])
|
|
& (ULONG) (FxnBits[uiFxn]));
|
|
ulResult = 0;
|
|
for (j = 0; j < NUM_VAR_BITS; j++)
|
|
{
|
|
ulResult += (ulTmp & 1);
|
|
ulTmp = ulTmp >> 1;
|
|
}
|
|
WsDecision[uiFxn][i] += ulResult;
|
|
WsDecision[i][uiFxn] += ulResult;
|
|
|
|
} /* End For each previous function's dword */
|
|
} /* End If there are bits set...*/
|
|
} /* End For each function... */
|
|
|
|
|
|
} /* End For each module... */
|
|
|
|
} /* End For each dword of bitstrings */
|
|
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
{
|
|
printf("\nRAW MATRIX:\n");
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
{
|
|
printf("row %4d:\n", uiFxn);
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
printf("0x%lx ", WsDecision[uiFxn][i]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedOpenWSR
|
|
*
|
|
*
|
|
* Effects:
|
|
* Opens the output WSR files, one per module. If only one module
|
|
* is being reduced, also opens a WLK file, setting the WLK file handle
|
|
* as a side effect.
|
|
*
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void. If an error is encountered, exits through wsRedExit()
|
|
* with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedOpenWSR(FILE **phFileWLK)
|
|
{
|
|
UINT uiMod = 0; // Index of module into WsrMod[]
|
|
// WSR file name
|
|
static CHAR szFileWSR[CCHMAXPATHCOMP] = "";
|
|
// Temporary file name
|
|
static CHAR szFileTmp[CCHMAXPATHCOMP] = "";
|
|
wsphdr_t wsHDR;
|
|
|
|
|
|
for (uiMod = 0; uiMod < cModsTot; uiMod++)
|
|
{
|
|
/* Close WSP file, and open module output file. */
|
|
fseek(WsrMod[uiMod].wsrmod_hFileWSP,0L,SEEK_SET);
|
|
fread(&wsHDR,sizeof(wsphdr_t),1,WsrMod[uiMod].wsrmod_hFileWSP);
|
|
|
|
fseek(WsrMod[uiMod].wsrmod_hFileWSP,sizeof(wsphdr_t),SEEK_SET);
|
|
|
|
fread(szFileTmp,wsHDR.wsphdr_dtqo.dtqo_cbPathname,1, WsrMod[uiMod].wsrmod_hFileWSP);
|
|
fclose(WsrMod[uiMod].wsrmod_hFileWSP);
|
|
szFileTmp[wsHDR.wsphdr_dtqo.dtqo_cbPathname] = '\0';
|
|
szFileWSR[0] = '\0';
|
|
strcat(szFileWSR, szFileTmp);
|
|
strcat(szFileWSR, ".WSR");
|
|
|
|
if ((WsrMod[uiMod].wsrmod_hFileWSR = fopen(szFileWSR, "w"))
|
|
== NULL)
|
|
{
|
|
wsRedExit(ERROR, PRINT_MSG,MSG_FILE_OPEN,rc, szFileWSR);
|
|
}
|
|
}
|
|
|
|
/* If we're only analyzing ONE module, then also open a WLK
|
|
* file. This file will contain the function names in their
|
|
* reordered sequence. The linker will use this file to
|
|
* automatically reorder functions. Note that we reuse szFileWSR
|
|
* here.
|
|
*/
|
|
|
|
if (cModsTot == 1)
|
|
{
|
|
strcpy(strstr(szFileWSR, ".WSR"), ".PRF");
|
|
if ((*phFileWLK = fopen(szFileWSR, "w")) == NULL)
|
|
wsRedExit(ERROR, PRINT_MSG,MSG_FILE_OPEN,rc, szFileWSR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedScaleWsDecision
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* If necessary, scales the diagonal values of the matrix to avoid overflow
|
|
* during calculations of the weighted edges (below). Sets up DiagonalFxn[]
|
|
* as a side effect. Note that we go through gyrations to set
|
|
* DiagonalFxn up backwards, so that qsort() will handle ties a little better.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void.
|
|
*/
|
|
|
|
VOID
|
|
wsRedScaleWsDecision()
|
|
{
|
|
UINT i = 0, j = 0; // Temporary loop indexes
|
|
UINT uiFxn = 0; // Function number
|
|
ULONG ulRefHi1 = 0; // Highest diagonal value
|
|
ULONG ulRefHi2 = 0; // Second highest diagonal value
|
|
float fTmp; // Temporary float variable
|
|
ULONG ulScale;
|
|
LONG lTmp;
|
|
|
|
|
|
for (uiFxn = 0, j = (cFxnsTot - 1); uiFxn < cFxnsTot; uiFxn++, j--)
|
|
{
|
|
#ifdef OPTIMIZE
|
|
DiagonalFxn[uiFxn] = j; // init unsorted DiagonalFxn[]
|
|
#endif /* OPTIMIZE */
|
|
ulTmp = WsDecision[uiFxn][uiFxn];
|
|
if (ulTmp > ulRefHi2)
|
|
if (ulTmp > ulRefHi1)
|
|
{
|
|
ulRefHi2 = ulRefHi1;
|
|
ulRefHi1 = ulTmp;
|
|
}
|
|
else
|
|
ulRefHi2 = ulTmp;
|
|
}
|
|
fTmp = (float) ((float) ulRefHi1 * (float) ulRefHi2);
|
|
if (fTmp > LONG_MAX)
|
|
{
|
|
// Scale down the diagonal. Don't allow rescaled entries
|
|
// to be zero if they were non-zero before scaling.
|
|
|
|
ulScale = (ULONG) ((float) (fTmp + LONG_MAX - 1) / LONG_MAX);
|
|
printf("%s %s: WARNING -- Scaling back the reduction matrix by %ld.\n",
|
|
szProgName, pszVersion, ulScale);
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
{
|
|
lTmp = WsDecision[uiFxn][uiFxn];
|
|
if (lTmp)
|
|
{
|
|
lTmp /= ulScale;
|
|
if (lTmp == 0)
|
|
WsDecision[uiFxn][uiFxn] = 1;
|
|
else
|
|
WsDecision[uiFxn][uiFxn] = lTmp;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
{
|
|
printf("\nSCALED MATRIX:\n");
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
{
|
|
printf("row %4d:\n", uiFxn);
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
printf("0x%lx ", WsDecision[uiFxn][i]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
{
|
|
printf("Got ulRefHi1 = %ld, ulRefHi2 = %ld\n",
|
|
ulRefHi1, ulRefHi2);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedWeightWsDecision
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Weights the decision matrix edges from start vertex to end vertex,
|
|
* depending on the relative importance of the end vertex.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void.
|
|
*/
|
|
|
|
VOID
|
|
wsRedWeightWsDecision()
|
|
{
|
|
UINT i = 0, j = 0; // Temporary loop indexes
|
|
UINT uiFxn = 0; // Function number
|
|
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
{
|
|
if (uiFxn == i)
|
|
continue;
|
|
WsDecision[uiFxn][i] *= WsDecision[i][i];
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
{
|
|
printf("\nWEIGHTED MATRIX:\n");
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
{
|
|
printf("row %4d:\n", uiFxn);
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
printf("0x%lx ", WsDecision[uiFxn][i]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
#ifndef OPTIMIZE
|
|
|
|
/*
|
|
*
|
|
***LP wsRedReorder
|
|
*
|
|
* Requires:
|
|
*
|
|
* Effects:
|
|
*
|
|
* A greedy algorithm is used to determine a better ordering for the functions
|
|
* whose reference patterns are represented in the decision matrix. The
|
|
* algorithm is as follows:
|
|
*
|
|
* o Select the function whose value on the diagonal is greatest.
|
|
* The selected function becomes the current starting vertex,
|
|
* and is first on the list of ordered functions. Mark that it
|
|
* is no longer a candidate function. Note that this does NOT mean
|
|
* that its vertex is removed from the graph.
|
|
*
|
|
* o While there is more than one function remaining as a candidate:
|
|
*
|
|
* - Choose the edge of greatest weight leading from the current
|
|
* starting vertex. Ties are broken as follows: If one of the
|
|
* tied ending vertices is in the selected set and the other is
|
|
* not, choose the edge whose ending vertex is already selected
|
|
* (because we already know that vertex is "important"); further
|
|
* ties are broken by choosing the end vertex whose diagonal value
|
|
* is greatest.
|
|
*
|
|
* - If the ending vertex chosen above is still a candidate (i.e., not
|
|
* already selected), then select it for the list of ordered
|
|
* functions, and mark that it is no longer a candidate.
|
|
*
|
|
* - Set the matrix entry for the chosen edge to some invalid value,
|
|
* so that edge will never be chosen again.
|
|
*
|
|
* - Set current starting vertex equal to the ending vertex chosen
|
|
* above.
|
|
*
|
|
* o Select the one remaining function for the list of ordered functions.
|
|
*
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void.
|
|
*/
|
|
|
|
VOID
|
|
wsRedReorder()
|
|
{
|
|
UINT uiFxn = 0; // Function number
|
|
UINT i = 0; // Temporary loop index
|
|
UINT uiSelected = 0; // Function ordinal selected
|
|
UINT cFxnOrder = 0; // Count of ordered functions
|
|
UINT cCandidates = 0; // Count of candidates remaining
|
|
UINT uiEdge = 0; // Function ordinal edge selected
|
|
ULONG cDiagMax = 0; // Max number encountered on diagonal
|
|
|
|
|
|
/* Reuse FxnBits[] for the ordered list of functions, FxnOrder[]. */
|
|
FxnOrder = FxnBits;
|
|
memset((PVOID) FxnOrder, 0, cFxnsTot * sizeof(ULONG));
|
|
|
|
cCandidates = cFxnsTot;
|
|
|
|
/* Initial selection is based on the number of bits set (diagonal). */
|
|
for (uiFxn = 0; uiFxn < (UINT)cFxnsTot; uiFxn++)
|
|
if (WsDecision[uiFxn][uiFxn] > (INT)cDiagMax)
|
|
{
|
|
cDiagMax = WsDecision[uiFxn][uiFxn];
|
|
uiSelected = uiFxn;
|
|
}
|
|
|
|
FxnOrder[cFxnOrder++] = uiSelected;
|
|
WsrFxn[uiSelected].wsrfxn_fCandidate = FALSE;
|
|
--cCandidates;
|
|
|
|
while (cCandidates > 1)
|
|
{
|
|
/* Follow highest weighted edge from selected vertex. */
|
|
uiEdge = wsRedChooseEdge(uiSelected);
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
printf("choose edge (%d->%d)\n", uiSelected, uiEdge);
|
|
#endif
|
|
uiSelected = uiEdge;
|
|
if (WsrFxn[uiEdge].wsrfxn_fCandidate == TRUE)
|
|
{
|
|
FxnOrder[cFxnOrder++] = uiSelected;
|
|
WsrFxn[uiSelected].wsrfxn_fCandidate = FALSE;
|
|
--cCandidates;
|
|
}
|
|
}
|
|
|
|
if (cCandidates == 1)
|
|
{
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
if (WsrFxn[uiFxn].wsrfxn_fCandidate == TRUE)
|
|
{
|
|
FxnOrder[cFxnOrder++] = uiFxn;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedChooseEdge
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* "Selects" a function from the candidate pool, based on weighted
|
|
* edge from 'index' function to a candidate function.
|
|
*
|
|
*
|
|
*
|
|
* Returns:
|
|
*
|
|
* Ordinal number of selected function.
|
|
*
|
|
*/
|
|
|
|
UINT
|
|
wsRedChooseEdge(uiIndex)
|
|
UINT uiIndex;
|
|
{
|
|
UINT uiFxn = 0; // Function ordinal number.
|
|
INT iMaxWt = -1; // Highest weighted edge encountered.
|
|
UINT uiRet = 0; // Return index.
|
|
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
{
|
|
if (uiFxn == uiIndex)
|
|
continue;
|
|
if (WsDecision[uiIndex][uiFxn] > iMaxWt)
|
|
{
|
|
iMaxWt = WsDecision[uiIndex][uiFxn];
|
|
uiRet = uiFxn;
|
|
}
|
|
else
|
|
if (WsDecision[uiIndex][uiFxn] == iMaxWt)
|
|
{
|
|
/* Need tiebreak. If 'uiFxn' has already been selected,
|
|
* we know it is important, so choose it. Otherwise,
|
|
* and in the case where more than one of the tied
|
|
* functions has already been selected, choose based
|
|
* on the diagonal value.
|
|
*/
|
|
if ((WsrFxn[uiFxn].wsrfxn_fCandidate == FALSE) &&
|
|
(WsrFxn[uiRet].wsrfxn_fCandidate == TRUE))
|
|
/* Choose 'uiFxn', it's been selected before */
|
|
uiRet = uiFxn;
|
|
else
|
|
if (WsDecision[uiFxn][uiFxn] > WsDecision[uiRet][uiRet])
|
|
uiRet = uiFxn;
|
|
}
|
|
}
|
|
|
|
WsDecision[uiIndex][uiRet] = WsDecision[uiRet][uiIndex] = -1;
|
|
return(uiRet);
|
|
}
|
|
|
|
#else /* OPTIMIZE */
|
|
|
|
/*
|
|
*
|
|
***LP wsRedSortDiagonal
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Sorts the list of diagonal functions. Sets up a translation between
|
|
* unsorted function index and sorted function index. Allocates shadow
|
|
* lists for edge moves.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void.
|
|
*/
|
|
|
|
VOID
|
|
wsRedSortDiagonal()
|
|
{
|
|
UINT i = 0, j; // Temporary loop index
|
|
UINT uiFxn = 0; // Function number
|
|
|
|
// Sort the list of diagonal functions.
|
|
qsort(DiagonalFxn, cFxnsTot, sizeof(ULONG), wsRedDiagCmp);
|
|
|
|
// Set up translation table for unsorted function index to
|
|
// sorted function index. Keep track of first function
|
|
// whose reference count is zero, if any.
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
{
|
|
j = DiagonalFxn[i];
|
|
FxnXlat[j] = i;
|
|
if ((WsDecision[j][j] == 0) && (lFirstZero == -1))
|
|
lFirstZero = i;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
{
|
|
printf("Sorted DiagonalFxn[]:\n");
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
printf("\t%ld -> %ld\n", i, FxnXlat[i]);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
|
|
// Allocate shadow lists containing next edge and max edge for
|
|
// DiagonalFxn[]. Next edge list will be same size as DiagonalFxn[].
|
|
// Max edge list is only allocated for DiagonalFxn entries up to,
|
|
// but not including, the first function that was reference 0 times.
|
|
|
|
NextEdge = (LONG *) malloc(cFxnsTot * sizeof(LONG));
|
|
memset((PVOID) NextEdge, -1, cFxnsTot * sizeof(LONG));
|
|
MaxEdge = (ULONG *) malloc(lFirstZero * sizeof(ULONG));
|
|
//Added
|
|
memset((PVOID)MaxEdge, 0x00, (lFirstZero * sizeof(ULONG));
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***LP wsRedDiagCmp
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Called by qsort() to choose the matrix diagonal entry of greater value.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Returns the difference between the number of function references
|
|
* for the specified functions.
|
|
*
|
|
*/
|
|
|
|
INT
|
|
wsRedDiagCmp(a, b)
|
|
INT *a, *b;
|
|
{
|
|
|
|
return(WsDecision[*b][*b] - WsDecision[*a][*a]);
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedSetupEdges
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Sets up edge moves for each function.
|
|
* - NextEdge[]
|
|
* - MaxEdge[]
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void.
|
|
*/
|
|
|
|
VOID
|
|
wsRedSetupEdges()
|
|
{
|
|
UINT i, k, uiFxnMaxNZ;
|
|
INT j;
|
|
|
|
if (lFirstZero == -1)
|
|
uiFxnMaxNZ = cFxnsTot;
|
|
else
|
|
uiFxnMaxNZ = lFirstZero;
|
|
|
|
|
|
// Setup NextEdge[] and MaxEdge[]. Determine number of valid
|
|
// edges for Edges[].
|
|
for (i = 0; i < uiFxnMaxNZ; i++)
|
|
{
|
|
if (i != 0)
|
|
MaxEdge[i - 1] = cEdgesTot; // Set prev max edge
|
|
|
|
for (j = 0; j < cFxnsTot; j++)
|
|
{
|
|
if (DiagonalFxn[i] == j)
|
|
continue;
|
|
if (WsDecision[DiagonalFxn[i]][j] != 0)
|
|
{
|
|
if (NextEdge[i] == -1)
|
|
NextEdge[i] = cEdgesTot; // Set next edge index
|
|
cEdgesTot++; // Track non-zero edge
|
|
}
|
|
}
|
|
}
|
|
|
|
MaxEdge[uiFxnMaxNZ - 1] = cEdgesTot; // Set last max edge
|
|
|
|
// Allocate and initialize the unsorted Edges[] list. Note that
|
|
// we tromp through WsDecision[][] again here. We did that above
|
|
// to determine how many valid edges there are, so that we can now
|
|
// allocate as small an Edges[] as possible. Again, set up Edges
|
|
// backwards so that qsort() will do the right thing for ties.
|
|
|
|
Edges = (ULONG *) malloc(cEdgesTot * sizeof(ULONG));
|
|
//Added
|
|
memset((PVOID)Edges, 0x00, (cEdgesTot * sizeof(ULONG));
|
|
for (i = 0, k = 0; i < uiFxnMaxNZ; i++)
|
|
for (j = cFxnsTot - 1; j >= 0; j--)
|
|
{
|
|
if (DiagonalFxn[i] == j)
|
|
continue;
|
|
if (WsDecision[DiagonalFxn[i]][j] != 0)
|
|
Edges[k++] = j; // Unsorted fxn index
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***LP wsRedSortEdges
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Sorts the edge moves for each function.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void.
|
|
*/
|
|
|
|
VOID
|
|
wsRedSortEdges()
|
|
{
|
|
UINT i, j, uiFxnMaxNZ;
|
|
|
|
if (lFirstZero == -1)
|
|
uiFxnMaxNZ = cFxnsTot;
|
|
else
|
|
uiFxnMaxNZ = lFirstZero;
|
|
|
|
// Sort Edges[] entries for each function that has non-zero
|
|
// references.
|
|
|
|
for (i = 0; i < uiFxnMaxNZ; i++)
|
|
{
|
|
// Set global WsDecision row index used by wsRedEdgeCmp(),
|
|
// and sort this row's valid edges in Edge[] using
|
|
// wsRedEdgeCmp().
|
|
|
|
uiEdgeCmpRow = DiagonalFxn[i];
|
|
if ((j = NextEdge[i]) != -1)
|
|
qsort(&Edges[j], MaxEdge[i] - j,
|
|
sizeof(ULONG), wsRedEdgeCmp);
|
|
}
|
|
|
|
|
|
// Translate the Edges[] entries into indexes into DiagonalFxn[],
|
|
// instead of indexes into the (unsorted) WsDecision[].
|
|
|
|
for (i = 0; i < cEdgesTot; i++)
|
|
{
|
|
Edges[i] = FxnXlat[Edges[i]];
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
{
|
|
for (i = 0; i < cFxnsTot; i++)
|
|
{
|
|
printf("DiagonalFxn %ld, NextEdge %ld, MaxEdge %ld:\n",
|
|
DiagonalFxn[i], NextEdge[i],
|
|
(i < lFirstZero) ? MaxEdge[i]:-1);
|
|
if (NextEdge[i] != -1)
|
|
{
|
|
for (j = NextEdge[i]; j < MaxEdge[i]; j++)
|
|
printf("\t%ld (-> %ld)\n",
|
|
DiagonalFxn[Edges[j]], Edges[j]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***LP wsRedEdgeCmp
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Called by qsort() to choose the edge move of greater value.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Returns the difference between the number of overlapping
|
|
* bits between the current function (uiEdgeCmpRow) and the specified
|
|
* functions.
|
|
*
|
|
*/
|
|
|
|
INT
|
|
wsRedEdgeCmp(a, b)
|
|
INT *a, *b;
|
|
{
|
|
|
|
return(WsDecision[uiEdgeCmpRow][*b] - WsDecision[uiEdgeCmpRow][*a]);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
***LP wsRedReorder
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* The following algorithm is used to determine a better ordering for the
|
|
* functions whose reference patterns were measured.
|
|
*
|
|
* o Select the function whose value on the diagonal is greatest. I.e.,
|
|
* select the first entry in the sorted diagonal list. The selected
|
|
* function is first on the list of ordered functions. Mark that it
|
|
* is no longer a candidate function.
|
|
*
|
|
* o While there are still functions that are candidates:
|
|
*
|
|
* - If there is an edge that can be taken from the current diagonal
|
|
* function, choose the edge of greatest weight. I.e., choose the
|
|
* first available entry in this function's sorted edge list. Bump
|
|
* the chosen edge from the function's sorted edge list, so that edge
|
|
* will never be chosen again.
|
|
*
|
|
* - If there is no edge to follow, choose the next highest entry in
|
|
* the sorted diagonal list.
|
|
*
|
|
* - If the edge/diagonal function chosen above is still a candidate
|
|
* (i.e., not already selected), then select it for the list of
|
|
* ordered functions, and mark that it is no longer a candidate.
|
|
*
|
|
* - Set current diagonal function to the edge/diagonal chosen
|
|
* above.
|
|
*
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void.
|
|
*
|
|
*/
|
|
|
|
VOID
|
|
wsRedReorder()
|
|
{
|
|
UINT uiFxn = 0; // Function number
|
|
UINT i = 0; // Temporary loop index
|
|
UINT uiSelected = 0; // Function ordinal selected
|
|
UINT uiDiagCur = 0; // Current index into DiagonalFxn
|
|
UINT uiDiagNext = 0; // Next index into DiagonalFxn
|
|
UINT cFxnOrder = 0; // Count of ordered functions
|
|
UINT cCandidates = 0; // Count of candidates remaining
|
|
UINT uiEdge = 0; // Function ordinal edge selected
|
|
|
|
|
|
/* Reuse FxnBits[] for the ordered list of functions, FxnOrder[]. */
|
|
FxnOrder = FxnBits;
|
|
memset((PVOID) FxnOrder, 0, cFxnsTot * sizeof(ULONG));
|
|
|
|
cCandidates = cFxnsTot;
|
|
|
|
|
|
uiSelected = DiagonalFxn[0];
|
|
FxnOrder[cFxnOrder++] = uiSelected;
|
|
WsrFxn[uiSelected].wsrfxn_fCandidate = FALSE;
|
|
--cCandidates;
|
|
|
|
while (cCandidates > 0)
|
|
{
|
|
/* Follow highest weighted edge from selected vertex. */
|
|
if (NextEdge[uiDiagCur] == -1)
|
|
{
|
|
// Take next highest diagonal entry.
|
|
if (uiDiagCur == uiDiagNext)
|
|
uiDiagNext++;
|
|
uiEdge = uiDiagNext;
|
|
}
|
|
else
|
|
{
|
|
// Take highest edge.
|
|
uiEdge = Edges[NextEdge[uiDiagCur]];
|
|
NextEdge[uiDiagCur]++;
|
|
if (NextEdge[uiDiagCur] >= MaxEdge[uiDiagCur])
|
|
{
|
|
NextEdge[uiDiagCur] = -1;
|
|
if (uiDiagCur == uiDiagNext)
|
|
uiDiagNext++;
|
|
}
|
|
}
|
|
|
|
uiSelected = DiagonalFxn[uiEdge];
|
|
|
|
if (WsrFxn[uiSelected].wsrfxn_fCandidate == TRUE)
|
|
{
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
printf("choose candidate edge %ld --> %ld (%ld --> %ld)\n",
|
|
DiagonalFxn[uiDiagCur], DiagonalFxn[uiEdge],
|
|
uiDiagCur, uiEdge);
|
|
#endif /* DEBUG */
|
|
|
|
// choose edge to candidate
|
|
uiDiagCur = uiEdge;
|
|
FxnOrder[cFxnOrder++] = uiSelected;
|
|
WsrFxn[uiSelected].wsrfxn_fCandidate = FALSE;
|
|
--cCandidates;
|
|
}
|
|
else
|
|
if ((NextEdge[uiEdge] == -1) && (uiEdge != uiDiagNext))
|
|
{
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
printf("*** skip edge %ld --> %ld (%ld --> %ld)\n",
|
|
DiagonalFxn[uiDiagCur], DiagonalFxn[uiEdge],
|
|
uiDiagCur, uiEdge);
|
|
#endif /* DEBUG */
|
|
continue; // skip this edge, it leads nowhere
|
|
}
|
|
else
|
|
{
|
|
// choose edge to non-candidate
|
|
|
|
#ifdef DEBUG
|
|
if (fVerbose == TRUE)
|
|
printf("choose edge %ld --> %ld (%ld --> %ld)\n",
|
|
DiagonalFxn[uiDiagCur], DiagonalFxn[uiEdge],
|
|
uiDiagCur, uiEdge);
|
|
#endif /* DEBUG */
|
|
uiDiagCur = uiEdge;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#endif /* OPTIMIZE */
|
|
|
|
/*
|
|
*
|
|
***LP wsRedOutput
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Prints the reordered list of functions, and writes each module's
|
|
* ordered list of function ordinals to the module's associated WSR file.
|
|
* If only one module is being processed, then we also write the ordered
|
|
* list of function names to a WLK file.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Void. If an error is encountered, exits through wsRedExit()
|
|
* with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedOutput()
|
|
{
|
|
UINT uiFxn;
|
|
UINT uiMod;
|
|
wsrfxn_t *pWsrFxn;
|
|
wsrmod_t *pWsrMod;
|
|
// fxn names for linker reordering
|
|
|
|
// Open one WSR file per module. If only one module is reduced,
|
|
// then also open a WLK file. Handle to WLK file is set in
|
|
// wsRedOpenWSR().
|
|
wsRedOpenWSR(&hFileWLK);
|
|
|
|
|
|
printf("\nDATA REDUCTION RESULTED IN THE FOLLOWING ORDERING:\n");
|
|
|
|
for (uiFxn = 0; uiFxn < cFxnsTot; uiFxn++)
|
|
{
|
|
pWsrFxn = &(WsrFxn[FxnOrder[uiFxn]]);
|
|
pWsrMod = &(WsrMod[pWsrFxn->wsrfxn_ulMod]);
|
|
|
|
/* Print the function information. */
|
|
#ifndef TMIFILEHACK
|
|
if (fFxnSizePresent == FALSE)
|
|
printf(" %s: %s\n",
|
|
pWsrMod->wsrmod_un.wsrmod_pchModName,
|
|
pWsrFxn->wsrfxn_pchFxnName);
|
|
else
|
|
#endif /* !TMIFILEHACK */
|
|
printf(" (0x%08lx bytes) %s: %s\n",
|
|
pWsrFxn->wsrfxn_cbFxn,
|
|
pWsrMod->wsrmod_un.wsrmod_pchModName,
|
|
pWsrFxn->wsrfxn_pchFxnName);
|
|
|
|
/* Write the function's ordinal number to its
|
|
* module's associated WSR output file.
|
|
*/
|
|
fprintf(pWsrMod->wsrmod_hFileWSR, "%ld\n",
|
|
pWsrFxn->wsrfxn_ulFxn);
|
|
|
|
/* Write the function name to the WLK file, for linker use. */
|
|
if (hFileWLK != NULL &&
|
|
strcmp("???", pWsrFxn->wsrfxn_pchFxnName) &&
|
|
strcmp("_penter", pWsrFxn->wsrfxn_pchFxnName))
|
|
fprintf(hFileWLK, "%s\n", pWsrFxn->wsrfxn_pchFxnName);
|
|
|
|
}
|
|
|
|
for (uiFxn = cFxnsTot; uiFxn < cTmiFxns; uiFxn++)
|
|
{
|
|
pWsrFxn = &(WsrFxn[FxnOrder[0]]);
|
|
pWsrMod = &(WsrMod[pWsrFxn->wsrfxn_ulMod]);
|
|
|
|
|
|
/* Write the function's ordinal number to its
|
|
* module's associated WSR output file.
|
|
*/
|
|
fprintf(pWsrMod->wsrmod_hFileWSR, "%ld\n",
|
|
uiFxn);
|
|
|
|
|
|
}
|
|
/* Close the WSR files. */
|
|
for (uiMod = 0; uiMod < cModsTot; uiMod++)
|
|
{
|
|
fclose(pWsrMod->wsrmod_hFileWSR);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
*
|
|
***LP wsRedUsage
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Prints out usage message, and exits with an error.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Exits with ERROR.
|
|
*/
|
|
|
|
VOID
|
|
wsRedUsage()
|
|
{
|
|
#ifdef DEBUG
|
|
printf("\nUsage: %s [/V] File.wsp [File.wsp ...]\n", szProgName);
|
|
printf(" /? Causes this usage message to be displayed\n");
|
|
printf(" /V Specifies verbose mode (debugging version only)\n");
|
|
#else
|
|
printf("\nUsage: %s File.wsp [File.wsp ...]\n", szProgName);
|
|
printf(" /? Causes this usage message to be displayed\n");
|
|
#endif /* DEBUG */
|
|
printf(" File.wsp Specifies a file containing module snapshot information.\n");
|
|
exit(ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***LP wsRedExit
|
|
*
|
|
***
|
|
* Requires:
|
|
*
|
|
*
|
|
***
|
|
*
|
|
* Effects:
|
|
*
|
|
* Frees up resources (as necessary). Exits with the specified
|
|
* exit code, or returns void if exit code is NOEXIT.
|
|
*
|
|
***
|
|
* Returns:
|
|
*
|
|
* Void, else exits.
|
|
*/
|
|
|
|
VOID
|
|
wsRedExit(uiExitCode, fPrintMsg, uiMsgCode, ulParam1, pszParam2)
|
|
UINT uiExitCode;
|
|
USHORT fPrintMsg;
|
|
UINT uiMsgCode;
|
|
ULONG ulParam1;
|
|
PSZ pszParam2;
|
|
{
|
|
|
|
|
|
/* Print message, if necessary. */
|
|
if (fPrintMsg == TRUE)
|
|
{
|
|
printf(pchMsg[uiMsgCode], szProgName, pszVersion, ulParam1, pszParam2);
|
|
}
|
|
|
|
// Special case: do NOT exit if called with NOEXIT.
|
|
if (uiExitCode == NOEXIT)
|
|
return;
|
|
|
|
exit(uiExitCode);
|
|
}
|
|
|
|
VOID wsRedCleanup(VOID)
|
|
{
|
|
INT x;
|
|
|
|
for (x=0;x < 5 ; x++ ) {
|
|
UnlockAndFreeMem(hMem[x]);
|
|
}
|
|
|
|
/* Close the WLK file. */
|
|
fclose(hFileWLK);
|
|
}
|
|
|
|
|
|
VOID wsRedWriteWlk(VOID)
|
|
{
|
|
FILE *hTmiFile;
|
|
CHAR chTmiLine[129];
|
|
//CHAR chFxnName[64];
|
|
UINT cbFxnName;
|
|
UINT x;
|
|
static CHAR szFxnName[CCHMAXPATHCOMP] = "";
|
|
|
|
|
|
hTmiFile = fopen(szFileTMI, "rt"); //Open TMI file to read balance of
|
|
//API's
|
|
//
|
|
// Next wee need to move the file pointer to the first API with a
|
|
// NULL Bitstring. This should be the API following the cbFxnsTot
|
|
// value plus 5 for the TMI header.
|
|
//
|
|
for (x=0;x < (cFxnsTot + 5) ; x++) {
|
|
fgets(chTmiLine, 128, hTmiFile);
|
|
}
|
|
|
|
|
|
//
|
|
// Now we read each function name and write it to the packing list.
|
|
//
|
|
|
|
while(!feof(hTmiFile))
|
|
{
|
|
|
|
cbFxnName = WsTMIReadRec(szFxnName,&ulFxnIndex,&ulTmp, hTmiFile,
|
|
(PFN) wsRedExit, (PCHAR)0);
|
|
if (hFileWLK != NULL &&
|
|
strcmp("???", szFxnName) &&
|
|
strcmp("_penter", szFxnName)) {
|
|
fprintf(hFileWLK, "%s\n", szFxnName);
|
|
}
|
|
}
|
|
|
|
|
|
fclose(hTmiFile);
|
|
|
|
}
|