[pypy-commit] pypy vmprof-native: copy over the changes from vmprof-python/f7df918fbdd
plan_rich
pypy.commits at gmail.com
Wed Mar 15 08:08:47 EDT 2017
Author: Richard Plangger <planrichi at gmail.com>
Branch: vmprof-native
Changeset: r90699:aa5c858b1622
Date: 2017-03-15 12:56 +0100
http://bitbucket.org/pypy/pypy/changeset/aa5c858b1622/
Log: copy over the changes from vmprof-python/f7df918fbdd
diff --git a/rpython/rlib/rvmprof/src/shared/_vmprof.c b/rpython/rlib/rvmprof/src/shared/_vmprof.c
--- a/rpython/rlib/rvmprof/src/shared/_vmprof.c
+++ b/rpython/rlib/rvmprof/src/shared/_vmprof.c
@@ -248,14 +248,15 @@
static PyObject *
-sample_stack_now(PyObject *module, PyObject *args)
+sample_stack_now(PyObject *module, PyObject * args)
{
PyThreadState * tstate = NULL;
- PyObject * list;
+ PyObject * list = NULL;
int i;
int entry_count;
void ** m;
void * routine_ip;
+ long skip = 0;
// stop any signal to occur
vmprof_ignore_signals(1);
@@ -265,6 +266,10 @@
goto error;
}
+ if (!PyArg_ParseTuple(args, "l", &skip)) {
+ goto error;
+ }
+
tstate = PyGILState_GetThisThreadState();
m = (void**)malloc(SINGLE_BUF_SIZE);
if (m == NULL) {
@@ -272,7 +277,7 @@
vmprof_ignore_signals(0);
return NULL;
}
- entry_count = vmp_walk_and_record_stack(tstate->frame, m, MAX_STACK_DEPTH-1, 0, 0);
+ entry_count = vmp_walk_and_record_stack(tstate->frame, m, MAX_STACK_DEPTH-1, skip, 0);
for (i = 0; i < entry_count; i++) {
routine_ip = m[i];
@@ -337,7 +342,7 @@
{"disable", disable_vmprof, METH_NOARGS, "Disable profiling."},
{"write_all_code_objects", write_all_code_objects, METH_NOARGS,
"Write eagerly all the IDs of code objects"},
- {"sample_stack_now", sample_stack_now, METH_NOARGS, "Sample the stack now"},
+ {"sample_stack_now", sample_stack_now, METH_VARARGS, "Sample the stack now"},
#ifdef VMP_SUPPORTS_NATIVE_PROFILING
{"resolve_addr", resolve_addr, METH_VARARGS, "Return the name of the addr"},
#endif
diff --git a/rpython/rlib/rvmprof/src/shared/compat.h b/rpython/rlib/rvmprof/src/shared/compat.h
--- a/rpython/rlib/rvmprof/src/shared/compat.h
+++ b/rpython/rlib/rvmprof/src/shared/compat.h
@@ -13,6 +13,7 @@
#define PyStr_GET_SIZE PyString_GET_SIZE
#define PyStr_NEW PyString_FromString
#define PyLong_NEW PyInt_FromSsize_t
+ #define PyLong_AsLong PyInt_AsLong
# endif
#endif
diff --git a/rpython/rlib/rvmprof/src/shared/machine.c b/rpython/rlib/rvmprof/src/shared/machine.c
--- a/rpython/rlib/rvmprof/src/shared/machine.c
+++ b/rpython/rlib/rvmprof/src/shared/machine.c
@@ -27,14 +27,3 @@
#endif
}
-#ifdef VMP_SUPPORTS_NATIVE_PROFILING
-#include "libudis86/udis86.h"
-unsigned int vmp_machine_code_instr_length(char* pc)
-{
- struct ud u;
- ud_init(&u);
- ud_set_input_buffer(&u, (uint8_t*)pc, 12);
- ud_set_mode(&u, vmp_machine_bits());
- return ud_decode(&u);
-}
-#endif
diff --git a/rpython/rlib/rvmprof/src/shared/machine.h b/rpython/rlib/rvmprof/src/shared/machine.h
--- a/rpython/rlib/rvmprof/src/shared/machine.h
+++ b/rpython/rlib/rvmprof/src/shared/machine.h
@@ -10,11 +10,3 @@
*/
const char * vmp_machine_os_name(void);
-/**
- * How many bytes does the x86 instruction take at pc[0..].
- *
- * Returns 0 on failure.
- */
-#ifdef VMP_SUPPORTS_NATIVE_PROFILING
-unsigned int vmp_machine_code_instr_length(char* pc);
-#endif
diff --git a/rpython/rlib/rvmprof/src/shared/trampoline.c b/rpython/rlib/rvmprof/src/shared/trampoline.c
--- a/rpython/rlib/rvmprof/src/shared/trampoline.c
+++ b/rpython/rlib/rvmprof/src/shared/trampoline.c
@@ -121,6 +121,16 @@
}
#endif
+#include "libudis86/udis86.h"
+unsigned int vmp_machine_code_instr_length(char* pc)
+{
+ struct ud u;
+ ud_init(&u);
+ ud_set_input_buffer(&u, (uint8_t*)pc, 12);
+ ud_set_mode(&u, vmp_machine_bits());
+ return ud_decode(&u);
+}
+
// a hilarious typo, tramp -> trump :)
int _redirect_trampoline_and_back(char * eval, char * trump, char * vmprof_eval) {
diff --git a/rpython/rlib/rvmprof/src/shared/vmp_stack.c b/rpython/rlib/rvmprof/src/shared/vmp_stack.c
--- a/rpython/rlib/rvmprof/src/shared/vmp_stack.c
+++ b/rpython/rlib/rvmprof/src/shared/vmp_stack.c
@@ -15,24 +15,18 @@
#include "compat.h"
#ifdef VMP_SUPPORTS_NATIVE_PROFILING
-#define UNW_LOCAL_ONLY
-#include "unwind/libunwind.h"
-# ifdef X86_64
-# define REG_RBX UNW_X86_64_RBX
-# elif defined(X86_32)
-# define REG_RBX UNW_X86_EDI
-# endif
+#include "unwind/vmprof_unwind.h"
+
+typedef mcontext_t unw_context_t;
// functions copied from libunwind using dlopen
-#ifdef VMPROF_UNIX
static int (*unw_get_reg)(unw_cursor_t*, int, unw_word_t*) = NULL;
static int (*unw_step)(unw_cursor_t*) = NULL;
static int (*unw_init_local)(unw_cursor_t *, unw_context_t *) = NULL;
static int (*unw_get_proc_info)(unw_cursor_t *, unw_proc_info_t *) = NULL;
static int (*unw_is_signal_frame)(unw_cursor_t *) = NULL;
-static int (*unw_getcontext)(unw_cursor_t *) = NULL;
-#endif
+static int (*unw_getcontext)(unw_context_t *) = NULL;
#endif
@@ -176,30 +170,39 @@
return 0;
}
+ if (signal < 0) {
+ while (signal < 0) {
+ int err = unw_step(&cursor);
+ if (err <= 0) {
+ return 0;
+ }
+ signal++;
+ }
+ } else {
#ifdef VMPROF_LINUX
- while (signal) {
- int is_signal_frame = unw_is_signal_frame(&cursor);
- if (is_signal_frame) {
- unw_step(&cursor); // step once more discard signal frame
- break;
+ while (signal) {
+ int is_signal_frame = unw_is_signal_frame(&cursor);
+ if (is_signal_frame) {
+ unw_step(&cursor); // step once more discard signal frame
+ break;
+ }
+ int err = unw_step(&cursor);
+ if (err <= 0) {
+ return 0;
+ }
}
- int err = unw_step(&cursor);
- if (err <= 0) {
- return 0;
+#else
+ // who would have guessed that unw_is_signal_frame does not work on mac os x
+ if (signal) {
+ unw_step(&cursor); // vmp_walk_and_record_stack
+ // get_stack_trace is inlined
+ unw_step(&cursor); // _vmprof_sample_stack
+ unw_step(&cursor); // sigprof_handler
+ unw_step(&cursor); // _sigtramp
}
+#endif
}
-#else
- // who would have guessed that unw_is_signal_frame does not work on mac os x
- if (signal) {
- unw_step(&cursor); // vmp_walk_and_record_stack
- // get_stack_trace is inlined
- unw_step(&cursor); // _vmprof_sample_stack
- unw_step(&cursor); // sigprof_handler
- unw_step(&cursor); // _sigtramp
- }
-#endif
- //printf("stack trace:\n");
int depth = 0;
PY_STACK_FRAME_T * top_most_frame = frame;
while (depth < max_depth) {
@@ -223,84 +226,39 @@
// printf("func_addr is 0, now %p\n", rip);
//}
+#ifdef PYPY
+ unw_word_t rip = 0;
+ if (unw_get_reg(&cursor, UNW_REG_IP, &rip) < 0) {
+ return 0;
+ }
+#endif
if (IS_VMPROF_EVAL((void*)pip.start_ip)) {
// yes we found one stack entry of the python frames!
-#ifndef RPYTHON_VMPROF
- unw_word_t rbx = 0;
- if (unw_get_reg(&cursor, REG_RBX, &rbx) < 0) {
- break;
- }
- if (rbx != (unw_word_t)top_most_frame) {
- // uh we are screwed! the ip indicates we are have context
- // to a PyEval_EvalFrameEx function, but when we tried to retrieve
- // the stack located py frame it has a different address than the
- // current top_most_frame
- return 0;
- } else {
-#else
- {
+ return vmp_walk_and_record_python_stack_only(frame, result, max_depth, depth, pc);
+#ifdef PYPY
+ } else if (IS_JIT_FRAME((void*)rip)) {
+ depth = vmprof_write_header_for_jit_addr(result, depth, pc, max_depth);
+ return vmp_walk_and_record_python_stack_only(frame, result, max_depth, depth, pc);
#endif
- if (top_most_frame != NULL) {
- top_most_frame = _write_python_stack_entry(top_most_frame, result, &depth, max_depth);
- } else {
- // Signals can occur at the two places (1) and (2), that will
- // have added a stack entry, but the function __vmprof_eval_vmprof
- // is not entered. This behaviour will swallow one Python stack frames
- //
- // (1) PyPy: enter_code happened, but __vmprof_eval_vmprof was not called
- // (2) PyPy: __vmprof_eval_vmprof was returned, but exit_code was not called
- //
- // destroy this sample, as it would display a strage sample
- return 0;
- }
- }
- } else if (vmp_ignore_ip((intptr_t)func_addr)) {
- // this is an instruction pointer that should be ignored
- // (that is any function name in the mapping range of
- // cpython or libpypy-c.so, but of course not
- // extenstions in site-packages)
} else {
// mark native routines with the first bit set,
// this is possible because compiler align to 8 bytes.
//
-#ifdef PYPY_JIT_CODEMAP
- // see vmp_dynamic.c on line ip->flags = DYN_JIT_FLAG
- if (pip.flags == DYN_JIT_FLAG) {
- if (top_most_frame->kind != VMPROF_JITTED_TAG) {
- // if this is encountered frequently something is wrong with
- // the stack building
- return 0;
- }
- intptr_t pc = ((intptr_t*)(top_most_frame->value - sizeof(intptr_t)))[0];
- depth = vmprof_write_header_for_jit_addr(result, depth, pc, max_depth);
- top_most_frame = FRAME_STEP(top_most_frame);
- } else if (func_addr != 0x0) {
- depth = _write_native_stack((void*)(func_addr | 0x1), result, depth);
- }
-#else
if (func_addr != 0x0) {
depth = _write_native_stack((void*)(func_addr | 0x1), result, depth);
}
-#endif
}
int err = unw_step(&cursor);
if (err == 0) {
- //printf("sample ended\n");
break;
} else if (err < 0) {
return 0; // this sample is broken, cannot walk it fully
}
}
- if (top_most_frame == NULL) {
- return depth;
- }
- // Whenever the trampoline is inserted, there might be a view python
- // stack levels that do not have the trampoline!
- // they should not be consumed, because the let native symbols flow forward.
- return depth; //vmp_walk_and_record_python_stack_only(top_most_frame, result, max_depth, depth);
+ return 0; // kill this sample, no python level was found
#else
return vmp_walk_and_record_python_stack_only(frame, result, max_depth, 0, pc);
#endif
@@ -492,30 +450,47 @@
static const char * vmprof_error = NULL;
+
+#ifdef VMPROF_LINUX
+#define LIBUNWIND "libunwind.so"
+#ifdef __i386__
+#define PREFIX "x86"
+#elif __x86_64__
+#define PREFIX "x86_64"
+#endif
+#define U_PREFIX "_U"
+#define UL_PREFIX "_UL"
+#else
+#define LIBUNWIND "/usr/lib/system/libunwind.dylib"
+#define PREFIX "unw"
+#define U_PREFIX ""
+#define UL_PREFIX ""
+#endif
+
int vmp_native_enable(void) {
void * libhandle;
vmp_native_traces_enabled = 1;
if (!unw_get_reg) {
- if (!(libhandle = dlopen("libunwind.so", RTLD_LAZY | RTLD_LOCAL))) {
+ if (!(libhandle = dlopen(LIBUNWIND, RTLD_LAZY | RTLD_LOCAL))) {
goto bail_out;
}
- if (!(unw_getcontext = dlsym(libhandle, "_ULx86_64_getcontext"))) {
+ if (!(unw_get_reg = dlsym(libhandle, UL_PREFIX PREFIX "_get_reg"))) {
goto bail_out;
}
- if (!(unw_get_reg = dlsym(libhandle, "_ULx86_64_get_reg"))) {
+ if (!(unw_get_proc_info = dlsym(libhandle, UL_PREFIX PREFIX "_get_proc_info"))){
goto bail_out;
}
- if (!(unw_get_proc_info = dlsym(libhandle, "_ULx86_64_get_proc_info"))){
+ if (!(unw_init_local = dlsym(libhandle, UL_PREFIX PREFIX "_init_local"))) {
goto bail_out;
}
- if (!(unw_init_local = dlsym(libhandle, "_ULx86_64_init_local"))) {
+ if (!(unw_step = dlsym(libhandle, UL_PREFIX PREFIX "_step"))) {
goto bail_out;
}
- if (!(unw_step = dlsym(libhandle, "_ULx86_64_step"))) {
+ if (!(unw_is_signal_frame = dlsym(libhandle, UL_PREFIX PREFIX "_is_signal_frame"))) {
goto bail_out;
}
- if (!(unw_is_signal_frame = dlsym(libhandle, "_ULx86_64_is_signal_frame"))) {
+ if (!(unw_getcontext = dlsym(libhandle, U_PREFIX PREFIX "_getcontext"))) {
goto bail_out;
}
if (dlclose(libhandle)) {
@@ -529,7 +504,9 @@
return vmp_read_vmaps(NULL);
#endif
bail_out:
+ vmprof_error = dlerror();
fprintf(stderr, "could not load libunwind at runtime. error: %s\n", vmprof_error);
+ vmp_native_traces_enabled = 0;
return 0;
}
diff --git a/rpython/rlib/rvmprof/src/shared/vmprof.h b/rpython/rlib/rvmprof/src/shared/vmprof.h
--- a/rpython/rlib/rvmprof/src/shared/vmprof.h
+++ b/rpython/rlib/rvmprof/src/shared/vmprof.h
@@ -61,9 +61,13 @@
#define PY_THREAD_STATE_T PyThreadState
#define FRAME_STEP(f) f->f_back
#define FRAME_CODE(f) f->f_code
-PY_EVAL_RETURN_T * vmprof_eval(PY_STACK_FRAME_T *f, int throwflag);
-#define VMPROF_EVAL() vmprof_eval
-#define IS_VMPROF_EVAL(PTR) PTR == (void*)vmprof_eval
+
+#if CPYTHON_HAS_FRAME_EVALUATION
+#define IS_VMPROF_EVAL(PTR) PTR == (void*)_PyEval_EvalFrameDefault
+#else
+#define IS_VMPROF_EVAL(PTR) (PTR == (void*)PyEval_EvalFrameEx || PTR == (void*)PyEval_EvalFrame)
#endif
+#endif
+
diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_main.h b/rpython/rlib/rvmprof/src/shared/vmprof_main.h
--- a/rpython/rlib/rvmprof/src/shared/vmprof_main.h
+++ b/rpython/rlib/rvmprof/src/shared/vmprof_main.h
@@ -337,39 +337,12 @@
vmp_native_disable();
return;
}
-#if CPYTHON_HAS_FRAME_EVALUATION
- PyThreadState *tstate = PyThreadState_GET();
- tstate->interp->eval_frame = vmprof_eval;
- _default_eval_loop = _PyEval_EvalFrameDefault;
-#elif defined(RPYTHON_VMPROF)
- // do nothing here, the stack is maintained by rpython
- // no need for a trampoline
-#else
- if (vmp_patch_callee_trampoline(PyEval_EvalFrameEx,
- vmprof_eval, (void*)&_default_eval_loop) == 0) {
- } else {
- fprintf(stderr, "FATAL: could not insert trampline, try with --no-native\n");
- // TODO dump the first few bytes and tell them to create an issue!
- exit(-1);
- }
-#endif
vmp_native_enable();
}
static void disable_cpyprof(void)
{
vmp_native_disable();
-#if CPYTHON_HAS_FRAME_EVALUATION
- PyThreadState *tstate = PyThreadState_GET();
- tstate->interp->eval_frame = _PyEval_EvalFrameDefault;
-#elif defined(RPYTHON_VMPROF)
- // TODO nothing?
-#else
- if (vmp_unpatch_callee_trampoline(PyEval_EvalFrameEx) > 0) {
- fprintf(stderr, "FATAL: could not remove trampoline\n");
- exit(-1);
- }
-#endif
dump_native_symbols(vmp_profile_fileno());
}
#endif
More information about the pypy-commit
mailing list