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;
64 *data = malloc (size);
65 if (fread (*data, size, 1, in) != 1)
74 #define WORKER_PREFIX(t) (WORKER ((t)) ? "w" : " ")
77 print_entry (int type, void *data)
79 switch (TYPE (type)) {
80 case SGEN_PROTOCOL_COLLECTION_FORCE: {
81 SGenProtocolCollectionForce *entry = data;
82 printf ("%s collection force generation %d\n", WORKER_PREFIX (type), entry->generation);
85 case SGEN_PROTOCOL_COLLECTION_BEGIN: {
86 SGenProtocolCollection *entry = data;
87 printf ("%s collection begin %d generation %d\n", WORKER_PREFIX (type), entry->index, entry->generation);
90 case SGEN_PROTOCOL_COLLECTION_END: {
91 SGenProtocolCollection *entry = data;
92 printf ("%s collection end %d generation %d\n", WORKER_PREFIX (type), entry->index, entry->generation);
95 case SGEN_PROTOCOL_CONCURRENT_START: {
96 printf ("%s concurrent start\n", WORKER_PREFIX (type));
99 case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH: {
100 printf ("%s concurrent update or finish\n", WORKER_PREFIX (type));
103 case SGEN_PROTOCOL_WORLD_STOPPING: {
104 SGenProtocolWorldStopping *entry = data;
105 printf ("%s world stopping timestamp %lld\n", WORKER_PREFIX (type), entry->timestamp);
108 case SGEN_PROTOCOL_WORLD_STOPPED: {
109 SGenProtocolWorldStopped *entry = data;
110 long long total = entry->total_major_cards + entry->total_los_cards;
111 long long marked = entry->marked_major_cards + entry->marked_los_cards;
112 printf ("%s world stopped timestamp %lld total %lld marked %lld %0.2f%%\n", WORKER_PREFIX (type), entry->timestamp, total, marked, 100.0 * (double) marked / (double) total);
115 case SGEN_PROTOCOL_WORLD_RESTARTING: {
116 SGenProtocolWorldRestarting *entry = data;
117 long long total = entry->total_major_cards + entry->total_los_cards;
118 long long marked = entry->marked_major_cards + entry->marked_los_cards;
119 printf ("%s world restarting generation %d timestamp %lld total %lld marked %lld %0.2f%%\n", WORKER_PREFIX (type), entry->generation, entry->timestamp, total, marked, 100.0 * (double) marked / (double) total);
122 case SGEN_PROTOCOL_WORLD_RESTARTED: {
123 SGenProtocolWorldRestarted *entry = data;
124 printf ("%s world restarted generation %d timestamp %lld\n", WORKER_PREFIX (type), entry->generation, entry->timestamp);
127 case SGEN_PROTOCOL_ALLOC: {
128 SGenProtocolAlloc *entry = data;
129 printf ("%s alloc obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
132 case SGEN_PROTOCOL_ALLOC_PINNED: {
133 SGenProtocolAlloc *entry = data;
134 printf ("%s alloc pinned obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
137 case SGEN_PROTOCOL_ALLOC_DEGRADED: {
138 SGenProtocolAlloc *entry = data;
139 printf ("%s alloc degraded obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
142 case SGEN_PROTOCOL_COPY: {
143 SGenProtocolCopy *entry = data;
144 printf ("%s copy from %p to %p vtable %p size %d\n", WORKER_PREFIX (type), entry->from, entry->to, entry->vtable, entry->size);
147 case SGEN_PROTOCOL_PIN: {
148 SGenProtocolPin *entry = data;
149 printf ("%s pin obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
152 case SGEN_PROTOCOL_MARK: {
153 SGenProtocolMark *entry = data;
154 printf ("%s mark obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
157 case SGEN_PROTOCOL_SCAN_BEGIN: {
158 SGenProtocolScanBegin *entry = data;
159 printf ("%s scan_begin obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
162 case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
163 SGenProtocolScanVTypeBegin *entry = data;
164 printf ("%s scan_vtype_begin obj %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->size);
167 case SGEN_PROTOCOL_WBARRIER: {
168 SGenProtocolWBarrier *entry = data;
169 printf ("%s wbarrier ptr %p value %p value_vtable %p\n", WORKER_PREFIX (type), entry->ptr, entry->value, entry->value_vtable);
172 case SGEN_PROTOCOL_GLOBAL_REMSET: {
173 SGenProtocolGlobalRemset *entry = data;
174 printf ("%s global_remset ptr %p value %p value_vtable %p\n", WORKER_PREFIX (type), entry->ptr, entry->value, entry->value_vtable);
177 case SGEN_PROTOCOL_PTR_UPDATE: {
178 SGenProtocolPtrUpdate *entry = data;
179 printf ("%s ptr_update ptr %p old_value %p new_value %p vtable %p size %d\n", WORKER_PREFIX (type),
180 entry->ptr, entry->old_value, entry->new_value, entry->vtable, entry->size);
183 case SGEN_PROTOCOL_CLEANUP: {
184 SGenProtocolCleanup *entry = data;
185 printf ("%s cleanup ptr %p vtable %p size %d\n", WORKER_PREFIX (type), entry->ptr, entry->vtable, entry->size);
188 case SGEN_PROTOCOL_EMPTY: {
189 SGenProtocolEmpty *entry = data;
190 printf ("%s empty start %p size %d\n", WORKER_PREFIX (type), entry->start, entry->size);
193 case SGEN_PROTOCOL_THREAD_SUSPEND: {
194 SGenProtocolThreadSuspend *entry = data;
195 printf ("%s thread_suspend thread %p ip %p\n", WORKER_PREFIX (type), entry->thread, entry->stopped_ip);
198 case SGEN_PROTOCOL_THREAD_RESTART: {
199 SGenProtocolThreadRestart *entry = data;
200 printf ("%s thread_restart thread %p\n", WORKER_PREFIX (type), entry->thread);
203 case SGEN_PROTOCOL_THREAD_REGISTER: {
204 SGenProtocolThreadRegister *entry = data;
205 printf ("%s thread_register thread %p\n", WORKER_PREFIX (type), entry->thread);
208 case SGEN_PROTOCOL_THREAD_UNREGISTER: {
209 SGenProtocolThreadUnregister *entry = data;
210 printf ("%s thread_unregister thread %p\n", WORKER_PREFIX (type), entry->thread);
213 case SGEN_PROTOCOL_MISSING_REMSET: {
214 SGenProtocolMissingRemset *entry = data;
215 printf ("%s missing_remset obj %p obj_vtable %p offset %d value %p value_vtable %p value_pinned %d\n", WORKER_PREFIX (type),
216 entry->obj, entry->obj_vtable, entry->offset, entry->value, entry->value_vtable, entry->value_pinned);
219 case SGEN_PROTOCOL_CARD_SCAN: {
220 SGenProtocolCardScan *entry = data;
221 printf ("%s card_scan start %p size %d\n", WORKER_PREFIX (type), entry->start, entry->size);
224 case SGEN_PROTOCOL_CEMENT: {
225 SGenProtocolCement *entry = data;
226 printf ("%s cement obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
229 case SGEN_PROTOCOL_CEMENT_RESET: {
230 printf ("%s cement_reset\n", WORKER_PREFIX (type));
233 case SGEN_PROTOCOL_DISLINK_UPDATE: {
234 SGenProtocolDislinkUpdate *entry = data;
235 printf ("%s dislink_update link %p obj %p staged %d", WORKER_PREFIX (type), entry->link, entry->obj, entry->staged);
237 printf (" track %d\n", entry->track);
242 case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
243 SGenProtocolDislinkUpdateStaged *entry = data;
244 printf ("%s dislink_update_staged link %p obj %p index %d", WORKER_PREFIX (type), entry->link, entry->obj, entry->index);
246 printf (" track %d\n", entry->track);
251 case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
252 SGenProtocolDislinkProcessStaged *entry = data;
253 printf ("%s dislink_process_staged link %p obj %p index %d\n", WORKER_PREFIX (type), entry->link, entry->obj, entry->index);
256 case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN: {
257 SGenProtocolDomainUnload *entry = data;
258 printf ("%s dislink_unload_begin domain %p\n", WORKER_PREFIX (type), entry->domain);
261 case SGEN_PROTOCOL_DOMAIN_UNLOAD_END: {
262 SGenProtocolDomainUnload *entry = data;
263 printf ("%s dislink_unload_end domain %p\n", WORKER_PREFIX (type), entry->domain);
272 matches_interval (gpointer ptr, gpointer start, int size)
274 return ptr >= start && (char*)ptr < (char*)start + size;
278 is_match (gpointer ptr, int type, void *data)
280 switch (TYPE (type)) {
281 case SGEN_PROTOCOL_COLLECTION_FORCE:
282 case SGEN_PROTOCOL_COLLECTION_BEGIN:
283 case SGEN_PROTOCOL_COLLECTION_END:
284 case SGEN_PROTOCOL_CONCURRENT_START:
285 case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH:
286 case SGEN_PROTOCOL_WORLD_STOPPING:
287 case SGEN_PROTOCOL_WORLD_STOPPED:
288 case SGEN_PROTOCOL_WORLD_RESTARTING:
289 case SGEN_PROTOCOL_WORLD_RESTARTED:
290 case SGEN_PROTOCOL_THREAD_SUSPEND:
291 case SGEN_PROTOCOL_THREAD_RESTART:
292 case SGEN_PROTOCOL_THREAD_REGISTER:
293 case SGEN_PROTOCOL_THREAD_UNREGISTER:
294 case SGEN_PROTOCOL_CEMENT_RESET:
295 case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN:
296 case SGEN_PROTOCOL_DOMAIN_UNLOAD_END:
298 case SGEN_PROTOCOL_ALLOC:
299 case SGEN_PROTOCOL_ALLOC_PINNED:
300 case SGEN_PROTOCOL_ALLOC_DEGRADED: {
301 SGenProtocolAlloc *entry = data;
302 return matches_interval (ptr, entry->obj, entry->size);
304 case SGEN_PROTOCOL_COPY: {
305 SGenProtocolCopy *entry = data;
306 return matches_interval (ptr, entry->from, entry->size) || matches_interval (ptr, entry->to, entry->size);
308 case SGEN_PROTOCOL_PIN: {
309 SGenProtocolPin *entry = data;
310 return matches_interval (ptr, entry->obj, entry->size);
312 case SGEN_PROTOCOL_MARK: {
313 SGenProtocolMark *entry = data;
314 return matches_interval (ptr, entry->obj, entry->size);
316 case SGEN_PROTOCOL_SCAN_BEGIN: {
317 SGenProtocolScanBegin *entry = data;
318 return matches_interval (ptr, entry->obj, entry->size);
320 case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
321 SGenProtocolScanVTypeBegin *entry = data;
322 return matches_interval (ptr, entry->obj, entry->size);
324 case SGEN_PROTOCOL_WBARRIER: {
325 SGenProtocolWBarrier *entry = data;
326 return ptr == entry->ptr || ptr == entry->value;
328 case SGEN_PROTOCOL_GLOBAL_REMSET: {
329 SGenProtocolGlobalRemset *entry = data;
330 return ptr == entry->ptr || ptr == entry->value;
332 case SGEN_PROTOCOL_PTR_UPDATE: {
333 SGenProtocolPtrUpdate *entry = data;
334 return ptr == entry->ptr ||
335 matches_interval (ptr, entry->old_value, entry->size) ||
336 matches_interval (ptr, entry->new_value, entry->size);
338 case SGEN_PROTOCOL_CLEANUP: {
339 SGenProtocolCleanup *entry = data;
340 return matches_interval (ptr, entry->ptr, entry->size);
342 case SGEN_PROTOCOL_EMPTY: {
343 SGenProtocolEmpty *entry = data;
344 return matches_interval (ptr, entry->start, entry->size);
346 case SGEN_PROTOCOL_MISSING_REMSET: {
347 SGenProtocolMissingRemset *entry = data;
348 return ptr == entry->obj || ptr == entry->value || ptr == (char*)entry->obj + entry->offset;
350 case SGEN_PROTOCOL_CARD_SCAN: {
351 SGenProtocolCardScan *entry = data;
352 return matches_interval (ptr, entry->start, entry->size);
354 case SGEN_PROTOCOL_CEMENT: {
355 SGenProtocolCement *entry = data;
356 return matches_interval (ptr, entry->obj, entry->size);
358 case SGEN_PROTOCOL_DISLINK_UPDATE: {
359 SGenProtocolDislinkUpdate *entry = data;
360 return ptr == entry->obj || ptr == entry->link;
362 case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
363 SGenProtocolDislinkUpdateStaged *entry = data;
364 return ptr == entry->obj || ptr == entry->link;
366 case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
367 SGenProtocolDislinkProcessStaged *entry = data;
368 return ptr == entry->obj || ptr == entry->link;
376 is_vtable_match (gpointer ptr, int type, void *data)
378 switch (TYPE (type)) {
379 case SGEN_PROTOCOL_ALLOC:
380 case SGEN_PROTOCOL_ALLOC_PINNED:
381 case SGEN_PROTOCOL_ALLOC_DEGRADED: {
382 SGenProtocolAlloc *entry = data;
383 return ptr == entry->vtable;
385 case SGEN_PROTOCOL_COPY: {
386 SGenProtocolCopy *entry = data;
387 return ptr == entry->vtable;
389 case SGEN_PROTOCOL_PIN: {
390 SGenProtocolPin *entry = data;
391 return ptr == entry->vtable;
393 case SGEN_PROTOCOL_SCAN_BEGIN: {
394 SGenProtocolScanBegin *entry = data;
395 return ptr == entry->vtable;
397 case SGEN_PROTOCOL_WBARRIER: {
398 SGenProtocolWBarrier *entry = data;
399 return ptr == entry->value_vtable;
401 case SGEN_PROTOCOL_GLOBAL_REMSET: {
402 SGenProtocolGlobalRemset *entry = data;
403 return ptr == entry->value_vtable;
405 case SGEN_PROTOCOL_PTR_UPDATE: {
406 SGenProtocolPtrUpdate *entry = data;
407 return ptr == entry->vtable;
409 case SGEN_PROTOCOL_CLEANUP: {
410 SGenProtocolCleanup *entry = data;
411 return ptr == entry->vtable;
413 case SGEN_PROTOCOL_MISSING_REMSET: {
414 SGenProtocolMissingRemset *entry = data;
415 return ptr == entry->obj_vtable || ptr == entry->value_vtable;
417 case SGEN_PROTOCOL_CEMENT: {
418 SGenProtocolCement *entry = data;
419 return ptr == entry->vtable;
427 main (int argc, char *argv[])
431 int num_args = argc - 1;
435 long nums [num_args];
436 long vtables [num_args];
437 gboolean dump_all = FALSE;
438 gboolean pause_times = FALSE;
439 gboolean pause_times_stopped = FALSE;
440 gboolean pause_times_concurrent = FALSE;
441 long long pause_times_ts = 0;
443 for (i = 0; i < num_args; ++i) {
444 char *arg = argv [i + 1];
445 char *next_arg = argv [i + 2];
446 if (!strcmp (arg, "--all")) {
448 } else if (!strcmp (arg, "--pause-times")) {
450 } else if (!strcmp (arg, "-v") || !strcmp (arg, "--vtable")) {
451 vtables [num_vtables++] = strtoul (next_arg, NULL, 16);
454 nums [num_nums++] = strtoul (arg, NULL, 16);
459 assert (!pause_times);
463 while ((type = read_entry (stdin, &data)) != SGEN_PROTOCOL_EOF) {
466 case SGEN_PROTOCOL_WORLD_STOPPING: {
467 SGenProtocolWorldStopping *entry = data;
468 assert (!pause_times_stopped);
469 pause_times_concurrent = FALSE;
470 pause_times_ts = entry->timestamp;
471 pause_times_stopped = TRUE;
474 case SGEN_PROTOCOL_CONCURRENT_START:
475 case SGEN_PROTOCOL_CONCURRENT_UPDATE_FINISH:
476 pause_times_concurrent = TRUE;
478 case SGEN_PROTOCOL_WORLD_RESTARTED: {
479 SGenProtocolWorldRestarted *entry = data;
480 assert (pause_times_stopped);
481 printf ("pause-time %d %d %lld %lld\n",
483 pause_times_concurrent,
484 entry->timestamp - pause_times_ts,
486 pause_times_stopped = FALSE;
491 gboolean match = num_nums == 0 ? is_match (NULL, type, data) : FALSE;
492 for (i = 0; i < num_nums; ++i) {
493 if (is_match ((gpointer) nums [i], type, data)) {
499 for (i = 0; i < num_vtables; ++i) {
500 if (is_vtable_match ((gpointer) vtables [i], type, data)) {
507 printf (match ? "* " : " ");
508 if (match || dump_all)
509 print_entry (type, data);