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.
This commit is contained in:
Fred Drake 2001-06-27 19:19:46 +00:00
parent 55fb6e0371
commit 5755ce693d
3 changed files with 182 additions and 150 deletions

View file

@ -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;
}