mirror of
https://github.com/python/cpython.git
synced 2025-10-21 14:12:27 +00:00
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:
parent
55fb6e0371
commit
5755ce693d
3 changed files with 182 additions and 150 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue