X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=prvm_exec.c;h=37daaaa252f19ccf84039862a5c2cd5c9d305c40;hp=d1e37f76c70b914a33c53644be3eb022a6783385;hb=023d02148e88cc846dbd76ffa312703c2eef1cd7;hpb=cfee52a1ec9db338098789cae89ae5cf1f7a6fbf diff --git a/prvm_exec.c b/prvm_exec.c index d1e37f76..37daaaa2 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -119,6 +119,7 @@ const char *prvm_opnames[] = PRVM_PrintStatement ================= */ +extern cvar_t prvm_coverage; extern cvar_t prvm_statementprofiling; extern cvar_t prvm_timeprofiling; static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s) @@ -129,7 +130,12 @@ static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s) Con_Printf("s%i: ", opnum); if( prog->statement_linenums ) - Con_Printf( "%s:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ] ); + { + if ( prog->statement_columnnums ) + Con_Printf( "%s:%i:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ], prog->statement_columnnums[ opnum ] ); + else + Con_Printf( "%s:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ] ); + } if (prvm_statementprofiling.integer) Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]); @@ -176,11 +182,15 @@ void PRVM_PrintFunctionStatements (prvm_prog_t *prog, const char *name) // now print the range of statements Con_Printf("%s progs: disassembly of function %s (statements %i-%i, locals %i-%i):\n", prog->name, name, firststatement, endstatement, func->parm_start, func->parm_start + func->locals - 1); + prog->xfunction = func; for (i = firststatement;i < endstatement;i++) { PRVM_PrintStatement(prog, prog->statements + i); - prog->statement_profile[i] = 0; + if (!(prvm_coverage.integer & 4)) + prog->statement_profile[i] = 0; } + if (prvm_coverage.integer & 4) + Con_Printf("Collecting statement coverage, not flushing statement profile.\n"); } /* @@ -223,7 +233,17 @@ void PRVM_StackTrace (prvm_prog_t *prog) if (!f) Con_Print("\n"); else - Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(prog, f->s_file), PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement); + { + if (prog->statement_linenums) + { + if (prog->statement_columnnums) + Con_Printf("%12s:%i:%i : %s : statement %i\n", PRVM_GetString(prog, f->s_file), prog->statement_linenums[prog->stack[i].s], prog->statement_columnnums[prog->stack[i].s], PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement); + else + Con_Printf("%12s:%i : %s : statement %i\n", PRVM_GetString(prog, f->s_file), prog->statement_linenums[prog->stack[i].s], PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement); + } + else + Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(prog, f->s_file), PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement); + } } } @@ -439,6 +459,12 @@ void PRVM_Profile_f (void) prvm_prog_t *prog; int howmany; + if (prvm_coverage.integer & 1) + { + Con_Printf("Collecting function coverage, cannot profile - sorry!\n"); + return; + } + howmany = 1<<30; if (Cmd_Argc() == 3) howmany = atoi(Cmd_Argv(2)); @@ -459,6 +485,12 @@ void PRVM_ChildProfile_f (void) prvm_prog_t *prog; int howmany; + if (prvm_coverage.integer & 1) + { + Con_Printf("Collecting function coverage, cannot profile - sorry!\n"); + return; + } + howmany = 1<<30; if (Cmd_Argc() == 3) howmany = atoi(Cmd_Argv(2)); @@ -474,21 +506,26 @@ void PRVM_ChildProfile_f (void) PRVM_Profile(prog, howmany, 0, 1); } -void PRVM_PrintState(prvm_prog_t *prog) +void PRVM_PrintState(prvm_prog_t *prog, int stack_index) { int i; + mfunction_t *func = prog->xfunction; + int st = prog->xstatement; + if (stack_index > 0 && stack_index <= prog->depth) + { + func = prog->stack[prog->depth - stack_index].f; + st = prog->stack[prog->depth - stack_index].s; + } if (prog->statestring) { Con_Printf("Caller-provided information: %s\n", prog->statestring); } - if (prog->xfunction) + if (func) { for (i = -7; i <= 0;i++) - if (prog->xstatement + i >= prog->xfunction->first_statement) - PRVM_PrintStatement(prog, prog->statements + prog->xstatement + i); + if (st + i >= func->first_statement) + PRVM_PrintStatement(prog, prog->statements + st + i); } - else - Con_Print("null function executing??\n"); PRVM_StackTrace(prog); } @@ -506,7 +543,7 @@ void PRVM_Crash(prvm_prog_t *prog) if( prog->depth > 0 ) { Con_Printf("QuakeC crash report for %s:\n", prog->name); - PRVM_PrintState(prog); + PRVM_PrintState(prog, 0); } if(prvm_errordump.integer) @@ -563,7 +600,7 @@ static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f) prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name); for (i=0 ; i < c ; i++) - prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i]; + prog->localstack[prog->localstack_used+i] = prog->globals.ip[f->parm_start + i]; prog->localstack_used += c; // copy parameters @@ -572,7 +609,7 @@ static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f) { for (j=0 ; jparm_size[i] ; j++) { - ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j]; + prog->globals.ip[o] = prog->globals.ip[OFS_PARM0+i*3+j]; o++; } } @@ -604,7 +641,7 @@ static int PRVM_LeaveFunction (prvm_prog_t *prog) prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name); for (i=0 ; i < c ; i++) - ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i]; + prog->globals.ip[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i]; // up stack prog->depth--; @@ -643,14 +680,55 @@ void PRVM_Init_Exec(prvm_prog_t *prog) // nothing here yet } -#define OPA ((prvm_eval_t *)&prog->globals.generic[st->operand[0]]) -#define OPB ((prvm_eval_t *)&prog->globals.generic[st->operand[1]]) -#define OPC ((prvm_eval_t *)&prog->globals.generic[st->operand[2]]) +/* +================== +Coverage +================== +*/ +// Note: in these two calls, prog->xfunction is assumed to be sane. +static const char *PRVM_WhereAmI(char *buf, size_t bufsize, prvm_prog_t *prog, mfunction_t *func, int statement) +{ + if (prog->statement_linenums) + { + if (prog->statement_columnnums) + return va(buf, bufsize, "%s:%i:%i(%s, %i)", PRVM_GetString(prog, func->s_file), prog->statement_linenums[statement], prog->statement_columnnums[statement], PRVM_GetString(prog, func->s_name), statement - func->first_statement); + else + return va(buf, bufsize, "%s:%i(%s, %i)", PRVM_GetString(prog, func->s_file), prog->statement_linenums[statement], PRVM_GetString(prog, func->s_name), statement - func->first_statement); + } + else + return va(buf, bufsize, "%s(%s, %i)", PRVM_GetString(prog, func->s_file), PRVM_GetString(prog, func->s_name), statement - func->first_statement); +} +static void PRVM_FunctionCoverageEvent(prvm_prog_t *prog, mfunction_t *func) +{ + ++prog->functions_covered; + Con_Printf("prvm_coverage: %s just called %s for the first time. Coverage: %.2f%%.\n", prog->name, PRVM_GetString(prog, func->s_name), prog->functions_covered * 100.0 / prog->numfunctions); +} +void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement) +{ + char vabuf[128]; + ++prog->explicit_covered; + Con_Printf("prvm_coverage: %s just executed a coverage() statement at %s for the first time. Coverage: %.2f%%.\n", prog->name, PRVM_WhereAmI(vabuf, sizeof(vabuf), prog, func, statement), prog->explicit_covered * 100.0 / prog->numexplicitcoveragestatements); +} +static void PRVM_StatementCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement) +{ + char vabuf[128]; + ++prog->statements_covered; + Con_Printf("prvm_coverage: %s just executed a statement at %s for the first time. Coverage: %.2f%%.\n", prog->name, PRVM_WhereAmI(vabuf, sizeof(vabuf), prog, func, statement), prog->statements_covered * 100.0 / prog->numstatements); +} + +#ifdef __GNUC__ +#define HAVE_COMPUTED_GOTOS 1 +#endif + +#define OPA ((prvm_eval_t *)&prog->globals.fp[st->operand[0]]) +#define OPB ((prvm_eval_t *)&prog->globals.fp[st->operand[1]]) +#define OPC ((prvm_eval_t *)&prog->globals.fp[st->operand[2]]) extern cvar_t prvm_traceqc; extern cvar_t prvm_statementprofiling; extern qboolean prvm_runawaycheck; #ifdef PROFILING +#ifdef CONFIG_MENU /* ==================== MVM_ExecuteProgram @@ -659,13 +737,27 @@ MVM_ExecuteProgram void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage) { mstatement_t *st, *startst; - mfunction_t *f, *newf; + mfunction_t *func, *enterfunc; prvm_edict_t *ed; prvm_eval_t *ptr; int jumpcount, cachedpr_trace, exitdepth; int restorevm_tempstringsbuf_cursize; double calltime; double tm, starttm; + prvm_vec_t tempfloat; + // these may become out of date when a builtin is called, and are updated accordingly + prvm_vec_t *cached_edictsfields = prog->edictsfields; + unsigned int cached_entityfields = prog->entityfields; + unsigned int cached_entityfields_3 = prog->entityfields - 3; + unsigned int cached_entityfieldsarea = prog->entityfieldsarea; + unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; + unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; + unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; + unsigned int cached_max_edicts = prog->max_edicts; + // these do not change + mstatement_t *cached_statements = prog->statements; + qboolean cached_allowworldwrites = prog->allowworldwrites; + unsigned int cached_flag = prog->flag; calltime = Sys_DirtyTime(); @@ -676,7 +768,7 @@ void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessag prog->error_cmd("MVM_ExecuteProgram: %s", errormessage); } - f = &prog->functions[fnum]; + func = &prog->functions[fnum]; // after executing this function, delete all tempstrings it created restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; @@ -687,7 +779,7 @@ void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessag exitdepth = prog->depth; // make a stack frame - st = &prog->statements[PRVM_EnterFunction(prog, f)]; + st = &prog->statements[PRVM_EnterFunction(prog, func)]; // 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) @@ -696,11 +788,12 @@ void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessag // 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++; + if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1)) + PRVM_FunctionCoverageEvent(prog, prog->xfunction); chooseexecprogram: cachedpr_trace = prog->trace; - if (prvm_statementprofiling.integer || prog->trace) + if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0) { #define PRVMSLOWINTERPRETER 1 if (prvm_timeprofiling.integer) @@ -736,11 +829,12 @@ cleanup: prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0; - f->totaltime += tm; + func->totaltime += tm; if (prog == SVVM_prog) SV_FlushBroadcastMessages(); } +#endif /* ==================== @@ -750,13 +844,27 @@ CLVM_ExecuteProgram void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage) { mstatement_t *st, *startst; - mfunction_t *f, *newf; + mfunction_t *func, *enterfunc; prvm_edict_t *ed; prvm_eval_t *ptr; int jumpcount, cachedpr_trace, exitdepth; int restorevm_tempstringsbuf_cursize; double calltime; double tm, starttm; + prvm_vec_t tempfloat; + // these may become out of date when a builtin is called, and are updated accordingly + prvm_vec_t *cached_edictsfields = prog->edictsfields; + unsigned int cached_entityfields = prog->entityfields; + unsigned int cached_entityfields_3 = prog->entityfields - 3; + unsigned int cached_entityfieldsarea = prog->entityfieldsarea; + unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; + unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; + unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; + unsigned int cached_max_edicts = prog->max_edicts; + // these do not change + mstatement_t *cached_statements = prog->statements; + qboolean cached_allowworldwrites = prog->allowworldwrites; + unsigned int cached_flag = prog->flag; calltime = Sys_DirtyTime(); @@ -767,7 +875,7 @@ void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage); } - f = &prog->functions[fnum]; + func = &prog->functions[fnum]; // after executing this function, delete all tempstrings it created restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; @@ -778,7 +886,7 @@ void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa exitdepth = prog->depth; // make a stack frame - st = &prog->statements[PRVM_EnterFunction(prog, f)]; + st = &prog->statements[PRVM_EnterFunction(prog, func)]; // 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) @@ -787,11 +895,12 @@ void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa // 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++; + if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1)) + PRVM_FunctionCoverageEvent(prog, prog->xfunction); chooseexecprogram: cachedpr_trace = prog->trace; - if (prvm_statementprofiling.integer || prog->trace) + if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0) { #define PRVMSLOWINTERPRETER 1 if (prvm_timeprofiling.integer) @@ -827,7 +936,7 @@ cleanup: prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0; - f->totaltime += tm; + func->totaltime += tm; if (prog == SVVM_prog) SV_FlushBroadcastMessages(); @@ -846,13 +955,27 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa #endif { mstatement_t *st, *startst; - mfunction_t *f, *newf; + mfunction_t *func, *enterfunc; prvm_edict_t *ed; prvm_eval_t *ptr; int jumpcount, cachedpr_trace, exitdepth; int restorevm_tempstringsbuf_cursize; double calltime; double tm, starttm; + prvm_vec_t tempfloat; + // these may become out of date when a builtin is called, and are updated accordingly + prvm_vec_t *cached_edictsfields = prog->edictsfields; + unsigned int cached_entityfields = prog->entityfields; + unsigned int cached_entityfields_3 = prog->entityfields - 3; + unsigned int cached_entityfieldsarea = prog->entityfieldsarea; + unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; + unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; + unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; + unsigned int cached_max_edicts = prog->max_edicts; + // these do not change + mstatement_t *cached_statements = prog->statements; + qboolean cached_allowworldwrites = prog->allowworldwrites; + unsigned int cached_flag = prog->flag; calltime = Sys_DirtyTime(); @@ -863,7 +986,7 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage); } - f = &prog->functions[fnum]; + func = &prog->functions[fnum]; // after executing this function, delete all tempstrings it created restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; @@ -874,7 +997,7 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa exitdepth = prog->depth; // make a stack frame - st = &prog->statements[PRVM_EnterFunction(prog, f)]; + st = &prog->statements[PRVM_EnterFunction(prog, func)]; // 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) @@ -883,11 +1006,12 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa // 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++; + if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1)) + PRVM_FunctionCoverageEvent(prog, prog->xfunction); chooseexecprogram: cachedpr_trace = prog->trace; - if (prvm_statementprofiling.integer || prog->trace) + if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0) { #define PRVMSLOWINTERPRETER 1 if (prvm_timeprofiling.integer) @@ -923,7 +1047,7 @@ cleanup: prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0; - f->totaltime += tm; + func->totaltime += tm; if (prog == SVVM_prog) SV_FlushBroadcastMessages();