[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