]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
This change adjusts the profiling/tracing support so that the common
authorFred Drake <fdrake@acm.org>
Tue, 3 Jul 2001 23:39:52 +0000 (23:39 +0000)
committerFred Drake <fdrake@acm.org>
Tue, 3 Jul 2001 23:39:52 +0000 (23:39 +0000)
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.

Include/pystate.h
Python/ceval.c
Python/pystate.c

index d5e2e1f119336f44dea4e1b41bd9c108c5a84c84..15a264c6789886e876c4be965ac655a16a85183e 100644 (file)
@@ -49,6 +49,7 @@ typedef struct _ts {
     int recursion_depth;
     int ticker;
     int tracing;
+    int use_tracing;
 
     Py_tracefunc c_profilefunc;
     Py_tracefunc c_tracefunc;
index 702380d75338f6a5e87ea2501ff7ddd568211045..79eb0add7f76ff1d918c5e76fc5eaed35a52209e 100644 (file)
@@ -1890,8 +1890,11 @@ eval_frame(PyFrameObject *f)
                        f->f_lasti = INSTR_OFFSET();
                        /* Inline call_trace() for performance: */
                        tstate->tracing++;
+                       tstate->use_tracing = 0;
                        err = (tstate->c_tracefunc)(tstate->c_traceobj, f,
                                                    PyTrace_LINE, Py_None);
+                       tstate->use_tracing = (tstate->c_tracefunc
+                                              || tstate->c_profilefunc);
                        tstate->tracing--;
                        break;
 
@@ -2142,12 +2145,14 @@ eval_frame(PyFrameObject *f)
                                f->f_lasti -= 2;
                        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);
+                       if (tstate->use_tracing) {
+                               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);
+                       }
                }
 
                /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
@@ -2228,24 +2233,26 @@ eval_frame(PyFrameObject *f)
        if (why != WHY_RETURN && why != WHY_YIELD)
                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)) {
+       if (tstate->use_tracing) {
+               if (tstate->c_tracefunc
+                   && (why == WHY_RETURN || why == WHY_YIELD)) {
+                       if (call_trace(tstate->c_tracefunc,
+                                      tstate->c_traceobj, f,
+                                      PyTrace_RETURN, retval)) {
                                Py_XDECREF(retval);
                                retval = NULL;
                                why = WHY_EXCEPTION;
                        }
                }
-       }
-
-       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;
-                       why = WHY_EXCEPTION;
+               if (tstate->c_profilefunc
+                   && (why == WHY_RETURN || why == WHY_YIELD)) {
+                       if (call_trace(tstate->c_profilefunc,
+                                      tstate->c_profileobj, f,
+                                      PyTrace_RETURN, retval)) {
+                               Py_XDECREF(retval);
+                               retval = NULL;
+                               why = WHY_EXCEPTION;
+                       }
                }
        }
 
@@ -2471,35 +2478,38 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
                }
        }
 
-       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.
-                  Its return value, if not None, is a function that
-                  will be called at the start of each executed line
-                  of code.  (Actually, the function must return
-                  itself in order to continue tracing.)
-                  The trace functions are called with three arguments:
-                  a pointer to the current frame, a string indicating
-                  why the function is called, and an argument which
-                  depends on the situation.  The global trace function
-                  (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;
+       if (tstate->use_tracing) {
+               if (tstate->c_tracefunc != NULL) {
+                       /* tstate->c_tracefunc, if defined, is a
+                          function that will be called on *every* entry
+                          to a code block.  Its return value, if not
+                          None, is a function that will be called at
+                          the start of each executed line of code.
+                          (Actually, the function must return itself
+                          in order to continue tracing.)  The trace
+                          functions are called with three arguments:
+                          a pointer to the current frame, a string
+                          indicating why the function is called, and
+                          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,
+                                      f, PyTrace_CALL, Py_None)) {
+                               /* XXX Need way to compute arguments?? */
+                               /* Trace function raised an error */
+                               goto fail;
+                       }
                }
-       }
-
-       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;
+               if (tstate->c_profilefunc != NULL) {
+                       /* Similar for c_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;
+                       }
                }
        }
 
@@ -2803,7 +2813,10 @@ call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
        if (tstate->tracing)
                return 0;
        tstate->tracing++;
+       tstate->use_tracing = 0;
        result = func(obj, frame, what, arg);
+       tstate->use_tracing = ((tstate->c_tracefunc != NULL)
+                              || (tstate->c_profilefunc != NULL));
        tstate->tracing--;
        return result;
 }
@@ -2816,9 +2829,11 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
        Py_XINCREF(arg);
        tstate->c_profilefunc = NULL;
        tstate->c_profileobj = NULL;
+       tstate->use_tracing = tstate->c_tracefunc != NULL;
        Py_XDECREF(temp);
        tstate->c_profilefunc = func;
        tstate->c_profileobj = arg;
+       tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL);
 }
 
 void
@@ -2829,9 +2844,12 @@ PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
        Py_XINCREF(arg);
        tstate->c_tracefunc = NULL;
        tstate->c_traceobj = NULL;
+       tstate->use_tracing = tstate->c_profilefunc != NULL;
        Py_XDECREF(temp);
        tstate->c_tracefunc = func;
        tstate->c_traceobj = arg;
+       tstate->use_tracing = ((func != NULL)
+                              || (tstate->c_profilefunc != NULL));
 }
 
 PyObject *
index 192c4c14f6263698f09cc255758e7830bd52dda2..cca1e7cdbea820ca1c15270971f2a5beea31288c 100644 (file)
@@ -109,6 +109,7 @@ PyThreadState_New(PyInterpreterState *interp)
                tstate->recursion_depth = 0;
                tstate->ticker = 0;
                tstate->tracing = 0;
+               tstate->use_tracing = 0;
 
                tstate->dict = NULL;