[Python-checkins] CVS: python/dist/src/Python ceval.c,2.258,2.259 pystate.c,2.16,2.17 sysmodule.c,2.87,2.88
Fred L. Drake
fdrake@users.sourceforge.net
Wed, 27 Jun 2001 12:19:48 -0700
Update of /cvsroot/python/python/dist/src/Python
In directory usw-pr-cvs1:/tmp/cvs-serv18718/Python
Modified Files:
ceval.c pystate.c sysmodule.c
Log Message:
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.
Index: ceval.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v
retrieving revision 2.258
retrieving revision 2.259
diff -C2 -r2.258 -r2.259
*** ceval.c 2001/06/26 22:24:51 2.258
--- ceval.c 2001/06/27 19:19:46 2.259
***************
*** 3,7 ****
/* XXX TO DO:
! XXX how to pass arguments to call_trace?
XXX speed up searching for keywords by using a dictionary
XXX document it!
--- 3,7 ----
/* XXX TO DO:
! XXX how to pass arguments to profile and trace functions?
XXX speed up searching for keywords by using a dictionary
XXX document it!
***************
*** 62,68 ****
static int prtrace(PyObject *, char *);
#endif
! static void call_exc_trace(PyObject **, PyObject**, PyFrameObject *);
! static int call_trace(PyObject **, PyObject **,
! PyFrameObject *, PyObject *, PyObject *);
static PyObject *loop_subscript(PyObject *, PyObject *);
static PyObject *apply_slice(PyObject *, PyObject *, PyObject *);
--- 62,68 ----
static int prtrace(PyObject *, char *);
#endif
! static int call_trace(Py_tracefunc, PyObject *, PyFrameObject *,
! int, PyObject *);
! static void call_exc_trace(Py_tracefunc, PyObject *, PyFrameObject *);
static PyObject *loop_subscript(PyObject *, PyObject *);
static PyObject *apply_slice(PyObject *, PyObject *, PyObject *);
***************
*** 99,111 ****
#endif
- /* Cached interned string objects used for calling the profile and
- * trace functions.
- */
- static PyObject *str_call = NULL;
- static PyObject *str_exception = NULL;
- static PyObject *str_line = NULL;
- static PyObject *str_return = NULL;
-
staticforward PyTypeObject gentype;
--- 99,103 ----
***************
*** 1893,1902 ****
#endif
f->f_lineno = oparg;
! if (f->f_trace == NULL)
continue;
/* Trace each line of code reached */
f->f_lasti = INSTR_OFFSET();
! err = call_trace(&f->f_trace, &f->f_trace,
! f, str_line, Py_None);
break;
--- 1885,1897 ----
#endif
f->f_lineno = oparg;
! if (tstate->c_tracefunc == NULL || tstate->tracing)
continue;
/* Trace each line of code reached */
f->f_lasti = INSTR_OFFSET();
! /* Inline call_trace() for performance: */
! tstate->tracing++;
! err = (tstate->c_tracefunc)(tstate->c_traceobj, f,
! PyTrace_LINE, Py_None);
! tstate->tracing--;
break;
***************
*** 2148,2156 ****
PyTraceBack_Here(f);
! if (f->f_trace)
! call_exc_trace(&f->f_trace, &f->f_trace, f);
! if (tstate->sys_profilefunc)
! call_exc_trace(&tstate->sys_profilefunc,
! (PyObject**)0, f);
}
--- 2143,2152 ----
PyTraceBack_Here(f);
! if (tstate->c_tracefunc)
! call_exc_trace(tstate->c_tracefunc,
! tstate->c_traceobj, f);
! if (tstate->c_profilefunc)
! call_exc_trace(tstate->c_profilefunc,
! tstate->c_profileobj, f);
}
***************
*** 2233,2240 ****
retval = NULL;
! if (f->f_trace) {
if (why == WHY_RETURN || why == WHY_YIELD) {
! if (call_trace(&f->f_trace, &f->f_trace, f,
! str_return, retval)) {
Py_XDECREF(retval);
retval = NULL;
--- 2229,2236 ----
retval = NULL;
! if (tstate->c_tracefunc && !tstate->tracing) {
if (why == WHY_RETURN || why == WHY_YIELD) {
! if (call_trace(tstate->c_tracefunc, tstate->c_traceobj,
! f, PyTrace_RETURN, retval)) {
Py_XDECREF(retval);
retval = NULL;
***************
*** 2244,2251 ****
}
! if (tstate->sys_profilefunc &&
! (why == WHY_RETURN || why == WHY_YIELD)) {
! if (call_trace(&tstate->sys_profilefunc, (PyObject**)0,
! f, str_return, retval)) {
Py_XDECREF(retval);
retval = NULL;
--- 2240,2247 ----
}
! if (tstate->c_profilefunc && !tstate->tracing
! && (why == WHY_RETURN || why == WHY_YIELD)) {
! if (call_trace(tstate->c_profilefunc, tstate->c_profileobj,
! f, PyTrace_RETURN, retval)) {
Py_XDECREF(retval);
retval = NULL;
***************
*** 2476,2480 ****
}
! if (tstate->sys_tracefunc != NULL) {
/* tstate->sys_tracefunc, if defined, is a function that
will be called on *every* entry to a code block.
--- 2472,2476 ----
}
! if (tstate->c_tracefunc != NULL && !tstate->tracing) {
/* tstate->sys_tracefunc, if defined, is a function that
will be called on *every* entry to a code block.
***************
*** 2489,2495 ****
(sys.trace) is also called whenever an exception
is detected. */
! if (call_trace(&tstate->sys_tracefunc,
! &f->f_trace, f, str_call,
! Py_None/*XXX how to compute arguments now?*/)) {
/* Trace function raised an error */
goto fail;
--- 2485,2491 ----
(sys.trace) is also called whenever an exception
is detected. */
! if (call_trace(tstate->c_tracefunc, tstate->c_traceobj,
! f, PyTrace_CALL, Py_None)) {
! /* XXX Need way to compute arguments?? */
/* Trace function raised an error */
goto fail;
***************
*** 2497,2506 ****
}
! if (tstate->sys_profilefunc != NULL) {
/* Similar for sys_profilefunc, except it needn't return
itself and isn't called for "line" events */
! if (call_trace(&tstate->sys_profilefunc,
! (PyObject**)0, f, str_call,
! Py_None/*XXX*/)) {
goto fail;
}
--- 2493,2503 ----
}
! if (tstate->c_profilefunc != NULL) {
/* Similar for sys_profilefunc, except it needn't return
itself and isn't called for "line" events */
! if (call_trace(tstate->c_profilefunc, tstate->c_profileobj,
! f, PyTrace_CALL, Py_None)) {
! /* XXX Need way to compute arguments?? */
! /* Profile function raised an error */
goto fail;
}
***************
*** 2773,2777 ****
static void
! call_exc_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f)
{
PyObject *type, *value, *traceback, *arg;
--- 2770,2774 ----
static void
! call_exc_trace(Py_tracefunc func, PyObject *self, PyFrameObject *f)
{
PyObject *type, *value, *traceback, *arg;
***************
*** 2787,2791 ****
return;
}
! err = call_trace(p_trace, p_newtrace, f, str_exception, arg);
Py_DECREF(arg);
if (err == 0)
--- 2784,2788 ----
return;
}
! err = call_trace(func, self, f, PyTrace_EXCEPTION, arg);
Py_DECREF(arg);
if (err == 0)
***************
*** 2798,2905 ****
}
- /* PyObject **p_trace: in/out; may not be NULL;
- may not point to NULL variable initially
- PyObject **p_newtrace: in/out; may be NULL;
- may point to NULL variable;
- may be same variable as p_newtrace
- PyObject *msg: in; must not be NULL
- */
-
static int
! call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
! PyObject *msg, PyObject *arg)
{
! PyThreadState *tstate = f->f_tstate;
! PyObject *args;
! PyObject *res = NULL;
!
! if (tstate->tracing) {
! /* Don't do recursive traces */
! if (p_newtrace) {
! Py_XDECREF(*p_newtrace);
! *p_newtrace = NULL;
! }
return 0;
- }
-
- args = PyTuple_New(3);
- if (args == NULL)
- goto cleanup;
- Py_INCREF(msg);
- Py_INCREF(f);
- PyTuple_SET_ITEM(args, 0, (PyObject *)f);
- PyTuple_SET_ITEM(args, 1, msg);
- if (arg == NULL)
- arg = Py_None;
- Py_INCREF(arg);
- PyTuple_SET_ITEM(args, 2, arg);
tstate->tracing++;
! PyFrame_FastToLocals(f);
! res = PyEval_CallObject(*p_trace, args); /* May clear *p_trace! */
! PyFrame_LocalsToFast(f, 1);
tstate->tracing--;
! cleanup:
! Py_XDECREF(args);
! if (res == NULL) {
! /* The trace proc raised an exception */
! PyTraceBack_Here(f);
! Py_XDECREF(*p_trace);
! *p_trace = NULL;
! if (p_newtrace) {
! Py_XDECREF(*p_newtrace);
! *p_newtrace = NULL;
! }
! /* to be extra double plus sure we don't get recursive
! * calls inf either tracefunc or profilefunc gets an
! * exception, zap the global variables.
! */
! Py_XDECREF(tstate->sys_tracefunc);
! tstate->sys_tracefunc = NULL;
! Py_XDECREF(tstate->sys_profilefunc);
! tstate->sys_profilefunc = NULL;
! return -1;
! }
! else {
! if (p_newtrace) {
! Py_XDECREF(*p_newtrace);
! if (res == Py_None)
! *p_newtrace = NULL;
! else {
! Py_INCREF(res);
! *p_newtrace = res;
! }
! }
! Py_DECREF(res);
! return 0;
! }
}
! /* Initialize the strings that get passed to the profile and trace functions;
! * this avoids doing this while we're actually profiling/tracing.
! */
! int
! _PyTrace_Init(void)
{
! if (str_call == NULL) {
! str_call = PyString_InternFromString("call");
! if (str_call == NULL)
! return -1;
! }
! if (str_exception == NULL) {
! str_exception = PyString_InternFromString("exception");
! if (str_exception == NULL)
! return -1;
! }
! if (str_line == NULL) {
! str_line = PyString_InternFromString("line");
! if (str_line == NULL)
! return -1;
! }
! if (str_return == NULL) {
! str_return = PyString_InternFromString("return");
! if (str_return == NULL)
! return -1;
! }
! return 0;
}
--- 2795,2836 ----
}
static int
! call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
! int what, PyObject *arg)
{
! register PyThreadState *tstate = frame->f_tstate;
! int result;
! if (tstate->tracing)
return 0;
tstate->tracing++;
! result = func(obj, frame, what, arg);
tstate->tracing--;
! return result;
}
! void
! PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
{
! PyThreadState *tstate = PyThreadState_Get();
! PyObject *temp = tstate->c_profileobj;
! Py_XINCREF(arg);
! tstate->c_profilefunc = NULL;
! tstate->c_profileobj = NULL;
! Py_XDECREF(temp);
! tstate->c_profilefunc = func;
! tstate->c_profileobj = arg;
! }
!
! void
! PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
! {
! PyThreadState *tstate = PyThreadState_Get();
! PyObject *temp = tstate->c_traceobj;
! Py_XINCREF(arg);
! tstate->c_tracefunc = NULL;
! tstate->c_traceobj = NULL;
! Py_XDECREF(temp);
! tstate->c_tracefunc = func;
! tstate->c_traceobj = arg;
}
Index: pystate.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v
retrieving revision 2.16
retrieving revision 2.17
diff -C2 -r2.16 -r2.17
*** pystate.c 2001/01/23 01:46:06 2.16
--- pystate.c 2001/06/27 19:19:46 2.17
***************
*** 121,126 ****
tstate->exc_traceback = NULL;
! tstate->sys_profilefunc = NULL;
! tstate->sys_tracefunc = NULL;
HEAD_LOCK();
--- 121,128 ----
tstate->exc_traceback = NULL;
! tstate->c_profilefunc = NULL;
! tstate->c_tracefunc = NULL;
! tstate->c_profileobj = NULL;
! tstate->c_traceobj = NULL;
HEAD_LOCK();
***************
*** 153,158 ****
ZAP(tstate->exc_traceback);
! ZAP(tstate->sys_profilefunc);
! ZAP(tstate->sys_tracefunc);
}
--- 155,162 ----
ZAP(tstate->exc_traceback);
! tstate->c_profilefunc = NULL;
! tstate->c_tracefunc = NULL;
! ZAP(tstate->c_profileobj);
! ZAP(tstate->c_traceobj);
}
Index: sysmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/sysmodule.c,v
retrieving revision 2.87
retrieving revision 2.88
diff -C2 -r2.87 -r2.88
*** sysmodule.c 2001/06/27 06:28:56 2.87
--- sysmodule.c 2001/06/27 19:19:46 2.88
***************
*** 197,214 ****
Set the current default string encoding used by the Unicode implementation.";
! extern int _PyTrace_Init(void);
static PyObject *
sys_settrace(PyObject *self, PyObject *args)
{
! PyThreadState *tstate = PyThreadState_Get();
! if (_PyTrace_Init() == -1)
return NULL;
if (args == Py_None)
! args = NULL;
else
! Py_XINCREF(args);
! Py_XDECREF(tstate->sys_tracefunc);
! tstate->sys_tracefunc = args;
Py_INCREF(Py_None);
return Py_None;
--- 197,314 ----
Set the current default string encoding used by the Unicode implementation.";
! /*
! * 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)
{
! if (trace_init() == -1)
return NULL;
if (args == Py_None)
! PyEval_SetTrace(NULL, NULL);
else
! PyEval_SetTrace(trace_trampoline, args);
Py_INCREF(Py_None);
return Py_None;
***************
*** 224,236 ****
sys_setprofile(PyObject *self, PyObject *args)
{
! PyThreadState *tstate = PyThreadState_Get();
! if (_PyTrace_Init() == -1)
return NULL;
if (args == Py_None)
! args = NULL;
else
! Py_XINCREF(args);
! Py_XDECREF(tstate->sys_profilefunc);
! tstate->sys_profilefunc = args;
Py_INCREF(Py_None);
return Py_None;
--- 324,333 ----
sys_setprofile(PyObject *self, PyObject *args)
{
! if (trace_init() == -1)
return NULL;
if (args == Py_None)
! PyEval_SetProfile(NULL, NULL);
else
! PyEval_SetProfile(profile_trampoline, args);
Py_INCREF(Py_None);
return Py_None;