#include #include #include #include #define SGEN_BINARY_PROTOCOL #define MONO_INTERNAL #include #define SGEN_PROTOCOL_EOF 255 #define TYPE(t) ((t) & 0x7f) #define WORKER(t) ((t) & 0x80) static int read_entry (FILE *in, void **data) { unsigned char type; int size; if (fread (&type, 1, 1, in) != 1) return SGEN_PROTOCOL_EOF; switch (TYPE (type)) { case SGEN_PROTOCOL_COLLECTION_FORCE: size = sizeof (SGenProtocolCollectionForce); break; case SGEN_PROTOCOL_COLLECTION_BEGIN: size = sizeof (SGenProtocolCollectionBegin); break; case SGEN_PROTOCOL_COLLECTION_END: size = sizeof (SGenProtocolCollectionEnd); break; case SGEN_PROTOCOL_CONCURRENT_START: size = 0; break; case SGEN_PROTOCOL_CONCURRENT_UPDATE: size = 0; break; case SGEN_PROTOCOL_CONCURRENT_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_STAGE: size = sizeof (SGenProtocolPinStage); 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_SCAN_PROCESS_REFERENCE: size = sizeof (SGenProtocolScanProcessReference); 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_CLEANUP: size = sizeof (SGenProtocolCleanup); break; case SGEN_PROTOCOL_EMPTY: size = sizeof (SGenProtocolEmpty); break; case SGEN_PROTOCOL_THREAD_SUSPEND: size = sizeof (SGenProtocolThreadSuspend); break; case SGEN_PROTOCOL_THREAD_RESTART: size = sizeof (SGenProtocolThreadRestart); 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); } 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: case SGEN_PROTOCOL_CONCURRENT_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: return TRUE; default: return FALSE; } } #define WORKER_PREFIX(t) (WORKER ((t)) ? "w" : " ") static void print_entry (int type, void *data) { 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: { SGenProtocolCollectionBegin *entry = data; printf ("collection begin %d generation %d\n", entry->index, entry->generation); break; } case SGEN_PROTOCOL_COLLECTION_END: { SGenProtocolCollectionEnd *entry = data; long long scanned = entry->num_scanned_objects; long long unique = entry->num_unique_scanned_objects; printf ("collection end %d generation %d scanned %lld unique %lld %0.2f%%\n", entry->index, entry->generation, scanned, unique, unique ? 100.0 * (double) scanned / (double) unique : 0.0); break; } case SGEN_PROTOCOL_CONCURRENT_START: { printf ("concurrent start\n"); break; } case SGEN_PROTOCOL_CONCURRENT_UPDATE: { printf ("concurrent update\n"); break; } case SGEN_PROTOCOL_CONCURRENT_FINISH: { printf ("concurrent 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: { SGenProtocolAlloc *entry = data; printf ("alloc obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size); break; } case SGEN_PROTOCOL_ALLOC_PINNED: { SGenProtocolAlloc *entry = data; printf ("alloc pinned obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size); break; } case SGEN_PROTOCOL_ALLOC_DEGRADED: { SGenProtocolAlloc *entry = data; printf ("alloc degraded obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size); break; } case SGEN_PROTOCOL_COPY: { SGenProtocolCopy *entry = data; printf ("copy from %p to %p vtable %p size %d\n", entry->from, entry->to, entry->vtable, entry->size); break; } case SGEN_PROTOCOL_PIN_STAGE: { SGenProtocolPinStage *entry = data; printf ("pin stage addr ptr %p addr %p\n", entry->addr_ptr, entry->addr); break; } case SGEN_PROTOCOL_PIN: { SGenProtocolPin *entry = data; printf ("pin obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size); break; } case SGEN_PROTOCOL_MARK: { SGenProtocolMark *entry = data; 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_SCAN_PROCESS_REFERENCE: { SGenProtocolScanProcessReference *entry = data; printf ("scan_process_reference obj %p ptr %p value %p\n", entry->obj, entry->ptr, entry->value); 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); break; } case SGEN_PROTOCOL_GLOBAL_REMSET: { SGenProtocolGlobalRemset *entry = data; printf ("global_remset ptr %p value %p value_vtable %p\n", entry->ptr, entry->value, entry->value_vtable); break; } case SGEN_PROTOCOL_PTR_UPDATE: { SGenProtocolPtrUpdate *entry = data; printf ("ptr_update ptr %p old_value %p new_value %p vtable %p size %d\n", entry->ptr, entry->old_value, entry->new_value, entry->vtable, entry->size); break; } case SGEN_PROTOCOL_CLEANUP: { SGenProtocolCleanup *entry = data; printf ("cleanup ptr %p vtable %p size %d\n", entry->ptr, entry->vtable, entry->size); break; } case SGEN_PROTOCOL_EMPTY: { SGenProtocolEmpty *entry = data; printf ("empty start %p size %d\n", entry->start, entry->size); break; } case SGEN_PROTOCOL_THREAD_SUSPEND: { SGenProtocolThreadSuspend *entry = data; printf ("thread_suspend thread %p ip %p\n", entry->thread, entry->stopped_ip); break; } case SGEN_PROTOCOL_THREAD_RESTART: { SGenProtocolThreadRestart *entry = data; printf ("thread_restart thread %p\n", entry->thread); break; } case SGEN_PROTOCOL_THREAD_REGISTER: { SGenProtocolThreadRegister *entry = data; printf ("thread_register thread %p\n", entry->thread); break; } case SGEN_PROTOCOL_THREAD_UNREGISTER: { SGenProtocolThreadUnregister *entry = data; printf ("thread_unregister thread %p\n", entry->thread); break; } case SGEN_PROTOCOL_MISSING_REMSET: { SGenProtocolMissingRemset *entry = data; printf ("missing_remset obj %p obj_vtable %p offset %d value %p value_vtable %p value_pinned %d\n", 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 matches_interval (gpointer ptr, gpointer start, int size) { return ptr >= start && (char*)ptr < (char*)start + size; } static gboolean is_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 matches_interval (ptr, entry->obj, entry->size); } case SGEN_PROTOCOL_COPY: { SGenProtocolCopy *entry = data; return matches_interval (ptr, entry->from, entry->size) || matches_interval (ptr, entry->to, entry->size); } case SGEN_PROTOCOL_PIN_STAGE: { SGenProtocolPinStage *entry = data; return ptr == entry->addr_ptr || ptr == entry->addr; } case SGEN_PROTOCOL_PIN: { SGenProtocolPin *entry = data; return matches_interval (ptr, entry->obj, entry->size); } case SGEN_PROTOCOL_MARK: { 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_SCAN_PROCESS_REFERENCE: { SGenProtocolScanProcessReference *entry = data; return ptr == entry->obj || ptr == entry->ptr || ptr == entry->value; } case SGEN_PROTOCOL_WBARRIER: { SGenProtocolWBarrier *entry = data; return ptr == entry->ptr || ptr == entry->value; } case SGEN_PROTOCOL_GLOBAL_REMSET: { SGenProtocolGlobalRemset *entry = data; return ptr == entry->ptr || ptr == entry->value; } case SGEN_PROTOCOL_PTR_UPDATE: { SGenProtocolPtrUpdate *entry = data; return ptr == entry->ptr || matches_interval (ptr, entry->old_value, entry->size) || matches_interval (ptr, entry->new_value, entry->size); } case SGEN_PROTOCOL_CLEANUP: { SGenProtocolCleanup *entry = data; return matches_interval (ptr, entry->ptr, entry->size); } case SGEN_PROTOCOL_EMPTY: { SGenProtocolEmpty *entry = data; return matches_interval (ptr, entry->start, entry->size); } case SGEN_PROTOCOL_MISSING_REMSET: { 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_args = argc - 1; int num_nums = 0; int num_vtables = 0; int i; 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; gboolean pause_times_finish = 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); } } if (dump_all) assert (!pause_times); if (pause_times) assert (!dump_all); while ((type = read_entry (stdin, &data)) != SGEN_PROTOCOL_EOF) { if (pause_times) { switch (type) { case SGEN_PROTOCOL_WORLD_STOPPING: { SGenProtocolWorldStopping *entry = data; assert (!pause_times_stopped); pause_times_concurrent = FALSE; pause_times_finish = FALSE; pause_times_ts = entry->timestamp; pause_times_stopped = TRUE; break; } case SGEN_PROTOCOL_CONCURRENT_FINISH: pause_times_finish = TRUE; case SGEN_PROTOCOL_CONCURRENT_START: case SGEN_PROTOCOL_CONCURRENT_UPDATE: pause_times_concurrent = TRUE; break; case SGEN_PROTOCOL_WORLD_RESTARTED: { SGenProtocolWorldRestarted *entry = data; assert (pause_times_stopped); printf ("pause-time %d %d %d %lld %lld\n", entry->generation, pause_times_concurrent, pause_times_finish, 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); } free (data); } return 0; }