#include "setup.h"
#if PROFILING_FUNCTIONS
#include "argacces.h"
#include "classcom.h"
#include "dffnxfun.h"
#include "envrnmnt.h"
#include "extnfunc.h"
#include "genrccom.h"
#include "genrcfun.h"
#include "memalloc.h"
#include "msgcom.h"
#include "router.h"
#include "sysdep.h"
#include "proflfun.h"
#include <string.h>
#define NO_PROFILE 0
#define USER_FUNCTIONS 1
#define CONSTRUCTS_CODE 2
#define OUTPUT_STRING "%-40s %7ld %15.6f %8.2f%% %15.6f %8.2f%%\n"
static bool OutputProfileInfo(Environment *,const char *,struct constructProfileInfo *,
const char *,const char *,const char *,const char **);
static void OutputUserFunctionsInfo(Environment *);
static void OutputConstructsCodeInfo(Environment *);
#if (! RUN_TIME)
static void ProfileClearFunction(Environment *,void *);
#endif
void ConstructProfilingFunctionDefinitions(
Environment *theEnv)
{
struct userDataRecord profileDataInfo = { 0, CreateProfileData, DeleteProfileData };
AllocateEnvironmentData(theEnv,PROFLFUN_DATA,sizeof(struct profileFunctionData),NULL);
memcpy(&ProfileFunctionData(theEnv)->ProfileDataInfo,&profileDataInfo,sizeof(struct userDataRecord));
ProfileFunctionData(theEnv)->LastProfileInfo = NO_PROFILE;
ProfileFunctionData(theEnv)->PercentThreshold = 0.0;
ProfileFunctionData(theEnv)->OutputString = OUTPUT_STRING;
#if ! RUN_TIME
AddUDF(theEnv,"profile","v",1,1,"y",ProfileCommand,"ProfileCommand",NULL);
AddUDF(theEnv,"profile-info","v",0,0,NULL, ProfileInfoCommand,"ProfileInfoCommand",NULL);
AddUDF(theEnv,"profile-reset","v",0,0,NULL,ProfileResetCommand,"ProfileResetCommand",NULL);
AddUDF(theEnv,"set-profile-percent-threshold","d",1,1,"ld",SetProfilePercentThresholdCommand,"SetProfilePercentThresholdCommand",NULL);
AddUDF(theEnv,"get-profile-percent-threshold","d",0,0,NULL,GetProfilePercentThresholdCommand,"GetProfilePercentThresholdCommand",NULL);
ProfileFunctionData(theEnv)->ProfileDataID = InstallUserDataRecord(theEnv,&ProfileFunctionData(theEnv)->ProfileDataInfo);
AddClearFunction(theEnv,"profile",ProfileClearFunction,0,NULL);
#endif
}
void *CreateProfileData(
Environment *theEnv)
{
struct constructProfileInfo *theInfo;
theInfo = (struct constructProfileInfo *)
genalloc(theEnv,sizeof(struct constructProfileInfo));
theInfo->numberOfEntries = 0;
theInfo->childCall = false;
theInfo->startTime = 0.0;
theInfo->totalSelfTime = 0.0;
theInfo->totalWithChildrenTime = 0.0;
return(theInfo);
}
void DeleteProfileData(
Environment *theEnv,
void *theData)
{
genfree(theEnv,theData,sizeof(struct constructProfileInfo));
}
void ProfileCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
const char *argument;
UDFValue theValue;
if (! UDFFirstArgument(context,SYMBOL_BIT,&theValue)) return;
argument = theValue.lexemeValue->contents;
if (! Profile(theEnv,argument))
{
UDFInvalidArgumentMessage(context,"symbol with value constructs, user-functions, or off");
return;
}
return;
}
bool Profile(
Environment *theEnv,
const char *argument)
{
if (strcmp(argument,"user-functions") == 0)
{
ProfileFunctionData(theEnv)->ProfileStartTime = gentime();
ProfileFunctionData(theEnv)->ProfileUserFunctions = true;
ProfileFunctionData(theEnv)->ProfileConstructs = false;
ProfileFunctionData(theEnv)->LastProfileInfo = USER_FUNCTIONS;
}
else if (strcmp(argument,"constructs") == 0)
{
ProfileFunctionData(theEnv)->ProfileStartTime = gentime();
ProfileFunctionData(theEnv)->ProfileUserFunctions = false;
ProfileFunctionData(theEnv)->ProfileConstructs = true;
ProfileFunctionData(theEnv)->LastProfileInfo = CONSTRUCTS_CODE;
}
else if (strcmp(argument,"off") == 0)
{
ProfileFunctionData(theEnv)->ProfileEndTime = gentime();
ProfileFunctionData(theEnv)->ProfileTotalTime += (ProfileFunctionData(theEnv)->ProfileEndTime - ProfileFunctionData(theEnv)->ProfileStartTime);
ProfileFunctionData(theEnv)->ProfileUserFunctions = false;
ProfileFunctionData(theEnv)->ProfileConstructs = false;
}
else
{ return false; }
return true;
}
void ProfileInfoCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
char buffer[512];
if (ProfileFunctionData(theEnv)->ProfileUserFunctions || ProfileFunctionData(theEnv)->ProfileConstructs)
{
ProfileFunctionData(theEnv)->ProfileEndTime = gentime();
ProfileFunctionData(theEnv)->ProfileTotalTime += (ProfileFunctionData(theEnv)->ProfileEndTime - ProfileFunctionData(theEnv)->ProfileStartTime);
}
if (ProfileFunctionData(theEnv)->LastProfileInfo != NO_PROFILE)
{
gensprintf(buffer,"Profile elapsed time = %g seconds\n",
ProfileFunctionData(theEnv)->ProfileTotalTime);
WriteString(theEnv,STDOUT,buffer);
if (ProfileFunctionData(theEnv)->LastProfileInfo == USER_FUNCTIONS)
{ WriteString(theEnv,STDOUT,"Function Name "); }
else if (ProfileFunctionData(theEnv)->LastProfileInfo == CONSTRUCTS_CODE)
{ WriteString(theEnv,STDOUT,"Construct Name "); }
WriteString(theEnv,STDOUT,"Entries Time % Time+Kids %+Kids\n");
if (ProfileFunctionData(theEnv)->LastProfileInfo == USER_FUNCTIONS)
{ WriteString(theEnv,STDOUT,"------------- "); }
else if (ProfileFunctionData(theEnv)->LastProfileInfo == CONSTRUCTS_CODE)
{ WriteString(theEnv,STDOUT,"-------------- "); }
WriteString(theEnv,STDOUT,"------- ------ ----- --------- ------\n");
}
if (ProfileFunctionData(theEnv)->LastProfileInfo == USER_FUNCTIONS) OutputUserFunctionsInfo(theEnv);
if (ProfileFunctionData(theEnv)->LastProfileInfo == CONSTRUCTS_CODE) OutputConstructsCodeInfo(theEnv);
}
void StartProfile(
Environment *theEnv,
struct profileFrameInfo *theFrame,
struct userData **theList,
bool checkFlag)
{
double startTime, addTime;
struct constructProfileInfo *profileInfo;
if (! checkFlag)
{
theFrame->profileOnExit = false;
return;
}
profileInfo = (struct constructProfileInfo *) FetchUserData(theEnv,ProfileFunctionData(theEnv)->ProfileDataID,theList);
theFrame->profileOnExit = true;
theFrame->parentCall = false;
startTime = gentime();
theFrame->oldProfileFrame = ProfileFunctionData(theEnv)->ActiveProfileFrame;
if (ProfileFunctionData(theEnv)->ActiveProfileFrame != NULL)
{
addTime = startTime - ProfileFunctionData(theEnv)->ActiveProfileFrame->startTime;
ProfileFunctionData(theEnv)->ActiveProfileFrame->totalSelfTime += addTime;
}
ProfileFunctionData(theEnv)->ActiveProfileFrame = profileInfo;
ProfileFunctionData(theEnv)->ActiveProfileFrame->numberOfEntries++;
ProfileFunctionData(theEnv)->ActiveProfileFrame->startTime = startTime;
if (! ProfileFunctionData(theEnv)->ActiveProfileFrame->childCall)
{
theFrame->parentCall = true;
theFrame->parentStartTime = startTime;
ProfileFunctionData(theEnv)->ActiveProfileFrame->childCall = true;
}
}
void EndProfile(
Environment *theEnv,
struct profileFrameInfo *theFrame)
{
double endTime, addTime;
if (! theFrame->profileOnExit) return;
endTime = gentime();
if (theFrame->parentCall)
{
addTime = endTime - theFrame->parentStartTime;
ProfileFunctionData(theEnv)->ActiveProfileFrame->totalWithChildrenTime += addTime;
ProfileFunctionData(theEnv)->ActiveProfileFrame->childCall = false;
}
ProfileFunctionData(theEnv)->ActiveProfileFrame->totalSelfTime += (endTime - ProfileFunctionData(theEnv)->ActiveProfileFrame->startTime);
if (theFrame->oldProfileFrame != NULL)
{ theFrame->oldProfileFrame->startTime = endTime; }
ProfileFunctionData(theEnv)->ActiveProfileFrame = theFrame->oldProfileFrame;
}
static bool OutputProfileInfo(
Environment *theEnv,
const char *itemName,
struct constructProfileInfo *profileInfo,
const char *printPrefixBefore,
const char *printPrefix,
const char *printPrefixAfter,
const char **banner)
{
double percent = 0.0, percentWithKids = 0.0;
char buffer[512];
if (profileInfo == NULL) return false;
if (profileInfo->numberOfEntries == 0) return false;
if (ProfileFunctionData(theEnv)->ProfileTotalTime != 0.0)
{
percent = (profileInfo->totalSelfTime * 100.0) / ProfileFunctionData(theEnv)->ProfileTotalTime;
if (percent < 0.005) percent = 0.0;
percentWithKids = (profileInfo->totalWithChildrenTime * 100.0) / ProfileFunctionData(theEnv)->ProfileTotalTime;
if (percentWithKids < 0.005) percentWithKids = 0.0;
}
if (percent < ProfileFunctionData(theEnv)->PercentThreshold) return false;
if ((banner != NULL) && (*banner != NULL))
{
WriteString(theEnv,STDOUT,*banner);
*banner = NULL;
}
if (printPrefixBefore != NULL)
{ WriteString(theEnv,STDOUT,printPrefixBefore); }
if (printPrefix != NULL)
{ WriteString(theEnv,STDOUT,printPrefix); }
if (printPrefixAfter != NULL)
{ WriteString(theEnv,STDOUT,printPrefixAfter); }
if (strlen(itemName) >= 40)
{
WriteString(theEnv,STDOUT,itemName);
WriteString(theEnv,STDOUT,"\n");
itemName = "";
}
gensprintf(buffer,ProfileFunctionData(theEnv)->OutputString,
itemName,
(long) profileInfo->numberOfEntries,
(double) profileInfo->totalSelfTime,
(double) percent,
(double) profileInfo->totalWithChildrenTime,
(double) percentWithKids);
WriteString(theEnv,STDOUT,buffer);
return true;
}
void ProfileResetCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
struct functionDefinition *theFunction;
int i;
#if DEFFUNCTION_CONSTRUCT
Deffunction *theDeffunction;
#endif
#if DEFRULE_CONSTRUCT
Defrule *theDefrule;
#endif
#if DEFGENERIC_CONSTRUCT
Defgeneric *theDefgeneric;
unsigned short methodIndex;
Defmethod *theMethod;
#endif
#if OBJECT_SYSTEM
Defclass *theDefclass;
DefmessageHandler *theHandler;
unsigned handlerIndex;
#endif
ProfileFunctionData(theEnv)->ProfileStartTime = 0.0;
ProfileFunctionData(theEnv)->ProfileEndTime = 0.0;
ProfileFunctionData(theEnv)->ProfileTotalTime = 0.0;
ProfileFunctionData(theEnv)->LastProfileInfo = NO_PROFILE;
for (theFunction = GetFunctionList(theEnv);
theFunction != NULL;
theFunction = theFunction->next)
{
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theFunction->usrData));
}
for (i = 0; i < MAXIMUM_PRIMITIVES; i++)
{
if (EvaluationData(theEnv)->PrimitivesArray[i] != NULL)
{
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,EvaluationData(theEnv)->PrimitivesArray[i]->usrData));
}
}
#if DEFFUNCTION_CONSTRUCT
for (theDeffunction = GetNextDeffunction(theEnv,NULL);
theDeffunction != NULL;
theDeffunction = GetNextDeffunction(theEnv,theDeffunction))
{
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theDeffunction->header.usrData));
}
#endif
#if DEFRULE_CONSTRUCT
for (theDefrule = GetNextDefrule(theEnv,NULL);
theDefrule != NULL;
theDefrule = GetNextDefrule(theEnv,theDefrule))
{
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theDefrule->header.usrData));
}
#endif
#if DEFGENERIC_CONSTRUCT
for (theDefgeneric = GetNextDefgeneric(theEnv,NULL);
theDefgeneric != NULL;
theDefgeneric = GetNextDefgeneric(theEnv,theDefgeneric))
{
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theDefgeneric->header.usrData));
for (methodIndex = GetNextDefmethod(theDefgeneric,0);
methodIndex != 0;
methodIndex = GetNextDefmethod(theDefgeneric,methodIndex))
{
theMethod = GetDefmethodPointer(theDefgeneric,methodIndex);
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theMethod->header.usrData));
}
}
#endif
#if OBJECT_SYSTEM
for (theDefclass = GetNextDefclass(theEnv,NULL);
theDefclass != NULL;
theDefclass = GetNextDefclass(theEnv,theDefclass))
{
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theDefclass->header.usrData));
for (handlerIndex = GetNextDefmessageHandler(theDefclass,0);
handlerIndex != 0;
handlerIndex = GetNextDefmessageHandler(theDefclass,handlerIndex))
{
theHandler = GetDefmessageHandlerPointer(theDefclass,handlerIndex);
ResetProfileInfo((struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theHandler->header.usrData));
}
}
#endif
}
void ResetProfileInfo(
struct constructProfileInfo *profileInfo)
{
if (profileInfo == NULL) return;
profileInfo->numberOfEntries = 0;
profileInfo->childCall = false;
profileInfo->startTime = 0.0;
profileInfo->totalSelfTime = 0.0;
profileInfo->totalWithChildrenTime = 0.0;
}
static void OutputUserFunctionsInfo(
Environment *theEnv)
{
struct functionDefinition *theFunction;
int i;
for (theFunction = GetFunctionList(theEnv);
theFunction != NULL;
theFunction = theFunction->next)
{
OutputProfileInfo(theEnv,theFunction->callFunctionName->contents,
(struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,
theFunction->usrData),
NULL,NULL,NULL,NULL);
}
for (i = 0; i < MAXIMUM_PRIMITIVES; i++)
{
if (EvaluationData(theEnv)->PrimitivesArray[i] != NULL)
{
OutputProfileInfo(theEnv,EvaluationData(theEnv)->PrimitivesArray[i]->name,
(struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,
EvaluationData(theEnv)->PrimitivesArray[i]->usrData),
NULL,NULL,NULL,NULL);
}
}
}
static void OutputConstructsCodeInfo(
Environment *theEnv)
{
#if (! DEFFUNCTION_CONSTRUCT) && (! DEFGENERIC_CONSTRUCT) && (! OBJECT_SYSTEM) && (! DEFRULE_CONSTRUCT)
#pragma unused(theEnv)
#endif
#if DEFFUNCTION_CONSTRUCT
Deffunction *theDeffunction;
#endif
#if DEFRULE_CONSTRUCT
Defrule *theDefrule;
#endif
#if DEFGENERIC_CONSTRUCT
Defgeneric *theDefgeneric;
Defmethod *theMethod;
unsigned short methodIndex;
StringBuilder *theSB;
#endif
#if OBJECT_SYSTEM
Defclass *theDefclass;
DefmessageHandler *theHandler;
unsigned handlerIndex;
#endif
#if DEFGENERIC_CONSTRUCT || OBJECT_SYSTEM
const char *prefix, *prefixBefore, *prefixAfter;
#endif
const char *banner;
banner = "\n*** Deffunctions ***\n\n";
#if DEFFUNCTION_CONSTRUCT
for (theDeffunction = GetNextDeffunction(theEnv,NULL);
theDeffunction != NULL;
theDeffunction = GetNextDeffunction(theEnv,theDeffunction))
{
OutputProfileInfo(theEnv,DeffunctionName(theDeffunction),
(struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theDeffunction->header.usrData),
NULL,NULL,NULL,&banner);
}
#endif
banner = "\n*** Defgenerics ***\n";
#if DEFGENERIC_CONSTRUCT
theSB = CreateStringBuilder(theEnv,512);
for (theDefgeneric = GetNextDefgeneric(theEnv,NULL);
theDefgeneric != NULL;
theDefgeneric = GetNextDefgeneric(theEnv,theDefgeneric))
{
prefixBefore = "\n";
prefix = DefgenericName(theDefgeneric);
prefixAfter = "\n";
for (methodIndex = GetNextDefmethod(theDefgeneric,0);
methodIndex != 0;
methodIndex = GetNextDefmethod(theDefgeneric,methodIndex))
{
theMethod = GetDefmethodPointer(theDefgeneric,methodIndex);
DefmethodDescription(theDefgeneric,methodIndex,theSB);
if (OutputProfileInfo(theEnv,theSB->contents,
(struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theMethod->header.usrData),
prefixBefore,prefix,prefixAfter,&banner))
{
prefixBefore = NULL;
prefix = NULL;
prefixAfter = NULL;
}
}
}
SBDispose(theSB);
#endif
banner = "\n*** Defclasses ***\n";
#if OBJECT_SYSTEM
for (theDefclass = GetNextDefclass(theEnv,NULL);
theDefclass != NULL;
theDefclass = GetNextDefclass(theEnv,theDefclass))
{
prefixAfter = "\n";
prefix = DefclassName(theDefclass);
prefixBefore = "\n";
for (handlerIndex = GetNextDefmessageHandler(theDefclass,0);
handlerIndex != 0;
handlerIndex = GetNextDefmessageHandler(theDefclass,handlerIndex))
{
theHandler = GetDefmessageHandlerPointer(theDefclass,handlerIndex);
if (OutputProfileInfo(theEnv,DefmessageHandlerName(theDefclass,handlerIndex),
(struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,
theHandler->header.usrData),
prefixBefore,prefix,prefixAfter,&banner))
{
prefixBefore = NULL;
prefix = NULL;
prefixAfter = NULL;
}
}
}
#endif
banner = "\n*** Defrules ***\n\n";
#if DEFRULE_CONSTRUCT
for (theDefrule = GetNextDefrule(theEnv,NULL);
theDefrule != NULL;
theDefrule = GetNextDefrule(theEnv,theDefrule))
{
OutputProfileInfo(theEnv,DefruleName(theDefrule),
(struct constructProfileInfo *)
TestUserData(ProfileFunctionData(theEnv)->ProfileDataID,theDefrule->header.usrData),
NULL,NULL,NULL,&banner);
}
#endif
}
void SetProfilePercentThresholdCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
UDFValue theValue;
double newThreshold;
if (! UDFFirstArgument(context,NUMBER_BITS,&theValue))
{ return; }
newThreshold = CVCoerceToFloat(&theValue);
if ((newThreshold < 0.0) || (newThreshold > 100.0))
{
UDFInvalidArgumentMessage(context,"number in the range 0 to 100");
returnValue->floatValue = CreateFloat(theEnv,-1.0);
}
else
{ returnValue->floatValue = CreateFloat(theEnv,SetProfilePercentThreshold(theEnv,newThreshold)); }
}
double SetProfilePercentThreshold(
Environment *theEnv,
double value)
{
double oldPercentThreshhold;
if ((value < 0.0) || (value > 100.0))
{ return(-1.0); }
oldPercentThreshhold = ProfileFunctionData(theEnv)->PercentThreshold;
ProfileFunctionData(theEnv)->PercentThreshold = value;
return(oldPercentThreshhold);
}
void GetProfilePercentThresholdCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->floatValue = CreateFloat(theEnv,ProfileFunctionData(theEnv)->PercentThreshold);
}
double GetProfilePercentThreshold(
Environment *theEnv)
{
return(ProfileFunctionData(theEnv)->PercentThreshold);
}
const char *SetProfileOutputString(
Environment *theEnv,
const char *value)
{
const char *oldOutputString;
if (value == NULL)
{ return(ProfileFunctionData(theEnv)->OutputString); }
oldOutputString = ProfileFunctionData(theEnv)->OutputString;
ProfileFunctionData(theEnv)->OutputString = value;
return(oldOutputString);
}
#if (! RUN_TIME)
static void ProfileClearFunction(
Environment *theEnv,
void *context)
{
struct functionDefinition *theFunction;
int i;
for (theFunction = GetFunctionList(theEnv);
theFunction != NULL;
theFunction = theFunction->next)
{
theFunction->usrData =
DeleteUserData(theEnv,ProfileFunctionData(theEnv)->ProfileDataID,theFunction->usrData);
}
for (i = 0; i < MAXIMUM_PRIMITIVES; i++)
{
if (EvaluationData(theEnv)->PrimitivesArray[i] != NULL)
{
EvaluationData(theEnv)->PrimitivesArray[i]->usrData =
DeleteUserData(theEnv,ProfileFunctionData(theEnv)->ProfileDataID,EvaluationData(theEnv)->PrimitivesArray[i]->usrData);
}
}
}
#endif
#endif