summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorŁukasz Langa <lukasz@langa.pl>2016-09-10 00:37:37 (GMT)
committerŁukasz Langa <lukasz@langa.pl>2016-09-10 00:37:37 (GMT)
commita785c87d6eacbed81543a8afe3cb098fabb9610a (patch)
treeee127bbbef66a386f4c7f7a21d1e69a54eed5a52 /Python
parent39b42ae8dbf81ee89dabf1c418c9081243b4ab97 (diff)
downloadcpython-a785c87d6eacbed81543a8afe3cb098fabb9610a.zip
cpython-a785c87d6eacbed81543a8afe3cb098fabb9610a.tar.gz
cpython-a785c87d6eacbed81543a8afe3cb098fabb9610a.tar.bz2
DTrace support: function calls, GC activity, line execution
Tested on macOS 10.11 dtrace, Ubuntu 16.04 SystemTap, and libbcc. Largely based by an initial patch by Jesús Cea Avión, with some influence from Dave Malcolm's SystemTap patch and Nikhil Benesch's unification patch. Things deliberately left out for simplicity: - ustack helpers, I have no way of testing them at this point since they are Solaris-specific - PyFrameObject * in function__entry/function__return, this is SystemTap-specific - SPARC support - dynamic tracing - sys module dtrace facility introspection All of those might be added later.
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c78
1 files changed, 76 insertions, 2 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index d3bd8b5..a396e81 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -15,6 +15,7 @@
#include "dictobject.h"
#include "frameobject.h"
#include "opcode.h"
+#include "pydtrace.h"
#include "setobject.h"
#include "structmember.h"
@@ -50,6 +51,9 @@ static void call_exc_trace(Py_tracefunc, PyObject *,
PyThreadState *, PyFrameObject *);
static int maybe_call_line_trace(Py_tracefunc, PyObject *,
PyThreadState *, PyFrameObject *, int *, int *, int *);
+static void maybe_dtrace_line(PyFrameObject *, int *, int *, int *);
+static void dtrace_function_entry(PyFrameObject *);
+static void dtrace_function_return(PyFrameObject *);
static PyObject * cmp_outcome(int, PyObject *, PyObject *);
static PyObject * import_name(PyFrameObject *, PyObject *, PyObject *, PyObject *);
@@ -822,7 +826,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
#ifdef LLTRACE
#define FAST_DISPATCH() \
{ \
- if (!lltrace && !_Py_TracingPossible) { \
+ if (!lltrace && !_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
@@ -832,7 +836,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
#else
#define FAST_DISPATCH() \
{ \
- if (!_Py_TracingPossible) { \
+ if (!_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
@@ -1042,6 +1046,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
}
}
+ if (PyDTrace_FUNCTION_ENTRY_ENABLED())
+ dtrace_function_entry(f);
+
co = f->f_code;
names = co->co_names;
consts = co->co_consts;
@@ -1162,6 +1169,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
fast_next_opcode:
f->f_lasti = INSTR_OFFSET();
+ if (PyDTrace_LINE_ENABLED())
+ maybe_dtrace_line(f, &instr_lb, &instr_ub, &instr_prev);
+
/* line-by-line tracing support */
if (_Py_TracingPossible &&
@@ -3620,6 +3630,8 @@ fast_yield:
/* pop frame */
exit_eval_frame:
+ if (PyDTrace_FUNCTION_RETURN_ENABLED())
+ dtrace_function_return(f);
Py_LeaveRecursiveCall();
f->f_executing = 0;
tstate->frame = f->f_back;
@@ -5415,3 +5427,65 @@ _PyEval_RequestCodeExtraIndex(freefunc free)
tstate->co_extra_freefuncs[new_index] = free;
return new_index;
}
+
+static void
+dtrace_function_entry(PyFrameObject *f)
+{
+ char* filename;
+ char* funcname;
+ int lineno;
+
+ filename = PyUnicode_AsUTF8(f->f_code->co_filename);
+ funcname = PyUnicode_AsUTF8(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+
+ PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
+}
+
+static void
+dtrace_function_return(PyFrameObject *f)
+{
+ char* filename;
+ char* funcname;
+ int lineno;
+
+ filename = PyUnicode_AsUTF8(f->f_code->co_filename);
+ funcname = PyUnicode_AsUTF8(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+
+ PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
+}
+
+/* DTrace equivalent of maybe_call_line_trace. */
+static void
+maybe_dtrace_line(PyFrameObject *frame,
+ int *instr_lb, int *instr_ub, int *instr_prev)
+{
+ int line = frame->f_lineno;
+ char *co_filename, *co_name;
+
+ /* If the last instruction executed isn't in the current
+ instruction window, reset the window.
+ */
+ if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) {
+ PyAddrPair bounds;
+ line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti,
+ &bounds);
+ *instr_lb = bounds.ap_lower;
+ *instr_ub = bounds.ap_upper;
+ }
+ /* If the last instruction falls at the start of a line or if
+ it represents a jump backwards, update the frame's line
+ number and call the trace function. */
+ if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) {
+ frame->f_lineno = line;
+ co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
+ if (!co_filename)
+ co_filename = "?";
+ co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
+ if (!co_name)
+ co_name = "?";
+ PyDTrace_LINE(co_filename, co_name, line);
+ }
+ *instr_prev = frame->f_lasti;
+}