Author: Armin Rigo <[email protected]>
Branch: improve-vmprof-testing
Changeset: r86052:271af761ce0b
Date: 2016-08-07 09:32 +0200
http://bitbucket.org/pypy/pypy/changeset/271af761ce0b/
Log: in-progress
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,7 +7,73 @@
from rpython.jit.backend.x86.arch import WORD
from rpython.jit.codewriter.policy import JitPolicy
+
class BaseRVMProfTest(object):
+
+ def setup_method(self, meth):
+ visited = []
+
+ def helper():
+ trace = []
+ stack = cintf.vmprof_tl_stack.getraw()
+ 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)
+
+ class CodeObj(object):
+ def __init__(self, name):
+ self.name = name
+
+ 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)
+
+ 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, c=c, i=i, codes=codes, n=n)
+ if code.name == "main":
+ c = f(codes, codes[1], 1, c)
+ driver.can_enter_jit(code=code, c=c, i=i, codes=codes, n=n)
+ else:
+ llfn()
+ c -= 1
+ i += 1
+ return c
+
+ def main(n):
+ 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)
+ 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_one(self):
# py.test.skip("needs thread-locals in the JIT, which is only available
"
# "after translation")
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
@@ -2082,20 +2082,10 @@
raise NotImplementedError(oopspec_name)
def _handle_rvmprof_call(self, op, oopspec_name, args):
- if oopspec_name == 'rvmprof.enter_code':
- leaving = 0
- elif oopspec_name == 'rvmprof.leave_code':
- leaving = 1
- else:
+ if oopspec_name != 'rvmprof.code':
raise NotImplementedError(oopspec_name)
- c_leaving = Constant(leaving, lltype.Signed)
- v_uniqueid = op.args[-1]
- ops = [SpaceOperation('rvmprof_code', [c_leaving, v_uniqueid], None)]
- if op.result.concretetype is not lltype.Void:
- c_null = Constant(lltype.nullptr(op.result.concretetype.TO),
- op.result.concretetype)
- ops.append(c_null)
- return ops
+ c_leaving, v_uniqueid = args
+ return SpaceOperation('rvmprof_code', [c_leaving, v_uniqueid], None)
def rewrite_op_ll_read_timestamp(self, op):
op1 = self.prepare_builtin_call(op, "ll_read_timestamp", [])
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:
@@ -1115,14 +1115,26 @@
from rpython.rlib.rvmprof import cintf
class MyFakeCallControl(FakeCallControl):
def guess_call_kind(self, op):
- return 'builtin'
+ if '_code' in repr(op):
+ return 'builtin'
+ return 'residual'
+ class X:
+ pass
+ def g():
+ debug.debug_print("foo")
+ return X()
+ g._dont_inline_ = True
def f(x):
- s = cintf.enter_code(x)
- cintf.leave_code(s, x)
+ cintf.jit_rvmprof_code(0, x)
+ res = g()
+ cintf.jit_rvmprof_code(1, x)
+ return res
self.encoding_test(f, [42], """
rvmprof_code $0, %i0
+ residual_call_r_r $<* fn g>, R[], <Descr> -> %r0
+ -live-
rvmprof_code $1, %i0
- void_return
+ ref_return %r0
""", transform=True, cc=MyFakeCallControl())
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
@@ -74,6 +74,8 @@
self.parent_snapshot = None
# counter for unrolling inlined loops
self.unroll_iterations = 1
+ # rvmprof
+ self.rvmprof_unique_id = -1
@specialize.arg(3)
def copy_constants(self, registers, constants, ConstClass):
@@ -1456,11 +1458,7 @@
@arguments("int", "box")
def opimpl_rvmprof_code(self, leaving, box_unique_id):
from rpython.rlib.rvmprof import cintf
- unique_id = box_unique_id.getint()
- if not leaving:
- cintf.enter_code(unique_id)
- else:
- cintf.leave_code_check(unique_id)
+ cintf.jit_rvmprof_code(leaving, box_unique_id.getint())
# ------------------------------
@@ -1813,6 +1811,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
@@ -2080,6 +2079,10 @@
target = ord(code[position+1]) | (ord(code[position+2])<<8)
frame.pc = target
raise ChangeFrame
+ if opcode == self.staticdata.op_rvmprof_code:
+ # do the 'leave_code' for rvmprof, but then continue
+ # popping frames
+ import pdb;pdb.set_trace()
self.popframe()
try:
self.compile_exit_frame_with_exception(self.last_exc_box)
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
@@ -86,22 +86,6 @@
ExternalCompilationInfo(includes=['vmprof_stack.h'],
include_dirs = [SRC]))
-# JIT notes:
-#
-# - When running JIT-generated assembler code, we have different custom
-# code to build the VMPROFSTACK, so the functions below are not used.
-#
-# - The jitcode for decorated_function() in rvmprof.py still contains
-# calls to these two oopspec functions, which are represented with
-# the 'rvmprof_code' jitcode opcode.
-#
-# - When meta-interpreting, the 'rvmprof_code' opcode causes pyjitpl
-# to call enter_code()/leave_code_check(), but otherwise
-# 'rvmprof_code' is ignored, i.e. doesn't produce any resop.
-#
-# - Blackhole: ...
-
[email protected]("rvmprof.enter_code(unique_id)")
def enter_code(unique_id):
do_use_eci()
s = lltype.malloc(VMPROFSTACK, flavor='raw')
@@ -111,12 +95,52 @@
vmprof_tl_stack.setraw(s)
return s
[email protected]("rvmprof.leave_code(s, unique_id)")
-def leave_code(s, unique_id):
+def leave_code(s):
vmprof_tl_stack.setraw(s.c_next)
lltype.free(s, flavor='raw')
-def leave_code_check(unique_id):
- s = vmprof_tl_stack.getraw()
- assert s.c_value == unique_id
- leave_code(s, unique_id)
+#
+# 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, if
+# we_are_jitted() calls the oopspec'ed function jit_rvmprof_code(),
+# which turns into a simple jitcode opcode. The jitcode has a
+# simple structure:
+#
+# rvmprof_code(0, unique_id)
+# res = inline_call FUNC
+# rvmprof_code(1, unique_id)
+#
+# with no catch_exception logic for a "finally:" block. Instead the
+# blackhole interp looks for this simple pattern. This is needed
+# because, when a guard fails, the blackhole interp first rebuilds
+# all the intermediate RPython frames; at that point it needs to
+# call enter_code() on all intermediate RPython frames, so it does
+# pattern matching to recognize frames and learn about unique_id.
+#
+# - The jitcode opcode 'rvmprof_code' doesn't produce any resop. When
+# meta-interpreting, it causes pyjitpl to call jit_enter_code(), and
+# jit_leave_code(). There is logic to call jit_leave_code() even if
+# we exit with an exception, even though there is no
+# 'catch_exception'.
+#
+# - When blackholing, the call to jit_enter_code() occurs imediately
+# as described above. For calling jit_leave_code(), we use the same
+# logic, detecting when we need to call it even though there is no
+# 'catch_exception'.
+
[email protected]("rvmprof.code(leaving, unique_id)")
+def jit_rvmprof_code(leaving, unique_id):
+ """Marker for the JIT. Also called directly from the metainterp and
+ the blackhole interp."""
+ if not leaving:
+ enter_code(unique_id) # ignore the return value
+ else:
+ s = vmprof_tl_stack.getraw()
+ assert s.c_value == unique_id
+ leave_code(s)
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
@@ -1,6 +1,6 @@
import sys, os
from rpython.rlib.objectmodel import specialize, we_are_translated
-from rpython.rlib import rposix
+from rpython.rlib import jit, rposix
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
@@ -162,19 +162,12 @@
"""
if _hack_update_stack_untranslated:
from rpython.rtyper.annlowlevel import llhelper
- from rpython.rlib import jit
- enter_code_untr = llhelper(lltype.Ptr(
+ enter_code = llhelper(lltype.Ptr(
lltype.FuncType([lltype.Signed], cintf.PVMPROFSTACK)),
cintf.enter_code)
- leave_code_untr = llhelper(lltype.Ptr(
- lltype.FuncType([cintf.PVMPROFSTACK, lltype.Signed], lltype.Void)),
+ leave_code = llhelper(lltype.Ptr(
+ lltype.FuncType([cintf.PVMPROFSTACK], lltype.Void)),
cintf.leave_code)
- @jit.oopspec("rvmprof.enter_code(unique_id)")
- def enter_code(unique_id):
- return enter_code_untr(unique_id)
- @jit.oopspec("rvmprof.leave_code(s)")
- def leave_code(s, unique_id):
- leave_code_untr(s, unique_id)
else:
enter_code = cintf.enter_code
leave_code = cintf.leave_code
@@ -185,13 +178,24 @@
except cintf.VMProfPlatformUnsupported:
return func
+ def decorated_jitted_function(unique_id, *args):
+ cintf.jit_rvmprof_code(0, unique_id)
+ res = func(*args)
+ cintf.jit_rvmprof_code(1, unique_id) # no 'finally:', see
cintf.py
+ return res
+ decorated_jitted_function._dont_inline_ = True
+
def decorated_function(*args):
unique_id = get_code_fn(*args)._vmprof_unique_id
- x = enter_code(unique_id)
- try:
- return func(*args)
- finally:
- leave_code(x, unique_id)
+ if not jit.we_are_jitted():
+ x = enter_code(unique_id)
+ try:
+ return func(*args)
+ finally:
+ leave_code(x)
+ else:
+ return decorated_jitted_function(unique_id, *args)
+ decorated_function._always_inline_ = True
decorated_function.__name__ = func.__name__ + '_rvmprof'
return decorated_function
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit