Author: Antonio Cuni <anto.c...@gmail.com> Branch: Changeset: r92973:4b7ad9d4be0d Date: 2017-11-08 17:47 +0100 http://bitbucket.org/pypy/pypy/changeset/4b7ad9d4be0d/
Log: merge the vmprof-0.4.10 branch: - copy the recent changes to the C part of vmprof from github - make sure that the tests are actually testing something: so far, most of the were just silently skipped on the nightly buildbot :( - test_native is broken: it has been broken since the merge of vmprof-0.4.8, but we didn't notice - I expect some tests to fail on weird architectures. Once we know which, we can explicitly skip them diff --git a/requirements.txt b/requirements.txt --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ cffi>=1.4.0 +vmprof>=0.4.10 # required to parse log files in rvmprof tests # hypothesis is used for test generation on untranslated tests hypothesis diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_common.c b/rpython/rlib/rvmprof/src/shared/vmprof_common.c --- a/rpython/rlib/rvmprof/src/shared/vmprof_common.c +++ b/rpython/rlib/rvmprof/src/shared/vmprof_common.c @@ -32,12 +32,21 @@ static size_t threads_size = 0; static size_t thread_count = 0; static size_t threads_size_step = 8; -#endif int vmprof_get_itimer_type(void) { return itimer_type; } +int vmprof_get_signal_type(void) { + return signal_type; +} +#endif + +#ifdef VMPROF_WINDOWS +#include "vmprof_win.h" +#endif + + int vmprof_is_enabled(void) { return is_enabled; } @@ -62,10 +71,6 @@ profile_interval_usec = value; } -int vmprof_get_signal_type(void) { - return signal_type; -} - char *vmprof_init(int fd, double interval, int memory, int proflines, const char *interp_name, int native, int real_time) { diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_common.h b/rpython/rlib/rvmprof/src/shared/vmprof_common.h --- a/rpython/rlib/rvmprof/src/shared/vmprof_common.h +++ b/rpython/rlib/rvmprof/src/shared/vmprof_common.h @@ -15,7 +15,9 @@ #include <pthread.h> #endif +#ifdef VMPROF_UNIX #include "vmprof_getpc.h" +#endif #ifdef VMPROF_LINUX #include <syscall.h> diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_memory.c b/rpython/rlib/rvmprof/src/shared/vmprof_memory.c --- a/rpython/rlib/rvmprof/src/shared/vmprof_memory.c +++ b/rpython/rlib/rvmprof/src/shared/vmprof_memory.c @@ -8,7 +8,7 @@ #include <mach/task_info.h> static mach_port_t mach_task; -#else +#elif defined(VMPROF_UNIX) #include <stdio.h> #include <stdlib.h> #include <sys/types.h> diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_unix.c b/rpython/rlib/rvmprof/src/shared/vmprof_unix.c --- a/rpython/rlib/rvmprof/src/shared/vmprof_unix.c +++ b/rpython/rlib/rvmprof/src/shared/vmprof_unix.c @@ -41,8 +41,6 @@ void vmprof_ignore_signals(int ignored) { if (ignored) { - /* set the last bit, and wait until concurrently-running signal - handlers finish */ __sync_add_and_fetch(&signal_handler_ignore, 1L); while (signal_handler_entries != 0L) { usleep(1); @@ -370,7 +368,7 @@ goto error; if (install_sigprof_timer() == -1) goto error; - vmprof_ignore_signals(0); + signal_handler_ignore = 0; return 0; error: @@ -394,7 +392,7 @@ int vmprof_disable(void) { - vmprof_ignore_signals(1); + signal_handler_ignore = 1; vmprof_set_profile_interval_usec(0); #ifdef VMP_SUPPORTS_NATIVE_PROFILING disable_cpyprof(); diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_win.c b/rpython/rlib/rvmprof/src/shared/vmprof_win.c --- a/rpython/rlib/rvmprof/src/shared/vmprof_win.c +++ b/rpython/rlib/rvmprof/src/shared/vmprof_win.c @@ -1,7 +1,7 @@ -// cannot include this header because it also has definitions -#include "windows.h" -#include "compat.h" -#include "vmp_stack.h" +#include "vmprof_win.h" + +volatile int thread_started = 0; +volatile int enabled = 0; HANDLE write_mutex; @@ -12,7 +12,20 @@ return 0; } -#include <tlhelp32.h> +int vmprof_register_virtual_function(char *code_name, intptr_t code_uid, + int auto_retry) +{ + char buf[2048]; + long namelen; + + namelen = (long)strnlen(code_name, 1023); + buf[0] = MARKER_VIRTUAL_IP; + *(intptr_t*)(buf + 1) = code_uid; + *(long*)(buf + 1 + sizeof(intptr_t)) = namelen; + memcpy(buf + 1 + sizeof(intptr_t) + sizeof(long), code_name, namelen); + vmp_write_all(buf, 1 + sizeof(intptr_t) + sizeof(long) + namelen); + return 0; +} int vmp_write_all(const char *buf, size_t bufsize) { @@ -40,3 +53,168 @@ return 0; } +HANDLE write_mutex; + +#include "vmprof_common.h" + +int vmprof_snapshot_thread(DWORD thread_id, PY_WIN_THREAD_STATE *tstate, prof_stacktrace_s *stack) +{ + HRESULT result; + HANDLE hThread; + int depth; + CONTEXT ctx; +#ifdef RPYTHON_LL2CTYPES + return 0; // not much we can do +#else +#if !defined(RPY_TLOFS_thread_ident) && defined(RPYTHON_VMPROF) + return 0; // we can't freeze threads, unsafe +#else + hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); + if (!hThread) { + return -1; + } + result = SuspendThread(hThread); + if(result == 0xffffffff) + return -1; // possible, e.g. attached debugger or thread alread suspended + // find the correct thread +#ifdef RPYTHON_VMPROF + ctx.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext(hThread, &ctx)) + return -1; + depth = get_stack_trace(tstate->vmprof_tl_stack, + stack->stack, MAX_STACK_DEPTH-2, ctx.Eip); + stack->depth = depth; + stack->stack[depth++] = thread_id; + stack->count = 1; + stack->marker = MARKER_STACKTRACE; + ResumeThread(hThread); + return depth; +#else + depth = vmp_walk_and_record_stack(tstate->frame, stack->stack, + MAX_STACK_DEPTH, 0, 0); + stack->depth = depth; + stack->stack[depth++] = (void*)((ULONG_PTR)thread_id); + stack->count = 1; + stack->marker = MARKER_STACKTRACE; + ResumeThread(hThread); + return depth; +#endif + +#endif +#endif +} + +#ifndef RPYTHON_VMPROF +static +PY_WIN_THREAD_STATE * get_current_thread_state(void) +{ +#if PY_MAJOR_VERSION < 3 + return _PyThreadState_Current; +#elif PY_VERSION_HEX < 0x03050200 + return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); +#else + return _PyThreadState_UncheckedGet(); +#endif +} +#endif + +long __stdcall vmprof_mainloop(void *arg) +{ +#ifdef RPYTHON_LL2CTYPES + // for tests only + return 0; +#else + // it is not a test case! + PY_WIN_THREAD_STATE *tstate; + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + prof_stacktrace_s *stack = (prof_stacktrace_s*)malloc(SINGLE_BUF_SIZE); + int depth; +#ifndef RPYTHON_VMPROF + // cpython version + while (1) { + Sleep(vmprof_get_profile_interval_usec() * 1000); + if (!enabled) { + continue; + } + tstate = get_current_thread_state(); + if (!tstate) + continue; + depth = vmprof_snapshot_thread(tstate->thread_id, tstate, stack); + if (depth > 0) { + vmp_write_all((char*)stack + offsetof(prof_stacktrace_s, marker), + SIZEOF_PROF_STACKTRACE + depth * sizeof(void*)); + } + } +#else + // pypy version + while (1) { + //Sleep(vmprof_get_profile_interval_usec() * 1000); + Sleep(10); + if (!enabled) { + continue; + } + _RPython_ThreadLocals_Acquire(); + tstate = _RPython_ThreadLocals_Head(); // the first one is one behind head + tstate = _RPython_ThreadLocals_Enum(tstate); + while (tstate) { + if (tstate->ready == 42) { + depth = vmprof_snapshot_thread(tstate->thread_ident, tstate, stack); + if (depth > 0) { + vmp_write_all((char*)stack + offsetof(prof_stacktrace_s, marker), + depth * sizeof(void *) + + sizeof(struct prof_stacktrace_s) - + offsetof(struct prof_stacktrace_s, marker)); + } + } + tstate = _RPython_ThreadLocals_Enum(tstate); + } + _RPython_ThreadLocals_Release(); + } +#endif +#endif +} + +RPY_EXTERN +int vmprof_enable(int memory, int native, int real_time) +{ + if (!thread_started) { + if (!CreateThread(NULL, 0, vmprof_mainloop, NULL, 0, NULL)) { + return -1; + } + thread_started = 1; + } + enabled = 1; + return 0; +} + +RPY_EXTERN +int vmprof_disable(void) +{ + char marker = MARKER_TRAILER; + (void)vmp_write_time_now(MARKER_TRAILER); + + enabled = 0; + vmp_set_profile_fileno(-1); + return 0; +} + +RPY_EXTERN +void vmprof_ignore_signals(int ignored) +{ + enabled = !ignored; +} + +int vmp_native_enable(void) +{ + return 0; +} + +void vmp_native_disable(void) +{ +} + +int get_stack_trace(PY_WIN_THREAD_STATE * current, void** result, + int max_depth, intptr_t pc) +{ + return 0; +} diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_win.h b/rpython/rlib/rvmprof/src/shared/vmprof_win.h --- a/rpython/rlib/rvmprof/src/shared/vmprof_win.h +++ b/rpython/rlib/rvmprof/src/shared/vmprof_win.h @@ -3,20 +3,13 @@ #include "windows.h" #include "compat.h" #include "vmp_stack.h" - -HANDLE write_mutex; +#include <tlhelp32.h> int prepare_concurrent_bufs(void); -#include "vmprof_common.h" -#include <tlhelp32.h> - // This file has been inspired (but not copied from since the LICENSE // would not allow it) from verysleepy profiler -volatile int thread_started = 0; -volatile int enabled = 0; - int vmp_write_all(const char *buf, size_t bufsize); #ifdef RPYTHON_VMPROF @@ -26,178 +19,14 @@ #endif -RPY_EXTERN int vmprof_register_virtual_function(char *code_name, intptr_t code_uid, - int auto_retry) -{ - char buf[2048]; - long namelen; + int auto_retry); - namelen = (long)strnlen(code_name, 1023); - buf[0] = MARKER_VIRTUAL_IP; - *(intptr_t*)(buf + 1) = code_uid; - *(long*)(buf + 1 + sizeof(intptr_t)) = namelen; - memcpy(buf + 1 + sizeof(intptr_t) + sizeof(long), code_name, namelen); - vmp_write_all(buf, 1 + sizeof(intptr_t) + sizeof(long) + namelen); - return 0; -} - -int vmprof_snapshot_thread(DWORD thread_id, PY_WIN_THREAD_STATE *tstate, prof_stacktrace_s *stack) -{ - HRESULT result; - HANDLE hThread; - int depth; - CONTEXT ctx; -#ifdef RPYTHON_LL2CTYPES - return 0; // not much we can do -#else -#if !defined(RPY_TLOFS_thread_ident) && defined(RPYTHON_VMPROF) - return 0; // we can't freeze threads, unsafe -#else - hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); - if (!hThread) { - return -1; - } - result = SuspendThread(hThread); - if(result == 0xffffffff) - return -1; // possible, e.g. attached debugger or thread alread suspended - // find the correct thread -#ifdef RPYTHON_VMPROF - ctx.ContextFlags = CONTEXT_FULL; - if (!GetThreadContext(hThread, &ctx)) - return -1; - depth = get_stack_trace(tstate->vmprof_tl_stack, - stack->stack, MAX_STACK_DEPTH-2, ctx.Eip); - stack->depth = depth; - stack->stack[depth++] = thread_id; - stack->count = 1; - stack->marker = MARKER_STACKTRACE; - ResumeThread(hThread); - return depth; -#else - depth = vmp_walk_and_record_stack(tstate->frame, stack->stack, - MAX_STACK_DEPTH, 0, 0); - stack->depth = depth; - stack->stack[depth++] = (void*)((ULONG_PTR)thread_id); - stack->count = 1; - stack->marker = MARKER_STACKTRACE; - ResumeThread(hThread); - return depth; -#endif - -#endif -#endif -} - -#ifndef RPYTHON_VMPROF -static -PY_WIN_THREAD_STATE * get_current_thread_state(void) -{ -#if PY_MAJOR_VERSION < 3 - return _PyThreadState_Current; -#elif PY_VERSION_HEX < 0x03050200 - return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); -#else - return _PyThreadState_UncheckedGet(); -#endif -} -#endif - -long __stdcall vmprof_mainloop(void *arg) -{ -#ifdef RPYTHON_LL2CTYPES - // for tests only - return 0; -#else - // it is not a test case! - PY_WIN_THREAD_STATE *tstate; - HANDLE hThreadSnap = INVALID_HANDLE_VALUE; - prof_stacktrace_s *stack = (prof_stacktrace_s*)malloc(SINGLE_BUF_SIZE); - int depth; -#ifndef RPYTHON_VMPROF - // cpython version - while (1) { - Sleep(profile_interval_usec * 1000); - if (!enabled) { - continue; - } - tstate = get_current_thread_state(); - if (!tstate) - continue; - depth = vmprof_snapshot_thread(tstate->thread_id, tstate, stack); - if (depth > 0) { - vmp_write_all((char*)stack + offsetof(prof_stacktrace_s, marker), - SIZEOF_PROF_STACKTRACE + depth * sizeof(void*)); - } - } -#else - // pypy version - while (1) { - //Sleep(profile_interval_usec * 1000); - Sleep(10); - if (!enabled) { - continue; - } - _RPython_ThreadLocals_Acquire(); - tstate = _RPython_ThreadLocals_Head(); // the first one is one behind head - tstate = _RPython_ThreadLocals_Enum(tstate); - while (tstate) { - if (tstate->ready == 42) { - depth = vmprof_snapshot_thread(tstate->thread_ident, tstate, stack); - if (depth > 0) { - vmp_write_all((char*)stack + offsetof(prof_stacktrace_s, marker), - depth * sizeof(void *) + - sizeof(struct prof_stacktrace_s) - - offsetof(struct prof_stacktrace_s, marker)); - } - } - tstate = _RPython_ThreadLocals_Enum(tstate); - } - _RPython_ThreadLocals_Release(); - } -#endif -#endif -} - -RPY_EXTERN -int vmprof_enable(int memory, int native, int real_time) -{ - if (!thread_started) { - if (!CreateThread(NULL, 0, vmprof_mainloop, NULL, 0, NULL)) { - return -1; - } - thread_started = 1; - } - enabled = 1; - return 0; -} - -RPY_EXTERN -int vmprof_disable(void) -{ - char marker = MARKER_TRAILER; - (void)vmp_write_time_now(MARKER_TRAILER); - - enabled = 0; - vmp_set_profile_fileno(-1); - return 0; -} - -RPY_EXTERN -void vmprof_ignore_signals(int ignored) -{ - enabled = !ignored; -} - -int vmp_native_enable(void) { - return 0; -} - -void vmp_native_disable(void) { -} - +PY_WIN_THREAD_STATE * get_current_thread_state(void); +int vmprof_enable(int memory, int native, int real_time); +int vmprof_disable(void); +void vmprof_ignore_signals(int ignored); +int vmp_native_enable(void); +void vmp_native_disable(void); int get_stack_trace(PY_WIN_THREAD_STATE * current, void** result, - int max_depth, intptr_t pc) -{ - return 0; -} + int max_depth, intptr_t pc); diff --git a/rpython/rlib/rvmprof/test/test_file.py b/rpython/rlib/rvmprof/test/test_file.py --- a/rpython/rlib/rvmprof/test/test_file.py +++ b/rpython/rlib/rvmprof/test/test_file.py @@ -2,25 +2,43 @@ import urllib2, py from os.path import join +RVMPROF = py.path.local(__file__).join('..', '..') def github_raw_file(repo, path, branch='master'): - return "https://raw.githubusercontent.com/{repo}/{branch}/{path}".format(**dict( - repo=repo, path=path, branch=branch - )) + url = "https://raw.githubusercontent.com/{repo}/{branch}/{path}" + return url.format(repo=repo, path=path, branch=branch) +def get_list_of_files(shared): + files = list(shared.visit('*.[ch]')) + # in PyPy we checkin the result of ./configure; as such, these files are + # not in github and can be skipped + files.remove(shared.join('libbacktrace', 'config-x86_32.h')) + files.remove(shared.join('libbacktrace', 'config-x86_64.h')) + files.remove(shared.join('libbacktrace', 'gstdint.h')) + return files def test_same_file(): - for root, dirs, files in os.walk('rpython/rlib/rvmprof/src/shared'): - for file in files: - if not (file.endswith(".c") or file.endswith(".h")): - continue - url = github_raw_file("vmprof/vmprof-python", "src/%s" % file) - source = urllib2.urlopen(url).read() - # - dest = py.path.local(join(root, file)).read() - if source != dest: - raise AssertionError("%s was updated, but changes were" - "not copied over to PyPy" % url) - else: - print("%s matches" % url) - break # do not walk dirs + shared = RVMPROF.join('src', 'shared') + files = get_list_of_files(shared) + assert files, 'cannot find any C file, probably the directory is wrong?' + no_matches = [] + print + for file in files: + path = file.relto(shared) + url = github_raw_file("vmprof/vmprof-python", "src/%s" % path) + source = urllib2.urlopen(url).read() + dest = file.read() + shortname = file.relto(RVMPROF) + if source == dest: + print '%s matches' % shortname + else: + print '%s does NOT match' % shortname + no_matches.append(file) + # + if no_matches: + print + print 'The following file dit NOT match' + for f in no_matches: + print ' ', f.relto(RVMPROF) + raise AssertionError("some files were updated on github, " + "but were not copied here") diff --git a/rpython/rlib/rvmprof/test/test_rvmprof.py b/rpython/rlib/rvmprof/test/test_rvmprof.py --- a/rpython/rlib/rvmprof/test/test_rvmprof.py +++ b/rpython/rlib/rvmprof/test/test_rvmprof.py @@ -1,214 +1,183 @@ import py, os +import pytest +import time from rpython.tool.udir import udir from rpython.rlib import rvmprof from rpython.translator.c.test.test_genc import compile -from rpython.rlib.objectmodel import we_are_translated -from rpython.rlib.nonconst import NonConstant from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.rtyper.lltypesystem import rffi, lltype +@pytest.mark.usefixtures('init') +class RVMProfTest(object): -def test_vmprof_execute_code_1(): + ENTRY_POINT_ARGS = () - class MyCode: - pass - try: - rvmprof.register_code_object_class(MyCode, lambda code: 'some code') - except rvmprof.VMProfPlatformUnsupported: - pass + class MyCode(object): + def __init__(self, name='py:code:0:noname'): + self.name = name - @rvmprof.vmprof_execute_code("xcode1", lambda code, num: code) - def main(code, num): + def get_name(self): + return self.name + + @pytest.fixture + def init(self): + self.register() + self.rpy_entry_point = compile(self.entry_point, self.ENTRY_POINT_ARGS) + + def register(self): + rvmprof.register_code_object_class(self.MyCode, + self.MyCode.get_name) + + +class TestExecuteCode(RVMProfTest): + + def entry_point(self): + res = self.main(self.MyCode(), 5) + assert res == 42 + return 0 + + @rvmprof.vmprof_execute_code("xcode1", lambda self, code, num: code) + def main(self, code, num): print num return 42 - def f(): - res = main(MyCode(), 5) + def test(self): + assert self.entry_point() == 0 + assert self.rpy_entry_point() == 0 + + +class TestResultClass(RVMProfTest): + + class A: pass + + @rvmprof.vmprof_execute_code("xcode2", lambda self, num, code: code, + result_class=A) + def main(self, num, code): + print num + return self.A() + + def entry_point(self): + a = self.main(7, self.MyCode()) + assert isinstance(a, self.A) + return 0 + + def test(self): + assert self.entry_point() == 0 + assert self.rpy_entry_point() == 0 + + +class TestRegisterCode(RVMProfTest): + + @rvmprof.vmprof_execute_code("xcode1", lambda self, code, num: code) + def main(self, code, num): + print num + return 42 + + def entry_point(self): + code = self.MyCode() + rvmprof.register_code(code, lambda code: 'some code') + res = self.main(code, 5) assert res == 42 return 0 - assert f() == 0 - fn = compile(f, []) - assert fn() == 0 + def test(self): + assert self.entry_point() == 0 + assert self.rpy_entry_point() == 0 -def test_vmprof_execute_code_2(): +class RVMProfSamplingTest(RVMProfTest): - class MyCode: - pass - try: - rvmprof.register_code_object_class(MyCode, lambda code: 'some code') - except rvmprof.VMProfPlatformUnsupported: - pass + # the kernel will deliver SIGPROF at max 250 Hz. See also + # https://github.com/vmprof/vmprof-python/issues/163 + SAMPLING_INTERVAL = 1/250.0 - class A: - pass + @pytest.fixture + def init(self, tmpdir): + self.tmpdir = tmpdir + self.tmpfile = tmpdir.join('profile.vmprof') + self.tmpfilename = str(self.tmpfile) + super(RVMProfSamplingTest, self).init() - @rvmprof.vmprof_execute_code("xcode2", lambda num, code: code, - result_class=A) - def main(num, code): - print num - return A() + ENTRY_POINT_ARGS = (int, float) + def entry_point(self, value, delta_t): + code = self.MyCode('py:code:52:test_enable') + rvmprof.register_code(code, self.MyCode.get_name) + fd = os.open(self.tmpfilename, os.O_WRONLY | os.O_CREAT, 0666) + rvmprof.enable(fd, self.SAMPLING_INTERVAL) + start = time.time() + res = 0 + while time.time() < start+delta_t: + res = self.main(code, value) + rvmprof.disable() + os.close(fd) + return res - def f(): - a = main(7, MyCode()) - assert isinstance(a, A) - return 0 + def approx_equal(self, a, b, tolerance=0.1): + max_diff = (a+b)/2.0 * tolerance + return abs(a-b) < max_diff - assert f() == 0 - fn = compile(f, []) - assert fn() == 0 +class TestEnable(RVMProfSamplingTest): -def test_register_code(): - - class MyCode: - pass - try: - rvmprof.register_code_object_class(MyCode, lambda code: 'some code') - except rvmprof.VMProfPlatformUnsupported as e: - py.test.skip(str(e)) - - @rvmprof.vmprof_execute_code("xcode1", lambda code, num: code) - def main(code, num): - print num - return 42 - - def f(): - code = MyCode() - rvmprof.register_code(code, lambda code: 'some code') - res = main(code, 5) - assert res == 42 - return 0 - - assert f() == 0 - fn = compile(f, [], gcpolicy="minimark") - assert fn() == 0 - - -def test_enable(): - - class MyCode: - pass - def get_name(code): - return 'py:code:52:x' - try: - rvmprof.register_code_object_class(MyCode, get_name) - except rvmprof.VMProfPlatformUnsupported as e: - py.test.skip(str(e)) - - @rvmprof.vmprof_execute_code("xcode1", lambda code, num: code) - def main(code, num): - print num + @rvmprof.vmprof_execute_code("xcode1", lambda self, code, count: code) + def main(self, code, count): s = 0 - for i in range(num): + for i in range(count): s += (i << 1) - if s % 2123423423 == 0: - print s return s - tmpfilename = str(udir.join('test_rvmprof')) + def test(self): + from vmprof import read_profile + assert self.entry_point(10**4, 0.1) == 99990000 + assert self.tmpfile.check() + self.tmpfile.remove() + # + assert self.rpy_entry_point(10**4, 0.5) == 99990000 + assert self.tmpfile.check() + prof = read_profile(self.tmpfilename) + tree = prof.get_tree() + assert tree.name == 'py:code:52:test_enable' + assert self.approx_equal(tree.count, 0.5/self.SAMPLING_INTERVAL) - def f(): - if NonConstant(False): - # Hack to give os.open() the correct annotation - os.open('foo', 1, 1) - code = MyCode() - rvmprof.register_code(code, get_name) - fd = os.open(tmpfilename, os.O_WRONLY | os.O_CREAT, 0666) - if we_are_translated(): - num = 100000000 - period = 0.0001 + +class TestNative(RVMProfSamplingTest): + + @pytest.fixture + def init(self, tmpdir): + eci = ExternalCompilationInfo(compile_extra=['-g','-O0'], + separate_module_sources=[""" + RPY_EXTERN int native_func(int d) { + int j = 0; + if (d > 0) { + return native_func(d-1); + } else { + for (int i = 0; i < 42000; i++) { + j += 1; + } + } + return j; + } + """]) + self.native_func = rffi.llexternal("native_func", [rffi.INT], rffi.INT, + compilation_info=eci) + super(TestNative, self).init(tmpdir) + + @rvmprof.vmprof_execute_code("xcode1", lambda self, code, count: code) + def main(self, code, count): + if count > 0: + return self.main(code, count-1) else: - num = 10000 - period = 0.9 - rvmprof.enable(fd, period) - res = main(code, num) - #assert res == 499999500000 - rvmprof.disable() - os.close(fd) - return 0 + return self.native_func(100) - def check_profile(filename): - from vmprof import read_profile - - prof = read_profile(filename) - assert prof.get_tree().name.startswith("py:") - assert prof.get_tree().count - - assert f() == 0 - assert os.path.exists(tmpfilename) - fn = compile(f, [], gcpolicy="minimark") - assert fn() == 0 - try: - import vmprof - except ImportError: - py.test.skip("vmprof unimportable") - else: - check_profile(tmpfilename) - finally: - assert os.path.exists(tmpfilename) - os.unlink(tmpfilename) - -def test_native(): - eci = ExternalCompilationInfo(compile_extra=['-g','-O0'], - separate_module_sources=[""" - RPY_EXTERN int native_func(int d) { - int j = 0; - if (d > 0) { - return native_func(d-1); - } else { - for (int i = 0; i < 42000; i++) { - j += d; - } - } - return j; - } - """]) - - native_func = rffi.llexternal("native_func", [rffi.INT], rffi.INT, - compilation_info=eci) - - class MyCode: - pass - def get_name(code): - return 'py:code:52:x' - - try: - rvmprof.register_code_object_class(MyCode, get_name) - except rvmprof.VMProfPlatformUnsupported as e: - py.test.skip(str(e)) - - @rvmprof.vmprof_execute_code("xcode1", lambda code, num: code) - def main(code, num): - if num > 0: - return main(code, num-1) - else: - return native_func(100) - - tmpfilename = str(udir.join('test_rvmprof')) - - def f(): - if NonConstant(False): - # Hack to give os.open() the correct annotation - os.open('foo', 1, 1) - code = MyCode() - rvmprof.register_code(code, get_name) - fd = os.open(tmpfilename, os.O_RDWR | os.O_CREAT, 0666) - num = 10000 - period = 0.0001 - rvmprof.enable(fd, period, native=1) - for i in range(num): - res = main(code, 3) - rvmprof.disable() - os.close(fd) - return 0 - - def check_profile(filename): + def test(self): + # XXX: this test is known to fail since rev a4f077ba651c, but buildbot + # never ran it. FIXME. from vmprof import read_profile from vmprof.show import PrettyPrinter - - prof = read_profile(filename) + assert self.rpy_entry_point(3, 0.5) == 42000 + assert self.tmpfile.check() + # + prof = read_profile(self.tmpfilename) tree = prof.get_tree() p = PrettyPrinter() p._print_tree(tree) @@ -227,16 +196,3 @@ del not_found[i] break assert not_found == [] - - fn = compile(f, [], gcpolicy="incminimark", lldebug=True) - assert fn() == 0 - try: - import vmprof - except ImportError: - py.test.skip("vmprof unimportable") - else: - check_profile(tmpfilename) - finally: - assert os.path.exists(tmpfilename) - os.unlink(tmpfilename) - diff --git a/rpython/translator/translator.py b/rpython/translator/translator.py --- a/rpython/translator/translator.py +++ b/rpython/translator/translator.py @@ -141,6 +141,9 @@ if isinstance(func, FunctionGraph): return func result = [] + if hasattr(func, 'im_func'): + # make it possible to translate bound methods + func = func.im_func for graph in translator.graphs: if getattr(graph, 'func', None) is func: result.append(graph) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit