globle intBool Profile( void *theEnv, char *argument) { /*======================================================*/ /* If the argument is the symbol "user-functions", then */ /* user-defined functions should be profiled. If the */ /* argument is the symbol "constructs", then */ /* deffunctions, generic functions, message-handlers, */ /* and rule RHS actions are profiled. */ /*======================================================*/ 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; } /*======================================================*/ /* Otherwise, if the argument is the symbol "off", then */ /* don't profile constructs and user-defined functions. */ /*======================================================*/ 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; } /*=====================================================*/ /* Otherwise, generate an error since the only allowed */ /* arguments are "on" or "off." */ /*=====================================================*/ else { return(FALSE); } return(TRUE); }
globle double TimerFunction( void *theEnv) { int numa, i; double startTime; DATA_OBJECT returnValue; startTime = gentime(); numa = EnvRtnArgCount(theEnv); i = 1; while ((i <= numa) && (GetHaltExecution(theEnv) != TRUE)) { EnvRtnUnknown(theEnv,i,&returnValue); i++; } return(gentime() - startTime); }
globle double TimeFunction( void *theEnv) { /*=========================================*/ /* The time function accepts no arguments. */ /*=========================================*/ EnvArgCountCheck(theEnv,"time",EXACTLY,0); /*==================*/ /* Return the time. */ /*==================*/ return(gentime()); }
void ProfileInfoCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { char buffer[512]; /*==================================*/ /* If code is still being profiled, */ /* update the profile end time. */ /*==================================*/ if (ProfileFunctionData(theEnv)->ProfileUserFunctions || ProfileFunctionData(theEnv)->ProfileConstructs) { ProfileFunctionData(theEnv)->ProfileEndTime = gentime(); ProfileFunctionData(theEnv)->ProfileTotalTime += (ProfileFunctionData(theEnv)->ProfileEndTime - ProfileFunctionData(theEnv)->ProfileStartTime); } /*==================================*/ /* Print the profiling information. */ /*==================================*/ 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); }
globle void StartProfile( void *theEnv, struct profileFrameInfo *theFrame, struct userData **theList, intBool 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; } }
globle void EndProfile( void *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; }
globle void ProfileInfoCommand( void *theEnv) { int argCount; DATA_OBJECT theValue; char buffer[512]; /*===================================*/ /* The profile-info command expects */ /* at most a single symbol argument. */ /*===================================*/ if ((argCount = EnvArgCountCheck(theEnv,"profile",NO_MORE_THAN,1)) == -1) return; /*===========================================*/ /* The first profile-info argument indicates */ /* the field on which sorting is performed. */ /*===========================================*/ if (argCount == 1) { if (EnvArgTypeCheck(theEnv,"profile",1,SYMBOL,&theValue) == FALSE) return; } /*==================================*/ /* If code is still being profiled, */ /* update the profile end time. */ /*==================================*/ if (ProfileFunctionData(theEnv)->ProfileUserFunctions || ProfileFunctionData(theEnv)->ProfileConstructs) { ProfileFunctionData(theEnv)->ProfileEndTime = gentime(); ProfileFunctionData(theEnv)->ProfileTotalTime += (ProfileFunctionData(theEnv)->ProfileEndTime - ProfileFunctionData(theEnv)->ProfileStartTime); } /*==================================*/ /* Print the profiling information. */ /*==================================*/ if (ProfileFunctionData(theEnv)->LastProfileInfo != NO_PROFILE) { sprintf(buffer,"Profile elapsed time = %g seconds\n", ProfileFunctionData(theEnv)->ProfileTotalTime); EnvPrintRouter(theEnv,WDISPLAY,buffer); if (ProfileFunctionData(theEnv)->LastProfileInfo == USER_FUNCTIONS) { EnvPrintRouter(theEnv,WDISPLAY,"Function Name "); } else if (ProfileFunctionData(theEnv)->LastProfileInfo == CONSTRUCTS_CODE) { EnvPrintRouter(theEnv,WDISPLAY,"Construct Name "); } EnvPrintRouter(theEnv,WDISPLAY,"Entries Time % Time+Kids %+Kids\n"); if (ProfileFunctionData(theEnv)->LastProfileInfo == USER_FUNCTIONS) { EnvPrintRouter(theEnv,WDISPLAY,"------------- "); } else if (ProfileFunctionData(theEnv)->LastProfileInfo == CONSTRUCTS_CODE) { EnvPrintRouter(theEnv,WDISPLAY,"-------------- "); } EnvPrintRouter(theEnv,WDISPLAY,"------- ------ ----- --------- ------\n"); } if (ProfileFunctionData(theEnv)->LastProfileInfo == USER_FUNCTIONS) OutputUserFunctionsInfo(theEnv); if (ProfileFunctionData(theEnv)->LastProfileInfo == CONSTRUCTS_CODE) OutputConstructsCodeInfo(theEnv); }
globle long int EnvRun( void *theEnv, long int runLimit) { long int rulesFired = 0; DATA_OBJECT result; struct callFunctionItem *theRunFunction; #if DEBUGGING_FUNCTIONS unsigned long maxActivations = 0, sumActivations = 0; #if DEFTEMPLATE_CONSTRUCT unsigned long maxFacts = 0, sumFacts = 0; #endif #if OBJECT_SYSTEM unsigned long maxInstances = 0, sumInstances = 0; #endif double endTime, startTime = 0.0; unsigned long tempValue; #endif unsigned int i; struct patternEntity *theMatchingItem; struct partialMatch *theBasis; ACTIVATION *theActivation; char *ruleFiring; #if PROFILING_FUNCTIONS struct profileFrameInfo profileFrame; #endif /*=====================================================*/ /* Make sure the run command is not already executing. */ /*=====================================================*/ if (EngineData(theEnv)->AlreadyRunning) return(0); EngineData(theEnv)->AlreadyRunning = TRUE; /*================================*/ /* Set up statistics information. */ /*================================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->WatchStatistics) { #if DEFTEMPLATE_CONSTRUCT maxFacts = GetNumberOfFacts(theEnv); sumFacts = maxFacts; #endif #if OBJECT_SYSTEM maxInstances = GetGlobalNumberOfInstances(theEnv); sumInstances = maxInstances; #endif maxActivations = GetNumberOfActivations(theEnv); sumActivations = maxActivations; startTime = gentime(); } #endif /*=============================*/ /* Set up execution variables. */ /*=============================*/ if (EvaluationData(theEnv)->CurrentEvaluationDepth == 0) SetHaltExecution(theEnv,FALSE); EngineData(theEnv)->HaltRules = FALSE; /*=====================================================*/ /* Fire rules until the agenda is empty, the run limit */ /* has been reached, or a rule execution error occurs. */ /*=====================================================*/ theActivation = NextActivationToFire(theEnv); while ((theActivation != NULL) && (runLimit != 0) && (EvaluationData(theEnv)->HaltExecution == FALSE) && (EngineData(theEnv)->HaltRules == FALSE)) { /*===========================================*/ /* Detach the activation from the agenda and */ /* determine which rule is firing. */ /*===========================================*/ DetachActivation(theEnv,theActivation); ruleFiring = EnvGetActivationName(theEnv,theActivation); theBasis = (struct partialMatch *) GetActivationBasis(theActivation); EngineData(theEnv)->ExecutingRule = (struct defrule *) GetActivationRule(theActivation); /*=============================================*/ /* Update the number of rules that have fired. */ /*=============================================*/ rulesFired++; if (runLimit > 0) { runLimit--; } /*==================================*/ /* If rules are being watched, then */ /* print an information message. */ /*==================================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->ExecutingRule->watchFiring) { char printSpace[60]; sprintf(printSpace,"FIRE %4ld ",rulesFired); EnvPrintRouter(theEnv,WTRACE,printSpace); EnvPrintRouter(theEnv,WTRACE,ruleFiring); EnvPrintRouter(theEnv,WTRACE,": "); PrintPartialMatch(theEnv,WTRACE,theBasis); EnvPrintRouter(theEnv,WTRACE,"\n"); } #endif /*=================================================*/ /* Remove the link between the activation and the */ /* completed match for the rule. Set the busy flag */ /* for the completed match to TRUE (so the match */ /* upon which our RHS variables are dependent is */ /* not deleted while our rule is firing). Set up */ /* the global pointers to the completed match for */ /* routines which do variable extractions. */ /*=================================================*/ theBasis->binds[theBasis->bcount].gm.theValue = NULL; theBasis->busy = TRUE; EngineData(theEnv)->GlobalLHSBinds = theBasis; EngineData(theEnv)->GlobalRHSBinds = NULL; /*===================================================================*/ /* Increment the count for each of the facts/objects associated with */ /* the rule activation so that the facts/objects cannot be deleted */ /* by garbage collection while the rule is executing. */ /*===================================================================*/ for (i = 0; i < theBasis->bcount; i++) { theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem; if (theMatchingItem != NULL) { (*theMatchingItem->theInfo->incrementBasisCount)(theEnv,theMatchingItem); } } /*====================================================*/ /* Execute the rule's right hand side actions. If the */ /* rule has logical CEs, set up the pointer to the */ /* rules logical join so the assert command will */ /* attach the appropriate dependencies to the facts. */ /*====================================================*/ EngineData(theEnv)->TheLogicalJoin = EngineData(theEnv)->ExecutingRule->logicalJoin; EvaluationData(theEnv)->CurrentEvaluationDepth++; SetEvaluationError(theEnv,FALSE); EngineData(theEnv)->ExecutingRule->executing = TRUE; #if PROFILING_FUNCTIONS StartProfile(theEnv,&profileFrame, &EngineData(theEnv)->ExecutingRule->header.usrData, ProfileFunctionData(theEnv)->ProfileConstructs); #endif EvaluateProcActions(theEnv,EngineData(theEnv)->ExecutingRule->header.whichModule->theModule, EngineData(theEnv)->ExecutingRule->actions,EngineData(theEnv)->ExecutingRule->localVarCnt, &result,NULL); #if PROFILING_FUNCTIONS EndProfile(theEnv,&profileFrame); #endif EngineData(theEnv)->ExecutingRule->executing = FALSE; SetEvaluationError(theEnv,FALSE); EvaluationData(theEnv)->CurrentEvaluationDepth--; EngineData(theEnv)->TheLogicalJoin = NULL; /*=====================================================*/ /* If rule execution was halted, then print a message. */ /*=====================================================*/ #if DEBUGGING_FUNCTIONS if ((EvaluationData(theEnv)->HaltExecution) || (EngineData(theEnv)->HaltRules && EngineData(theEnv)->ExecutingRule->watchFiring)) #else if ((EvaluationData(theEnv)->HaltExecution) || (EngineData(theEnv)->HaltRules)) #endif { PrintErrorID(theEnv,"PRCCODE",4,FALSE); EnvPrintRouter(theEnv,WERROR,"Execution halted during the actions of defrule "); EnvPrintRouter(theEnv,WERROR,ruleFiring); EnvPrintRouter(theEnv,WERROR,".\n"); } /*===================================================================*/ /* Decrement the count for each of the facts/objects associated with */ /* the rule activation. If the last match for the activation */ /* is from a not CE, then we need to make sure that the last */ /* match is an actual match for the CE and not a counter. */ /*===================================================================*/ theBasis->busy = FALSE; for (i = 0; i < (theBasis->bcount - 1); i++) { theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem; if (theMatchingItem != NULL) { (*theMatchingItem->theInfo->decrementBasisCount)(theEnv,theMatchingItem); } } i = (unsigned) (theBasis->bcount - 1); if (theBasis->counterf == FALSE) { theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem; if (theMatchingItem != NULL) { (*theMatchingItem->theInfo->decrementBasisCount)(theEnv,theMatchingItem); } } /*========================================*/ /* Return the agenda node to free memory. */ /*========================================*/ RemoveActivation(theEnv,theActivation,FALSE,FALSE); /*======================================*/ /* Get rid of partial matches discarded */ /* while executing the rule's RHS. */ /*======================================*/ FlushGarbagePartialMatches(theEnv); /*==================================*/ /* Get rid of other garbage created */ /* while executing the rule's RHS. */ /*==================================*/ PeriodicCleanup(theEnv,FALSE,TRUE); /*==========================*/ /* Keep up with statistics. */ /*==========================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->WatchStatistics) { #if DEFTEMPLATE_CONSTRUCT tempValue = GetNumberOfFacts(theEnv); if (tempValue > maxFacts) maxFacts = tempValue; sumFacts += tempValue; #endif #if OBJECT_SYSTEM tempValue = GetGlobalNumberOfInstances(theEnv); if (tempValue > maxInstances) maxInstances = tempValue; sumInstances += tempValue; #endif tempValue = GetNumberOfActivations(theEnv); if (tempValue > maxActivations) maxActivations = tempValue; sumActivations += tempValue; } #endif /*==================================*/ /* Update saliences if appropriate. */ /*==================================*/ if (EnvGetSalienceEvaluation(theEnv) == EVERY_CYCLE) EnvRefreshAgenda(theEnv,NULL); /*========================================*/ /* Execute the list of functions that are */ /* to be called after each rule firing. */ /*========================================*/ for (theRunFunction = EngineData(theEnv)->ListOfRunFunctions; theRunFunction != NULL; theRunFunction = theRunFunction->next) { if (theRunFunction->environmentAware) { (*theRunFunction->func)(theEnv); } else { ((void (*)(void))(*theRunFunction->func))(); } } /*========================================*/ /* If a return was issued on the RHS of a */ /* rule, then remove *that* rule's module */ /* from the focus stack */ /*========================================*/ if (ProcedureFunctionData(theEnv)->ReturnFlag == TRUE) { RemoveFocus(theEnv,EngineData(theEnv)->ExecutingRule->header.whichModule->theModule); } ProcedureFunctionData(theEnv)->ReturnFlag = FALSE; /*========================================*/ /* Determine the next activation to fire. */ /*========================================*/ theActivation = (struct activation *) NextActivationToFire(theEnv); /*==============================*/ /* Check for a rule breakpoint. */ /*==============================*/ if (theActivation != NULL) { if (((struct defrule *) GetActivationRule(theActivation))->afterBreakpoint) { EngineData(theEnv)->HaltRules = TRUE; EnvPrintRouter(theEnv,WDIALOG,"Breaking on rule "); EnvPrintRouter(theEnv,WDIALOG,EnvGetActivationName(theEnv,theActivation)); EnvPrintRouter(theEnv,WDIALOG,".\n"); } } } /*=====================================================*/ /* Make sure run functions are executed at least once. */ /*=====================================================*/ if (rulesFired == 0) { for (theRunFunction = EngineData(theEnv)->ListOfRunFunctions; theRunFunction != NULL; theRunFunction = theRunFunction->next) { if (theRunFunction->environmentAware) { (*theRunFunction->func)(theEnv); } else { ((void (*)(void))(*theRunFunction->func))(); } } } /*======================================================*/ /* If rule execution was halted because the rule firing */ /* limit was reached, then print a message. */ /*======================================================*/ if (runLimit == rulesFired) { EnvPrintRouter(theEnv,WDIALOG,"rule firing limit reached\n"); } /*==============================*/ /* Restore execution variables. */ /*==============================*/ EngineData(theEnv)->ExecutingRule = NULL; EngineData(theEnv)->HaltRules = FALSE; /*=================================================*/ /* Print out statistics if they are being watched. */ /*=================================================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->WatchStatistics) { char printSpace[60]; endTime = gentime(); PrintLongInteger(theEnv,WDIALOG,rulesFired); EnvPrintRouter(theEnv,WDIALOG," rules fired"); #if (! GENERIC) if (startTime != endTime) { EnvPrintRouter(theEnv,WDIALOG," Run time is "); PrintFloat(theEnv,WDIALOG,endTime - startTime); EnvPrintRouter(theEnv,WDIALOG," seconds.\n"); PrintFloat(theEnv,WDIALOG,(double) rulesFired / (endTime - startTime)); EnvPrintRouter(theEnv,WDIALOG," rules per second.\n"); } else { EnvPrintRouter(theEnv,WDIALOG,"\n"); } #endif #if DEFTEMPLATE_CONSTRUCT sprintf(printSpace,"%ld mean number of facts (%ld maximum).\n", (long) (((double) sumFacts / (rulesFired + 1)) + 0.5), maxFacts); EnvPrintRouter(theEnv,WDIALOG,printSpace); #endif #if OBJECT_SYSTEM sprintf(printSpace,"%ld mean number of instances (%ld maximum).\n", (long) (((double) sumInstances / (rulesFired + 1)) + 0.5), maxInstances); EnvPrintRouter(theEnv,WDIALOG,printSpace); #endif sprintf(printSpace,"%ld mean number of activations (%ld maximum).\n", (long) (((double) sumActivations / (rulesFired + 1)) + 0.5), maxActivations); EnvPrintRouter(theEnv,WDIALOG,printSpace); } #endif /*==========================================*/ /* The current module should be the current */ /* focus when the run finishes. */ /*==========================================*/ if (EngineData(theEnv)->CurrentFocus != NULL) { if (EngineData(theEnv)->CurrentFocus->theModule != ((struct defmodule *) EnvGetCurrentModule(theEnv))) { EnvSetCurrentModule(theEnv,(void *) EngineData(theEnv)->CurrentFocus->theModule); } } /*===================================*/ /* Return the number of rules fired. */ /*===================================*/ EngineData(theEnv)->AlreadyRunning = FALSE; return(rulesFired); }