diff options
author | Fred Drake <fdrake@acm.org> | 2001-06-27 19:19:46 (GMT) |
---|---|---|
committer | Fred Drake <fdrake@acm.org> | 2001-06-27 19:19:46 (GMT) |
commit | 5755ce693dfc497389ab89e8ae0e62c3cc89d4ff (patch) | |
tree | 1a6eac014a12e3c1094ac93cc976c621d3de9870 /Python/sysmodule.c | |
parent | 55fb6e037170ddb645c552079ec8fe6c042de542 (diff) | |
download | cpython-5755ce693dfc497389ab89e8ae0e62c3cc89d4ff.zip cpython-5755ce693dfc497389ab89e8ae0e62c3cc89d4ff.tar.gz cpython-5755ce693dfc497389ab89e8ae0e62c3cc89d4ff.tar.bz2 |
Revise the interface to the profiling and tracing support for the
Python interpreter.
This change adds two new C-level APIs: PyEval_SetProfile() and
PyEval_SetTrace(). These can be used to install profile and trace
functions implemented in C, which can operate at much higher speeds
than Python-based functions. The overhead for calling a C-based
profile function is a very small fraction of a percent of the overhead
involved in calling a Python-based function.
The machinery required to call a Python-based profile or trace
function been moved to sysmodule.c, where sys.setprofile() and
sys.setprofile() simply become users of the new interface.
As a side effect, SF bug #436058 is fixed; there is no longer a
_PyTrace_Init() function to declare.
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r-- | Python/sysmodule.c | 123 |
1 files changed, 110 insertions, 13 deletions
diff --git a/Python/sysmodule.c b/Python/sysmodule.c index fe880d5..76d40bf 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -196,20 +196,120 @@ static char setdefaultencoding_doc[] = \n\ Set the current default string encoding used by the Unicode implementation."; -extern int _PyTrace_Init(void); +/* + * Cached interned string objects used for calling the profile and + * trace functions. Initialized by trace_init(). + */ +static PyObject *whatstrings[4] = {NULL, NULL, NULL, NULL}; + +static int +trace_init(void) +{ + static char *whatnames[4] = {"call", "exception", "line", "return"}; + PyObject *name; + int i; + for (i = 0; i < 4; ++i) { + if (whatstrings[i] == NULL) { + name = PyString_InternFromString(whatnames[i]); + if (name == NULL) + return -1; + whatstrings[i] = name; + } + } + return 0; +} + + +static PyObject * +call_trampoline(PyThreadState *tstate, PyObject* callback, + PyFrameObject *frame, int what, PyObject *arg) +{ + PyObject *args = PyTuple_New(3); + PyObject *whatstr; + PyObject *result; + + if (args == NULL) + return NULL; + Py_INCREF(frame); + whatstr = whatstrings[what]; + Py_INCREF(whatstr); + if (arg == NULL) + arg = Py_None; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 0, (PyObject *)frame); + PyTuple_SET_ITEM(args, 1, whatstr); + PyTuple_SET_ITEM(args, 2, arg); + + /* call the Python-level function */ + PyFrame_FastToLocals(frame); + result = PyEval_CallObject(callback, args); + PyFrame_LocalsToFast(frame, 1); + if (result == NULL) + PyTraceBack_Here(frame); + + /* cleanup */ + Py_DECREF(args); + return result; +} + +static int +profile_trampoline(PyObject *self, PyFrameObject *frame, + int what, PyObject *arg) +{ + PyThreadState *tstate = frame->f_tstate; + PyObject *result; + + result = call_trampoline(tstate, self, frame, what, arg); + if (result == NULL) { + PyEval_SetProfile(NULL, NULL); + return -1; + } + Py_DECREF(result); + return 0; +} + +static int +trace_trampoline(PyObject *self, PyFrameObject *frame, + int what, PyObject *arg) +{ + PyThreadState *tstate = frame->f_tstate; + PyObject *callback; + PyObject *result; + + if (what == PyTrace_CALL) + callback = self; + else + callback = frame->f_trace; + if (callback == NULL) + return 0; + result = call_trampoline(tstate, callback, frame, what, arg); + if (result == NULL) { + PyEval_SetTrace(NULL, NULL); + Py_XDECREF(frame->f_trace); + frame->f_trace = NULL; + return -1; + } + if (result != Py_None) { + PyObject *temp = frame->f_trace; + frame->f_trace = NULL; + Py_XDECREF(temp); + frame->f_trace = result; + } + else { + Py_DECREF(result); + } + return 0; +} static PyObject * sys_settrace(PyObject *self, PyObject *args) { - PyThreadState *tstate = PyThreadState_Get(); - if (_PyTrace_Init() == -1) + if (trace_init() == -1) return NULL; if (args == Py_None) - args = NULL; + PyEval_SetTrace(NULL, NULL); else - Py_XINCREF(args); - Py_XDECREF(tstate->sys_tracefunc); - tstate->sys_tracefunc = args; + PyEval_SetTrace(trace_trampoline, args); Py_INCREF(Py_None); return Py_None; } @@ -223,15 +323,12 @@ function call. See the debugger chapter in the library manual."; static PyObject * sys_setprofile(PyObject *self, PyObject *args) { - PyThreadState *tstate = PyThreadState_Get(); - if (_PyTrace_Init() == -1) + if (trace_init() == -1) return NULL; if (args == Py_None) - args = NULL; + PyEval_SetProfile(NULL, NULL); else - Py_XINCREF(args); - Py_XDECREF(tstate->sys_profilefunc); - tstate->sys_profilefunc = args; + PyEval_SetProfile(profile_trampoline, args); Py_INCREF(Py_None); return Py_None; } |