[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