call_trace(): Add an additional parameter -- pointer to a PyObject*
that should be used to cache an interned version of the event string passed to the profile/trace function. call_trace() will create interned strings and cache them in using the storage specified by this additional parameter, avoiding a lot of string object creation at runtime when using the profiling or tracing functions. All call sites are modified to pass the additional parameter, and four static PyObject* variables are allocated to cache the interned string objects. This closes SF patch #431257.
This commit is contained in:
parent
edb5ffb2c1
commit
904aa7bb00
|
@ -62,7 +62,7 @@ static int prtrace(PyObject *, char *);
|
|||
#endif
|
||||
static void call_exc_trace(PyObject **, PyObject**, PyFrameObject *);
|
||||
static int call_trace(PyObject **, PyObject **,
|
||||
PyFrameObject *, char *, PyObject *);
|
||||
PyFrameObject *, char *, PyObject **, PyObject *);
|
||||
static PyObject *loop_subscript(PyObject *, PyObject *);
|
||||
static PyObject *apply_slice(PyObject *, PyObject *, PyObject *);
|
||||
static int assign_slice(PyObject *, PyObject *,
|
||||
|
@ -97,6 +97,15 @@ static long dxp[256];
|
|||
#endif
|
||||
#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;
|
||||
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
|
||||
#ifndef DONT_HAVE_ERRNO_H
|
||||
|
@ -645,7 +654,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
(sys.trace) is also called whenever an exception
|
||||
is detected. */
|
||||
if (call_trace(&tstate->sys_tracefunc,
|
||||
&f->f_trace, f, "call",
|
||||
&f->f_trace, f, "call", &str_call,
|
||||
Py_None/*XXX how to compute arguments now?*/)) {
|
||||
/* Trace function raised an error */
|
||||
goto fail;
|
||||
|
@ -656,7 +665,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
/* 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, "call",
|
||||
(PyObject**)0, f, "call", &str_call,
|
||||
Py_None/*XXX*/)) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1952,7 +1961,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
/* Trace each line of code reached */
|
||||
f->f_lasti = INSTR_OFFSET();
|
||||
err = call_trace(&f->f_trace, &f->f_trace,
|
||||
f, "line", Py_None);
|
||||
f, "line", &str_line, Py_None);
|
||||
break;
|
||||
|
||||
case CALL_FUNCTION:
|
||||
|
@ -2297,7 +2306,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
if (f->f_trace) {
|
||||
if (why == WHY_RETURN) {
|
||||
if (call_trace(&f->f_trace, &f->f_trace, f,
|
||||
"return", retval)) {
|
||||
"return", &str_return, retval)) {
|
||||
Py_XDECREF(retval);
|
||||
retval = NULL;
|
||||
why = WHY_EXCEPTION;
|
||||
|
@ -2307,7 +2316,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
|
||||
if (tstate->sys_profilefunc && why == WHY_RETURN) {
|
||||
if (call_trace(&tstate->sys_profilefunc, (PyObject**)0,
|
||||
f, "return", retval)) {
|
||||
f, "return", &str_return, retval)) {
|
||||
Py_XDECREF(retval);
|
||||
retval = NULL;
|
||||
why = WHY_EXCEPTION;
|
||||
|
@ -2575,7 +2584,8 @@ call_exc_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f)
|
|||
PyErr_Restore(type, value, traceback);
|
||||
return;
|
||||
}
|
||||
err = call_trace(p_trace, p_newtrace, f, "exception", arg);
|
||||
err = call_trace(p_trace, p_newtrace, f,
|
||||
"exception", &str_exception, arg);
|
||||
Py_DECREF(arg);
|
||||
if (err == 0)
|
||||
PyErr_Restore(type, value, traceback);
|
||||
|
@ -2588,13 +2598,18 @@ call_exc_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f)
|
|||
|
||||
/* PyObject **p_trace: in/out; may not be NULL;
|
||||
may not point to NULL variable initially
|
||||
PyObject **p_newtrace: in/out; may be NULL;
|
||||
PyObject **p_newtrace: in/out; may be NULL;
|
||||
may point to NULL variable;
|
||||
may be same variable as p_newtrace */
|
||||
may be same variable as p_newtrace
|
||||
PyObject **p_omsg: in/out; may not be NULL;
|
||||
if non-null & *p_omsg == NULL, will be
|
||||
initialized with an interned string
|
||||
corresponding to msg.
|
||||
*/
|
||||
|
||||
static int
|
||||
call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
|
||||
char *msg, PyObject *arg)
|
||||
char *msg, PyObject **p_omsg, PyObject *arg)
|
||||
{
|
||||
PyThreadState *tstate = f->f_tstate;
|
||||
PyObject *args, *what;
|
||||
|
@ -2612,9 +2627,17 @@ call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
|
|||
args = PyTuple_New(3);
|
||||
if (args == NULL)
|
||||
goto cleanup;
|
||||
what = PyString_FromString(msg);
|
||||
if (what == NULL)
|
||||
goto cleanup;
|
||||
if (*p_omsg != NULL) {
|
||||
what = *p_omsg;
|
||||
Py_INCREF(what);
|
||||
}
|
||||
else {
|
||||
what = PyString_InternFromString(msg);
|
||||
if (what == NULL)
|
||||
goto cleanup;
|
||||
*p_omsg = what;
|
||||
Py_INCREF(what);
|
||||
}
|
||||
Py_INCREF(f);
|
||||
PyTuple_SET_ITEM(args, 0, (PyObject *)f);
|
||||
PyTuple_SET_ITEM(args, 1, what);
|
||||
|
|
Loading…
Reference in New Issue