Author: Armin Rigo <[email protected]>
Branch:
Changeset: r86094:7b02cc6e8bfd
Date: 2016-08-09 09:42 +0200
http://bitbucket.org/pypy/pypy/changeset/7b02cc6e8bfd/
Log: hg merge improve-vmprof-testing
Improved vmprof support: now tries hard to not miss any Python-level
frame in the captured stacks, even if there is the metainterp or
blackhole interp involved.
Also fix the stacklet (greenlet) support.
Contains some sanity checks that will fail an assertion, even when
running without vmprof enabled.
diff --git a/rpython/jit/backend/test/test_rvmprof.py
b/rpython/jit/backend/test/test_rvmprof.py
--- a/rpython/jit/backend/test/test_rvmprof.py
+++ b/rpython/jit/backend/test/test_rvmprof.py
@@ -7,64 +7,152 @@
from rpython.jit.backend.x86.arch import WORD
from rpython.jit.codewriter.policy import JitPolicy
+
class BaseRVMProfTest(object):
- def test_one(self):
- py.test.skip("needs thread-locals in the JIT, which is only available "
- "after translation")
+
+ def setup_method(self, meth):
visited = []
def helper():
+ trace = []
stack = cintf.vmprof_tl_stack.getraw()
- print stack
- if stack:
- # not during tracing
- visited.append(stack.c_value)
- else:
- visited.append(0)
+ while stack:
+ trace.append((stack.c_kind, stack.c_value))
+ stack = stack.c_next
+ visited.append(trace)
llfn = llhelper(lltype.Ptr(lltype.FuncType([], lltype.Void)), helper)
- driver = jit.JitDriver(greens=['code'], reds='auto')
+ class CodeObj(object):
+ def __init__(self, name):
+ self.name = name
- class CodeObj(object):
- pass
-
- def get_code_fn(code, arg):
+ def get_code_fn(codes, code, arg, c):
return code
def get_name(code):
return "foo"
+ _get_vmprof().use_weaklist = False
register_code_object_class(CodeObj, get_name)
- @vmprof_execute_code("main", get_code_fn)
- def f(code, n):
+ self.misc = visited, llfn, CodeObj, get_code_fn, get_name
+
+
+ def teardown_method(self, meth):
+ del _get_vmprof().use_weaklist
+
+
+ def test_simple(self):
+ visited, llfn, CodeObj, get_code_fn, get_name = self.misc
+ driver = jit.JitDriver(greens=['code'], reds=['c', 'i', 'n', 'codes'])
+
+ @vmprof_execute_code("main", get_code_fn,
+ _hack_update_stack_untranslated=True)
+ def f(codes, code, n, c):
i = 0
while i < n:
- driver.jit_merge_point(code=code)
+ driver.jit_merge_point(code=code, c=c, i=i, codes=codes, n=n)
+ if code.name == "main":
+ c = f(codes, codes[1], 1, c)
+ else:
+ llfn()
+ c -= 1
i += 1
- llfn()
+ return c
def main(n):
- cintf.vmprof_tl_stack.setraw(null) # make it empty
- vmprof = _get_vmprof()
- code = CodeObj()
- register_code(code, get_name)
- return f(code, n)
-
- class Hooks(jit.JitHookInterface):
- def after_compile(self, debug_info):
- self.raw_start = debug_info.asminfo.rawstart
-
- hooks = Hooks()
+ codes = [CodeObj("main"), CodeObj("not main")]
+ for code in codes:
+ register_code(code, get_name)
+ return f(codes, codes[0], n, 8)
null = lltype.nullptr(cintf.VMPROFSTACK)
- self.meta_interp(main, [10], policy=JitPolicy(hooks))
- print visited
- #v = set(visited)
- #assert 0 in v
- #v.remove(0)
- #assert len(v) == 1
- #assert 0 <= list(v)[0] - hooks.raw_start <= 10*1024
- #assert cintf.vmprof_tl_stack.getraw() == null
- # ^^^ make sure we didn't leave anything dangling
+ cintf.vmprof_tl_stack.setraw(null)
+ self.meta_interp(main, [30], inline=True)
+ assert visited[:3] == [[(1, 12), (1, 8)], [(1, 12), (1, 8)], [(1, 12),
(1, 8)]]
+
+
+ def test_leaving_with_exception(self):
+ visited, llfn, CodeObj, get_code_fn, get_name = self.misc
+ driver = jit.JitDriver(greens=['code'], reds=['c', 'i', 'n', 'codes'])
+
+ class MyExc(Exception):
+ def __init__(self, c):
+ self.c = c
+
+ @vmprof_execute_code("main", get_code_fn,
+ _hack_update_stack_untranslated=True)
+ def f(codes, code, n, c):
+ i = 0
+ while i < n:
+ driver.jit_merge_point(code=code, c=c, i=i, codes=codes, n=n)
+ if code.name == "main":
+ try:
+ f(codes, codes[1], 1, c)
+ except MyExc as e:
+ c = e.c
+ else:
+ llfn()
+ c -= 1
+ i += 1
+ raise MyExc(c)
+
+ def main(n):
+ codes = [CodeObj("main"), CodeObj("not main")]
+ for code in codes:
+ register_code(code, get_name)
+ try:
+ f(codes, codes[0], n, 8)
+ except MyExc as e:
+ return e.c
+
+ null = lltype.nullptr(cintf.VMPROFSTACK)
+ cintf.vmprof_tl_stack.setraw(null)
+ self.meta_interp(main, [30], inline=True)
+ assert visited[:3] == [[(1, 12), (1, 8)], [(1, 12), (1, 8)], [(1, 12),
(1, 8)]]
+
+
+ def test_leaving_with_exception_in_blackhole(self):
+ visited, llfn, CodeObj, get_code_fn, get_name = self.misc
+ driver = jit.JitDriver(greens=['code'], reds=['c', 'i', 'n', 'codes'])
+
+ class MyExc(Exception):
+ def __init__(self, c):
+ self.c = c
+
+ @vmprof_execute_code("main", get_code_fn,
+ _hack_update_stack_untranslated=True)
+ def f(codes, code, n, c):
+ i = 0
+ while True:
+ driver.jit_merge_point(code=code, c=c, i=i, codes=codes, n=n)
+ if i >= n:
+ break
+ i += 1
+ if code.name == "main":
+ try:
+ f(codes, codes[1], 1, c)
+ except MyExc as e:
+ c = e.c
+ driver.can_enter_jit(code=code, c=c, i=i, codes=codes, n=n)
+ else:
+ llfn()
+ c -= 1
+ if c & 1: # a failing guard
+ pass
+ raise MyExc(c)
+
+ def main(n):
+ codes = [CodeObj("main"), CodeObj("not main")]
+ for code in codes:
+ register_code(code, get_name)
+ try:
+ f(codes, codes[0], n, 8)
+ except MyExc as e:
+ return e.c
+
+ null = lltype.nullptr(cintf.VMPROFSTACK)
+ cintf.vmprof_tl_stack.setraw(null)
+ self.meta_interp(main, [30], inline=True)
+ assert visited[:3] == [[(1, 12), (1, 8)], [(1, 12), (1, 8)], [(1, 12),
(1, 8)]]
diff --git a/rpython/jit/codewriter/jtransform.py
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -452,6 +452,8 @@
prepare = self._handle_math_sqrt_call
elif oopspec_name.startswith('rgc.'):
prepare = self._handle_rgc_call
+ elif oopspec_name.startswith('rvmprof.'):
+ prepare = self._handle_rvmprof_call
elif oopspec_name.endswith('dict.lookup'):
# also ordereddict.lookup
prepare = self._handle_dict_lookup_call
@@ -2079,6 +2081,32 @@
else:
raise NotImplementedError(oopspec_name)
+ def _handle_rvmprof_call(self, op, oopspec_name, args):
+ if oopspec_name != 'rvmprof.jitted':
+ raise NotImplementedError(oopspec_name)
+ c_entering = Constant(0, lltype.Signed)
+ c_leaving = Constant(1, lltype.Signed)
+ v_uniqueid = args[0]
+ op1 = SpaceOperation('rvmprof_code', [c_entering, v_uniqueid], None)
+ op2 = SpaceOperation('rvmprof_code', [c_leaving, v_uniqueid], None)
+ #
+ # fish fish inside the oopspec's graph for the ll_func pointer
+ block = op.args[0].value._obj.graph.startblock
+ while True:
+ assert len(block.exits) == 1
+ nextblock = block.exits[0].target
+ if nextblock.operations == ():
+ break
+ block = nextblock
+ last_op = block.operations[-1]
+ assert last_op.opname == 'direct_call'
+ c_ll_func = last_op.args[0]
+ #
+ args = [c_ll_func] + op.args[2:]
+ ops = self.rewrite_op_direct_call(SpaceOperation('direct_call',
+ args, op.result))
+ return [op1] + ops + [op2]
+
def rewrite_op_ll_read_timestamp(self, op):
op1 = self.prepare_builtin_call(op, "ll_read_timestamp", [])
return self.handle_residual_call(op1,
diff --git a/rpython/jit/codewriter/test/test_flatten.py
b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -14,7 +14,7 @@
from rpython.rlib.rarithmetic import ovfcheck, r_uint, r_longlong, r_ulonglong
from rpython.rlib.jit import dont_look_inside, _we_are_jitted, JitDriver
from rpython.rlib.objectmodel import keepalive_until_here
-from rpython.rlib import jit
+from rpython.rlib import jit, debug
class FakeRegAlloc:
@@ -140,7 +140,6 @@
def encoding_test(self, func, args, expected,
transform=False, liveness=False, cc=None, jd=None):
-
graphs = self.make_graphs(func, args)
#graphs[0].show()
if transform:
@@ -1112,6 +1111,31 @@
assert str(e.value).startswith("A virtualizable array is passed aroun")
assert "<Descr>" in str(e.value)
+ def test_rvmprof_code(self):
+ from rpython.rlib.rvmprof import cintf
+ class MyFakeCallControl(FakeCallControl):
+ def guess_call_kind(self, op):
+ if 'jitted' in repr(op):
+ return 'builtin'
+ return 'residual'
+ class X:
+ pass
+ def g(x, y):
+ debug.debug_print("foo")
+ return X()
+ @jit.oopspec("rvmprof.jitted(unique_id)")
+ def decorated_jitted_function(unique_id, *args):
+ return g(*args)
+ def f(id, x, y):
+ return decorated_jitted_function(id, x, y)
+ self.encoding_test(f, [42, 56, 74], """
+ rvmprof_code $0, %i0
+ residual_call_ir_r $<* fn g>, I[%i1, %i2], R[], <Descr> -> %r0
+ -live-
+ rvmprof_code $1, %i0
+ ref_return %r0
+ """, transform=True, cc=MyFakeCallControl())
+
def check_force_cast(FROM, TO, operations, value):
"""Check that the test is correctly written..."""
diff --git a/rpython/jit/metainterp/blackhole.py
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -64,6 +64,7 @@
assert self._insns[value] is None
self._insns[value] = key
self.op_catch_exception = insns.get('catch_exception/L', -1)
+ self.op_rvmprof_code = insns.get('rvmprof_code/ii', -1)
#
all_funcs = []
for key in self._insns:
@@ -270,6 +271,7 @@
self.dispatch_loop = builder.dispatch_loop
self.descrs = builder.descrs
self.op_catch_exception = builder.op_catch_exception
+ self.op_rvmprof_code = builder.op_rvmprof_code
self.count_interpreter = count_interpreter
#
if we_are_translated():
@@ -373,9 +375,32 @@
target = ord(code[position+1]) | (ord(code[position+2])<<8)
self.position = target
return
+ if opcode == self.op_rvmprof_code:
+ # call the 'jit_rvmprof_code(1)' for rvmprof, but then
+ # continue popping frames. Decode the 'rvmprof_code' insn
+ # manually here.
+ from rpython.rlib.rvmprof import cintf
+ arg1 = self.registers_i[ord(code[position + 1])]
+ arg2 = self.registers_i[ord(code[position + 2])]
+ assert arg1 == 1
+ cintf.jit_rvmprof_code(arg1, arg2)
# no 'catch_exception' insn follows: just reraise
reraise(e)
+ def handle_rvmprof_enter(self):
+ code = self.jitcode.code
+ position = self.position
+ opcode = ord(code[position])
+ if opcode == self.op_rvmprof_code:
+ arg1 = self.registers_i[ord(code[position + 1])]
+ arg2 = self.registers_i[ord(code[position + 2])]
+ if arg1 == 1:
+ # we are resuming at a position that will do a
+ # jit_rvmprof_code(1), when really executed. That's a
+ # hint for the need for a jit_rvmprof_code(0).
+ from rpython.rlib.rvmprof import cintf
+ cintf.jit_rvmprof_code(0, arg2)
+
def copy_constants(self, registers, constants):
"""Copy jitcode.constants[0] to registers[255],
jitcode.constants[1] to registers[254],
@@ -1501,6 +1526,11 @@
def bhimpl_copyunicodecontent(cpu, src, dst, srcstart, dststart, length):
cpu.bh_copyunicodecontent(src, dst, srcstart, dststart, length)
+ @arguments("i", "i")
+ def bhimpl_rvmprof_code(leaving, unique_id):
+ from rpython.rlib.rvmprof import cintf
+ cintf.jit_rvmprof_code(leaving, unique_id)
+
# ----------
# helpers to resume running in blackhole mode when a guard failed
diff --git a/rpython/jit/metainterp/pyjitpl.py
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1453,6 +1453,25 @@
metainterp.history.record(rop.VIRTUAL_REF_FINISH,
[vrefbox, nullbox], None)
+ @arguments("int", "box")
+ def opimpl_rvmprof_code(self, leaving, box_unique_id):
+ from rpython.rlib.rvmprof import cintf
+ cintf.jit_rvmprof_code(leaving, box_unique_id.getint())
+
+ def handle_rvmprof_enter_on_resume(self):
+ code = self.bytecode
+ position = self.pc
+ opcode = ord(code[position])
+ if opcode == self.metainterp.staticdata.op_rvmprof_code:
+ arg1 = self.registers_i[ord(code[position + 1])].getint()
+ arg2 = self.registers_i[ord(code[position + 2])].getint()
+ if arg1 == 1:
+ # we are resuming at a position that will do a
+ # jit_rvmprof_code(1), when really executed. That's a
+ # hint for the need for a jit_rvmprof_code(0).
+ from rpython.rlib.rvmprof import cintf
+ cintf.jit_rvmprof_code(0, arg2)
+
# ------------------------------
def setup_call(self, argboxes):
@@ -1804,6 +1823,7 @@
opimpl = _get_opimpl_method(name, argcodes)
self.opcode_implementations[value] = opimpl
self.op_catch_exception = insns.get('catch_exception/L', -1)
+ self.op_rvmprof_code = insns.get('rvmprof_code/ii', -1)
def setup_descrs(self, descrs):
self.opcode_descrs = descrs
@@ -2071,6 +2091,15 @@
target = ord(code[position+1]) | (ord(code[position+2])<<8)
frame.pc = target
raise ChangeFrame
+ if opcode == self.staticdata.op_rvmprof_code:
+ # call the 'jit_rvmprof_code(1)' for rvmprof, but then
+ # continue popping frames. Decode the 'rvmprof_code' insn
+ # manually here.
+ from rpython.rlib.rvmprof import cintf
+ arg1 = frame.registers_i[ord(code[position + 1])].getint()
+ arg2 = frame.registers_i[ord(code[position + 2])].getint()
+ assert arg1 == 1
+ cintf.jit_rvmprof_code(arg1, arg2)
self.popframe()
try:
self.compile_exit_frame_with_exception(self.last_exc_box)
diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py
--- a/rpython/jit/metainterp/resume.py
+++ b/rpython/jit/metainterp/resume.py
@@ -1058,6 +1058,7 @@
f.setup_resume_at_op(pc)
resumereader.consume_boxes(f.get_current_position_info(),
f.registers_i, f.registers_r, f.registers_f)
+ f.handle_rvmprof_enter_on_resume()
return resumereader.liveboxes, virtualizable_boxes, virtualref_boxes
@@ -1343,6 +1344,7 @@
jitcode = jitcodes[jitcode_pos]
curbh.setposition(jitcode, pc)
resumereader.consume_one_section(curbh)
+ curbh.handle_rvmprof_enter()
return curbh
def force_from_resumedata(metainterp_sd, storage, deadframe, vinfo, ginfo):
diff --git a/rpython/rlib/rstacklet.py b/rpython/rlib/rstacklet.py
--- a/rpython/rlib/rstacklet.py
+++ b/rpython/rlib/rstacklet.py
@@ -3,6 +3,7 @@
from rpython.rlib import jit
from rpython.rlib.objectmodel import fetch_translated_config
from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rlib.rvmprof import cintf
DEBUG = False
@@ -24,7 +25,12 @@
def new(self, callback, arg=llmemory.NULL):
if DEBUG:
callback = _debug_wrapper(callback)
- h = self._gcrootfinder.new(self, callback, arg)
+ x = cintf.save_rvmprof_stack()
+ try:
+ cintf.empty_rvmprof_stack()
+ h = self._gcrootfinder.new(self, callback, arg)
+ finally:
+ cintf.restore_rvmprof_stack(x)
if DEBUG:
debug.add(h)
return h
@@ -34,7 +40,11 @@
def switch(self, stacklet):
if DEBUG:
debug.remove(stacklet)
- h = self._gcrootfinder.switch(stacklet)
+ x = cintf.save_rvmprof_stack()
+ try:
+ h = self._gcrootfinder.switch(stacklet)
+ finally:
+ cintf.restore_rvmprof_stack(x)
if DEBUG:
debug.add(h)
return h
diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py
--- a/rpython/rlib/rvmprof/cintf.py
+++ b/rpython/rlib/rvmprof/cintf.py
@@ -6,7 +6,8 @@
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rtyper.tool import rffi_platform as platform
-from rpython.rlib import rthread
+from rpython.rlib import rthread, jit
+from rpython.rlib.objectmodel import we_are_translated
class VMProfPlatformUnsupported(Exception):
pass
@@ -96,5 +97,60 @@
return s
def leave_code(s):
+ if not we_are_translated():
+ assert vmprof_tl_stack.getraw() == s
vmprof_tl_stack.setraw(s.c_next)
lltype.free(s, flavor='raw')
+
+#
+# JIT notes:
+#
+# - When running JIT-generated assembler code, we have different custom
+# code to build the VMPROFSTACK, so the functions above are not used.
+# (It uses kind == VMPROF_JITTED_TAG and the VMPROFSTACK is allocated
+# in the C stack.)
+#
+# - The jitcode for decorated_jitted_function() in rvmprof.py is
+# special-cased by jtransform.py to produce this:
+#
+# rvmprof_code(0, unique_id)
+# res = inline_call FUNC <- for func(*args)
+# rvmprof_code(1, unique_id)
+# return res
+#
+# There is no 'catch_exception', but the second 'rvmprof_code' is
+# meant to be executed even in case there was an exception. This is
+# done by a special case in pyjitpl.py and blackhole.py. The point
+# is that the above simple pattern can be detected by the blackhole
+# interp, when it first rebuilds all the intermediate RPython
+# frames; at that point it needs to call jit_rvmprof_code(0) on all
+# intermediate RPython frames, so it does pattern matching to
+# recognize when it must call that and with which 'unique_id' value.
+#
+# - The jitcode opcode 'rvmprof_code' doesn't produce any resop. When
+# meta-interpreting, it causes pyjitpl to call jit_rvmprof_code().
+# As mentioned above, there is logic to call jit_rvmprof_code(1)
+# even if we exit with an exception, even though there is no
+# 'catch_exception'. There is similar logic inside the blackhole
+# interpreter.
+
+
+def jit_rvmprof_code(leaving, unique_id):
+ if leaving == 0:
+ enter_code(unique_id) # ignore the return value
+ else:
+ s = vmprof_tl_stack.getraw()
+ assert s.c_value == unique_id and s.c_kind == VMPROF_CODE_TAG
+ leave_code(s)
+
+#
+# stacklet support
+
+def save_rvmprof_stack():
+ return vmprof_tl_stack.get_or_make_raw()
+
+def empty_rvmprof_stack():
+ vmprof_tl_stack.setraw(lltype.nullptr(VMPROFSTACK))
+
+def restore_rvmprof_stack(x):
+ vmprof_tl_stack.setraw(x)
diff --git a/rpython/rlib/rvmprof/rvmprof.py b/rpython/rlib/rvmprof/rvmprof.py
--- a/rpython/rlib/rvmprof/rvmprof.py
+++ b/rpython/rlib/rvmprof/rvmprof.py
@@ -4,7 +4,7 @@
from rpython.rlib.rvmprof import cintf
from rpython.rtyper.annlowlevel import cast_instance_to_gcref
from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
-from rpython.rtyper.lltypesystem import rffi, llmemory
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rlib.rweaklist import RWeakListMixin
@@ -25,10 +25,16 @@
def __str__(self):
return self.msg
+class FakeWeakCodeObjectList(object):
+ def add_handle(self, handle):
+ pass
+
class VMProf(object):
_immutable_fields_ = ['is_enabled?']
+ use_weaklist = True # False for tests
+
def __init__(self):
"NOT_RPYTHON: use _get_vmprof()"
self._code_classes = set()
@@ -40,6 +46,7 @@
def _cleanup_(self):
self.is_enabled = False
+ @jit.dont_look_inside
@specialize.argtype(1)
def register_code(self, code, full_name_func):
"""Register the code object. Call when a new code object is made.
@@ -56,7 +63,7 @@
self._code_unique_id = uid
if self.is_enabled:
self._write_code_registration(uid, full_name_func(code))
- else:
+ elif self.use_weaklist:
code._vmprof_weak_list.add_handle(code)
def register_code_object_class(self, CodeClass, full_name_func):
@@ -81,12 +88,17 @@
if CodeClass in self._code_classes:
return
CodeClass._vmprof_unique_id = 0 # default value: "unknown"
+ immut = CodeClass.__dict__.get('_immutable_fields_', [])
+ CodeClass._immutable_fields_ = list(immut) + ['_vmprof_unique_id']
self._code_classes.add(CodeClass)
#
class WeakCodeObjectList(RWeakListMixin):
def __init__(self):
self.initialize()
- CodeClass._vmprof_weak_list = WeakCodeObjectList()
+ if self.use_weaklist:
+ CodeClass._vmprof_weak_list = WeakCodeObjectList()
+ else:
+ CodeClass._vmprof_weak_list = FakeWeakCodeObjectList()
#
def gather_all_code_objs():
all_code_wrefs = CodeClass._vmprof_weak_list.get_all_handles()
@@ -102,6 +114,7 @@
prev = self._gather_all_code_objs
self._gather_all_code_objs = gather_all_code_objs
+ @jit.dont_look_inside
def enable(self, fileno, interval):
"""Enable vmprof. Writes go to the given 'fileno'.
The sampling interval is given by 'interval' as a number of
@@ -122,6 +135,7 @@
raise VMProfError(os.strerror(rposix.get_saved_errno()))
self.is_enabled = True
+ @jit.dont_look_inside
def disable(self):
"""Disable vmprof.
Raises VMProfError if something goes wrong.
@@ -140,7 +154,8 @@
if self.cintf.vmprof_register_virtual_function(name, uid, 500000) < 0:
raise VMProfError("vmprof buffers full! disk full or too slow")
-def vmprof_execute_code(name, get_code_fn, result_class=None):
+def vmprof_execute_code(name, get_code_fn, result_class=None,
+ _hack_update_stack_untranslated=False):
"""Decorator to be used on the function that interprets a code object.
'name' must be a unique name.
@@ -150,24 +165,40 @@
'result_class' is ignored (backward compatibility).
"""
+ if _hack_update_stack_untranslated:
+ from rpython.rtyper.annlowlevel import llhelper
+ enter_code = llhelper(lltype.Ptr(
+ lltype.FuncType([lltype.Signed], cintf.PVMPROFSTACK)),
+ cintf.enter_code)
+ leave_code = llhelper(lltype.Ptr(
+ lltype.FuncType([cintf.PVMPROFSTACK], lltype.Void)),
+ cintf.leave_code)
+ else:
+ enter_code = cintf.enter_code
+ leave_code = cintf.leave_code
+
def decorate(func):
try:
_get_vmprof()
except cintf.VMProfPlatformUnsupported:
return func
+ @jit.oopspec("rvmprof.jitted(unique_id)")
+ def decorated_jitted_function(unique_id, *args):
+ return func(*args)
+
def decorated_function(*args):
- # If we are being JITted, we want to skip the trampoline, else the
- # JIT cannot see through it.
+ unique_id = get_code_fn(*args)._vmprof_unique_id
+ unique_id = rffi.cast(lltype.Signed, unique_id)
+ # ^^^ removes the "known non-negative" hint for annotation
if not jit.we_are_jitted():
- unique_id = get_code_fn(*args)._vmprof_unique_id
- x = cintf.enter_code(unique_id)
+ x = enter_code(unique_id)
try:
return func(*args)
finally:
- cintf.leave_code(x)
+ leave_code(x)
else:
- return func(*args)
+ return decorated_jitted_function(unique_id, *args)
decorated_function.__name__ = func.__name__ + '_rvmprof'
return decorated_function
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit