[pypy-commit] pypy reverse-debugger: Change the API of get_unique_id(), start implementing it

arigo pypy.commits at gmail.com
Tue Jun 14 14:06:30 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85166:b0f1d132948c
Date: 2016-06-14 20:07 +0200
http://bitbucket.org/pypy/pypy/changeset/b0f1d132948c/

Log:	Change the API of get_unique_id(), start implementing it

diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py
--- a/rpython/memory/gctransform/boehm.py
+++ b/rpython/memory/gctransform/boehm.py
@@ -29,7 +29,7 @@
 
         fields = [("hash", lltype.Signed)]
         if translator.config.translation.reverse_debugger:
-            fields.append(("ctime", lltype.SignedLongLong))
+            fields.append(("uid", lltype.SignedLongLong))
         self.HDR = lltype.Struct("header", *fields)
         HDRPTR = lltype.Ptr(self.HDR)
 
diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -1,12 +1,11 @@
 import sys
 from rpython.rlib.objectmodel import we_are_translated, fetch_translated_config
 from rpython.rlib.objectmodel import specialize
-from rpython.rtyper.lltypesystem import lltype, rstr
+from rpython.rtyper.lltypesystem import lltype, llmemory, rstr
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper.extregistry import ExtRegistryEntry
 from rpython.rtyper.annlowlevel import llhelper, hlstr
-from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
-from rpython.rtyper.rclass import OBJECTPTR
+from rpython.rtyper.annlowlevel import cast_gcref_to_instance
 
 
 def stop_point():
@@ -45,24 +44,6 @@
     as the total number of stop-points)."""
     return llop.revdb_get_value(lltype.SignedLongLong, 't')
 
- at specialize.argtype(0)
-def creation_time_of(x):
-    """Returns the time at which the object 'x' was created.
-    More precisely, returns t such that object 'x' was created when
-    current_time()==t; this means that the object exists at the stop
-    point number t+1, but does not exist yet at the stop point number t.
-    """
-    return llop.revdb_creation_time_of(lltype.SignedLongLong, x)
-
- at specialize.argtype(0)
-def object_to_id(x):
-    return llop.revdb_object_to_id(lltype.Signed, x)
-
- at specialize.arg(0)
-def id_to_object(Class, object_id):
-    x = llop.revdb_id_to_object(OBJECTPTR, object_id)
-    return cast_base_ptr_to_instance(Class, x)
-
 @specialize.arg(1)
 def go_forward(time_delta, callback, arg_string):
     """For RPython debug commands: tells that after this function finishes,
