6 #define SGEN_BINARY_PROTOCOL
9 #include <mono/metadata/sgen-protocol.h>
11 #define SGEN_PROTOCOL_EOF 255
13 #define TYPE(t) ((t) & 0x7f)
14 #define WORKER(t) ((t) & 0x80)
17 read_entry (FILE *in, void **data)
22 if (fread (&type, 1, 1, in) != 1)
23 return SGEN_PROTOCOL_EOF;
24 switch (TYPE (type)) {
25 case SGEN_PROTOCOL_COLLECTION_FORCE: size = sizeof (SGenProtocolCollectionForce); break;
26 case SGEN_PROTOCOL_COLLECTION_BEGIN: size = sizeof (SGenProtocolCollection); break;
27 case SGEN_PROTOCOL_COLLECTION_END: size = sizeof (SGenProtocolCollection); break;
28 case SGEN_PROTOCOL_CONCURRENT_START: size = 0; break;
29 case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH: size = 0; break;
30 case SGEN_PROTOCOL_WORLD_STOPPING: size = sizeof (SGenProtocolWorldStopping); break;
31 case SGEN_PROTOCOL_WORLD_STOPPED: size = sizeof (SGenProtocolWorldStopped); break;
32 case SGEN_PROTOCOL_WORLD_RESTARTING: size = sizeof (SGenProtocolWorldRestarting); break;
33 case SGEN_PROTOCOL_WORLD_RESTARTED: size = sizeof (SGenProtocolWorldRestarted); break;
34 case SGEN_PROTOCOL_ALLOC: size = sizeof (SGenProtocolAlloc); break;
35 case SGEN_PROTOCOL_ALLOC_PINNED: size = sizeof (SGenProtocolAlloc); break;
36 case SGEN_PROTOCOL_ALLOC_DEGRADED: size = sizeof (SGenProtocolAlloc); break;
37 case SGEN_PROTOCOL_COPY: size = sizeof (SGenProtocolCopy); break;
38 case SGEN_PROTOCOL_PIN: size = sizeof (SGenProtocolPin); break;
39 case SGEN_PROTOCOL_MARK: size = sizeof (SGenProtocolMark); break;
40 case SGEN_PROTOCOL_SCAN_BEGIN: size = sizeof (SGenProtocolScanBegin); break;
41 case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: size = sizeof (SGenProtocolScanVTypeBegin); break;
42 case SGEN_PROTOCOL_WBARRIER: size = sizeof (SGenProtocolWBarrier); break;
43 case SGEN_PROTOCOL_GLOBAL_REMSET: size = sizeof (SGenProtocolGlobalRemset); break;
44 case SGEN_PROTOCOL_PTR_UPDATE: size = sizeof (SGenProtocolPtrUpdate); break;
45 case SGEN_PROTOCOL_CLEANUP: size = sizeof (SGenProtocolCleanup); break;
46 case SGEN_PROTOCOL_EMPTY: size = sizeof (SGenProtocolEmpty); break;
47 case SGEN_PROTOCOL_THREAD_SUSPEND: size = sizeof (SGenProtocolThreadSuspend); break;
48 case SGEN_PROTOCOL_THREAD_RESTART: size = sizeof (SGenProtocolThreadRestart); break;
49 case SGEN_PROTOCOL_THREAD_REGISTER: size = sizeof (SGenProtocolThreadRegister); break;
50 case SGEN_PROTOCOL_THREAD_UNREGISTER: size = sizeof (SGenProtocolThreadUnregister); break;
51 case SGEN_PROTOCOL_MISSING_REMSET: size = sizeof (SGenProtocolMissingRemset); break;
52 case SGEN_PROTOCOL_CARD_SCAN: size = sizeof (SGenProtocolCardScan); break;
53 case SGEN_PROTOCOL_CEMENT: size = sizeof (SGenProtocolCement); break;
54 case SGEN_PROTOCOL_CEMENT_RESET: size = 0; break;
55 case SGEN_PROTOCOL_DISLINK_UPDATE: size = sizeof (SGenProtocolDislinkUpdate); break;
56 case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: size = sizeof (SGenProtocolDislinkUpdateStaged); break;
57 case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: size = sizeof (SGenProtocolDislinkProcessStaged); break;
58 case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN: size = sizeof (SGenProtocolDomainUnload); break;
59 case SGEN_PROTOCOL_DOMAIN_UNLOAD_END: size = sizeof (SGenProtocolDomainUnload); break;
60 case SGEN_PROTOCOL_GRAY_ENQUEUE: size = sizeof (SGenProtocolGrayQueue); break;
61 case SGEN_PROTOCOL_GRAY_DEQUEUE: size = sizeof (SGenProtocolGrayQueue); break;
66 *data = malloc (size);
67 if (fread (*data, size, 1, in) != 1)
77 is_always_match (int type)
79 switch (TYPE (type)) {
80 case SGEN_PROTOCOL_COLLECTION_FORCE:
81 case SGEN_PROTOCOL_COLLECTION_BEGIN:
82 case SGEN_PROTOCOL_COLLECTION_END:
83 case SGEN_PROTOCOL_CONCURRENT_START:
84 case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH:
85 case SGEN_PROTOCOL_WORLD_STOPPING:
86 case SGEN_PROTOCOL_WORLD_STOPPED:
87 case SGEN_PROTOCOL_WORLD_RESTARTING:
88 case SGEN_PROTOCOL_WORLD_RESTARTED:
89 case SGEN_PROTOCOL_THREAD_SUSPEND:
90 case SGEN_PROTOCOL_THREAD_RESTART:
91 case SGEN_PROTOCOL_THREAD_REGISTER:
92 case SGEN_PROTOCOL_THREAD_UNREGISTER:
93 case SGEN_PROTOCOL_CEMENT_RESET:
94 case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN:
95 case SGEN_PROTOCOL_DOMAIN_UNLOAD_END:
96 case SGEN_PROTOCOL_GRAY_ENQUEUE:
97 case SGEN_PROTOCOL_GRAY_DEQUEUE:
104 #define WORKER_PREFIX(t) (WORKER ((t)) ? "w" : " ")
107 print_entry (int type, void *data)
109 const char *always_prefix = is_always_match (type) ? " " : "";
110 printf ("%s%s ", WORKER_PREFIX (type), always_prefix);
112 switch (TYPE (type)) {
113 case SGEN_PROTOCOL_COLLECTION_FORCE: {
114 SGenProtocolCollectionForce *entry = data;
115 printf ("collection force generation %d\n", entry->generation);
118 case SGEN_PROTOCOL_COLLECTION_BEGIN: {
119 SGenProtocolCollection *entry = data;
120 printf ("collection begin %d generation %d\n", entry->index, entry->generation);
123 case SGEN_PROTOCOL_COLLECTION_END: {
124 SGenProtocolCollection *entry = data;
125 printf ("collection end %d generation %d\n", entry->index, entry->generation);
128 case SGEN_PROTOCOL_CONCURRENT_START: {
129 printf ("concurrent start\n");
132 case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH: {
133 printf ("concurrent update or finish\n");
136 case SGEN_PROTOCOL_WORLD_STOPPING: {
137 SGenProtocolWorldStopping *entry = data;
138 printf ("world stopping timestamp %lld\n", entry->timestamp);
141 case SGEN_PROTOCOL_WORLD_STOPPED: {
142 SGenProtocolWorldStopped *entry = data;
143 long long total = entry->total_major_cards + entry->total_los_cards;
144 long long marked = entry->marked_major_cards + entry->marked_los_cards;
145 printf ("world stopped timestamp %lld total %lld marked %lld %0.2f%%\n", entry->timestamp, total, marked, 100.0 * (double) marked / (double) total);
148 case SGEN_PROTOCOL_WORLD_RESTARTING: {
149 SGenProtocolWorldRestarting *entry = data;
150 long long total = entry->total_major_cards + entry->total_los_cards;
151 long long marked = entry->marked_major_cards + entry->marked_los_cards;
152 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);
155 case SGEN_PROTOCOL_WORLD_RESTARTED: {
156 SGenProtocolWorldRestarted *entry = data;
157 printf ("world restarted generation %d timestamp %lld\n", entry->generation, entry->timestamp);
160 case SGEN_PROTOCOL_ALLOC: {
161 SGenProtocolAlloc *entry = data;
162 printf ("alloc obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
165 case SGEN_PROTOCOL_ALLOC_PINNED: {
166 SGenProtocolAlloc *entry = data;
167 printf ("alloc pinned obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
170 case SGEN_PROTOCOL_ALLOC_DEGRADED: {
171 SGenProtocolAlloc *entry = data;
172 printf ("alloc degraded obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
175 case SGEN_PROTOCOL_COPY: {
176 SGenProtocolCopy *entry = data;
177 printf ("copy from %p to %p vtable %p size %d\n", entry->from, entry->to, entry->vtable, entry->size);
180 case SGEN_PROTOCOL_PIN: {
181 SGenProtocolPin *entry = data;
182 printf ("pin obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
185 case SGEN_PROTOCOL_MARK: {
186 SGenProtocolMark *entry = data;
187 printf ("mark obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
190 case SGEN_PROTOCOL_SCAN_BEGIN: {
191 SGenProtocolScanBegin *entry = data;
192 printf ("scan_begin obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
195 case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
196 SGenProtocolScanVTypeBegin *entry = data;
197 printf ("scan_vtype_begin obj %p size %d\n", entry->obj, entry->size);
200 case SGEN_PROTOCOL_WBARRIER: {
201 SGenProtocolWBarrier *entry = data;
202 printf ("wbarrier ptr %p value %p value_vtable %p\n", entry->ptr, entry->value, entry->value_vtable);
205 case SGEN_PROTOCOL_GLOBAL_REMSET: {
206 SGenProtocolGlobalRemset *entry = data;
207 printf ("global_remset ptr %p value %p value_vtable %p\n", entry->ptr, entry->value, entry->value_vtable);
210 case SGEN_PROTOCOL_PTR_UPDATE: {
211 SGenProtocolPtrUpdate *entry = data;
212 printf ("ptr_update ptr %p old_value %p new_value %p vtable %p size %d\n",
213 entry->ptr, entry->old_value, entry->new_value, entry->vtable, entry->size);
216 case SGEN_PROTOCOL_CLEANUP: {
217 SGenProtocolCleanup *entry = data;
218 printf ("cleanup ptr %p vtable %p size %d\n", entry->ptr, entry->vtable, entry->size);
221 case SGEN_PROTOCOL_EMPTY: {
222 SGenProtocolEmpty *entry = data;
223 printf ("empty start %p size %d\n", entry->start, entry->size);
226 case SGEN_PROTOCOL_THREAD_SUSPEND: {
227 SGenProtocolThreadSuspend *entry = data;
228 printf ("thread_suspend thread %p ip %p\n", entry->thread, entry->stopped_ip);
231 case SGEN_PROTOCOL_THREAD_RESTART: {
232 SGenProtocolThreadRestart *entry = data;
233 printf ("thread_restart thread %p\n", entry->thread);
236 case SGEN_PROTOCOL_THREAD_REGISTER: {
237 SGenProtocolThreadRegister *entry = data;
238 printf ("thread_register thread %p\n", entry->thread);
241 case SGEN_PROTOCOL_THREAD_UNREGISTER: {
242 SGenProtocolThreadUnregister *entry = data;
243 printf ("thread_unregister thread %p\n", entry->thread);
246 case SGEN_PROTOCOL_MISSING_REMSET: {
247 SGenProtocolMissingRemset *entry = data;
248 printf ("missing_remset obj %p obj_vtable %p offset %d value %p value_vtable %p value_pinned %d\n",
249 entry->obj, entry->obj_vtable, entry->offset, entry->value, entry->value_vtable, entry->value_pinned);
252 case SGEN_PROTOCOL_CARD_SCAN: {
253 SGenProtocolCardScan *entry = data;
254 printf ("card_scan start %p size %d\n", entry->start, entry->size);
257 case SGEN_PROTOCOL_CEMENT: {
258 SGenProtocolCement *entry = data;
259 printf ("cement obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size);
262 case SGEN_PROTOCOL_CEMENT_RESET: {
263 printf ("cement_reset\n");
266 case SGEN_PROTOCOL_DISLINK_UPDATE: {
267 SGenProtocolDislinkUpdate *entry = data;
268 printf ("dislink_update link %p obj %p staged %d", entry->link, entry->obj, entry->staged);
270 printf (" track %d\n", entry->track);
275 case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
276 SGenProtocolDislinkUpdateStaged *entry = data;
277 printf ("dislink_update_staged link %p obj %p index %d", entry->link, entry->obj, entry->index);
279 printf (" track %d\n", entry->track);
284 case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
285 SGenProtocolDislinkProcessStaged *entry = data;
286 printf ("dislink_process_staged link %p obj %p index %d\n", entry->link, entry->obj, entry->index);
289 case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN: {
290 SGenProtocolDomainUnload *entry = data;
291 printf ("dislink_unload_begin domain %p\n", entry->domain);
294 case SGEN_PROTOCOL_DOMAIN_UNLOAD_END: {
295 SGenProtocolDomainUnload *entry = data;
296 printf ("dislink_unload_end domain %p\n", entry->domain);
299 case SGEN_PROTOCOL_GRAY_ENQUEUE: {
300 SGenProtocolGrayQueue *entry = data;
301 printf ("enqueue queue %p cursor %p value %p\n", entry->queue, entry->cursor, entry->value);
304 case SGEN_PROTOCOL_GRAY_DEQUEUE: {
305 SGenProtocolGrayQueue *entry = data;
306 printf ("dequeue queue %p cursor %p value %p\n", entry->queue, entry->cursor, entry->value);
315 matches_interval (gpointer ptr, gpointer start, int size)
317 return ptr >= start && (char*)ptr < (char*)start + size;
321 is_match (gpointer ptr, int type, void *data)
323 switch (TYPE (type)) {
324 case SGEN_PROTOCOL_ALLOC:
325 case SGEN_PROTOCOL_ALLOC_PINNED:
326 case SGEN_PROTOCOL_ALLOC_DEGRADED: {
327 SGenProtocolAlloc *entry = data;
328 return matches_interval (ptr, entry->obj, entry->size);
330 case SGEN_PROTOCOL_COPY: {
331 SGenProtocolCopy *entry = data;
332 return matches_interval (ptr, entry->from, entry->size) || matches_interval (ptr, entry->to, entry->size);
334 case SGEN_PROTOCOL_PIN: {
335 SGenProtocolPin *entry = data;
336 return matches_interval (ptr, entry->obj, entry->size);
338 case SGEN_PROTOCOL_MARK: {
339 SGenProtocolMark *entry = data;
340 return matches_interval (ptr, entry->obj, entry->size);
342 case SGEN_PROTOCOL_SCAN_BEGIN: {
343 SGenProtocolScanBegin *entry = data;
344 return matches_interval (ptr, entry->obj, entry->size);
346 case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
347 SGenProtocolScanVTypeBegin *entry = data;
348 return matches_interval (ptr, entry->obj, entry->size);
350 case SGEN_PROTOCOL_WBARRIER: {
351 SGenProtocolWBarrier *entry = data;
352 return ptr == entry->ptr || ptr == entry->value;
354 case SGEN_PROTOCOL_GLOBAL_REMSET: {
355 SGenProtocolGlobalRemset *entry = data;
356 return ptr == entry->ptr || ptr == entry->value;
358 case SGEN_PROTOCOL_PTR_UPDATE: {
359 SGenProtocolPtrUpdate *entry = data;
360 return ptr == entry->ptr ||
361 matches_interval (ptr, entry->old_value, entry->size) ||
362 matches_interval (ptr, entry->new_value, entry->size);
364 case SGEN_PROTOCOL_CLEANUP: {
365 SGenProtocolCleanup *entry = data;
366 return matches_interval (ptr, entry->ptr, entry->size);
368 case SGEN_PROTOCOL_EMPTY: {
369 SGenProtocolEmpty *entry = data;
370 return matches_interval (ptr, entry->start, entry->size);
372 case SGEN_PROTOCOL_MISSING_REMSET: {
373 SGenProtocolMissingRemset *entry = data;
374 return ptr == entry->obj || ptr == entry->value || ptr == (char*)entry->obj + entry->offset;
376 case SGEN_PROTOCOL_CARD_SCAN: {
377 SGenProtocolCardScan *entry = data;
378 return matches_interval (ptr, entry->start, entry->size);
380 case SGEN_PROTOCOL_CEMENT: {
381 SGenProtocolCement *entry = data;
382 return matches_interval (ptr, entry->obj, entry->size);
384 case SGEN_PROTOCOL_DISLINK_UPDATE: {
385 SGenProtocolDislinkUpdate *entry = data;
386 return ptr == entry->obj || ptr == entry->link;
388 case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
389 SGenProtocolDislinkUpdateStaged *entry = data;
390 return ptr == entry->obj || ptr == entry->link;
392 case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
393 SGenProtocolDislinkProcessStaged *entry = data;
394 return ptr == entry->obj || ptr == entry->link;
396 case SGEN_PROTOCOL_GRAY_ENQUEUE: {
397 SGenProtocolGrayQueue *entry = data;
398 return ptr == entry->cursor || ptr == entry->value;
400 case SGEN_PROTOCOL_GRAY_DEQUEUE: {
401 SGenProtocolGrayQueue *entry = data;
402 return ptr == entry->cursor || ptr == entry->value;
405 if (is_always_match (type))
412 is_vtable_match (gpointer ptr, int type, void *data)
414 switch (TYPE (type)) {
415 case SGEN_PROTOCOL_ALLOC:
416 case SGEN_PROTOCOL_ALLOC_PINNED:
417 case SGEN_PROTOCOL_ALLOC_DEGRADED: {
418 SGenProtocolAlloc *entry = data;
419 return ptr == entry->vtable;
421 case SGEN_PROTOCOL_COPY: {
422 SGenProtocolCopy *entry = data;
423 return ptr == entry->vtable;
425 case SGEN_PROTOCOL_PIN: {
426 SGenProtocolPin *entry = data;
427 return ptr == entry->vtable;
429 case SGEN_PROTOCOL_SCAN_BEGIN: {
430 SGenProtocolScanBegin *entry = data;
431 return ptr == entry->vtable;
433 case SGEN_PROTOCOL_WBARRIER: {
434 SGenProtocolWBarrier *entry = data;
435 return ptr == entry->value_vtable;
437 case SGEN_PROTOCOL_GLOBAL_REMSET: {
438 SGenProtocolGlobalRemset *entry = data;
439 return ptr == entry->value_vtable;
441 case SGEN_PROTOCOL_PTR_UPDATE: {
442 SGenProtocolPtrUpdate *entry = data;
443 return ptr == entry->vtable;
445 case SGEN_PROTOCOL_CLEANUP: {
446 SGenProtocolCleanup *entry = data;
447 return ptr == entry->vtable;
449 case SGEN_PROTOCOL_MISSING_REMSET: {
450 SGenProtocolMissingRemset *entry = data;
451 return ptr == entry->obj_vtable || ptr == entry->value_vtable;
453 case SGEN_PROTOCOL_CEMENT: {
454 SGenProtocolCement *entry = data;
455 return ptr == entry->vtable;
463 main (int argc, char *argv[])
467 int num_args = argc - 1;
471 long nums [num_args];
472 long vtables [num_args];
473 gboolean dump_all = FALSE;
474 gboolean pause_times = FALSE;
475 gboolean pause_times_stopped = FALSE;
476 gboolean pause_times_concurrent = FALSE;
477 long long pause_times_ts = 0;
479 for (i = 0; i < num_args; ++i) {
480 char *arg = argv [i + 1];
481 char *next_arg = argv [i + 2];
482 if (!strcmp (arg, "--all")) {
484 } else if (!strcmp (arg, "--pause-times")) {
486 } else if (!strcmp (arg, "-v") || !strcmp (arg, "--vtable")) {
487 vtables [num_vtables++] = strtoul (next_arg, NULL, 16);
490 nums [num_nums++] = strtoul (arg, NULL, 16);
495 assert (!pause_times);
499 while ((type = read_entry (stdin, &data)) != SGEN_PROTOCOL_EOF) {
502 case SGEN_PROTOCOL_WORLD_STOPPING: {
503 SGenProtocolWorldStopping *entry = data;
504 assert (!pause_times_stopped);
505 pause_times_concurrent = FALSE;
506 pause_times_ts = entry->timestamp;
507 pause_times_stopped = TRUE;
510 case SGEN_PROTOCOL_CONCURRENT_START:
511 case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH:
512 pause_times_concurrent = TRUE;
514 case SGEN_PROTOCOL_WORLD_RESTARTED: {
515 SGenProtocolWorldRestarted *entry = data;
516 assert (pause_times_stopped);
517 printf ("pause-time %d %d %lld %lld\n",
519 pause_times_concurrent,
520 entry->timestamp - pause_times_ts,
522 pause_times_stopped = FALSE;
527 gboolean match = num_nums == 0 ? is_match (NULL, type, data) : FALSE;
528 for (i = 0; i < num_nums; ++i) {
529 if (is_match ((gpointer) nums [i], type, data)) {
535 for (i = 0; i < num_vtables; ++i) {
536 if (is_vtable_match ((gpointer) vtables [i], type, data)) {
543 printf (match ? "* " : " ");
544 if (match || dump_all)
545 print_entry (type, data);