[pypy-commit] pypy gc-hooks: add a count stat which counts how many events have been fired since the last time the hook was called; also, make duration cumulative, so that we can know the total time spent in each event since the last hook was called

antocuni pypy.commits at gmail.com
Tue Apr 10 04:47:32 EDT 2018


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: gc-hooks
Changeset: r94302:ada614ebe930
Date: 2018-04-10 10:43 +0200
http://bitbucket.org/pypy/pypy/changeset/ada614ebe930/

Log:	add a count stat which counts how many events have been fired since
	the last time the hook was called; also, make duration cumulative,
	so that we can know the total time spent in each event since the
	last hook was called

diff --git a/pypy/module/gc/hook.py b/pypy/module/gc/hook.py
--- a/pypy/module/gc/hook.py
+++ b/pypy/module/gc/hook.py
@@ -33,14 +33,16 @@
 
     def on_gc_minor(self, duration, total_memory_used, pinned_objects):
         action = self.w_hooks.gc_minor
-        action.duration = duration
+        action.count += 1
+        action.duration += duration
         action.total_memory_used = total_memory_used
         action.pinned_objects = pinned_objects
         action.fire()
 
     def on_gc_collect_step(self, duration, oldstate, newstate):
         action = self.w_hooks.gc_collect_step
-        action.duration = duration
+        action.count += 1
+        action.duration += duration
         action.oldstate = oldstate
         action.newstate = newstate
         action.fire()
@@ -50,6 +52,7 @@
                       arenas_bytes, rawmalloc_bytes_before,
                       rawmalloc_bytes_after):
         action = self.w_hooks.gc_collect
+        action.count += 1
         action.num_major_collects = num_major_collects
         action.arenas_count_before = arenas_count_before
         action.arenas_count_after = arenas_count_after
@@ -109,6 +112,7 @@
 
 
 class GcMinorHookAction(AsyncAction):
+    count = 0
     duration = 0
     total_memory_used = 0
     pinned_objects = 0
@@ -117,11 +121,16 @@
         AsyncAction.__init__(self, space)
         self.w_callable = space.w_None
 
+    def reset(self):
+        self.count = 0
+        self.duration = 0
+
     def fix_annotation(self):
         # the annotation of the class and its attributes must be completed
         # BEFORE we do the gc transform; this makes sure that everything is
         # annotated with the correct types
         if NonConstant(False):
+            self.count = NonConstant(-42)
             self.duration = NonConstant(-42)
             self.total_memory_used = NonConstant(r_uint(42))
             self.pinned_objects = NonConstant(-42)
@@ -129,13 +138,16 @@
 
     def perform(self, ec, frame):
         w_stats = W_GcMinorStats(
+            self.count,
             self.duration,
             self.total_memory_used,
             self.pinned_objects)
+        self.reset()
         self.space.call_function(self.w_callable, w_stats)
 
 
 class GcCollectStepHookAction(AsyncAction):
+    count = 0
     duration = 0
     oldstate = 0
     newstate = 0
@@ -144,11 +156,16 @@
         AsyncAction.__init__(self, space)
         self.w_callable = space.w_None
 
+    def reset(self):
+        self.count = 0
+        self.duration = 0
+
     def fix_annotation(self):
         # the annotation of the class and its attributes must be completed
         # BEFORE we do the gc transform; this makes sure that everything is
         # annotated with the correct types
         if NonConstant(False):
+            self.count = NonConstant(-42)
             self.duration = NonConstant(-42)
             self.oldstate = NonConstant(-42)
             self.newstate = NonConstant(-42)
@@ -156,13 +173,16 @@
 
     def perform(self, ec, frame):
         w_stats = W_GcCollectStepStats(
+            self.count,
             self.duration,
             self.oldstate,
             self.newstate)
+        self.reset()
         self.space.call_function(self.w_callable, w_stats)
 
 
 class GcCollectHookAction(AsyncAction):
+    count = 0
     num_major_collects = 0
     arenas_count_before = 0
     arenas_count_after = 0
