X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=prvm_exec.c;h=f32ff3f22c2355651dc466faf0bfc1147909c4e5;hp=a889f66b1f7b1b01d256d7678b74623605d67786;hb=b19c27fd82074c42e1aba5b9d293f70f90995d02;hpb=631460dc33a02b110ac3b44227afbb4d19cd969d diff --git a/prvm_exec.c b/prvm_exec.c index a889f66b..f32ff3f2 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -112,6 +112,7 @@ char *prvm_opnames[] = char *PRVM_GlobalString (int ofs); char *PRVM_GlobalStringNoContents (int ofs); +extern ddef_t *PRVM_ED_FieldAtOfs(int ofs); //============================================================================= @@ -265,14 +266,83 @@ void PRVM_StackTrace (void) } } +void PRVM_ShortStackTrace(char *buf, size_t bufsize) +{ + mfunction_t *f; + int i; + + if(prog) + { + dpsnprintf(buf, bufsize, "(%s) ", prog->name); + } + else + { + strlcpy(buf, "", bufsize); + return; + } -void PRVM_Profile (int maxfunctions, int mininstructions) + prog->stack[prog->depth].s = prog->xstatement; + prog->stack[prog->depth].f = prog->xfunction; + for (i = prog->depth;i > 0;i--) + { + f = prog->stack[i].f; + + if(strlcat(buf, + f + ? va("%s:%s(%i) ", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement) + : " ", + bufsize + ) >= bufsize) + break; + } +} + + +void PRVM_CallProfile (void) +{ + mfunction_t *f, *best; + int i; + double max; + double sum; + + Con_Printf( "%s Call Profile:\n", PRVM_NAME ); + + sum = 0; + do + { + max = 0; + best = NULL; + for (i=0 ; iprogs->numfunctions ; i++) + { + f = &prog->functions[i]; + if (max < f->totaltime) + { + max = f->totaltime; + best = f; + } + } + if (best) + { + sum += best->totaltime; + Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(best->s_name)); + best->totaltime = 0; + } + } while (best); + + Con_Printf("Total time since last profile reset: %9.4f\n", Sys_DoubleTime() - prog->starttime); + Con_Printf(" - used by QC code of this VM: %9.4f\n", sum); + + prog->starttime = Sys_DoubleTime(); +} + +void PRVM_Profile (int maxfunctions, int mininstructions, int sortby) { mfunction_t *f, *best; int i, num; double max; - Con_Printf( "%s Profile:\n[CallCount] [Statements] [BuiltinCost]\n", PRVM_NAME ); + Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", PRVM_NAME ); + // 12345678901 12345678901 12345678901 12345678901 12345678901 123.45% num = 0; do @@ -282,10 +352,21 @@ void PRVM_Profile (int maxfunctions, int mininstructions) for (i=0 ; iprogs->numfunctions ; i++) { f = &prog->functions[i]; - if (max < f->profile + f->builtinsprofile + f->callcount) + if(sortby) { - max = f->profile + f->builtinsprofile + f->callcount; - best = f; + if (max < f->profile_total + f->builtinsprofile_total + f->callcount) + { + max = f->profile_total + f->builtinsprofile_total + f->callcount; + best = f; + } + } + else + { + if (max < f->profile + f->builtinsprofile + f->callcount) + { + max = f->profile + f->builtinsprofile + f->callcount; + best = f; + } } } if (best) @@ -293,18 +374,44 @@ void PRVM_Profile (int maxfunctions, int mininstructions) if (num < maxfunctions && max >= mininstructions) { if (best->first_statement < 0) - Con_Printf("%9.0f ----- builtin ----- %s\n", best->callcount, PRVM_GetString(best->s_name)); + Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(best->s_name)); + // 12345678901 12345678901 12345678901 12345678901 123.45% else - Con_Printf("%9.0f %9.0f %9.0f %s\n", best->callcount, best->profile, best->builtinsprofile, PRVM_GetString(best->s_name)); + Con_Printf("%11.0f %11.0f %11.0f %11.0f %11.0f %6.2f%% %s\n", best->callcount, best->profile, best->builtinsprofile, best->profile_total, best->builtinsprofile_total, (best->profile + best->builtinsprofile) * 100.0 / (best->profile_total + best->builtinsprofile_total), PRVM_GetString(best->s_name)); } num++; best->profile = 0; best->builtinsprofile = 0; + best->profile_total = 0; + best->builtinsprofile_total = 0; best->callcount = 0; } } while (best); } +/* +============ +PRVM_CallProfile_f + +============ +*/ +void PRVM_CallProfile_f (void) +{ + if (Cmd_Argc() != 2) + { + Con_Print("prvm_callprofile \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_CallProfile(); + + PRVM_End; +} + /* ============ PRVM_Profile_f @@ -328,12 +435,34 @@ void PRVM_Profile_f (void) if(!PRVM_SetProgFromString(Cmd_Argv(1))) return; - PRVM_Profile(howmany, 1); + PRVM_Profile(howmany, 1, 0); PRVM_End; } -void PRVM_CrashAll() +void PRVM_ChildProfile_f (void) +{ + int howmany; + + howmany = 1<<30; + if (Cmd_Argc() == 3) + howmany = atoi(Cmd_Argv(2)); + else if (Cmd_Argc() != 2) + { + Con_Print("prvm_childprofile \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_Profile(howmany, 1, 1); + + PRVM_End; +} + +void PRVM_CrashAll(void) { int i; prvm_prog_t *oldprog = prog; @@ -352,6 +481,10 @@ void PRVM_CrashAll() void PRVM_PrintState(void) { int i; + if(prog->statestring) + { + Con_Printf("Caller-provided information: %s\n", prog->statestring); + } if (prog->xfunction) { for (i = -7; i <= 0;i++) @@ -364,17 +497,27 @@ void PRVM_PrintState(void) } extern sizebuf_t vm_tempstringsbuf; +extern cvar_t prvm_errordump; +void Host_Savegame_to (const char *name); void PRVM_Crash(void) { if (prog == NULL) return; + prog->funcoffsets.SV_Shutdown = 0; // don't call SV_Shutdown on crash + if( prog->depth > 0 ) { Con_Printf("QuakeC crash report for %s:\n", PRVM_NAME); PRVM_PrintState(); } + if(prvm_errordump.integer) + { + // make a savegame + Host_Savegame_to(va("crash-%s.dmp", PRVM_NAME)); + } + // dump the stack so host_error can shutdown functions prog->depth = 0; prog->localstack_used = 0; @@ -410,6 +553,8 @@ int PRVM_EnterFunction (mfunction_t *f) prog->stack[prog->depth].s = prog->xstatement; prog->stack[prog->depth].f = prog->xfunction; + prog->stack[prog->depth].profile_acc = -f->profile; + prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile; prog->depth++; if (prog->depth >=PRVM_MAX_STACK_DEPTH) PRVM_ERROR ("stack overflow"); @@ -434,6 +579,7 @@ int PRVM_EnterFunction (mfunction_t *f) } } + ++f->recursion; prog->xfunction = f; return f->first_statement - 1; // offset the s++ } @@ -446,6 +592,7 @@ PRVM_LeaveFunction int PRVM_LeaveFunction (void) { int i, c; + mfunction_t *f; if (prog->depth <= 0) PRVM_ERROR ("prog stack underflow in %s", PRVM_NAME); @@ -463,7 +610,26 @@ int PRVM_LeaveFunction (void) // up stack prog->depth--; + f = prog->xfunction; + --f->recursion; prog->xfunction = prog->stack[prog->depth].f; + prog->stack[prog->depth].profile_acc += f->profile; + prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile; + if(prog->depth > 0) + { + prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc; + prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc; + } + if(!f->recursion) + { + // if f is already on the call stack... + // we cannot add this profile data to it now + // or we would add it more than once + // so, let's only add to the function's profile if it is the outermost call + f->profile_total += prog->stack[prog->depth].profile_acc; + f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc; + } + return prog->stack[prog->depth].s; } @@ -478,18 +644,19 @@ void PRVM_Init_Exec(void) /* ==================== -PRVM_ExecuteProgram +MVM_ExecuteProgram ==================== */ // LordHavoc: optimized #define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a]) #define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b]) #define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c]) -extern cvar_t prvm_boundscheck; extern cvar_t prvm_traceqc; extern cvar_t prvm_statementprofiling; extern sizebuf_t vm_tempstringsbuf; -void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) +extern qboolean prvm_runawaycheck; +extern qboolean prvm_boundscheck; +void MVM_ExecuteProgram (func_t fnum, const char *errormessage) { dstatement_t *st, *startst; mfunction_t *f, *newf; @@ -497,12 +664,15 @@ void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) prvm_eval_t *ptr; int jumpcount, cachedpr_trace, exitdepth; int restorevm_tempstringsbuf_cursize; + double calltime; + + calltime = Sys_DoubleTime(); if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) { if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict) PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL); - PRVM_ERROR ("PRVM_ExecuteProgram: %s", errormessage); + PRVM_ERROR ("MVM_ExecuteProgram: %s", errormessage); } f = &prog->functions[fnum]; @@ -528,76 +698,558 @@ void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) chooseexecprogram: cachedpr_trace = prog->trace; - if (prvm_statementprofiling.integer) + if (prvm_runawaycheck) { -#define PRVMSTATEMENTPROFILING 1 - if (prvm_boundscheck.integer) +#define PRVMRUNAWAYCHECK 1 + if (prvm_statementprofiling.integer) { +#define PRVMSTATEMENTPROFILING 1 + if (prvm_boundscheck) + { #define PRVMBOUNDSCHECK 1 - if (prog->trace) + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK + } + else { + if (prog->trace) + { #define PRVMTRACE 1 #include "prvm_execprogram.h" #undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } +#undef PRVMSTATEMENTPROFILING + } + else + { + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK } else { + if (prog->trace) + { +#define PRVMTRACE 1 #include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } } + } +#undef PRVMRUNAWAYCHECK + } + else + { + if (prvm_statementprofiling.integer) + { +#define PRVMSTATEMENTPROFILING 1 + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } #undef PRVMBOUNDSCHECK + } + else + { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } +#undef PRVMSTATEMENTPROFILING } else { - if (prog->trace) + if (prvm_boundscheck) { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { #define PRVMTRACE 1 #include "prvm_execprogram.h" #undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK } else { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { #include "prvm_execprogram.h" + } } } + } + +cleanup: + if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_Printf("MVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + f->totaltime += (Sys_DoubleTime() - calltime); + + SV_FlushBroadcastMessages(); +} + +/* +==================== +CLVM_ExecuteProgram +==================== +*/ +// LordHavoc: optimized +#define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a]) +#define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b]) +#define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c]) +extern cvar_t prvm_traceqc; +extern cvar_t prvm_statementprofiling; +extern sizebuf_t vm_tempstringsbuf; +extern qboolean prvm_runawaycheck; +extern qboolean prvm_boundscheck; +void CLVM_ExecuteProgram (func_t fnum, const char *errormessage) +{ + dstatement_t *st, *startst; + mfunction_t *f, *newf; + prvm_edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + + calltime = Sys_DoubleTime(); + + if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) + { + if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict) + PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL); + PRVM_ERROR ("CLVM_ExecuteProgram: %s", errormessage); + } + + f = &prog->functions[fnum]; + + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + + prog->trace = prvm_traceqc.integer; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + +// make a stack frame + st = &prog->statements[PRVM_EnterFunction (f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + if (prvm_runawaycheck) + { +#define PRVMRUNAWAYCHECK 1 + if (prvm_statementprofiling.integer) + { +#define PRVMSTATEMENTPROFILING 1 + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK + } + else + { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } #undef PRVMSTATEMENTPROFILING + } + else + { + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK + } + else + { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } + } +#undef PRVMRUNAWAYCHECK } else { - if (prvm_boundscheck.integer) + if (prvm_statementprofiling.integer) + { +#define PRVMSTATEMENTPROFILING 1 + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK + } + else + { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } +#undef PRVMSTATEMENTPROFILING + } + else + { + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK + } + else + { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } + } + } + +cleanup: + if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_Printf("CLVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + f->totaltime += (Sys_DoubleTime() - calltime); + + SV_FlushBroadcastMessages(); +} + +/* +==================== +SVVM_ExecuteProgram +==================== +*/ +// LordHavoc: optimized +#define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a]) +#define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b]) +#define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c]) +extern cvar_t prvm_traceqc; +extern cvar_t prvm_statementprofiling; +extern sizebuf_t vm_tempstringsbuf; +extern qboolean prvm_runawaycheck; +extern qboolean prvm_boundscheck; +void SVVM_ExecuteProgram (func_t fnum, const char *errormessage) +{ + dstatement_t *st, *startst; + mfunction_t *f, *newf; + prvm_edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + + calltime = Sys_DoubleTime(); + + if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) + { + if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict) + PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL); + PRVM_ERROR ("SVVM_ExecuteProgram: %s", errormessage); + } + + f = &prog->functions[fnum]; + + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + + prog->trace = prvm_traceqc.integer; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + +// make a stack frame + st = &prog->statements[PRVM_EnterFunction (f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + if (prvm_runawaycheck) + { +#define PRVMRUNAWAYCHECK 1 + if (prvm_statementprofiling.integer) { +#define PRVMSTATEMENTPROFILING 1 + if (prvm_boundscheck) + { #define PRVMBOUNDSCHECK 1 - if (prog->trace) + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK + } + else { + if (prog->trace) + { #define PRVMTRACE 1 #include "prvm_execprogram.h" #undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } +#undef PRVMSTATEMENTPROFILING + } + else + { + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK } else { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { #include "prvm_execprogram.h" + } } + } +#undef PRVMRUNAWAYCHECK + } + else + { + if (prvm_statementprofiling.integer) + { +#define PRVMSTATEMENTPROFILING 1 + if (prvm_boundscheck) + { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } #undef PRVMBOUNDSCHECK + } + else + { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } + } +#undef PRVMSTATEMENTPROFILING } else { - if (prog->trace) + if (prvm_boundscheck) { +#define PRVMBOUNDSCHECK 1 + if (prog->trace) + { #define PRVMTRACE 1 #include "prvm_execprogram.h" #undef PRVMTRACE + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMBOUNDSCHECK } else { + if (prog->trace) + { +#define PRVMTRACE 1 +#include "prvm_execprogram.h" +#undef PRVMTRACE + } + else + { #include "prvm_execprogram.h" + } } } } cleanup: if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) - Con_Printf("PRVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + Con_Printf("SVVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); // delete tempstrings created by this function vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + f->totaltime += (Sys_DoubleTime() - calltime); + SV_FlushBroadcastMessages(); }