Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

561 lines
16 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: profile.c
//
// Contents: PROFILER code
//
// History: 22-Nov-93 SethuR created
//
// Notes:
//
//--------------------------------------------------------------------------
// #include <ctype.h>
// #include <sys\types.h>
// #include <sys\stat.h>
// #include "ntsdp.h"
#include <profile.h>
#define MAX_STACK_HEIGHT 2000
#define INVOCATIONS_TO_PRINT 0
// Stack element used by wt profiling
typedef struct _SStackElement
{
unsigned char Symbol[MAX_SYMBOL_LEN];
unsigned long cInstructions;
unsigned long cLevel;
} SStackElement;
typedef SStackElement *PSStackElement;
PSStackElement CallStack;
LONG iStackDepth = -1;
PSProfile ps_ProfileDLL;
PSProfile ps_ProfileTrace;
BOOLEAN fProfilingDLL;
//-----------------------------------------------------------------
//
// Function: InitProfile
//
// Purpose: Initializes the data structure for Profiling.
// The profiling data structure uses a hash table
// to determine where to search/put new entries in
// the entries table.
//
// Input: Profile - pointer to profiler data structure
//
// Output: None
//
//------------------------------------------------------------------
void InitProfile(PSProfile Profile)
{
// Set all the entries in the profiler hash table to NULL
int i;
if (!CallStack) {
CallStack = calloc(MAX_STACK_HEIGHT, sizeof(SStackElement));
ps_ProfileDLL = calloc(1, sizeof(SProfile));
ps_ProfileTrace = calloc(1, sizeof(SProfile));
} else {
for (i = 0;i < MAX_NUM_OF_BUCKETS;i++) {
Profile->Buckets[i] = NULL;
}
// Set the used count
Profile->cUsed = 0;
}
}
//-----------------------------------------------------------------
//
// Function: AllocProfilerEntry
//
// Purpose: Allocates and initialized an entry in the profiler's
// entry table.
//
// Input: Profile - pointer to the profiling data structure
//
// Output: SProfileRecord * - pointer to the new entry in the
// profiler's entry table if one can
// be allocated. Otherwise, NULL is
// returned.
//
//------------------------------------------------------------------
SProfileRecord *AllocProfilerEntry(SProfile *Profile)
{
if (Profile->cUsed < MAX_PROFILE_ENTRIES)
{
SProfileRecord *pRecord = &(Profile->ProfileRecords[Profile->cUsed]);
pRecord->pNext = NULL;
Profile->cUsed++;
// Initialize the record ...
pRecord->cInvocations = 0;
pRecord->cMaxInstructions = 0;
pRecord->cMinInstructions = 0;
pRecord->cCumInstructions = 0;
return (pRecord);
}
else
{
// We need to assert the fact that the statically allocated pool
// has been overrun.
dprintf("Profile Allocation size exceeded, Report to SethuR\n");
return NULL;
}
}
//-----------------------------------------------------------------
//
// Function: SearchStructure
//
// Purpose: Searches the profiler data struture for the function
// name.
//
// Input: Profile - pointer to profiler data structure
// Symbol - pointer to name to search for
//
// Output: SProfileRecord - pointer to the entry that contains
// the name, Symbol, if found. Otherwise
// NULL is returned.
//
//------------------------------------------------------------------
SProfileRecord * SearchStructure (SProfile *Profile, UCHAR *Symbol)
{
unsigned long cHashNumber;
unsigned long iBucket;
SProfileRecord *pProfileRecord;
// Hash on the first + last letters of the symbol
cHashNumber = (unsigned long)Symbol[0] + (unsigned long)Symbol[strlen(Symbol)-1];
iBucket = HASH(cHashNumber);
// Search the bucket for the corresponding entry
pProfileRecord = Profile->Buckets[iBucket];
while (pProfileRecord != NULL)
{
if (!strcmp(pProfileRecord->Symbol, Symbol))
break;
else
pProfileRecord = pProfileRecord->pNext;
}
return (pProfileRecord);
}
//-----------------------------------------------------------------
//
// Function: UpdateProfile
//
// Purpose: Searches the profiler data structure for the name,
// Symbol. If one is found, the information in the
// corresponding entry is updated. Otherwise, a new
// entry is allocated and the information saved.
//
// For wt profiling, cValue contains the instruction
// count for the function. For function profiling,
// cValue contains the breakpoint number of the function.
//
// Input: Profile - pointer to profiling data structure
// Symbol - function name
// cValue - value to update
//
// Output: None
//
//------------------------------------------------------------------
void
UpdateProfile(
PSProfile *pProfile,
unsigned char Symbol[],
unsigned long cValue
)
{
unsigned long iBucket;
SProfileRecord *pProfileRecord;
unsigned long cHashNumber;
PSProfile Profile;
// Initialize the Profiler if not initialized already
if (!*pProfile) {
InitProfile(*pProfile);
}
Profile = *pProfile;
// Search data structure
pProfileRecord = SearchStructure (Profile, Symbol);
// If the search was unsuccessful record the new call Site.
if (pProfileRecord == NULL)
{
pProfileRecord = AllocProfilerEntry(Profile);
// Hash on the first + last letters of the symbol
cHashNumber = (unsigned long)Symbol[0] + (unsigned long)Symbol[strlen(Symbol)-1];
iBucket = HASH(cHashNumber);
if (pProfileRecord != NULL)
{
pProfileRecord->pNext = Profile->Buckets[iBucket];
strcpy (pProfileRecord->Symbol, Symbol);
if (PROFILING)
{
pProfileRecord->cInvocations = 0;
pProfileRecord->cBrkptType = BRKPT_PROFILE;
pProfileRecord->cBrkptNo = cValue;
}
else
{
pProfileRecord->cInvocations = 1;
pProfileRecord->cMinInstructions = cValue;
pProfileRecord->cMaxInstructions = cValue;
pProfileRecord->cCumInstructions = cValue;
}
Profile->Buckets[iBucket] = pProfileRecord;
}
}
else
{
// Augment the invocation count.
pProfileRecord->cInvocations++;
if (!PROFILING)
{
if (pProfileRecord->cMinInstructions > cValue)
pProfileRecord->cMinInstructions = cValue;
if (pProfileRecord->cMaxInstructions < cValue)
pProfileRecord->cMaxInstructions = cValue;
pProfileRecord->cCumInstructions += cValue;
}
}
}
//-----------------------------------------------------------------
//
// Function: DumpProfile
//
// Purpose: Display the information in the profiler data structure.
//
// Input: Profile - pointer to profiler data structure
//
// Output: None
//
//------------------------------------------------------------------
void
DumpProfile(
SProfile *Profile
)
{
unsigned long i;
if (!PROFILING)
dprintf ("\n\n%-30.30s Invocations MinInstr MaxInstr AvgInstr\n\n", "Function Name");
else
dprintf ("\n\n%-60.60s Invocations\n\n", "FunctionName");
for (i = 0; i < Profile->cUsed; i++)
{
if (Profile->ProfileRecords[i].cInvocations > INVOCATIONS_TO_PRINT)
{
if (!PROFILING )
{
dprintf("%-30.30s %8d %8d %8d %8d\n",
Profile->ProfileRecords[i].Symbol,
Profile->ProfileRecords[i].cInvocations,
Profile->ProfileRecords[i].cMinInstructions,
Profile->ProfileRecords[i].cMaxInstructions,
( Profile->ProfileRecords[i].cCumInstructions /
Profile->ProfileRecords[i].cInvocations));
}
else
{
dprintf("%-60.60s %8d\n", Profile->ProfileRecords[i].Symbol,
Profile->ProfileRecords[i].cInvocations);
}
}
Profile->ProfileRecords[i].cInvocations = 0;
Profile->ProfileRecords[i].pNext = &(Profile->ProfileRecords[i+1]);
}
}
//-----------------------------------------------------------------
//
// Function: Profile
//
// Purpose: Used by wt profiling to keep track of trace information.
// A stack is used to keep track of the call tree. The
// function invocation count is incremented only when
// the function is removed from the stack. A function
// is removed from the stack when another function of
// a lower level is reached.
//
// Input: Profile - pointer to profiling data structure
// Symbol - function name to store in profiler data structure.
// cInstructions - instructions executed by the function
// cLevel - level in the call tree
//
// Output: None
//
//------------------------------------------------------------------
void
Profile(
PSProfile *pProfile,
unsigned char *Symbol,
unsigned long cInstructions,
unsigned long cLevel
)
{
long cNewLevel = -1;
PSProfile Profile;
if (!*pProfile) {
InitProfile(*pProfile);
}
Profile = *pProfile;
if (iStackDepth == -1)
{
iStackDepth = 0;
cNewLevel = 0;
}
else
{
// See if this is a lower level function than the current function on
// the stack. If so, pop the stack until at the same level
if (CallStack[iStackDepth].cLevel > cLevel)
{
for ( ; CallStack[iStackDepth].cLevel > cLevel; iStackDepth -= 1)
{
UpdateProfile(pProfile,
CallStack[iStackDepth].Symbol,
CallStack[iStackDepth].cInstructions);
CallStack[iStackDepth-1].cInstructions += CallStack[iStackDepth].cInstructions;
}
}
if (CallStack[iStackDepth].cLevel == cLevel)
{
if (!strcmp(CallStack[iStackDepth].Symbol, Symbol))
{
// Function hasn't finished executing
CallStack[iStackDepth].cInstructions += cInstructions;
}
else
{
// Function finished executing. Save info in Profile
UpdateProfile(pProfile,
CallStack[iStackDepth].Symbol,
CallStack[iStackDepth].cInstructions);
CallStack[iStackDepth-1].cInstructions += CallStack[iStackDepth].cInstructions;
cNewLevel = iStackDepth;
}
}
else if (CallStack[iStackDepth].cLevel < cLevel)
{
// New symbol at higher level
iStackDepth++;
cNewLevel = iStackDepth;
}
}
if (cNewLevel != -1)
{
// Initialize the new stack element
strcpy(CallStack[cNewLevel].Symbol , Symbol);
CallStack[cNewLevel].cInstructions = cInstructions;
CallStack[cNewLevel].cLevel = cLevel;
}
}
//-----------------------------------------------------------------
//
// Function: ProcDump
//
// Purpose: Called by wt profiling to dump out the information in
// profiling data structre. The stack is cleared of
// functions.
//
// Input: Profile - pointer to profiler data structure
//
// Output: None
//
//------------------------------------------------------------------
void ProcDump (PSProfile *Profile )
{
// Clear the stack of any symbols
for ( ; iStackDepth >= 0; iStackDepth -= 1)
{
UpdateProfile(Profile,
CallStack[iStackDepth].Symbol,
CallStack[iStackDepth].cInstructions);
if (iStackDepth != 0)
{
CallStack[iStackDepth-1].cInstructions += CallStack[iStackDepth].cInstructions;
}
}
DumpProfile (*Profile);
InitProfile (*Profile);
}
//-----------------------------------------------------------------
//
// Function: UpdateBrkpt
//
// Purpose: Update the type of breakpoint to BrkptType.
//
// Input: Profile - pointer to profiling data structure
// BrkptNo - break point number to update
// BrkptType - break point type to update breakpoint to
//
// Output: BOOLEAN - TRUE for successful update
// FALSE for breakpoint breakpoint number not found.
//
//------------------------------------------------------------------
BOOLEAN UpdateBrkpt (SProfile *Profile, ULONG BrkptNo, ULONG BrkptType)
{
ULONG i;
if (Profile == NULL)
{
return (FALSE);
}
//Search data structure for the breakpoint
for (i = 0; i < Profile->cUsed; i ++)
{
if (Profile->ProfileRecords[i].cBrkptNo == BrkptNo)
{
Profile->ProfileRecords[i].cBrkptType = BrkptType;
return (TRUE);
}
}
return (FALSE);
}
//-----------------------------------------------------------------
//
// Function: GetBrkptType
//
// Purpose: Get the type of breakpoint.
//
// Input: Profile - pointer to profiling data structure
// BrkptNo - break point number to look at
//
// Output: BRKPT_PROFILE - breakpoint is a profiling breakpoint
// BRKPT_USER - brkpt is profiling breakpoint but
// it is currently set manually by user.
// BRKPT_NOT_FOUND - brkpt is not a profiling breakpoint
//
//------------------------------------------------------------------
LONG GetBrkptType (SProfile *Profile, ULONG BrkptNo)
{
ULONG i;
for (i = 0; i < Profile->cUsed; i++)
{
if (Profile->ProfileRecords[i].cBrkptNo == BrkptNo)
{
return (Profile->ProfileRecords[i].cBrkptType);
}
}
return (BRKPT_NOT_FOUND);
}
//-----------------------------------------------------------------
//
// Function: fnStartProfilingDLL
//
// Purpose: Set up the breakpoints for profiling. The parseExamine()
// routine is called to find the list of brkpts corresponding
// to the user request. Breakpoints are set as each
// function is found in parseExamine().
//
// Input: Profile - pointer to profiling data structure
//
// Output: TRUE - successful
// FALSE - unsuccessful - function name not entered
//
//------------------------------------------------------------------
BOOLEAN fnStartProfilingDLL (PSProfile *Profile)
{
UCHAR ch;
UCHAR chDLL[50];
// Get the DLL name entered
ch = PeekChar();
if (ch == '\0')
{
dprintf ("A DLL name must be entered with this command.\n");
return (FALSE);
}
// set command to invoke the 'x' functionality
strcpy (chDLL, pchCommand);
pchCommand = &chCommand[0];
strcpy (pchCommand, chDLL);
// call function to parse the 'x' command
parseExamine();
return (TRUE);
}
//-----------------------------------------------------------------
//
// Function: fnStopProfilingDLL
//
// Purpose: Stops profiling functions. Clears all profiling
// breakpoints that are not being used by the user.
// The data in profiling data structure is dumped out.
//
// Input: Profile - pointer to profiling data structure
//
// Output: None
//
//------------------------------------------------------------------
void fnStopProfilingDLL (PSProfile *Profile)
{
ULONG cEntries;
// clear all breakpoints set for profiling
for (cEntries = 0; cEntries < (*Profile)->cUsed; cEntries++)
{
if ((*Profile)->ProfileRecords[cEntries].cBrkptType == BRKPT_PROFILE)
fnChangeBpState ((*Profile)->ProfileRecords[cEntries].cBrkptNo, 'c');
}
DumpProfile(*Profile);
InitProfile(*Profile);
}