@@ -174,11 +194,16 @@
         AsyncAction.__init__(self, space)
         self.w_callable = space.w_None
 
+    def reset(self):
+        self.count = 0
+        self.duration = 0
+
     def fix_annotation(self):
         # the annotation of the class and its attributes must be completed
         # BEFORE we do the gc transform; this makes sure that everything is
         # annotated with the correct types
         if NonConstant(False):
+            self.count = NonConstant(-42)
             self.num_major_collects = NonConstant(-42)
             self.arenas_count_before = NonConstant(-42)
             self.arenas_count_after = NonConstant(-42)
@@ -188,18 +213,21 @@
             self.fire()
 
     def perform(self, ec, frame):
-        w_stats = W_GcCollectStats(self.num_major_collects,
+        w_stats = W_GcCollectStats(self.count,
+                                   self.num_major_collects,
                                    self.arenas_count_before,
                                    self.arenas_count_after,
                                    self.arenas_bytes,
                                    self.rawmalloc_bytes_before,
                                    self.rawmalloc_bytes_after)
+        self.reset()
         self.space.call_function(self.w_callable, w_stats)
 
 
 class W_GcMinorStats(W_Root):
 
-    def __init__(self, duration, total_memory_used, pinned_objects):
+    def __init__(self, count, duration, total_memory_used, pinned_objects):
+        self.count = count
         self.duration = duration
         self.total_memory_used = total_memory_used
         self.pinned_objects = pinned_objects
@@ -207,17 +235,19 @@
 
 class W_GcCollectStepStats(W_Root):
 
-    def __init__(self, duration, oldstate, newstate):
+    def __init__(self, count, duration, oldstate, newstate):
+        self.count = count
         self.duration = duration
         self.oldstate = oldstate
         self.newstate = newstate
 
 
 class W_GcCollectStats(W_Root):
-    def __init__(self, num_major_collects,
+    def __init__(self, count, num_major_collects,
                  arenas_count_before, arenas_count_after,
                  arenas_bytes, rawmalloc_bytes_before,
                  rawmalloc_bytes_after):
+        self.count = count
         self.num_major_collects = num_major_collects
         self.arenas_count_before = arenas_count_before
         self.arenas_count_after = arenas_count_after
@@ -255,6 +285,7 @@
 W_GcMinorStats.typedef = TypeDef(
     "GcMinorStats",
     **wrap_many_ints(W_GcMinorStats, (
+        "count",
         "duration",
         "total_memory_used",
         "pinned_objects"))
@@ -268,6 +299,7 @@
     STATE_FINALIZING = incminimark.STATE_FINALIZING,
     GC_STATES = tuple(incminimark.GC_STATES),
     **wrap_many_ints(W_GcCollectStepStats, (
+        "count",
         "duration",
         "oldstate",
         "newstate"))
@@ -276,6 +308,7 @@
 W_GcCollectStats.typedef = TypeDef(
     "GcCollectStats",
     **wrap_many_ints(W_GcCollectStats, (
+        "count",
         "num_major_collects",
         "arenas_count_before",
         "arenas_count_after",
diff --git a/pypy/module/gc/test/test_hook.py b/pypy/module/gc/test/test_hook.py
--- a/pypy/module/gc/test/test_hook.py
+++ b/pypy/module/gc/test/test_hook.py
@@ -26,8 +26,11 @@
 
         @unwrap_spec(ObjSpace)
         def fire_many(space):
-            gchooks.fire_gc_minor(0, 0, 0)
-            gchooks.fire_gc_collect_step(0, 0, 0)
+            gchooks.fire_gc_minor(5, 0, 0)
+            gchooks.fire_gc_minor(7, 0, 0)
+            gchooks.fire_gc_collect_step(5, 0, 0)
+            gchooks.fire_gc_collect_step(15, 0, 0)
+            gchooks.fire_gc_collect_step(22, 0, 0)
             gchooks.fire_gc_collect(1, 2, 3, 4, 5, 6)
 
         cls.w_fire_gc_minor = space.wrap(interp2app(fire_gc_minor))
@@ -45,49 +48,54 @@
         import gc
         lst = []
         def on_gc_minor(stats):
-            tup = (stats.duration, stats.total_memory_used, stats.pinned_objects)
-            lst.append(tup)
+            lst.append((stats.count,
+                        stats.duration,
+                        stats.total_memory_used,
+                        stats.pinned_objects))
         gc.hooks.on_gc_minor = on_gc_minor
         self.fire_gc_minor(10, 20, 30)
         self.fire_gc_minor(40, 50, 60)
         assert lst == [
-            (10, 20, 30),
-            (40, 50, 60),
+            (1, 10, 20, 30),
+            (1, 40, 50, 60),
             ]
         #
         gc.hooks.on_gc_minor = None
         self.fire_gc_minor(70, 80, 90)  # won't fire because the hooks is disabled
         assert lst == [
-            (10, 20, 30),
-            (40, 50, 60),
+            (1, 10, 20, 30),
+            (1, 40, 50, 60),
             ]
 
     def test_on_gc_collect_step(self):
         import gc
         lst = []
         def on_gc_collect_step(stats):
-            tup = (stats.duration, stats.oldstate, stats.newstate)
-            lst.append(tup)
+            lst.append((stats.count,
+                        stats.duration,
+                        stats.oldstate,
+                        stats.newstate))
         gc.hooks.on_gc_collect_step = on_gc_collect_step
         self.fire_gc_collect_step(10, 20, 30)
         self.fire_gc_collect_step(40, 50, 60)
         assert lst == [
-            (10, 20, 30),
-            (40, 50, 60),
+            (1, 10, 20, 30),
+            (1, 40, 50, 60),
             ]
         #
         gc.hooks.on_gc_collect_step = None
         self.fire_gc_collect_step(70, 80, 90)  # won't fire
         assert lst == [
-            (10, 20, 30),
-            (40, 50, 60),
+            (1, 10, 20, 30),
+            (1, 40, 50, 60),
             ]
 
     def test_on_gc_collect(self):
         import gc
         lst = []
         def on_gc_collect(stats):
-            lst.append((stats.num_major_collects,
+            lst.append((stats.count,
+                        stats.num_major_collects,
                         stats.arenas_count_before,
                         stats.arenas_count_after,
                         stats.arenas_bytes,
@@ -97,15 +105,15 @@
         self.fire_gc_collect(1, 2, 3, 4, 5, 6)
         self.fire_gc_collect(7, 8, 9, 10, 11, 12)
         assert lst == [
-            (1, 2, 3, 4, 5, 6),
-            (7, 8, 9, 10, 11, 12),
+            (1, 1, 2, 3, 4, 5, 6),
+            (1, 7, 8, 9, 10, 11, 12),
             ]
         #
         gc.hooks.on_gc_collect = None
         self.fire_gc_collect(42, 42, 42, 42, 42, 42)  # won't fire
         assert lst == [
-            (1, 2, 3, 4, 5, 6),
-            (7, 8, 9, 10, 11, 12),
+            (1, 1, 2, 3, 4, 5, 6),
+            (1, 7, 8, 9, 10, 11, 12),
             ]
 
     def test_consts(self):
@@ -117,6 +125,28 @@
         assert S.STATE_FINALIZING == 3
         assert S.GC_STATES == ('SCANNING', 'MARKING', 'SWEEPING', 'FINALIZING')
 
+    def test_cumulative(self):
+        import gc
+        class MyHooks(object):
+
+            def __init__(self):
+                self.minors = []
+                self.steps = []
+
+            def on_gc_minor(self, stats):
+                self.minors.append((stats.count, stats.duration))
+
+            def on_gc_collect_step(self, stats):
+                self.steps.append((stats.count, stats.duration))
+
+            on_gc_collect = None
+
+        myhooks = MyHooks()
+        gc.hooks.set(myhooks)
+        self.fire_many()
+        assert myhooks.minors == [(2, 12)]
+        assert myhooks.steps == [(3, 42)]
+
     def test_clear_queue(self):
         import gc
         class MyHooks(object):


More information about the pypy-commit mailing list