Instead of initializing & interning the strings passed to the profile
and trace functions lazily, which incurs extra argument pushing and checks in the C overhead for profiling/tracing, create the strings semi-lazily when the Python code first registers a profile or trace function. This simplifies the trampoline into the profile/trace functions.
This commit is contained in:
parent
70128a1ba6
commit
d083839fb4
|
@ -62,7 +62,7 @@ static int prtrace(PyObject *, char *);
|
||||||
#endif
|
#endif
|
||||||
static void call_exc_trace(PyObject **, PyObject**, PyFrameObject *);
|
static void call_exc_trace(PyObject **, PyObject**, PyFrameObject *);
|
||||||
static int call_trace(PyObject **, PyObject **,
|
static int call_trace(PyObject **, PyObject **,
|
||||||
PyFrameObject *, char *, PyObject **, PyObject *);
|
PyFrameObject *, PyObject *, PyObject *);
|
||||||
static PyObject *loop_subscript(PyObject *, PyObject *);
|
static PyObject *loop_subscript(PyObject *, PyObject *);
|
||||||
static PyObject *apply_slice(PyObject *, PyObject *, PyObject *);
|
static PyObject *apply_slice(PyObject *, PyObject *, PyObject *);
|
||||||
static int assign_slice(PyObject *, PyObject *,
|
static int assign_slice(PyObject *, PyObject *,
|
||||||
|
@ -654,7 +654,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
(sys.trace) is also called whenever an exception
|
(sys.trace) is also called whenever an exception
|
||||||
is detected. */
|
is detected. */
|
||||||
if (call_trace(&tstate->sys_tracefunc,
|
if (call_trace(&tstate->sys_tracefunc,
|
||||||
&f->f_trace, f, "call", &str_call,
|
&f->f_trace, f, str_call,
|
||||||
Py_None/*XXX how to compute arguments now?*/)) {
|
Py_None/*XXX how to compute arguments now?*/)) {
|
||||||
/* Trace function raised an error */
|
/* Trace function raised an error */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -665,7 +665,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
/* Similar for sys_profilefunc, except it needn't return
|
/* Similar for sys_profilefunc, except it needn't return
|
||||||
itself and isn't called for "line" events */
|
itself and isn't called for "line" events */
|
||||||
if (call_trace(&tstate->sys_profilefunc,
|
if (call_trace(&tstate->sys_profilefunc,
|
||||||
(PyObject**)0, f, "call", &str_call,
|
(PyObject**)0, f, str_call,
|
||||||
Py_None/*XXX*/)) {
|
Py_None/*XXX*/)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1961,7 +1961,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
/* Trace each line of code reached */
|
/* Trace each line of code reached */
|
||||||
f->f_lasti = INSTR_OFFSET();
|
f->f_lasti = INSTR_OFFSET();
|
||||||
err = call_trace(&f->f_trace, &f->f_trace,
|
err = call_trace(&f->f_trace, &f->f_trace,
|
||||||
f, "line", &str_line, Py_None);
|
f, str_line, Py_None);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CALL_FUNCTION:
|
case CALL_FUNCTION:
|
||||||
|
@ -2306,7 +2306,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
if (f->f_trace) {
|
if (f->f_trace) {
|
||||||
if (why == WHY_RETURN) {
|
if (why == WHY_RETURN) {
|
||||||
if (call_trace(&f->f_trace, &f->f_trace, f,
|
if (call_trace(&f->f_trace, &f->f_trace, f,
|
||||||
"return", &str_return, retval)) {
|
str_return, retval)) {
|
||||||
Py_XDECREF(retval);
|
Py_XDECREF(retval);
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
why = WHY_EXCEPTION;
|
why = WHY_EXCEPTION;
|
||||||
|
@ -2316,7 +2316,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
|
|
||||||
if (tstate->sys_profilefunc && why == WHY_RETURN) {
|
if (tstate->sys_profilefunc && why == WHY_RETURN) {
|
||||||
if (call_trace(&tstate->sys_profilefunc, (PyObject**)0,
|
if (call_trace(&tstate->sys_profilefunc, (PyObject**)0,
|
||||||
f, "return", &str_return, retval)) {
|
f, str_return, retval)) {
|
||||||
Py_XDECREF(retval);
|
Py_XDECREF(retval);
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
why = WHY_EXCEPTION;
|
why = WHY_EXCEPTION;
|
||||||
|
@ -2584,8 +2584,7 @@ call_exc_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f)
|
||||||
PyErr_Restore(type, value, traceback);
|
PyErr_Restore(type, value, traceback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
err = call_trace(p_trace, p_newtrace, f,
|
err = call_trace(p_trace, p_newtrace, f, str_exception, arg);
|
||||||
"exception", &str_exception, arg);
|
|
||||||
Py_DECREF(arg);
|
Py_DECREF(arg);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
PyErr_Restore(type, value, traceback);
|
PyErr_Restore(type, value, traceback);
|
||||||
|
@ -2601,18 +2600,15 @@ call_exc_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f)
|
||||||
PyObject **p_newtrace: in/out; may be NULL;
|
PyObject **p_newtrace: in/out; may be NULL;
|
||||||
may point to NULL variable;
|
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;
|
PyObject *msg: in; must not be NULL
|
||||||
if non-null & *p_omsg == NULL, will be
|
|
||||||
initialized with an interned string
|
|
||||||
corresponding to msg.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
|
call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
|
||||||
char *msg, PyObject **p_omsg, PyObject *arg)
|
PyObject *msg, PyObject *arg)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = f->f_tstate;
|
PyThreadState *tstate = f->f_tstate;
|
||||||
PyObject *args, *what;
|
PyObject *args;
|
||||||
PyObject *res = NULL;
|
PyObject *res = NULL;
|
||||||
|
|
||||||
if (tstate->tracing) {
|
if (tstate->tracing) {
|
||||||
|
@ -2627,20 +2623,10 @@ call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
|
||||||
args = PyTuple_New(3);
|
args = PyTuple_New(3);
|
||||||
if (args == NULL)
|
if (args == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
if (*p_omsg != NULL) {
|
Py_INCREF(msg);
|
||||||
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);
|
Py_INCREF(f);
|
||||||
PyTuple_SET_ITEM(args, 0, (PyObject *)f);
|
PyTuple_SET_ITEM(args, 0, (PyObject *)f);
|
||||||
PyTuple_SET_ITEM(args, 1, what);
|
PyTuple_SET_ITEM(args, 1, msg);
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
arg = Py_None;
|
arg = Py_None;
|
||||||
Py_INCREF(arg);
|
Py_INCREF(arg);
|
||||||
|
@ -2686,6 +2672,36 @@ call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyEval_GetBuiltins(void)
|
PyEval_GetBuiltins(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -196,10 +196,14 @@ static char setdefaultencoding_doc[] =
|
||||||
\n\
|
\n\
|
||||||
Set the current default string encoding used by the Unicode implementation.";
|
Set the current default string encoding used by the Unicode implementation.";
|
||||||
|
|
||||||
|
extern int _PyTrace_Init(void);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
sys_settrace(PyObject *self, PyObject *args)
|
sys_settrace(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = PyThreadState_Get();
|
PyThreadState *tstate = PyThreadState_Get();
|
||||||
|
if (_PyTrace_Init() == -1)
|
||||||
|
return NULL;
|
||||||
if (args == Py_None)
|
if (args == Py_None)
|
||||||
args = NULL;
|
args = NULL;
|
||||||
else
|
else
|
||||||
|
@ -220,6 +224,8 @@ static PyObject *
|
||||||
sys_setprofile(PyObject *self, PyObject *args)
|
sys_setprofile(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = PyThreadState_Get();
|
PyThreadState *tstate = PyThreadState_Get();
|
||||||
|
if (_PyTrace_Init() == -1)
|
||||||
|
return NULL;
|
||||||
if (args == Py_None)
|
if (args == Py_None)
|
||||||
args = NULL;
|
args = NULL;
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue