[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