]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
significant optimizations to the progs interpreter, changed the runaway loop counter...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 25 Apr 2006 06:14:44 +0000 (06:14 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 25 Apr 2006 06:14:44 +0000 (06:14 +0000)
changed prvm_profile report to show callcount before statements and builtincost, changed the sorting order to use summed callcount+statements+builtincost (and this made it print call counts for builtin functions as well)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6326 d7cf8633-e32d-0410-b094-e92efae38249

prvm_exec.c
prvm_execprogram.h

index 2f8c97aeebc3d12de5e056dc07e4ed1261029017..e85c3eed21be9b3096dfbade7d36829d2d98b5fd 100644 (file)
@@ -211,7 +211,7 @@ void PRVM_Profile_f (void)
        if(!PRVM_SetProgFromString(Cmd_Argv(1)))
                return;
 
-       Con_Printf( "%s Profile:\n[Profile] [BuiltinProfile] [CallCount]\n", PRVM_NAME );
+       Con_Printf( "%s Profile:\n[CallCount] [Statements] [BuiltinCost]\n", PRVM_NAME );
 
        num = 0;
        do
@@ -221,16 +221,19 @@ void PRVM_Profile_f (void)
                for (i=0 ; i<prog->progs->numfunctions ; i++)
                {
                        f = &prog->functions[i];
-                       if (f->profile > max)
+                       if (max < f->profile + f->builtinsprofile + f->callcount)
                        {
-                               max = f->profile;
+                               max = f->profile + f->builtinsprofile + f->callcount;
                                best = f;
                        }
                }
                if (best)
                {
                        //if (num < howmany)
-                               Con_Printf("%7i %7i %7i %s\n", best->profile, best->builtinsprofile, best->callcount, PRVM_GetString(best->s_name));
+                       if (best->first_statement < 0)
+                               Con_Printf("%7i -- builtin -- %s\n", best->callcount, PRVM_GetString(best->s_name));
+                       else
+                               Con_Printf("%7i%7i%7i %s\n", best->callcount, best->profile, best->builtinsprofile, PRVM_GetString(best->s_name));
                        num++;
                        best->profile = 0;
                        best->builtinsprofile = 0;
@@ -395,11 +398,11 @@ extern int                PRVM_ED_FindFieldOffset (const char *field);
 extern ddef_t* PRVM_ED_FindGlobal(const char *name);
 void PRVM_ExecuteProgram (func_t fnum, const char *errormessage)
 {
-       dstatement_t    *st;
+       dstatement_t    *st, *startst;
        mfunction_t     *f, *newf;
        prvm_edict_t    *ed;
        prvm_eval_t     *ptr;
-       int             profile, startprofile, cachedpr_trace, exitdepth;
+       int             jumpcount, cachedpr_trace, exitdepth;
 
        if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
        {
@@ -417,7 +420,14 @@ void PRVM_ExecuteProgram (func_t fnum, const char *errormessage)
 
 // make a stack frame
        st = &prog->statements[PRVM_EnterFunction (f)];
-       startprofile = profile = 0;
+       // 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;
index f188586401f8b622cd51154cdee3d19fcafb93eb..97f50b94f6e64157c0d05c6c356c8d074b8ed98f 100644 (file)
@@ -4,21 +4,8 @@
                while (1)
                {
                        st++;
-                       if (++profile > 10000000) // LordHavoc: increased runaway loop limit 100x
-                       {
-                               // LordHavoc: update profile counter for debugging reasons
-                               // (identifying erroneous loops and recursion patterns)
-                               prog->xfunction->profile += profile - startprofile;
-                               startprofile = profile;
-                               // update the statement number before we error out
-                               prog->xstatement = st - prog->statements;
-                               PRVM_ERROR("runaway loop counter hit limit of %d opcodes\ntip: if having trouble identifying the problem, try typing profile now in %s", profile, PRVM_NAME);
-                       }
 
 #if PRVMTRACE
-                       prog->xfunction->profile += profile - startprofile;
-                       startprofile = profile;
-                       prog->xstatement = st - prog->statements;
                        PRVM_PrintStatement(st);
 #endif
 
 #if PRVMBOUNDSCHECK
                                if (OPB->_int < 0 || OPB->_int + 4 > prog->edictareasize)
                                {
-                                       prog->xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
+                                       prog->xfunction->profile += (st - startst);
                                        prog->xstatement = st - prog->statements;
                                        PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
                                        return;
 #if PRVMBOUNDSCHECK
                                if (OPB->_int < 0 || OPB->_int + 12 > prog->edictareasize)
                                {
-                                       prog->xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
+                                       prog->xfunction->profile += (st - startst);
                                        prog->xstatement = st - prog->statements;
                                        PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
                                        return;
 #if PRVMBOUNDSCHECK
                                if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
                                {
-                                       prog->xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
+                                       prog->xfunction->profile += (st - startst);
                                        prog->xstatement = st - prog->statements;
                                        PRVM_ERROR("%s attempted to address an invalid field (%i) in an edict", PRVM_NAME, OPB->_int);
                                        return;
 #endif
                                if (OPA->edict == 0 && !prog->allowworldwrites)
                                {
-                                       prog->xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
+                                       prog->xfunction->profile += (st - startst);
                                        prog->xstatement = st - prog->statements;
                                        PRVM_ERROR("forbidden assignment to null/world entity in %s", PRVM_NAME);
                                        return;
 #if PRVMBOUNDSCHECK
                                if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
                                {
-                                       prog->xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
+                                       prog->xfunction->profile += (st - startst);
                                        prog->xstatement = st - prog->statements;
                                        PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
                                        return;
 #if PRVMBOUNDSCHECK
                                if (OPB->_int < 0 || OPB->_int + 2 >= prog->progs->entityfields)
                                {
-                                       prog->xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
+                                       prog->xfunction->profile += (st - startst);
                                        prog->xstatement = st - prog->statements;
                                        PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
                                        return;
 
                        case OP_IFNOT:
                                if (!OPA->_int)
+                               {
+                                       prog->xfunction->profile += (st - startst);
                                        st += st->b - 1;        // offset the s++
+                                       startst = st;
+                                       if (++jumpcount> 1000000)
+                                       {
+                                               prog->xstatement = st - prog->statements;
+                                               PRVM_ERROR("runaway loop counter hit limit of %d jumps\ntip: if having trouble identifying the problem, try typing profile now in %s", jumpcount, PRVM_NAME);
+                                       }
+                               }
                                break;
 
                        case OP_IF:
                                if (OPA->_int)
+                               {
+                                       prog->xfunction->profile += (st - startst);
                                        st += st->b - 1;        // offset the s++
+                                       startst = st;
+                                       if (++jumpcount> 1000000)
+                                       {
+                                               prog->xstatement = st - prog->statements;
+                                               PRVM_ERROR("runaway loop counter hit limit of %d jumps\ntip: if having trouble identifying the problem, try typing profile now in %s", jumpcount, PRVM_NAME);
+                                       }
+                               }
                                break;
 
                        case OP_GOTO:
+                               prog->xfunction->profile += (st - startst);
                                st += st->a - 1;        // offset the s++
+                               startst = st;
+                               if (++jumpcount> 1000000)
+                               {
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR("runaway loop counter hit limit of %d jumps\ntip: if having trouble identifying the problem, try typing profile now in %s", jumpcount, PRVM_NAME);
+                               }
                                break;
 
                        case OP_CALL0:
                        case OP_CALL6:
                        case OP_CALL7:
                        case OP_CALL8:
-                               prog->xfunction->profile += profile - startprofile;
-                               startprofile = profile;
+                               prog->xfunction->profile += (st - startst);
+                               startst = st;
                                prog->xstatement = st - prog->statements;
                                prog->argc = st->op - OP_CALL0;
                                if (!OPA->function)
                                }
                                else
                                        st = prog->statements + PRVM_EnterFunction(newf);
+                               startst = st;
                                break;
 
                        case OP_DONE:
                        case OP_RETURN:
-                               prog->xfunction->profile += profile - startprofile;
-                               startprofile = profile;
+                               prog->xfunction->profile += (st - startst);
                                prog->xstatement = st - prog->statements;
 
                                prog->globals.generic[OFS_RETURN] = prog->globals.generic[(unsigned short) st->a];
                                prog->globals.generic[OFS_RETURN+2] = prog->globals.generic[(unsigned short) st->a+2];
 
                                st = prog->statements + PRVM_LeaveFunction();
+                               startst = st;
                                if (prog->depth <= exitdepth)
                                        return;         // all done
                                if (prog->trace != cachedpr_trace)
                        case OP_STATE:
                                if(prog->flag & PRVM_OP_STATE)
                                {
-                                       prog->xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       prog->xstatement = st - prog->statements;
                                        ed = PRVM_PROG_TO_EDICT(PRVM_G_INT(prog->self->ofs));
                                        PRVM_E_FLOAT(ed,PRVM_ED_FindField ("nextthink")->ofs) = *prog->time + 0.1;
                                        PRVM_E_FLOAT(ed,PRVM_ED_FindField ("frame")->ofs) = OPA->_float;
                                        *(func_t *)((float*)ed->fields.vp + PRVM_ED_FindField ("think")->ofs) = OPB->function;
                                }
                                else
+                               {
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
                                        PRVM_ERROR("OP_STATE not supported by %s", PRVM_NAME);
+                               }
                                break;
 
 // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
 #if PRBOUNDSCHECK
                                if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to write to an out of bounds edict");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to write to an out of bounds edict", PRVM_NAME);
                                        return;
                                }
 #endif
 #if PRBOUNDSCHECK
                                if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to read an out of bounds edict number");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
                                        return;
                                }
                                if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to read an invalid field in an edict");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to read an invalid field in an edict", PRVM_NAME);
                                        return;
                                }
 #endif
 #if PRBOUNDSCHECK
                                if (OPB->_int < 0 || OPB->_int >= pr_globaldefs)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to write to an invalid indexed global");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME);
                                        return;
                                }
 #endif
 #if PRBOUNDSCHECK
                                if (OPB->_int < 0 || OPB->_int + 2 >= pr_globaldefs)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to write to an invalid indexed global");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME);
                                        return;
                                }
 #endif
 #if PRBOUNDSCHECK
                                if (i < 0 || i >= pr_globaldefs)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to address an out of bounds global");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to address an out of bounds global", PRVM_NAME);
                                        return;
                                }
 #endif
 #if PRBOUNDSCHECK
                                if (OPA->_int < 0 || OPA->_int >= pr_globaldefs)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to read an invalid indexed global");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME);
                                        return;
                                }
 #endif
 #if PRBOUNDSCHECK
                                if (OPA->_int < 0 || OPA->_int + 2 >= pr_globaldefs)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs attempted to read an invalid indexed global");
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME);
                                        return;
                                }
 #endif
                        case OP_BOUNDCHECK:
                                if (OPA->_int < 0 || OPA->_int >= st->b)
                                {
-                                       pr_xfunction->profile += profile - startprofile;
-                                       startprofile = profile;
-                                       pr_xstatement = st - pr_statements;
-                                       Host_Error("Progs boundcheck failed at line number %d, value is < 0 or >= %d", st->b, st->c);
+                                       prog->xfunction->profile += (st - startst);
+                                       prog->xstatement = st - prog->statements;
+                                       PRVM_ERROR ("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", PRVM_NAME, st->b, st->c);
                                        return;
                                }
                                break;
 */
 
                        default:
-                               prog->xfunction->profile += profile - startprofile;
-                               startprofile = profile;
+                               prog->xfunction->profile += (st - startst);
                                prog->xstatement = st - prog->statements;
                                PRVM_ERROR ("Bad opcode %i in %s", st->op, PRVM_NAME);
                        }