[pypy-commit] pypy even-more-jit-hooks: a bit no idea how to test it, but expose stats at applevel
fijal
noreply at buildbot.pypy.org
Sat Jul 7 18:34:10 CEST 2012
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: even-more-jit-hooks
Changeset: r55971:b6bb3e8bd394
Date: 2012-07-07 18:33 +0200
http://bitbucket.org/pypy/pypy/changeset/b6bb3e8bd394/
Log: a bit no idea how to test it, but expose stats at applevel
diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py
--- a/pypy/module/pypyjit/__init__.py
+++ b/pypy/module/pypyjit/__init__.py
@@ -10,8 +10,12 @@
'set_compile_hook': 'interp_resop.set_compile_hook',
'set_optimize_hook': 'interp_resop.set_optimize_hook',
'set_abort_hook': 'interp_resop.set_abort_hook',
+ 'get_stats_snapshot': 'interp_resop.get_stats_snapshot',
+ 'enable_debug': 'interp_resop.enable_debug',
+ 'disable_debug': 'interp_resop.disable_debug',
'ResOperation': 'interp_resop.WrappedOp',
'DebugMergePoint': 'interp_resop.DebugMergePoint',
+ 'JitLoopInfo': 'interp_resop.W_JitLoopInfo',
'Box': 'interp_resop.WrappedBox',
'PARAMETER_DOCS': 'space.wrap(pypy.rlib.jit.PARAMETER_DOCS)',
}
diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py
--- a/pypy/module/pypyjit/interp_resop.py
+++ b/pypy/module/pypyjit/interp_resop.py
@@ -11,16 +11,22 @@
from pypy.jit.metainterp.resoperation import rop, AbstractResOp
from pypy.rlib.nonconst import NonConstant
from pypy.rlib import jit_hooks
+from pypy.rlib.jit import Counters
from pypy.module.pypyjit.interp_jit import pypyjitdriver
class Cache(object):
in_recursion = False
+ no = 0
def __init__(self, space):
self.w_compile_hook = space.w_None
self.w_abort_hook = space.w_None
self.w_optimize_hook = space.w_None
+ def getno(self):
+ self.no += 1
+ return self.no - 1
+
def wrap_greenkey(space, jitdriver, greenkey, greenkey_repr):
if greenkey is None:
return space.w_None
@@ -40,26 +46,9 @@
""" set_compile_hook(hook)
Set a compiling hook that will be called each time a loop is compiled.
- The hook will be called with the following signature:
- hook(jitdriver_name, loop_type, greenkey or guard_number, operations,
- loopno, assembler_addr, assembler_length)
- assembler_addr, assembler_length)
- jitdriver_name is the name of this particular jitdriver, 'pypyjit' is
- the main interpreter loop
-
- loop_type can be either `loop` `entry_bridge` or `bridge`
- in case loop is not `bridge`, greenkey will be a tuple of constants
- or a string describing it.
-
- for the main interpreter loop` it'll be a tuple
- (code, offset, is_being_profiled)
-
- assembler_addr is an integer describing where assembler starts,
- can be accessed via ctypes, assembler_lenght is the lenght of compiled
- asm
-
- loopno is the unique loop identifier (int)
+ The hook will be called with the pypyjit.JitLoopInfo object. Refer to it's
+ docstring for details.
Note that jit hook is not reentrant. It means that if the code
inside the jit hook is itself jitted, it will get compiled, but the
@@ -76,25 +65,8 @@
but before assembler compilation. This allows to add additional
optimizations on Python level.
- The hook will be called with the following signature:
- hook(jitdriver_name, loop_type, greenkey or guard_number, operations,
- loopno)
-
- jitdriver_name is the name of this particular jitdriver, 'pypyjit' is
- the main interpreter loop
-
- loop_type can be either `loop` `entry_bridge` or `bridge`
- in case loop is not `bridge`, greenkey will be a tuple of constants
- or a string describing it.
-
- for the interpreter loop` it'll be a tuple
- (code, offset, is_being_profiled)
-
- Note that jit hook is not reentrant. It means that if the code
- inside the jit hook is itself jitted, it will get compiled, but the
- jit hook won't be called for that.
-
- loopno is the unique loop identifier (int)
+ The hook will be called with the pypyjit.JitLoopInfo object. Refer to it's
+ docstring for details.
Result value will be the resulting list of operations, or None
"""
@@ -304,7 +276,7 @@
debug_info.get_jitdriver(),
debug_info.greenkey,
debug_info.get_greenkey_repr())
- self.loop_no = debug_info.looptoken.number
+ self.loop_no = space.fromcache(Cache).getno()
asminfo = debug_info.asminfo
if asminfo is not None:
self.asmaddr = asminfo.asmaddr
@@ -324,12 +296,79 @@
__doc__ = W_JitLoopInfo.__doc__,
jitdriver_name = interp_attrproperty('jd_name', cls=W_JitLoopInfo,
doc="Name of the JitDriver, pypyjit for the main one"),
- greenkey = interp_attrproperty_w('w_green_key', cls=W_JitLoopInfo,
+ greenkey = interp_attrproperty_w('w_green_key', cls=W_JitLoopInfo,
doc="Representation of place where the loop was compiled. "
"In the case of the main interpreter loop, it's a triplet "
"(code, ofs, is_profiled)"),
- operations = interp_attrproperty_w('w_ops', cls=W_JitLoopInfo, doc=
- "List of operations in this loop."),
+ operations = interp_attrproperty_w('w_ops', cls=W_JitLoopInfo, doc=
+ "List of operations in this loop."),
+ loop_no = interp_attrproperty('loop_no', cls=W_JitLoopInfo, doc=
+ "Loop cardinal number"),
__repr__ = interp2app(W_JitLoopInfo.descr_repr),
)
W_JitLoopInfo.acceptable_as_base_class = False
+
+class W_JitInfoSnapshot(Wrappable):
+ def __init__(self, space, w_times, w_counters, w_counter_times):
+ self.w_loop_run_times = w_times
+ self.w_counters = w_counters
+ self.w_counter_times = w_counter_times
+
+W_JitInfoSnapshot.typedef = TypeDef(
+ "JitInfoSnapshot",
+ w_loop_run_times = interp_attrproperty_w("w_loop_run_times",
+ cls=W_JitInfoSnapshot),
+ w_counters = interp_attrproperty_w("w_counters",
+ cls=W_JitInfoSnapshot,
+ doc="various JIT counters"),
+ w_counter_times = interp_attrproperty_w("w_counter_times",
+ cls=W_JitInfoSnapshot,
+ doc="various JIT timers")
+)
+W_JitInfoSnapshot.acceptable_as_base_class = False
+
+def get_stats_snapshot(space):
+ """ Get the jit status in the specific moment in time. Note that this
+ is eager - the attribute access is not lazy, if you need new stats
+ you need to call this function again.
+ """
+ stats = jit_hooks.get_stats()
+ if not stats:
+ raise OperationError(space.w_TypeError, space.wrap(
+ "JIT not enabled, not stats available"))
+ ll_times = jit_hooks.stats_get_loop_run_times(stats)
+ w_times = space.newdict()
+ for i in range(len(ll_times)):
+ space.setitem(w_times, space.wrap(ll_times[i].number),
+ space.wrap(ll_times[i].counter))
+ w_counters = space.newdict()
+ for i, counter_name in enumerate(Counters.counter_names):
+ v = jit_hooks.stats_get_counter_value(stats, i)
+ space.setitem_str(w_counters, counter_name, space.wrap(v))
+ w_counter_times = space.newdict()
+ tr_time = jit_hooks.stats_get_times_value(stats, Counters.TRACING)
+ space.setitem_str(w_counter_times, 'TRACING', space.wrap(tr_time))
+ b_time = jit_hooks.stats_get_times_value(stats, Counters.BACKEND)
+ space.setitem_str(w_counter_times, 'BACKEND', space.wrap(b_time))
+ return space.wrap(W_JitInfoSnapshot(space, w_times, w_counters,
+ w_counter_times))
+
+def enable_debug(space):
+ """ Set the jit debugging - completely necessary for some stats to work,
+ most notably assembler counters.
+ """
+ stats = jit_hooks.get_stats()
+ if not stats:
+ raise OperationError(space.w_TypeError, space.wrap(
+ "JIT not enabled, not stats available"))
+ jit_hooks.stats_set_debug(stats, True)
+
+def disable_debug(space):
+ """ Disable the jit debugging. This means some very small loops will be
+ marginally faster and the counters will stop working.
+ """
+ stats = jit_hooks.get_stats()
+ if not stats:
+ raise OperationError(space.w_TypeError, space.wrap(
+ "JIT not enabled, not stats available"))
+ jit_hooks.stats_set_debug(stats, False)
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py
--- a/pypy/module/pypyjit/test/test_jit_hook.py
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -94,6 +94,7 @@
cls.w_dmp_num = space.wrap(rop.DEBUG_MERGE_POINT)
cls.w_on_optimize = space.wrap(interp2app(interp_on_optimize))
cls.orig_oplist = oplist
+ cls.w_sorted_keys = space.wrap(sorted(Counters.counter_names))
def setup_method(self, meth):
self.__class__.oplist = self.orig_oplist[:]
@@ -115,6 +116,7 @@
assert info.greenkey[0].co_name == 'function'
assert info.greenkey[1] == 0
assert info.greenkey[2] == False
+ assert info.loop_no == 0
assert len(info.operations) == 4
int_add = info.operations[0]
dmp = info.operations[1]
@@ -237,3 +239,13 @@
op = DebugMergePoint([Box(0)], 'repr', 'notmain', 5, 4, ('str',))
raises(AttributeError, 'op.pycode')
assert op.call_depth == 5
+
+ def test_get_stats_snapshot(self):
+ skip("a bit no idea how to test it")
+ from pypyjit import get_stats_snapshot
+
+ stats = get_stats_snapshot() # we can't do much here, unfortunately
+ assert stats.w_loop_run_times == []
+ assert isinstance(stats.w_counters, dict)
+ assert sorted(stats.w_counters.keys()) == self.sorted_keys
+
diff --git a/pypy/rlib/jit_hooks.py b/pypy/rlib/jit_hooks.py
--- a/pypy/rlib/jit_hooks.py
+++ b/pypy/rlib/jit_hooks.py
@@ -136,10 +136,14 @@
def stats_set_debug(llref, flag):
return _cast_to_warmrunnerdesc(llref).metainterp_sd.cpu.set_debug(flag)
- at register_helper(annmodel.SomeFloat())
+ at register_helper(annmodel.SomeInteger())
def stats_get_counter_value(llref, no):
return _cast_to_warmrunnerdesc(llref).metainterp_sd.profiler.get_counter(no)
+ at register_helper(annmodel.SomeFloat())
+def stats_get_times_value(llref, no):
+ return _cast_to_warmrunnerdesc(llref).metainterp_sd.profiler.times[no]
+
LOOP_RUN_CONTAINER = lltype.GcArray(lltype.Struct('elem',
('type', lltype.Char),
('number', lltype.Signed),
More information about the pypy-commit
mailing list