#define SGEN_PROTOCOL_EOF 255
+#define TYPE(t) ((t) & 0x7f)
+#define WORKER(t) ((t) & 0x80)
+
static int
read_entry (FILE *in, void **data)
{
if (fread (&type, 1, 1, in) != 1)
return SGEN_PROTOCOL_EOF;
- switch (type) {
- case SGEN_PROTOCOL_COLLECTION: size = sizeof (SGenProtocolCollection); break;
+ switch (TYPE (type)) {
+ case SGEN_PROTOCOL_COLLECTION_FORCE: size = sizeof (SGenProtocolCollectionForce); break;
+ case SGEN_PROTOCOL_COLLECTION_BEGIN: size = sizeof (SGenProtocolCollection); break;
+ case SGEN_PROTOCOL_COLLECTION_END: size = sizeof (SGenProtocolCollection); break;
+ case SGEN_PROTOCOL_CONCURRENT_START: size = 0; break;
+ case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH: size = 0; break;
+ case SGEN_PROTOCOL_WORLD_STOPPING: size = sizeof (SGenProtocolWorldStopping); break;
+ case SGEN_PROTOCOL_WORLD_STOPPED: size = sizeof (SGenProtocolWorldStopped); break;
+ case SGEN_PROTOCOL_WORLD_RESTARTING: size = sizeof (SGenProtocolWorldRestarting); break;
+ case SGEN_PROTOCOL_WORLD_RESTARTED: size = sizeof (SGenProtocolWorldRestarted); break;
case SGEN_PROTOCOL_ALLOC: size = sizeof (SGenProtocolAlloc); break;
case SGEN_PROTOCOL_ALLOC_PINNED: size = sizeof (SGenProtocolAlloc); break;
case SGEN_PROTOCOL_ALLOC_DEGRADED: size = sizeof (SGenProtocolAlloc); break;
case SGEN_PROTOCOL_COPY: size = sizeof (SGenProtocolCopy); break;
case SGEN_PROTOCOL_PIN: size = sizeof (SGenProtocolPin); break;
case SGEN_PROTOCOL_MARK: size = sizeof (SGenProtocolMark); break;
+ case SGEN_PROTOCOL_SCAN_BEGIN: size = sizeof (SGenProtocolScanBegin); break;
+ case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: size = sizeof (SGenProtocolScanVTypeBegin); break;
case SGEN_PROTOCOL_WBARRIER: size = sizeof (SGenProtocolWBarrier); break;
case SGEN_PROTOCOL_GLOBAL_REMSET: size = sizeof (SGenProtocolGlobalRemset); break;
case SGEN_PROTOCOL_PTR_UPDATE: size = sizeof (SGenProtocolPtrUpdate); break;
case SGEN_PROTOCOL_THREAD_REGISTER: size = sizeof (SGenProtocolThreadRegister); break;
case SGEN_PROTOCOL_THREAD_UNREGISTER: size = sizeof (SGenProtocolThreadUnregister); break;
case SGEN_PROTOCOL_MISSING_REMSET: size = sizeof (SGenProtocolMissingRemset); break;
+ case SGEN_PROTOCOL_CARD_SCAN: size = sizeof (SGenProtocolCardScan); break;
+ case SGEN_PROTOCOL_CEMENT: size = sizeof (SGenProtocolCement); break;
+ case SGEN_PROTOCOL_CEMENT_RESET: size = 0; break;
+ case SGEN_PROTOCOL_DISLINK_UPDATE: size = sizeof (SGenProtocolDislinkUpdate); break;
+ case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: size = sizeof (SGenProtocolDislinkUpdateStaged); break;
+ case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: size = sizeof (SGenProtocolDislinkProcessStaged); break;
+ case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN: size = sizeof (SGenProtocolDomainUnload); break;
+ case SGEN_PROTOCOL_DOMAIN_UNLOAD_END: size = sizeof (SGenProtocolDomainUnload); break;
+ case SGEN_PROTOCOL_GRAY_ENQUEUE: size = sizeof (SGenProtocolGrayQueue); break;
+ case SGEN_PROTOCOL_GRAY_DEQUEUE: size = sizeof (SGenProtocolGrayQueue); break;
default: assert (0);
}
- *data = malloc (size);
- if (fread (*data, size, 1, in) != 1)
- assert (0);
+ if (size) {
+ *data = malloc (size);
+ if (fread (*data, size, 1, in) != 1)
+ assert (0);
+ } else {
+ *data = NULL;
+ }
return (int)type;
}
+static gboolean
+is_always_match (int type)
+{
+ switch (TYPE (type)) {
+ case SGEN_PROTOCOL_COLLECTION_FORCE:
+ case SGEN_PROTOCOL_COLLECTION_BEGIN:
+ case SGEN_PROTOCOL_COLLECTION_END:
+ case SGEN_PROTOCOL_CONCURRENT_START:
+ case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH:
+ case SGEN_PROTOCOL_WORLD_STOPPING:
+ case SGEN_PROTOCOL_WORLD_STOPPED:
+ case SGEN_PROTOCOL_WORLD_RESTARTING:
+ case SGEN_PROTOCOL_WORLD_RESTARTED:
+ case SGEN_PROTOCOL_THREAD_SUSPEND:
+ case SGEN_PROTOCOL_THREAD_RESTART:
+ case SGEN_PROTOCOL_THREAD_REGISTER:
+ case SGEN_PROTOCOL_THREAD_UNREGISTER:
+ case SGEN_PROTOCOL_CEMENT_RESET:
+ case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN:
+ case SGEN_PROTOCOL_DOMAIN_UNLOAD_END:
+ case SGEN_PROTOCOL_GRAY_ENQUEUE:
+ case SGEN_PROTOCOL_GRAY_DEQUEUE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+#define WORKER_PREFIX(t) (WORKER ((t)) ? "w" : " ")
+
static void
print_entry (int type, void *data)
{
- switch (type) {
- case SGEN_PROTOCOL_COLLECTION: {
+ const char *always_prefix = is_always_match (type) ? " " : "";
+ printf ("%s%s ", WORKER_PREFIX (type), always_prefix);
+
+ switch (TYPE (type)) {
+ case SGEN_PROTOCOL_COLLECTION_FORCE: {
+ SGenProtocolCollectionForce *entry = data;
+ printf ("collection force generation %d\n", entry->generation);
+ break;
+ }
+ case SGEN_PROTOCOL_COLLECTION_BEGIN: {
+ SGenProtocolCollection *entry = data;
+ printf ("collection begin %d generation %d\n", entry->index, entry->generation);
+ break;
+ }
+ case SGEN_PROTOCOL_COLLECTION_END: {
SGenProtocolCollection *entry = data;
- printf ("collection %d generation %d\n", entry->index, entry->generation);
+ printf ("collection end %d generation %d\n", entry->index, entry->generation);
+ break;
+ }
+ case SGEN_PROTOCOL_CONCURRENT_START: {
+ printf ("concurrent start\n");
+ break;
+ }
+ case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH: {
+ printf ("concurrent update or finish\n");
+ break;
+ }
+ case SGEN_PROTOCOL_WORLD_STOPPING: {
+ SGenProtocolWorldStopping *entry = data;
+ printf ("world stopping timestamp %lld\n", entry->timestamp);
+ break;
+ }
+ case SGEN_PROTOCOL_WORLD_STOPPED: {
+ SGenProtocolWorldStopped *entry = data;
+ long long total = entry->total_major_cards + entry->total_los_cards;
+ long long marked = entry->marked_major_cards + entry->marked_los_cards;
+ printf ("world stopped timestamp %lld total %lld marked %lld %0.2f%%\n", entry->timestamp, total, marked, 100.0 * (double) marked / (double) total);
+ break;
+ }
+ case SGEN_PROTOCOL_WORLD_RESTARTING: {
+ SGenProtocolWorldRestarting *entry = data;
+ long long total = entry->total_major_cards + entry->total_los_cards;
+ long long marked = entry->marked_major_cards + entry->marked_los_cards;
+ printf ("world restarting generation %d timestamp %lld total %lld marked %lld %0.2f%%\n", entry->generation, entry->timestamp, total, marked, 100.0 * (double) marked / (double) total);
+ break;
+ }
+ case SGEN_PROTOCOL_WORLD_RESTARTED: {
+ SGenProtocolWorldRestarted *entry = data;
+ printf ("world restarted generation %d timestamp %lld\n", entry->generation, entry->timestamp);
break;
}
case SGEN_PROTOCOL_ALLOC: {
printf ("mark obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
break;
}
+ case SGEN_PROTOCOL_SCAN_BEGIN: {
+ SGenProtocolScanBegin *entry = data;
+ printf ("scan_begin obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
+ break;
+ }
+ case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
+ SGenProtocolScanVTypeBegin *entry = data;
+ printf ("scan_vtype_begin obj %p size %d\n", entry->obj, entry->size);
+ break;
+ }
case SGEN_PROTOCOL_WBARRIER: {
SGenProtocolWBarrier *entry = data;
printf ("wbarrier ptr %p value %p value_vtable %p\n", entry->ptr, entry->value, entry->value_vtable);
entry->obj, entry->obj_vtable, entry->offset, entry->value, entry->value_vtable, entry->value_pinned);
break;
}
+ case SGEN_PROTOCOL_CARD_SCAN: {
+ SGenProtocolCardScan *entry = data;
+ printf ("card_scan start %p size %d\n", entry->start, entry->size);
+ break;
+ }
+ case SGEN_PROTOCOL_CEMENT: {
+ SGenProtocolCement *entry = data;
+ printf ("cement obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
+ break;
+ }
+ case SGEN_PROTOCOL_CEMENT_RESET: {
+ printf ("cement_reset\n");
+ break;
+ }
+ case SGEN_PROTOCOL_DISLINK_UPDATE: {
+ SGenProtocolDislinkUpdate *entry = data;
+ printf ("dislink_update link %p obj %p staged %d", entry->link, entry->obj, entry->staged);
+ if (entry->obj)
+ printf (" track %d\n", entry->track);
+ else
+ printf ("\n");
+ break;
+ }
+ case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
+ SGenProtocolDislinkUpdateStaged *entry = data;
+ printf ("dislink_update_staged link %p obj %p index %d", entry->link, entry->obj, entry->index);
+ if (entry->obj)
+ printf (" track %d\n", entry->track);
+ else
+ printf ("\n");
+ break;
+ }
+ case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
+ SGenProtocolDislinkProcessStaged *entry = data;
+ printf ("dislink_process_staged link %p obj %p index %d\n", entry->link, entry->obj, entry->index);
+ break;
+ }
+ case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN: {
+ SGenProtocolDomainUnload *entry = data;
+ printf ("dislink_unload_begin domain %p\n", entry->domain);
+ break;
+ }
+ case SGEN_PROTOCOL_DOMAIN_UNLOAD_END: {
+ SGenProtocolDomainUnload *entry = data;
+ printf ("dislink_unload_end domain %p\n", entry->domain);
+ break;
+ }
+ case SGEN_PROTOCOL_GRAY_ENQUEUE: {
+ SGenProtocolGrayQueue *entry = data;
+ printf ("enqueue queue %p cursor %p value %p\n", entry->queue, entry->cursor, entry->value);
+ break;
+ }
+ case SGEN_PROTOCOL_GRAY_DEQUEUE: {
+ SGenProtocolGrayQueue *entry = data;
+ printf ("dequeue queue %p cursor %p value %p\n", entry->queue, entry->cursor, entry->value);
+ break;
+ }
default:
assert (0);
}
static gboolean
is_match (gpointer ptr, int type, void *data)
{
- switch (type) {
- case SGEN_PROTOCOL_COLLECTION:
- case SGEN_PROTOCOL_THREAD_SUSPEND:
- case SGEN_PROTOCOL_THREAD_RESTART:
- case SGEN_PROTOCOL_THREAD_REGISTER:
- case SGEN_PROTOCOL_THREAD_UNREGISTER:
- return TRUE;
+ switch (TYPE (type)) {
case SGEN_PROTOCOL_ALLOC:
case SGEN_PROTOCOL_ALLOC_PINNED:
case SGEN_PROTOCOL_ALLOC_DEGRADED: {
SGenProtocolMark *entry = data;
return matches_interval (ptr, entry->obj, entry->size);
}
+ case SGEN_PROTOCOL_SCAN_BEGIN: {
+ SGenProtocolScanBegin *entry = data;
+ return matches_interval (ptr, entry->obj, entry->size);
+ }
+ case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
+ SGenProtocolScanVTypeBegin *entry = data;
+ return matches_interval (ptr, entry->obj, entry->size);
+ }
case SGEN_PROTOCOL_WBARRIER: {
SGenProtocolWBarrier *entry = data;
return ptr == entry->ptr || ptr == entry->value;
SGenProtocolMissingRemset *entry = data;
return ptr == entry->obj || ptr == entry->value || ptr == (char*)entry->obj + entry->offset;
}
+ case SGEN_PROTOCOL_CARD_SCAN: {
+ SGenProtocolCardScan *entry = data;
+ return matches_interval (ptr, entry->start, entry->size);
+ }
+ case SGEN_PROTOCOL_CEMENT: {
+ SGenProtocolCement *entry = data;
+ return matches_interval (ptr, entry->obj, entry->size);
+ }
+ case SGEN_PROTOCOL_DISLINK_UPDATE: {
+ SGenProtocolDislinkUpdate *entry = data;
+ return ptr == entry->obj || ptr == entry->link;
+ }
+ case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
+ SGenProtocolDislinkUpdateStaged *entry = data;
+ return ptr == entry->obj || ptr == entry->link;
+ }
+ case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
+ SGenProtocolDislinkProcessStaged *entry = data;
+ return ptr == entry->obj || ptr == entry->link;
+ }
+ case SGEN_PROTOCOL_GRAY_ENQUEUE: {
+ SGenProtocolGrayQueue *entry = data;
+ return ptr == entry->cursor || ptr == entry->value;
+ }
+ case SGEN_PROTOCOL_GRAY_DEQUEUE: {
+ SGenProtocolGrayQueue *entry = data;
+ return ptr == entry->cursor || ptr == entry->value;
+ }
default:
+ if (is_always_match (type))
+ return TRUE;
assert (0);
}
}
+static gboolean
+is_vtable_match (gpointer ptr, int type, void *data)
+{
+ switch (TYPE (type)) {
+ case SGEN_PROTOCOL_ALLOC:
+ case SGEN_PROTOCOL_ALLOC_PINNED:
+ case SGEN_PROTOCOL_ALLOC_DEGRADED: {
+ SGenProtocolAlloc *entry = data;
+ return ptr == entry->vtable;
+ }
+ case SGEN_PROTOCOL_COPY: {
+ SGenProtocolCopy *entry = data;
+ return ptr == entry->vtable;
+ }
+ case SGEN_PROTOCOL_PIN: {
+ SGenProtocolPin *entry = data;
+ return ptr == entry->vtable;
+ }
+ case SGEN_PROTOCOL_SCAN_BEGIN: {
+ SGenProtocolScanBegin *entry = data;
+ return ptr == entry->vtable;
+ }
+ case SGEN_PROTOCOL_WBARRIER: {
+ SGenProtocolWBarrier *entry = data;
+ return ptr == entry->value_vtable;
+ }
+ case SGEN_PROTOCOL_GLOBAL_REMSET: {
+ SGenProtocolGlobalRemset *entry = data;
+ return ptr == entry->value_vtable;
+ }
+ case SGEN_PROTOCOL_PTR_UPDATE: {
+ SGenProtocolPtrUpdate *entry = data;
+ return ptr == entry->vtable;
+ }
+ case SGEN_PROTOCOL_CLEANUP: {
+ SGenProtocolCleanup *entry = data;
+ return ptr == entry->vtable;
+ }
+ case SGEN_PROTOCOL_MISSING_REMSET: {
+ SGenProtocolMissingRemset *entry = data;
+ return ptr == entry->obj_vtable || ptr == entry->value_vtable;
+ }
+ case SGEN_PROTOCOL_CEMENT: {
+ SGenProtocolCement *entry = data;
+ return ptr == entry->vtable;
+ }
+ default:
+ return FALSE;
+ }
+}
+
int
main (int argc, char *argv[])
{
int type;
void *data;
- int num_nums = argc - 1;
+ int num_args = argc - 1;
+ int num_nums = 0;
+ int num_vtables = 0;
int i;
- long nums [num_nums];
+ long nums [num_args];
+ long vtables [num_args];
+ gboolean dump_all = FALSE;
+ gboolean pause_times = FALSE;
+ gboolean pause_times_stopped = FALSE;
+ gboolean pause_times_concurrent = FALSE;
+ long long pause_times_ts = 0;
+
+ for (i = 0; i < num_args; ++i) {
+ char *arg = argv [i + 1];
+ char *next_arg = argv [i + 2];
+ if (!strcmp (arg, "--all")) {
+ dump_all = TRUE;
+ } else if (!strcmp (arg, "--pause-times")) {
+ pause_times = TRUE;
+ } else if (!strcmp (arg, "-v") || !strcmp (arg, "--vtable")) {
+ vtables [num_vtables++] = strtoul (next_arg, NULL, 16);
+ ++i;
+ } else {
+ nums [num_nums++] = strtoul (arg, NULL, 16);
+ }
+ }
- for (i = 0; i < num_nums; ++i)
- nums [i] = strtoul (argv [i + 1], NULL, 16);
+ if (dump_all)
+ assert (!pause_times);
+ if (pause_times)
+ assert (!dump_all);
while ((type = read_entry (stdin, &data)) != SGEN_PROTOCOL_EOF) {
- gboolean match = FALSE;
- for (i = 0; i < num_nums; ++i) {
- if (is_match ((gpointer) nums [i], type, data)) {
- match = TRUE;
+ if (pause_times) {
+ switch (type) {
+ case SGEN_PROTOCOL_WORLD_STOPPING: {
+ SGenProtocolWorldStopping *entry = data;
+ assert (!pause_times_stopped);
+ pause_times_concurrent = FALSE;
+ pause_times_ts = entry->timestamp;
+ pause_times_stopped = TRUE;
+ break;
+ }
+ case SGEN_PROTOCOL_CONCURRENT_START:
+ case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH:
+ pause_times_concurrent = TRUE;
+ break;
+ case SGEN_PROTOCOL_WORLD_RESTARTED: {
+ SGenProtocolWorldRestarted *entry = data;
+ assert (pause_times_stopped);
+ printf ("pause-time %d %d %lld %lld\n",
+ entry->generation,
+ pause_times_concurrent,
+ entry->timestamp - pause_times_ts,
+ pause_times_ts);
+ pause_times_stopped = FALSE;
break;
}
+ }
+ } else {
+ gboolean match = num_nums == 0 ? is_match (NULL, type, data) : FALSE;
+ for (i = 0; i < num_nums; ++i) {
+ if (is_match ((gpointer) nums [i], type, data)) {
+ match = TRUE;
+ break;
+ }
+ }
+ if (!match) {
+ for (i = 0; i < num_vtables; ++i) {
+ if (is_vtable_match ((gpointer) vtables [i], type, data)) {
+ match = TRUE;
+ break;
+ }
+ }
+ }
+ if (dump_all)
+ printf (match ? "* " : " ");
+ if (match || dump_all)
+ print_entry (type, data);
}
- if (match)
- print_entry (type, data);
free (data);
}