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:
Fred Drake 2001-06-16 21:02:31 +00:00
parent 70128a1ba6
commit d083839fb4
2 changed files with 48 additions and 26 deletions

View file

@ -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 **, PyObject *);
PyFrameObject *, PyObject *, PyObject *);
static PyObject *loop_subscript(PyObject *, PyObject *);
static PyObject *apply_slice(PyObject *, 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
is detected. */
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?*/)) {
/* Trace function raised an error */
goto fail;
@ -665,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", &str_call,
(PyObject**)0, f, str_call,
Py_None/*XXX*/)) {
goto fail;
}
@ -1961,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", &str_line, Py_None);
f, str_line, Py_None);
break;
case CALL_FUNCTION:
@ -2306,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", &str_return, retval)) {
str_return, retval)) {
Py_XDECREF(retval);
retval = NULL;
why = WHY_EXCEPTION;
@ -2316,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", &str_return, retval)) {
f, str_return, retval)) {
Py_XDECREF(retval);
retval = NULL;
why = WHY_EXCEPTION;
@ -2584,8 +2584,7 @@ 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", &str_exception, arg);
err = call_trace(p_trace, p_newtrace, f, str_exception, arg);
Py_DECREF(arg);
if (err == 0)
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;
may point to NULL variable;
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.
PyObject *msg: in; must not be NULL
*/
static int
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;
PyObject *args, *what;
PyObject *args;
PyObject *res = NULL;
if (tstate->tracing) {
@ -2627,20 +2623,10 @@ call_trace(PyObject **p_trace, PyObject **p_newtrace, PyFrameObject *f,
args = PyTuple_New(3);
if (args == 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(msg);
Py_INCREF(f);
PyTuple_SET_ITEM(args, 0, (PyObject *)f);
PyTuple_SET_ITEM(args, 1, what);
PyTuple_SET_ITEM(args, 1, msg);
if (arg == NULL)
arg = Py_None;
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 *
PyEval_GetBuiltins(void)
{

View file

@ -196,10 +196,14 @@ static char setdefaultencoding_doc[] =
\n\
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
@ -220,6 +224,8 @@ static PyObject *
sys_setprofile(PyObject *self, PyObject *args)
{
PyThreadState *tstate = PyThreadState_Get();
if (_PyTrace_Init() == -1)
return NULL;
if (args == Py_None)
args = NULL;
else