Commit 9e3ad784 authored by Fred Drake's avatar Fred Drake

This change adjusts the profiling/tracing support so that the common

path (with no profile/trace function) through eval_code2() and
eval_frame() avoids several checks.

In the common cases of calls, returns, and exception propogation,
eval_code2() and eval_frame() used to test two values in the
thread-state: the profiling function and the tracing function.  With
this change, a flag is set in the thread-state if either of these is
active, allowing a single check to suffice when both are NULL.  This
also simplifies the code needed when either function is in use but is
already active (to avoid profiling/tracing the profiler/tracer); the
flag is set to 0 when the profile/trace code is entered, allowing the
same check to suffice for "already in the tracer" for call/return/
exception events.
parent d89a2e77
...@@ -49,6 +49,7 @@ typedef struct _ts { ...@@ -49,6 +49,7 @@ typedef struct _ts {
int recursion_depth; int recursion_depth;
int ticker; int ticker;
int tracing; int tracing;
int use_tracing;
Py_tracefunc c_profilefunc; Py_tracefunc c_profilefunc;
Py_tracefunc c_tracefunc; Py_tracefunc c_tracefunc;
......
...@@ -1890,8 +1890,11 @@ eval_frame(PyFrameObject *f) ...@@ -1890,8 +1890,11 @@ eval_frame(PyFrameObject *f)
f->f_lasti = INSTR_OFFSET(); f->f_lasti = INSTR_OFFSET();
/* Inline call_trace() for performance: */ /* Inline call_trace() for performance: */
tstate->tracing++; tstate->tracing++;
tstate->use_tracing = 0;
err = (tstate->c_tracefunc)(tstate->c_traceobj, f, err = (tstate->c_tracefunc)(tstate->c_traceobj, f,
PyTrace_LINE, Py_None); PyTrace_LINE, Py_None);
tstate->use_tracing = (tstate->c_tracefunc
|| tstate->c_profilefunc);
tstate->tracing--; tstate->tracing--;
break; break;
...@@ -2142,12 +2145,14 @@ eval_frame(PyFrameObject *f) ...@@ -2142,12 +2145,14 @@ eval_frame(PyFrameObject *f)
f->f_lasti -= 2; f->f_lasti -= 2;
PyTraceBack_Here(f); PyTraceBack_Here(f);
if (tstate->use_tracing) {
if (tstate->c_tracefunc) if (tstate->c_tracefunc)
call_exc_trace(tstate->c_tracefunc, call_exc_trace(tstate->c_tracefunc,
tstate->c_traceobj, f); tstate->c_traceobj, f);
if (tstate->c_profilefunc) if (tstate->c_profilefunc)
call_exc_trace(tstate->c_profilefunc, call_exc_trace(tstate->c_profilefunc,
tstate->c_profileobj, f); tstate->c_profileobj,f);
}
} }
/* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
...@@ -2228,26 +2233,28 @@ eval_frame(PyFrameObject *f) ...@@ -2228,26 +2233,28 @@ eval_frame(PyFrameObject *f)
if (why != WHY_RETURN && why != WHY_YIELD) if (why != WHY_RETURN && why != WHY_YIELD)
retval = NULL; retval = NULL;
if (tstate->c_tracefunc && !tstate->tracing) { if (tstate->use_tracing) {
if (why == WHY_RETURN || why == WHY_YIELD) { if (tstate->c_tracefunc
if (call_trace(tstate->c_tracefunc, tstate->c_traceobj, && (why == WHY_RETURN || why == WHY_YIELD)) {
f, PyTrace_RETURN, retval)) { if (call_trace(tstate->c_tracefunc,
tstate->c_traceobj, f,
PyTrace_RETURN, retval)) {
Py_XDECREF(retval); Py_XDECREF(retval);
retval = NULL; retval = NULL;
why = WHY_EXCEPTION; why = WHY_EXCEPTION;
} }
} }
} if (tstate->c_profilefunc
if (tstate->c_profilefunc && !tstate->tracing
&& (why == WHY_RETURN || why == WHY_YIELD)) { && (why == WHY_RETURN || why == WHY_YIELD)) {
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, if (call_trace(tstate->c_profilefunc,
f, PyTrace_RETURN, retval)) { tstate->c_profileobj, f,
PyTrace_RETURN, retval)) {
Py_XDECREF(retval); Py_XDECREF(retval);
retval = NULL; retval = NULL;
why = WHY_EXCEPTION; why = WHY_EXCEPTION;
} }
} }
}
reset_exc_info(tstate); reset_exc_info(tstate);
...@@ -2471,19 +2478,21 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -2471,19 +2478,21 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
} }
} }
if (tstate->c_tracefunc != NULL && !tstate->tracing) { if (tstate->use_tracing) {
/* tstate->sys_tracefunc, if defined, is a function that if (tstate->c_tracefunc != NULL) {
will be called on *every* entry to a code block. /* tstate->c_tracefunc, if defined, is a
Its return value, if not None, is a function that function that will be called on *every* entry
will be called at the start of each executed line to a code block. Its return value, if not
of code. (Actually, the function must return None, is a function that will be called at
itself in order to continue tracing.) the start of each executed line of code.
The trace functions are called with three arguments: (Actually, the function must return itself
a pointer to the current frame, a string indicating in order to continue tracing.) The trace
why the function is called, and an argument which functions are called with three arguments:
depends on the situation. The global trace function a pointer to the current frame, a string
(sys.trace) is also called whenever an exception indicating why the function is called, and
is detected. */ an argument which depends on the situation.
The global trace function is also called
whenever an exception is detected. */
if (call_trace(tstate->c_tracefunc, tstate->c_traceobj, if (call_trace(tstate->c_tracefunc, tstate->c_traceobj,
f, PyTrace_CALL, Py_None)) { f, PyTrace_CALL, Py_None)) {
/* XXX Need way to compute arguments?? */ /* XXX Need way to compute arguments?? */
...@@ -2491,17 +2500,18 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -2491,17 +2500,18 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
goto fail; goto fail;
} }
} }
if (tstate->c_profilefunc != NULL) { if (tstate->c_profilefunc != NULL) {
/* Similar for sys_profilefunc, except it needn't return /* Similar for c_profilefunc, except it needn't
itself and isn't called for "line" events */ return itself and isn't called for "line" events */
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, if (call_trace(tstate->c_profilefunc,
tstate->c_profileobj,
f, PyTrace_CALL, Py_None)) { f, PyTrace_CALL, Py_None)) {
/* XXX Need way to compute arguments?? */ /* XXX Need way to compute arguments?? */
/* Profile function raised an error */ /* Profile function raised an error */
goto fail; goto fail;
} }
} }
}
if (co->co_flags & CO_GENERATOR) { if (co->co_flags & CO_GENERATOR) {
/* Don't need to keep the reference to f_back, it will be set /* Don't need to keep the reference to f_back, it will be set
...@@ -2803,7 +2813,10 @@ call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, ...@@ -2803,7 +2813,10 @@ call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
if (tstate->tracing) if (tstate->tracing)
return 0; return 0;
tstate->tracing++; tstate->tracing++;
tstate->use_tracing = 0;
result = func(obj, frame, what, arg); result = func(obj, frame, what, arg);
tstate->use_tracing = ((tstate->c_tracefunc != NULL)
|| (tstate->c_profilefunc != NULL));
tstate->tracing--; tstate->tracing--;
return result; return result;
} }
...@@ -2816,9 +2829,11 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg) ...@@ -2816,9 +2829,11 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
Py_XINCREF(arg); Py_XINCREF(arg);
tstate->c_profilefunc = NULL; tstate->c_profilefunc = NULL;
tstate->c_profileobj = NULL; tstate->c_profileobj = NULL;
tstate->use_tracing = tstate->c_tracefunc != NULL;
Py_XDECREF(temp); Py_XDECREF(temp);
tstate->c_profilefunc = func; tstate->c_profilefunc = func;
tstate->c_profileobj = arg; tstate->c_profileobj = arg;
tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL);
} }
void void
...@@ -2829,9 +2844,12 @@ PyEval_SetTrace(Py_tracefunc func, PyObject *arg) ...@@ -2829,9 +2844,12 @@ PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
Py_XINCREF(arg); Py_XINCREF(arg);
tstate->c_tracefunc = NULL; tstate->c_tracefunc = NULL;
tstate->c_traceobj = NULL; tstate->c_traceobj = NULL;
tstate->use_tracing = tstate->c_profilefunc != NULL;
Py_XDECREF(temp); Py_XDECREF(temp);
tstate->c_tracefunc = func; tstate->c_tracefunc = func;
tstate->c_traceobj = arg; tstate->c_traceobj = arg;
tstate->use_tracing = ((func != NULL)
|| (tstate->c_profilefunc != NULL));
} }
PyObject * PyObject *
......
...@@ -109,6 +109,7 @@ PyThreadState_New(PyInterpreterState *interp) ...@@ -109,6 +109,7 @@ PyThreadState_New(PyInterpreterState *interp)
tstate->recursion_depth = 0; tstate->recursion_depth = 0;
tstate->ticker = 0; tstate->ticker = 0;
tstate->tracing = 0; tstate->tracing = 0;
tstate->use_tracing = 0;
tstate->dict = NULL; tstate->dict = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment