=== cd /home/jeremy/src/python/dist/src/ === cvs diff -u configure.in pyconfig.h.in Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.289 diff -c -u -r1.289 configure.in cvs server: conflicting specifications of output style --- configure.in 2002/01/01 18:41:32 1.289 +++ configure.in 2002/01/30 13:05:59 @@ -1325,6 +1325,16 @@ AC_MSG_RESULT($with_cycle_gc) # Check for Python-specific malloc support +AC_MSG_CHECKING(for --with-tsc) +AC_ARG_WITH(tsc, +[ --with(out)-tsc enable/disable timestamp counter profile], [ +if test "$withval" != no +then AC_DEFINE(WITH_TSC) AC_MSG_RESULT(yes) +else AC_MSG_RESULT(no) +fi], +[AC_MSG_RESULT(no)]) + +# Check for Python-specific malloc support AC_MSG_CHECKING(for --with-pymalloc) AC_ARG_WITH(pymalloc, [ --with(out)-pymalloc disable/enable specialized mallocs], [ Index: pyconfig.h.in =================================================================== RCS file: /cvsroot/python/python/dist/src/pyconfig.h.in,v retrieving revision 1.21 diff -c -u -r1.21 pyconfig.h.in cvs server: conflicting specifications of output style --- pyconfig.h.in 2002/01/01 18:41:32 1.21 +++ pyconfig.h.in 2002/01/30 13:06:00 @@ -280,6 +280,9 @@ /* Define if you want to compile in Python-specific mallocs */ #undef WITH_PYMALLOC +/* Define if you want Pentium TSC profiling available */ +#undef WITH_TSC + /* Define if you want to produce an OpenStep/Rhapsody framework (shared library plus accessory files). */ #undef WITH_NEXT_FRAMEWORK === Exit status: 1 === cd /home/jeremy/src/python/dist/src/Include/ === cvs diff -u pystate.h Index: pystate.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/pystate.h,v retrieving revision 2.18 diff -c -u -r2.18 pystate.h cvs server: conflicting specifications of output style --- pystate.h 2001/07/19 12:19:11 2.18 +++ pystate.h 2002/01/30 13:06:02 @@ -26,6 +26,9 @@ #ifdef HAVE_DLOPEN int dlopenflags; #endif +#ifdef WITH_TSC + int tscdump; +#endif } PyInterpreterState; === Exit status: 1 === cd /home/jeremy/src/python/dist/src/Python/ === cvs diff -u ceval.c pystate.c sysmodule.c Index: ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.303 diff -c -u -r2.303 ceval.c cvs server: conflicting specifications of output style --- ceval.c 2002/01/01 19:59:11 2.303 +++ ceval.c 2002/01/30 13:06:06 @@ -20,6 +20,26 @@ #include +#ifdef WITH_TSC +#include + +typedef unsigned long long uint64; + +void dump_tsc(int opcode, int ticked, uint64 inst0, uint64 inst1, + uint64 loop0, uint64 loop1, uint64 intr0, uint64 intr1) +{ + uint64 intr, inst, loop; + PyThreadState *tstate = PyThreadState_Get(); + if (!tstate->interp->tscdump) + return; + intr = intr1 - intr0; + inst = inst1 - inst0 - intr; + loop = loop1 - loop0 - intr; + fprintf(stderr, "opcode=%03d t=%d inst=%06lld loop=%06lld\n", + opcode, ticked, inst, loop); +} +#endif + /* Turn this on if your compiler chokes on the big switch: */ /* #define CASE_TOO_BIG 1 */ @@ -522,6 +542,44 @@ char *filename; #endif +#ifdef WITH_TSC +/* Use Pentium timestamp counter to mark certain events: + inst0 -- beginning of switch statement for opcode dispatch + inst1 -- end of switch statement (may be skipped) + loop0 -- the top of the mainloop + loop1 -- place where control returns again to top of mainloop + (may be skipped) + intr1 -- beginning of long interruption + intr2 -- end of long interruption + + Many opcodes call out to helper C functions. In some cases, the + time in those functions should be counted towards the time for the + opcode, but not in all cases. For example, a CALL_FUNCTION opcode + calls another Python function; there's no point in charge all the + bytecode executed by the called function to the caller. + + It's hard to make a useful judgement statically. In the presence + of operator overloading, it's impossible to tell if a call will + execute new Python code or not. + + It's a case-by-case judgement. I'll use intr1 for the following + cases: + + EXEC_STMT + IMPORT_STAR + IMPORT_FROM + CALL_FUNCTION (and friends) + + */ + uint64 inst0, inst1, loop0, loop1, intr0 = 0, intr1 = 0; + int ticked = 0; + + rdtscll(inst0); + rdtscll(inst1); + rdtscll(loop0); + rdtscll(loop1); +#endif + /* Code access macros */ #define GETCONST(i) Getconst(f, i) @@ -634,6 +692,23 @@ w = NULL; for (;;) { +#ifdef WITH_TSC + if (inst1 == 0) { + /* Almost surely, the opcode executed a break + or a continue, preventing inst1 from being set + on the way out of the loop. + */ + rdtscll(inst1); + loop1 = inst1; + } + dump_tsc(opcode, ticked, inst0, inst1, loop0, loop1, + intr0, intr1); + ticked = 0; + inst1 = 0; + intr0 = 0; + intr1 = 0; + rdtscll(loop0); +#endif assert(stack_pointer >= f->f_valuestack); /* else underflow */ assert(STACK_LEVEL() <= f->f_stacksize); /* else overflow */ /* Do periodic things. Doing this every time through @@ -645,6 +720,9 @@ Py_MakePendingCalls() above. */ if (things_to_do || --tstate->ticker < 0) { +#ifdef WITH_TSC + ticked = 1; +#endif tstate->ticker = tstate->interp->checkinterval; if (things_to_do) { if (Py_MakePendingCalls() < 0) { @@ -714,6 +792,9 @@ } #endif /* Main switch on opcode */ +#ifdef WITH_TSC + rdtscll(inst0); +#endif switch (opcode) { @@ -1467,7 +1548,13 @@ w = POP(); v = POP(); u = POP(); +#ifdef WITH_TSC + rdtscll(intr0); +#endif err = exec_statement(f, u, v, w); +#ifdef WITH_TSC + rdtscll(intr1); +#endif Py_DECREF(u); Py_DECREF(v); Py_DECREF(w); @@ -1828,7 +1915,13 @@ x = NULL; break; } +#ifdef WITH_TSC + rdtscll(intr0); +#endif x = PyEval_CallObject(x, w); +#ifdef WITH_TSC + rdtscll(intr1); +#endif Py_DECREF(w); PUSH(x); if (x != NULL) continue; @@ -1842,7 +1935,13 @@ "no locals found during 'import *'"); break; } +#ifdef WITH_TSC + rdtscll(intr0); +#endif err = import_all_from(x, v); +#ifdef WITH_TSC + rdtscll(intr1); +#endif PyFrame_LocalsToFast(f, 0); Py_DECREF(v); if (err == 0) continue; @@ -1851,7 +1950,13 @@ case IMPORT_FROM: w = GETNAMEV(oparg); v = TOP(); +#ifdef WITH_TSC + rdtscll(intr0); +#endif x = import_from(v, w); +#ifdef WITH_TSC + rdtscll(intr1); +#endif PUSH(x); if (x != NULL) continue; break; @@ -1993,11 +2098,24 @@ else if (flags == METH_VARARGS) { PyObject *callargs; callargs = load_args(&stack_pointer, na); +#ifdef WITH_TSC + rdtscll(intr0); +#endif x = PyCFunction_Call(func, callargs, NULL); +#ifdef WITH_TSC + rdtscll(intr1); +#endif Py_XDECREF(callargs); - } else + } else { +#ifdef WITH_TSC + rdtscll(intr0); +#endif x = fast_cfunction(func, &stack_pointer, na); +#ifdef WITH_TSC + rdtscll(intr1); +#endif + } } else { if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { @@ -2012,6 +2130,9 @@ n++; } else Py_INCREF(func); +#ifdef WITH_TSC + rdtscll(intr0); +#endif if (PyFunction_Check(func)) { x = fast_function(func, &stack_pointer, n, na, nk); @@ -2019,6 +2140,9 @@ x = do_call(func, &stack_pointer, na, nk); } +#ifdef WITH_TSC + rdtscll(intr1); +#endif Py_DECREF(func); } @@ -2061,7 +2185,13 @@ n++; } else Py_INCREF(func); +#ifdef WITH_TSC + rdtscll(intr0); +#endif x = ext_do_call(func, &stack_pointer, flags, na, nk); +#ifdef WITH_TSC + rdtscll(intr1); +#endif Py_DECREF(func); while (stack_pointer > pfunc) { @@ -2172,6 +2302,10 @@ on_error: +#ifdef WITH_TSC + rdtscll(inst1); +#endif + /* Quickly continue if no error occurred */ if (why == WHY_NOT) { @@ -2181,9 +2315,15 @@ if (PyErr_Occurred()) fprintf(stderr, "XXX undetected error\n"); - else + else { #endif +#ifdef WITH_TSC + rdtscll(loop1); +#endif continue; /* Normal, fast path */ +#ifdef CHECKEXC + } +#endif } why = WHY_EXCEPTION; x = Py_None; @@ -2300,6 +2440,9 @@ if (why != WHY_NOT) break; +#ifdef WITH_TSC + rdtscll(loop1); +#endif } /* main loop */ Index: pystate.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v retrieving revision 2.20 diff -c -u -r2.20 pystate.c cvs server: conflicting specifications of output style --- pystate.c 2001/07/19 12:19:27 2.20 +++ pystate.c 2002/01/30 13:06:06 @@ -56,6 +56,9 @@ interp->dlopenflags = RTLD_LAZY; #endif #endif +#ifdef WITH_TSC + interp->tscdump = 0; +#endif HEAD_LOCK(); interp->next = interp_head; Index: sysmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/sysmodule.c,v retrieving revision 2.100 diff -c -u -r2.100 sysmodule.c cvs server: conflicting specifications of output style --- sysmodule.c 2002/01/29 00:53:41 2.100 +++ sysmodule.c 2002/01/30 13:06:07 @@ -354,7 +354,33 @@ Tell the Python interpreter to check for asynchronous events every\n\ n instructions. This also affects how often thread switches occur."; +#ifdef WITH_TSC static PyObject * +sys_settscdump(PyObject *self, PyObject *args) +{ + int bool; + PyThreadState *tstate = PyThreadState_Get(); + + if (!PyArg_ParseTuple(args, "i:settscdump", &bool)) + return NULL; + if (bool) + tstate->interp->tscdump = 1; + else + tstate->interp->tscdump = 0; + Py_INCREF(Py_None); + return Py_None; + +} + +static char settscdump_doc[] = +"settscdump(bool)\n\ +\n\ +If true, tell the Python interpreter to dump VM measurements to +stderr. If false, turn off dump. The measurements are based on the +Pentium time-stamp counter."; +#endif TSC + +static PyObject * sys_setrecursionlimit(PyObject *self, PyObject *args) { int new_limit; @@ -567,6 +593,9 @@ {"setprofile", sys_setprofile, METH_OLDARGS, setprofile_doc}, {"setrecursionlimit", sys_setrecursionlimit, METH_VARARGS, setrecursionlimit_doc}, +#ifdef WITH_TSC + {"settscdump", sys_settscdump, METH_VARARGS, settscdump_doc}, +#endif {"settrace", sys_settrace, METH_OLDARGS, settrace_doc}, {NULL, NULL} /* sentinel */ }; === Exit status: 1