@@ -81,6 +62,46 @@
     """
     _change_time('g', target_time, callback, arg_string)
 
+def currently_created_objects():
+    """For RPython debug commands: returns the current value of
+    the object creation counter.  All objects created so far have
+    a lower unique id; all objects created afterwards will have a
+    unique id greater or equal."""
+    return llop.revdb_get_value(lltype.SignedLongLong, 'u')
+
+ at specialize.argtype(0)
+def get_unique_id(x):
+    """Returns the creation number of the object 'x'.  For objects created
+    by the program, it is globally unique, monotonic, and reproducible
+    among multiple processes.  For objects created by a debug command,
+    this returns a (random) negative number.  Right now, this returns 0
+    for all prebuilt objects.
+    """
+    return llop.revdb_get_unique_id(lltype.SignedLongLong, x)
+
+def track_objects(unique_id):
+    """Track the creation of the object given by its unique_id, which must
+    be in the future (i.e. >= currently_created_objects()).  Call this
+    before go_forward().  If go_forward() goes over the creation of this
+    object, then afterwards, get_tracked_object() returns the object.
+    Going forward is also interrupted at the following stop point.
+    """
+    return llop.revdb_track_object(lltype.Bool, x)
+
+ at specialize.arg(0)
+def get_tracked_object(Class=llmemory.GCREF):   # or an RPython class
+    """Get the tracked object if it was created during the last go_forward().
+    Otherwise, returns None.  (Note: this API is minimal: to get an
+    object from its unique id, you need first to search backward for a
+    time where currently_created_objects() is lower than the unique_id,
+    then use track_object() and go_forward() to come back.  You can't
+    really track several objects, only one.)
+    """
+    x = llop.revdb_get_tracked_object(llmemory.GCREF)
+    if Class is llmemory.GCREF:
+        return x
+    return cast_gcref_to_instance(Class, x)
+
 
 # ____________________________________________________________
 
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -571,9 +571,9 @@
     'revdb_get_value':      LLOp(sideeffects=False),
     'revdb_set_value':      LLOp(),
     'revdb_identityhash':   LLOp(),
-    'revdb_creation_time_of': LLOp(sideeffects=False),
-    'revdb_object_to_id':   LLOp(sideeffects=False),
-    'revdb_id_to_object':   LLOp(sideeffects=False),
+    'revdb_get_unique_id':  LLOp(sideeffects=False),
+    'revdb_track_object':   LLOp(),
+    'revdb_get_tracked_object': LLOp(sideeffects=False),
 }
 # ***** Run test_lloperation after changes. *****
 
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -586,7 +586,7 @@
             is_atomic)
         if self.db.reverse_debugger:
             from rpython.translator.revdb import revdb_genc
-            res += revdb_genc.record_malloc_ctime(expr_result)
+            res += revdb_genc.record_malloc_uid(expr_result)
         return res
 
     def OP_BOEHM_MALLOC(self, op):
diff --git a/rpython/translator/revdb/revdb_genc.py b/rpython/translator/revdb/revdb_genc.py
--- a/rpython/translator/revdb/revdb_genc.py
+++ b/rpython/translator/revdb/revdb_genc.py
@@ -18,8 +18,8 @@
         return emit_void(normal_code)
     return 'RPY_REVDB_EMIT(%s, %s, %s);' % (normal_code, cdecl(tp, '_e'), value)
 
-def record_malloc_ctime(expr):
-    return ' RPY_REVDB_REC_CTIME(%s);' % (expr,)
+def record_malloc_uid(expr):
+    return ' RPY_REVDB_REC_UID(%s);' % (expr,)
 
 
 def prepare_database(db):
diff --git a/rpython/translator/revdb/src-revdb/revdb.c b/rpython/translator/revdb/src-revdb/revdb.c
--- a/rpython/translator/revdb/src-revdb/revdb.c
+++ b/rpython/translator/revdb/src-revdb/revdb.c
@@ -104,6 +104,7 @@
     assert(RPY_RDB_REPLAY == 0);
     rpy_revdb.buf_p = rpy_rev_buffer;
     rpy_revdb.buf_limit = rpy_rev_buffer + sizeof(rpy_rev_buffer) - 32;
+    rpy_revdb.unique_id_seen = 1;
 
     if (filename && *filename) {
         putenv("PYPYRDB=");
@@ -225,6 +226,7 @@
 static uint64_t most_recent_fork;
 static uint64_t total_stop_points;
 static uint64_t stopped_time;
+static uint64_t stopped_uid;
 
 static void (*invoke_after_forward)(RPyString *);
 static RPyString *invoke_argument;
@@ -324,6 +326,7 @@
     rpy_revdb.buf_p = rpy_rev_buffer;
     rpy_revdb.buf_limit = rpy_rev_buffer;
     rpy_revdb.stop_point_break = 1;
+    rpy_revdb.unique_id_seen = 1;
 
     if (pipe(frozen_pipe_signal) < 0) {
         perror("pipe");
@@ -781,6 +784,8 @@
     };
     while (rpy_revdb.stop_point_break == rpy_revdb.stop_point_seen) {
         stopped_time = rpy_revdb.stop_point_seen;
+        stopped_uid = rpy_revdb.unique_id_seen;
+        rpy_revdb.unique_id_seen = (-1ULL) << 63;
         if (invoke_after_forward != NULL) {
             execute_rpy_function(invoke_after_forward, invoke_argument);
         }
@@ -795,7 +800,9 @@
             }
             process_input(input, "command", 1, actions_1);
         }
+        rpy_revdb.unique_id_seen = stopped_uid;
         stopped_time = 0;
+        stopped_uid = 0;
     }
 }
 
@@ -856,12 +863,21 @@
         return most_recent_fork;
     case 't':       /* total_time() */
         return total_stop_points;
-    case 'b':
+    case 'b':       /* current_break_time() */
         return rpy_revdb.stop_point_break;
+    case 'u':       /* currently_created_objects() */
+        return stopped_uid ? stopped_uid : rpy_revdb.unique_id_seen;
     default:
         return -1;
     }
 }
 
+RPY_EXTERN
+uint64_t rpy_reverse_db_unique_id_break(void *new_object)
+{
+    fprintf(stderr, "PING\n");
+    abort();
+}
+
 
 /* ------------------------------------------------------------ */
diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h b/rpython/translator/revdb/src-revdb/revdb_include.h
--- a/rpython/translator/revdb/src-revdb/revdb_include.h
+++ b/rpython/translator/revdb/src-revdb/revdb_include.h
@@ -18,6 +18,7 @@
 #endif
     char *buf_p, *buf_limit;
     uint64_t stop_point_seen, stop_point_break;
+    uint64_t unique_id_seen, unique_id_break;
 } rpy_revdb_t;
 
 RPY_EXTERN rpy_revdb_t rpy_revdb;
@@ -67,10 +68,14 @@
 #define RPY_REVDB_EMIT_VOID(normal_code)                                \
     if (!RPY_RDB_REPLAY) { normal_code } else { }
 
-#define RPY_REVDB_REC_CTIME(expr)                                       \
-    if (expr)                                                           \
-        ((struct pypy_header0 *)expr)->h_ctime = rpy_revdb.stop_point_seen
-
+#define RPY_REVDB_REC_UID(expr)                                         \
+    do {                                                                \
+        uint64_t uid = rpy_revdb.unique_id_seen;                        \
+        if (uid == rpy_revdb.unique_id_break || !expr)                  \
+            uid = rpy_reverse_db_unique_id_break(expr);                 \
+        rpy_revdb.unique_id_seen = uid + 1;                             \
+        ((struct pypy_header0 *)expr)->h_uid = uid;                     \
+    } while (0)
 
 #define OP_REVDB_STOP_POINT(r)                                          \
     if (++rpy_revdb.stop_point_seen == rpy_revdb.stop_point_break)      \
@@ -88,14 +93,8 @@
 #define OP_REVDB_IDENTITYHASH(obj, r)                                   \
     r = rpy_reverse_db_identityhash((struct pypy_header0 *)(obj))
 
-#define OP_REVDB_CREATION_TIME_OF(x, r)                                 \
-    r = ((struct pypy_header0 *)x)->h_ctime
-
-#define OP_REVDB_OBJECT_TO_ID(x, r)                                     \
-    r = (Signed)x
-
-#define OP_REVDB_ID_TO_OBJECT(x, r)                                     \
-    r = (void *)x
+#define OP_REVDB_GET_UNIQUE_ID(x, r)                                    \
+    r = ((struct pypy_header0 *)x)->h_uid
 
 RPY_EXTERN void rpy_reverse_db_flush(void);
 RPY_EXTERN char *rpy_reverse_db_fetch(int expected_size,
@@ -107,6 +106,7 @@
                                            void callback(RPyString *),
                                            RPyString *arg);
 RPY_EXTERN long long rpy_reverse_db_get_value(char value_id);
+RPY_EXTERN uint64_t rpy_reverse_db_unique_id_break(void *new_object);
 
 
 /* ------------------------------------------------------------ */
diff --git a/rpython/translator/revdb/test/test_basic.py b/rpython/translator/revdb/test/test_basic.py
--- a/rpython/translator/revdb/test/test_basic.py
+++ b/rpython/translator/revdb/test/test_basic.py
@@ -337,11 +337,13 @@
             if cmdline == 'set-break-after-0':
                 dbstate.break_after = 0
             if cmdline == 'print-id':
-                revdb.send_output('%d\n' % (revdb.object_to_id(dbstate.stuff),))
-            if cmdline.startswith('check-id '):
-                obj_id = int(cmdline[len('check-id '):])
-                revdb.send_output("%d\n" %
-                    int(revdb.id_to_object(Stuff, obj_id) is dbstate.stuff))
+                revdb.send_output('%d %d\n' % (
+                    revdb.get_unique_id(dbstate.stuff),
+                    revdb.currently_created_objects()))
+            #if cmdline.startswith('check-id '):
+            #    obj_id = int(cmdline[len('check-id '):])
+            #    revdb.send_output("%d\n" %
+            #        int(revdb.id_to_object(Stuff, obj_id) is dbstate.stuff))
             revdb.send_output('blipped\n')
         lambda_blip = lambda: blip
         #
@@ -350,9 +352,10 @@
         dbstate = DBState()
         #
         def main(argv):
-            dbstate.stuff = Stuff()
             revdb.register_debug_command('r', lambda_blip)
             for i, op in enumerate(argv[1:]):
+                dbstate.stuff = Stuff()
+                dbstate.stuff.x = i + 1000
                 revdb.stop_point()
                 if i == dbstate.break_after:
                     revdb.send_output('breakpoint!\n')
@@ -440,6 +443,7 @@
                       '(3)$ ')
 
     def test_dynamic_breakpoint(self):
+        py.test.skip("unsure if that's needed")
         child = self.replay()
         child.expectx('(3)$ ')
         child.sendline('__go 1')
@@ -450,16 +454,19 @@
         child.expectx('breakpoint!\r\n'
                       '(2)$ ')
 
-    def test_object_to_id(self):
+    def test_get_unique_id(self):
         child = self.replay()
         child.expectx('(3)$ ')
         child.sendline('r print-id')
         child.expect(re.escape('<<<print-id>>>\r\n')
-                     + r'(-?\d+)'
+                     + r'(\d+) (\d+)'
                      + re.escape('\r\n'
                                  'blipped\r\n'
                                  '(3)$ '))
-        object_id = child.match.group(1)
+        object_id = int(child.match.group(1))
+        currenty_created_objects = int(child.match.group(2))
+        assert 0 < object_id < currenty_created_objects
+        XXX
         for at_time in [1, 2, 3]:
             child.sendline('__go %d' % at_time)
             child.expectx('(%d)$ ' % at_time)


More information about the pypy-commit mailing list