summaryrefslogtreecommitdiffstats
path: root/Python/sysmodule.c
diff options
context:
space:
mode:
authorFred Drake <fdrake@acm.org>2001-06-27 19:19:46 (GMT)
committerFred Drake <fdrake@acm.org>2001-06-27 19:19:46 (GMT)
commit5755ce693dfc497389ab89e8ae0e62c3cc89d4ff (patch)
tree1a6eac014a12e3c1094ac93cc976c621d3de9870 /Python/sysmodule.c
parent55fb6e037170ddb645c552079ec8fe6c042de542 (diff)
downloadcpython-5755ce693dfc497389ab89e8ae0e62c3cc89d4ff.zip
cpython-5755ce693dfc497389ab89e8ae0e62c3cc89d4ff.tar.gz
cpython-5755ce693dfc497389ab89e8ae0e62c3cc89d4ff.tar.bz2
Revise the interface to the profiling and tracing support for the
Python interpreter. This change adds two new C-level APIs: PyEval_SetProfile() and PyEval_SetTrace(). These can be used to install profile and trace functions implemented in C, which can operate at much higher speeds than Python-based functions. The overhead for calling a C-based profile function is a very small fraction of a percent of the overhead involved in calling a Python-based function. The machinery required to call a Python-based profile or trace function been moved to sysmodule.c, where sys.setprofile() and sys.setprofile() simply become users of the new interface. As a side effect, SF bug #436058 is fixed; there is no longer a _PyTrace_Init() function to declare.
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r--Python/sysmodule.c123
1 files changed, 110 insertions, 13 deletions
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index fe880d5..76d40bf 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -196,20 +196,120 @@ static char setdefaultencoding_doc[] =
\n\
Set the current default string encoding used by the Unicode implementation.";
-extern int _PyTrace_Init(void);
+/*
+ * Cached interned string objects used for calling the profile and
+ * trace functions. Initialized by trace_init().
+ */
+static PyObject *whatstrings[4] = {NULL, NULL, NULL, NULL};
+
+static int
+trace_init(void)
+{
+ static char *whatnames[4] = {"call", "exception", "line", "return"};
+ PyObject *name;
+ int i;
+ for (i = 0; i < 4; ++i) {
+ if (whatstrings[i] == NULL) {
+ name = PyString_InternFromString(whatnames[i]);
+ if (name == NULL)
+ return -1;
+ whatstrings[i] = name;
+ }
+ }
+ return 0;
+}
+
+
+static PyObject *
+call_trampoline(PyThreadState *tstate, PyObject* callback,
+ PyFrameObject *frame, int what, PyObject *arg)
+{
+ PyObject *args = PyTuple_New(3);
+ PyObject *whatstr;
+ PyObject *result;
+
+ if (args == NULL)
+ return NULL;
+ Py_INCREF(frame);
+ whatstr = whatstrings[what];
+ Py_INCREF(whatstr);
+ if (arg == NULL)
+ arg = Py_None;
+ Py_INCREF(arg);
+ PyTuple_SET_ITEM(args, 0, (PyObject *)frame);
+ PyTuple_SET_ITEM(args, 1, whatstr);
+ PyTuple_SET_ITEM(args, 2, arg);
+
+ /* call the Python-level function */
+ PyFrame_FastToLocals(frame);
+ result = PyEval_CallObject(callback, args);
+ PyFrame_LocalsToFast(frame, 1);
+ if (result == NULL)
+ PyTraceBack_Here(frame);
+
+ /* cleanup */
+ Py_DECREF(args);
+ return result;
+}
+
+static int
+profile_trampoline(PyObject *self, PyFrameObject *frame,
+ int what, PyObject *arg)
+{
+ PyThreadState *tstate = frame->f_tstate;
+ PyObject *result;
+
+ result = call_trampoline(tstate, self, frame, what, arg);
+ if (result == NULL) {
+ PyEval_SetProfile(NULL, NULL);
+ return -1;
+ }
+ Py_DECREF(result);
+ return 0;
+}
+
+static int
+trace_trampoline(PyObject *self, PyFrameObject *frame,
+ int what, PyObject *arg)
+{
+ PyThreadState *tstate = frame->f_tstate;
+ PyObject *callback;
+ PyObject *result;
+
+ if (what == PyTrace_CALL)
+ callback = self;
+ else
+ callback = frame->f_trace;
+ if (callback == NULL)
+ return 0;
+ result = call_trampoline(tstate, callback, frame, what, arg);
+ if (result == NULL) {
+ PyEval_SetTrace(NULL, NULL);
+ Py_XDECREF(frame->f_trace);
+ frame->f_trace = NULL;
+ return -1;
+ }
+ if (result != Py_None) {
+ PyObject *temp = frame->f_trace;
+ frame->f_trace = NULL;
+ Py_XDECREF(temp);
+ frame->f_trace = result;
+ }
+ else {
+ Py_DECREF(result);
+ }
+ return 0;
+}
static PyObject *
sys_settrace(PyObject *self, PyObject *args)
{
- PyThreadState *tstate = PyThreadState_Get();
- if (_PyTrace_Init() == -1)
+ if (trace_init() == -1)
return NULL;
if (args == Py_None)
- args = NULL;
+ PyEval_SetTrace(NULL, NULL);
else
- Py_XINCREF(args);
- Py_XDECREF(tstate->sys_tracefunc);
- tstate->sys_tracefunc = args;
+ PyEval_SetTrace(trace_trampoline, args);
Py_INCREF(Py_None);
return Py_None;
}
@@ -223,15 +323,12 @@ function call. See the debugger chapter in the library manual.";
static PyObject *
sys_setprofile(PyObject *self, PyObject *args)
{
- PyThreadState *tstate = PyThreadState_Get();
- if (_PyTrace_Init() == -1)
+ if (trace_init() == -1)
return NULL;
if (args == Py_None)
- args = NULL;
+ PyEval_SetProfile(NULL, NULL);
else
- Py_XINCREF(args);
- Py_XDECREF(tstate->sys_profilefunc);
- tstate->sys_profilefunc = args;
+ PyEval_SetProfile(profile_trampoline, args);
Py_INCREF(Py_None);
return Py_None;
}