NonmovingCensus: Emit samples to eventlog
[ghc.git] / rts / eventlog / EventLog.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 2008-2009
4 *
5 * Support for fast binary event logging.
6 *
7 * ---------------------------------------------------------------------------*/
8
9 #include "PosixSource.h"
10 #include "Rts.h"
11
12 #if defined(TRACING)
13
14 #include "Trace.h"
15 #include "Capability.h"
16 #include "RtsUtils.h"
17 #include "Stats.h"
18 #include "EventLog.h"
19
20 #include <string.h>
21 #include <stdio.h>
22 #if defined(HAVE_SYS_TYPES_H)
23 #include <sys/types.h>
24 #endif
25 #if defined(HAVE_UNISTD_H)
26 #include <unistd.h>
27 #endif
28
29 static const EventLogWriter *event_log_writer;
30
31 #define EVENT_LOG_SIZE 2 * (1024 * 1024) // 2MB
32
33 static int flushCount;
34
35 // Struct for record keeping of buffer to store event types and events.
36 typedef struct _EventsBuf {
37 StgInt8 *begin;
38 StgInt8 *pos;
39 StgInt8 *marker;
40 StgWord64 size;
41 EventCapNo capno; // which capability this buffer belongs to, or -1
42 } EventsBuf;
43
44 EventsBuf *capEventBuf; // one EventsBuf for each Capability
45
46 EventsBuf eventBuf; // an EventsBuf not associated with any Capability
47 #if defined(THREADED_RTS)
48 Mutex eventBufMutex; // protected by this mutex
49 #endif
50
51 char *EventDesc[] = {
52 [EVENT_CREATE_THREAD] = "Create thread",
53 [EVENT_RUN_THREAD] = "Run thread",
54 [EVENT_STOP_THREAD] = "Stop thread",
55 [EVENT_THREAD_RUNNABLE] = "Thread runnable",
56 [EVENT_MIGRATE_THREAD] = "Migrate thread",
57 [EVENT_THREAD_WAKEUP] = "Wakeup thread",
58 [EVENT_THREAD_LABEL] = "Thread label",
59 [EVENT_CAP_CREATE] = "Create capability",
60 [EVENT_CAP_DELETE] = "Delete capability",
61 [EVENT_CAP_DISABLE] = "Disable capability",
62 [EVENT_CAP_ENABLE] = "Enable capability",
63 [EVENT_GC_START] = "Starting GC",
64 [EVENT_GC_END] = "Finished GC",
65 [EVENT_REQUEST_SEQ_GC] = "Request sequential GC",
66 [EVENT_REQUEST_PAR_GC] = "Request parallel GC",
67 [EVENT_GC_GLOBAL_SYNC] = "Synchronise stop-the-world GC",
68 [EVENT_GC_STATS_GHC] = "GC statistics",
69 [EVENT_HEAP_INFO_GHC] = "Heap static parameters",
70 [EVENT_HEAP_ALLOCATED] = "Total heap mem ever allocated",
71 [EVENT_HEAP_SIZE] = "Current heap size",
72 [EVENT_HEAP_LIVE] = "Current heap live data",
73 [EVENT_CREATE_SPARK_THREAD] = "Create spark thread",
74 [EVENT_LOG_MSG] = "Log message",
75 [EVENT_USER_MSG] = "User message",
76 [EVENT_USER_MARKER] = "User marker",
77 [EVENT_GC_IDLE] = "GC idle",
78 [EVENT_GC_WORK] = "GC working",
79 [EVENT_GC_DONE] = "GC done",
80 [EVENT_BLOCK_MARKER] = "Block marker",
81 [EVENT_CAPSET_CREATE] = "Create capability set",
82 [EVENT_CAPSET_DELETE] = "Delete capability set",
83 [EVENT_CAPSET_ASSIGN_CAP] = "Add capability to capability set",
84 [EVENT_CAPSET_REMOVE_CAP] = "Remove capability from capability set",
85 [EVENT_RTS_IDENTIFIER] = "RTS name and version",
86 [EVENT_PROGRAM_ARGS] = "Program arguments",
87 [EVENT_PROGRAM_ENV] = "Program environment variables",
88 [EVENT_OSPROCESS_PID] = "Process ID",
89 [EVENT_OSPROCESS_PPID] = "Parent process ID",
90 [EVENT_WALL_CLOCK_TIME] = "Wall clock time",
91 [EVENT_SPARK_COUNTERS] = "Spark counters",
92 [EVENT_SPARK_CREATE] = "Spark create",
93 [EVENT_SPARK_DUD] = "Spark dud",
94 [EVENT_SPARK_OVERFLOW] = "Spark overflow",
95 [EVENT_SPARK_RUN] = "Spark run",
96 [EVENT_SPARK_STEAL] = "Spark steal",
97 [EVENT_SPARK_FIZZLE] = "Spark fizzle",
98 [EVENT_SPARK_GC] = "Spark GC",
99 [EVENT_TASK_CREATE] = "Task create",
100 [EVENT_TASK_MIGRATE] = "Task migrate",
101 [EVENT_TASK_DELETE] = "Task delete",
102 [EVENT_HACK_BUG_T9003] = "Empty event for bug #9003",
103 [EVENT_HEAP_PROF_BEGIN] = "Start of heap profile",
104 [EVENT_HEAP_PROF_COST_CENTRE] = "Cost center definition",
105 [EVENT_HEAP_PROF_SAMPLE_BEGIN] = "Start of heap profile sample",
106 [EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN] = "Start of heap profile (biographical) sample",
107 [EVENT_HEAP_PROF_SAMPLE_END] = "End of heap profile sample",
108 [EVENT_HEAP_PROF_SAMPLE_STRING] = "Heap profile string sample",
109 [EVENT_HEAP_PROF_SAMPLE_COST_CENTRE] = "Heap profile cost-centre sample",
110 [EVENT_USER_BINARY_MSG] = "User binary message",
111 [EVENT_CONC_MARK_BEGIN] = "Begin concurrent mark phase",
112 [EVENT_CONC_MARK_END] = "End concurrent mark phase",
113 [EVENT_CONC_SYNC_BEGIN] = "Begin concurrent GC synchronisation",
114 [EVENT_CONC_SYNC_END] = "End concurrent GC synchronisation",
115 [EVENT_CONC_SWEEP_BEGIN] = "Begin concurrent sweep",
116 [EVENT_CONC_SWEEP_END] = "End concurrent sweep",
117 [EVENT_CONC_UPD_REM_SET_FLUSH] = "Update remembered set flushed",
118 [EVENT_NONMOVING_HEAP_CENSUS] = "Nonmoving heap census"
119 };
120
121 // Event type.
122
123 typedef struct _EventType {
124 EventTypeNum etNum; // Event Type number.
125 uint32_t size; // size of the payload in bytes
126 char *desc; // Description
127 } EventType;
128
129 EventType eventTypes[NUM_GHC_EVENT_TAGS];
130
131 static void initEventsBuf(EventsBuf* eb, StgWord64 size, EventCapNo capno);
132 static void resetEventsBuf(EventsBuf* eb);
133 static void printAndClearEventBuf (EventsBuf *eventsBuf);
134
135 static void postEventType(EventsBuf *eb, EventType *et);
136
137 static void postLogMsg(EventsBuf *eb, EventTypeNum type, char *msg, va_list ap);
138
139 static void postBlockMarker(EventsBuf *eb);
140 static void closeBlockMarker(EventsBuf *ebuf);
141
142 static StgBool hasRoomForEvent(EventsBuf *eb, EventTypeNum eNum);
143 static StgBool hasRoomForVariableEvent(EventsBuf *eb, uint32_t payload_bytes);
144
145 static void ensureRoomForEvent(EventsBuf *eb, EventTypeNum tag);
146 static int ensureRoomForVariableEvent(EventsBuf *eb, StgWord16 size);
147
148 static inline void postWord8(EventsBuf *eb, StgWord8 i)
149 {
150 *(eb->pos++) = i;
151 }
152
153 static inline void postWord16(EventsBuf *eb, StgWord16 i)
154 {
155 postWord8(eb, (StgWord8)(i >> 8));
156 postWord8(eb, (StgWord8)i);
157 }
158
159 static inline void postWord32(EventsBuf *eb, StgWord32 i)
160 {
161 postWord16(eb, (StgWord16)(i >> 16));
162 postWord16(eb, (StgWord16)i);
163 }
164
165 static inline void postWord64(EventsBuf *eb, StgWord64 i)
166 {
167 postWord32(eb, (StgWord32)(i >> 32));
168 postWord32(eb, (StgWord32)i);
169 }
170
171 static inline void postBuf(EventsBuf *eb, StgWord8 *buf, uint32_t size)
172 {
173 memcpy(eb->pos, buf, size);
174 eb->pos += size;
175 }
176
177 /* Post a null-terminated string to the event log.
178 * It is the caller's responsibility to ensure that there is
179 * enough room for strlen(buf)+1 bytes.
180 */
181 static inline void postString(EventsBuf *eb, const char *buf)
182 {
183 if (buf) {
184 const int len = strlen(buf);
185 ASSERT(eb->begin + eb->size > eb->pos + len);
186 memcpy(eb->pos, buf, len);
187 eb->pos += len;
188 }
189 *eb->pos = 0;
190 eb->pos++;
191 }
192
193 static inline StgWord64 time_ns(void)
194 { return TimeToNS(stat_getElapsedTime()); }
195
196 static inline void postEventTypeNum(EventsBuf *eb, EventTypeNum etNum)
197 { postWord16(eb, etNum); }
198
199 static inline void postTimestamp(EventsBuf *eb)
200 { postWord64(eb, time_ns()); }
201
202 static inline void postThreadID(EventsBuf *eb, EventThreadID id)
203 { postWord32(eb,id); }
204
205 static inline void postCapNo(EventsBuf *eb, EventCapNo no)
206 { postWord16(eb,no); }
207
208 static inline void postCapsetID(EventsBuf *eb, EventCapsetID id)
209 { postWord32(eb,id); }
210
211 static inline void postCapsetType(EventsBuf *eb, EventCapsetType type)
212 { postWord16(eb,type); }
213
214 static inline void postOSProcessId(EventsBuf *eb, pid_t pid)
215 { postWord32(eb, pid); }
216
217 static inline void postKernelThreadId(EventsBuf *eb, EventKernelThreadId tid)
218 { postWord64(eb, tid); }
219
220 static inline void postTaskId(EventsBuf *eb, EventTaskId tUniq)
221 { postWord64(eb, tUniq); }
222
223 static inline void postPayloadSize(EventsBuf *eb, EventPayloadSize size)
224 { postWord16(eb,size); }
225
226 static inline void postEventHeader(EventsBuf *eb, EventTypeNum type)
227 {
228 postEventTypeNum(eb, type);
229 postTimestamp(eb);
230 }
231
232 static inline void postInt8(EventsBuf *eb, StgInt8 i)
233 { postWord8(eb, (StgWord8)i); }
234
235 static inline void postInt32(EventsBuf *eb, StgInt32 i)
236 { postWord32(eb, (StgWord32)i); }
237
238 #define EVENT_SIZE_DYNAMIC (-1)
239
240 static void
241 initEventLogWriter(void)
242 {
243 if (event_log_writer != NULL &&
244 event_log_writer->initEventLogWriter != NULL) {
245 event_log_writer->initEventLogWriter();
246 }
247 }
248
249 static bool
250 writeEventLog(void *eventlog, size_t eventlog_size)
251 {
252 if (event_log_writer != NULL &&
253 event_log_writer->writeEventLog != NULL) {
254 return event_log_writer->writeEventLog(eventlog, eventlog_size);
255 } else {
256 return false;
257 }
258 }
259
260 static void
261 stopEventLogWriter(void)
262 {
263 if (event_log_writer != NULL &&
264 event_log_writer->stopEventLogWriter != NULL) {
265 event_log_writer->stopEventLogWriter();
266 }
267 }
268
269 void
270 flushEventLog(void)
271 {
272 if (event_log_writer != NULL &&
273 event_log_writer->flushEventLog != NULL) {
274 event_log_writer->flushEventLog();
275 }
276 }
277
278 static void
279 init_event_types(void)
280 {
281 for (int t = 0; t < NUM_GHC_EVENT_TAGS; ++t) {
282 eventTypes[t].etNum = t;
283 eventTypes[t].desc = EventDesc[t];
284
285 switch (t) {
286 case EVENT_CREATE_THREAD: // (cap, thread)
287 case EVENT_RUN_THREAD: // (cap, thread)
288 case EVENT_THREAD_RUNNABLE: // (cap, thread)
289 case EVENT_CREATE_SPARK_THREAD: // (cap, spark_thread)
290 eventTypes[t].size = sizeof(EventThreadID);
291 break;
292
293 case EVENT_MIGRATE_THREAD: // (cap, thread, new_cap)
294 case EVENT_THREAD_WAKEUP: // (cap, thread, other_cap)
295 eventTypes[t].size =
296 sizeof(EventThreadID) + sizeof(EventCapNo);
297 break;
298
299 case EVENT_STOP_THREAD: // (cap, thread, status)
300 eventTypes[t].size = sizeof(EventThreadID)
301 + sizeof(StgWord16)
302 + sizeof(EventThreadID);
303 break;
304
305 case EVENT_CAP_CREATE: // (cap)
306 case EVENT_CAP_DELETE: // (cap)
307 case EVENT_CAP_ENABLE: // (cap)
308 case EVENT_CAP_DISABLE: // (cap)
309 eventTypes[t].size = sizeof(EventCapNo);
310 break;
311
312 case EVENT_CAPSET_CREATE: // (capset, capset_type)
313 eventTypes[t].size =
314 sizeof(EventCapsetID) + sizeof(EventCapsetType);
315 break;
316
317 case EVENT_CAPSET_DELETE: // (capset)
318 eventTypes[t].size = sizeof(EventCapsetID);
319 break;
320
321 case EVENT_CAPSET_ASSIGN_CAP: // (capset, cap)
322 case EVENT_CAPSET_REMOVE_CAP:
323 eventTypes[t].size =
324 sizeof(EventCapsetID) + sizeof(EventCapNo);
325 break;
326
327 case EVENT_OSPROCESS_PID: // (cap, pid)
328 case EVENT_OSPROCESS_PPID:
329 eventTypes[t].size =
330 sizeof(EventCapsetID) + sizeof(StgWord32);
331 break;
332
333 case EVENT_WALL_CLOCK_TIME: // (capset, unix_epoch_seconds, nanoseconds)
334 eventTypes[t].size =
335 sizeof(EventCapsetID) + sizeof(StgWord64) + sizeof(StgWord32);
336 break;
337
338 case EVENT_SPARK_STEAL: // (cap, victim_cap)
339 eventTypes[t].size =
340 sizeof(EventCapNo);
341 break;
342
343 case EVENT_REQUEST_SEQ_GC: // (cap)
344 case EVENT_REQUEST_PAR_GC: // (cap)
345 case EVENT_GC_START: // (cap)
346 case EVENT_GC_END: // (cap)
347 case EVENT_GC_IDLE:
348 case EVENT_GC_WORK:
349 case EVENT_GC_DONE:
350 case EVENT_GC_GLOBAL_SYNC: // (cap)
351 case EVENT_SPARK_CREATE: // (cap)
352 case EVENT_SPARK_DUD: // (cap)
353 case EVENT_SPARK_OVERFLOW: // (cap)
354 case EVENT_SPARK_RUN: // (cap)
355 case EVENT_SPARK_FIZZLE: // (cap)
356 case EVENT_SPARK_GC: // (cap)
357 eventTypes[t].size = 0;
358 break;
359
360 case EVENT_LOG_MSG: // (msg)
361 case EVENT_USER_MSG: // (msg)
362 case EVENT_USER_MARKER: // (markername)
363 case EVENT_RTS_IDENTIFIER: // (capset, str)
364 case EVENT_PROGRAM_ARGS: // (capset, strvec)
365 case EVENT_PROGRAM_ENV: // (capset, strvec)
366 case EVENT_THREAD_LABEL: // (thread, str)
367 eventTypes[t].size = 0xffff;
368 break;
369
370 case EVENT_SPARK_COUNTERS: // (cap, 7*counter)
371 eventTypes[t].size = 7 * sizeof(StgWord64);
372 break;
373
374 case EVENT_HEAP_ALLOCATED: // (heap_capset, alloc_bytes)
375 case EVENT_HEAP_SIZE: // (heap_capset, size_bytes)
376 case EVENT_HEAP_LIVE: // (heap_capset, live_bytes)
377 eventTypes[t].size = sizeof(EventCapsetID) + sizeof(StgWord64);
378 break;
379
380 case EVENT_HEAP_INFO_GHC: // (heap_capset, n_generations,
381 // max_heap_size, alloc_area_size,
382 // mblock_size, block_size)
383 eventTypes[t].size = sizeof(EventCapsetID)
384 + sizeof(StgWord16)
385 + sizeof(StgWord64) * 4;
386 break;
387
388 case EVENT_GC_STATS_GHC: // (heap_capset, generation,
389 // copied_bytes, slop_bytes, frag_bytes,
390 // par_n_threads,
391 // par_max_copied, par_tot_copied,
392 // par_balanced_copied
393 // )
394 eventTypes[t].size = sizeof(EventCapsetID)
395 + sizeof(StgWord16)
396 + sizeof(StgWord64) * 3
397 + sizeof(StgWord32)
398 + sizeof(StgWord64) * 3;
399 break;
400
401 case EVENT_TASK_CREATE: // (taskId, cap, tid)
402 eventTypes[t].size = sizeof(EventTaskId)
403 + sizeof(EventCapNo)
404 + sizeof(EventKernelThreadId);
405 break;
406
407 case EVENT_TASK_MIGRATE: // (taskId, cap, new_cap)
408 eventTypes[t].size =
409 sizeof(EventTaskId) + sizeof(EventCapNo) + sizeof(EventCapNo);
410 break;
411
412 case EVENT_TASK_DELETE: // (taskId)
413 eventTypes[t].size = sizeof(EventTaskId);
414 break;
415
416 case EVENT_BLOCK_MARKER:
417 eventTypes[t].size = sizeof(StgWord32) + sizeof(EventTimestamp) +
418 sizeof(EventCapNo);
419 break;
420
421 case EVENT_HACK_BUG_T9003:
422 eventTypes[t].size = 0;
423 break;
424
425 case EVENT_HEAP_PROF_BEGIN:
426 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
427 break;
428
429 case EVENT_HEAP_PROF_COST_CENTRE:
430 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
431 break;
432
433 case EVENT_HEAP_PROF_SAMPLE_BEGIN:
434 eventTypes[t].size = 8;
435 break;
436
437 case EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN:
438 eventTypes[t].size = 16;
439 break;
440
441 case EVENT_HEAP_PROF_SAMPLE_END:
442 eventTypes[t].size = 8;
443 break;
444
445 case EVENT_HEAP_PROF_SAMPLE_STRING:
446 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
447 break;
448
449 case EVENT_HEAP_PROF_SAMPLE_COST_CENTRE:
450 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
451 break;
452
453 case EVENT_USER_BINARY_MSG:
454 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
455 break;
456
457 case EVENT_CONC_MARK_BEGIN:
458 case EVENT_CONC_SYNC_BEGIN:
459 case EVENT_CONC_SYNC_END:
460 case EVENT_CONC_SWEEP_BEGIN:
461 case EVENT_CONC_SWEEP_END:
462 eventTypes[t].size = 0;
463 break;
464
465 case EVENT_CONC_MARK_END:
466 eventTypes[t].size = 4;
467 break;
468
469 case EVENT_CONC_UPD_REM_SET_FLUSH: // (cap)
470 eventTypes[t].size =
471 sizeof(EventCapNo);
472 break;
473
474 case EVENT_NONMOVING_HEAP_CENSUS: // (cap, blk_size, active_segs, filled_segs, live_blks)
475 eventTypes[t].size = 13;
476 break;
477
478 default:
479 continue; /* ignore deprecated events */
480 }
481 }
482 }
483
484 static void
485 postHeaderEvents(void)
486 {
487 // Write in buffer: the header begin marker.
488 postInt32(&eventBuf, EVENT_HEADER_BEGIN);
489
490 // Mark beginning of event types in the header.
491 postInt32(&eventBuf, EVENT_HET_BEGIN);
492
493 for (int t = 0; t < NUM_GHC_EVENT_TAGS; ++t) {
494 // Write in buffer: the start event type.
495 if (eventTypes[t].desc)
496 postEventType(&eventBuf, &eventTypes[t]);
497 }
498
499 // Mark end of event types in the header.
500 postInt32(&eventBuf, EVENT_HET_END);
501
502 // Write in buffer: the header end marker.
503 postInt32(&eventBuf, EVENT_HEADER_END);
504
505 // Prepare event buffer for events (data).
506 postInt32(&eventBuf, EVENT_DATA_BEGIN);
507 }
508
509 void
510 initEventLogging(const EventLogWriter *ev_writer)
511 {
512 uint32_t n_caps;
513
514 init_event_types();
515
516 event_log_writer = ev_writer;
517 initEventLogWriter();
518
519 int num_descs = sizeof(EventDesc) / sizeof(char*);
520 if (num_descs != NUM_GHC_EVENT_TAGS) {
521 barf("EventDesc array has the wrong number of elements (%d, NUM_GHC_EVENT_TAGS=%d)",
522 num_descs, NUM_GHC_EVENT_TAGS);
523 }
524
525 /*
526 * Allocate buffer(s) to store events.
527 * Create buffer large enough for the header begin marker, all event
528 * types, and header end marker to prevent checking if buffer has room
529 * for each of these steps, and remove the need to flush the buffer to
530 * disk during initialization.
531 *
532 * Use a single buffer to store the header with event types, then flush
533 * the buffer so all buffers are empty for writing events.
534 */
535 #if defined(THREADED_RTS)
536 // XXX n_capabilities hasn't been initialized yet
537 n_caps = RtsFlags.ParFlags.nCapabilities;
538 #else
539 n_caps = 1;
540 #endif
541 moreCapEventBufs(0, n_caps);
542
543 initEventsBuf(&eventBuf, EVENT_LOG_SIZE, (EventCapNo)(-1));
544 #if defined(THREADED_RTS)
545 initMutex(&eventBufMutex);
546 #endif
547
548 postHeaderEvents();
549
550 // Flush capEventBuf with header.
551 /*
552 * Flush header and data begin marker to the file, thus preparing the
553 * file to have events written to it.
554 */
555 printAndClearEventBuf(&eventBuf);
556
557 for (uint32_t c = 0; c < n_caps; ++c) {
558 postBlockMarker(&capEventBuf[c]);
559 }
560 }
561
562 void
563 endEventLogging(void)
564 {
565 // Flush all events remaining in the buffers.
566 for (uint32_t c = 0; c < n_capabilities; ++c) {
567 printAndClearEventBuf(&capEventBuf[c]);
568 }
569 printAndClearEventBuf(&eventBuf);
570 resetEventsBuf(&eventBuf); // we don't want the block marker
571
572 // Mark end of events (data).
573 postEventTypeNum(&eventBuf, EVENT_DATA_END);
574
575 // Flush the end of data marker.
576 printAndClearEventBuf(&eventBuf);
577
578 stopEventLogWriter();
579 }
580
581 void
582 moreCapEventBufs (uint32_t from, uint32_t to)
583 {
584 if (from > 0) {
585 capEventBuf = stgReallocBytes(capEventBuf, to * sizeof(EventsBuf),
586 "moreCapEventBufs");
587 } else {
588 capEventBuf = stgMallocBytes(to * sizeof(EventsBuf),
589 "moreCapEventBufs");
590 }
591
592 for (uint32_t c = from; c < to; ++c) {
593 initEventsBuf(&capEventBuf[c], EVENT_LOG_SIZE, c);
594 }
595
596 // The from == 0 already covered in initEventLogging, so we are interested
597 // only in case when we are increasing capabilities number
598 if (from > 0) {
599 for (uint32_t c = from; c < to; ++c) {
600 postBlockMarker(&capEventBuf[c]);
601 }
602 }
603 }
604
605
606 void
607 freeEventLogging(void)
608 {
609 // Free events buffer.
610 for (uint32_t c = 0; c < n_capabilities; ++c) {
611 if (capEventBuf[c].begin != NULL)
612 stgFree(capEventBuf[c].begin);
613 }
614 if (capEventBuf != NULL) {
615 stgFree(capEventBuf);
616 }
617 }
618
619 void
620 abortEventLogging(void)
621 {
622 freeEventLogging();
623 stopEventLogWriter();
624 }
625
626 /*
627 * Post an event message to the capability's eventlog buffer.
628 * If the buffer is full, prints out the buffer and clears it.
629 */
630 void
631 postSchedEvent (Capability *cap,
632 EventTypeNum tag,
633 StgThreadID thread,
634 StgWord info1,
635 StgWord info2)
636 {
637 EventsBuf *eb = &capEventBuf[cap->no];
638 ensureRoomForEvent(eb, tag);
639
640 postEventHeader(eb, tag);
641
642 switch (tag) {
643 case EVENT_CREATE_THREAD: // (cap, thread)
644 case EVENT_RUN_THREAD: // (cap, thread)
645 case EVENT_THREAD_RUNNABLE: // (cap, thread)
646 {
647 postThreadID(eb,thread);
648 break;
649 }
650
651 case EVENT_CREATE_SPARK_THREAD: // (cap, spark_thread)
652 {
653 postThreadID(eb,info1 /* spark_thread */);
654 break;
655 }
656
657 case EVENT_MIGRATE_THREAD: // (cap, thread, new_cap)
658 case EVENT_THREAD_WAKEUP: // (cap, thread, other_cap)
659 {
660 postThreadID(eb,thread);
661 postCapNo(eb,info1 /* new_cap | victim_cap | other_cap */);
662 break;
663 }
664
665 case EVENT_STOP_THREAD: // (cap, thread, status)
666 {
667 postThreadID(eb,thread);
668 postWord16(eb,info1 /* status */);
669 postThreadID(eb,info2 /* blocked on thread */);
670 break;
671 }
672
673 default:
674 barf("postSchedEvent: unknown event tag %d", tag);
675 }
676 }
677
678 void
679 postSparkEvent (Capability *cap,
680 EventTypeNum tag,
681 StgWord info1)
682 {
683 EventsBuf *eb = &capEventBuf[cap->no];
684 ensureRoomForEvent(eb, tag);
685
686 postEventHeader(eb, tag);
687
688 switch (tag) {
689 case EVENT_CREATE_SPARK_THREAD: // (cap, spark_thread)
690 {
691 postThreadID(eb,info1 /* spark_thread */);
692 break;
693 }
694
695 case EVENT_SPARK_STEAL: // (cap, victim_cap)
696 {
697 postCapNo(eb,info1 /* victim_cap */);
698 break;
699 }
700
701 case EVENT_SPARK_CREATE: // (cap)
702 case EVENT_SPARK_DUD: // (cap)
703 case EVENT_SPARK_OVERFLOW: // (cap)
704 case EVENT_SPARK_RUN: // (cap)
705 case EVENT_SPARK_FIZZLE: // (cap)
706 case EVENT_SPARK_GC: // (cap)
707 {
708 break;
709 }
710
711 default:
712 barf("postSparkEvent: unknown event tag %d", tag);
713 }
714 }
715
716 void
717 postSparkCountersEvent (Capability *cap,
718 SparkCounters counters,
719 StgWord remaining)
720 {
721 EventsBuf *eb = &capEventBuf[cap->no];
722 ensureRoomForEvent(eb, EVENT_SPARK_COUNTERS);
723
724 postEventHeader(eb, EVENT_SPARK_COUNTERS);
725 /* EVENT_SPARK_COUNTERS (crt,dud,ovf,cnv,gcd,fiz,rem) */
726 postWord64(eb,counters.created);
727 postWord64(eb,counters.dud);
728 postWord64(eb,counters.overflowed);
729 postWord64(eb,counters.converted);
730 postWord64(eb,counters.gcd);
731 postWord64(eb,counters.fizzled);
732 postWord64(eb,remaining);
733 }
734
735 void
736 postCapEvent (EventTypeNum tag,
737 EventCapNo capno)
738 {
739 ACQUIRE_LOCK(&eventBufMutex);
740 ensureRoomForEvent(&eventBuf, tag);
741
742 postEventHeader(&eventBuf, tag);
743
744 switch (tag) {
745 case EVENT_CAP_CREATE: // (cap)
746 case EVENT_CAP_DELETE: // (cap)
747 case EVENT_CAP_ENABLE: // (cap)
748 case EVENT_CAP_DISABLE: // (cap)
749 {
750 postCapNo(&eventBuf,capno);
751 break;
752 }
753
754 default:
755 barf("postCapEvent: unknown event tag %d", tag);
756 }
757
758 RELEASE_LOCK(&eventBufMutex);
759 }
760
761 void postCapsetEvent (EventTypeNum tag,
762 EventCapsetID capset,
763 StgWord info)
764 {
765 ACQUIRE_LOCK(&eventBufMutex);
766 ensureRoomForEvent(&eventBuf, tag);
767
768 postEventHeader(&eventBuf, tag);
769 postCapsetID(&eventBuf, capset);
770
771 switch (tag) {
772 case EVENT_CAPSET_CREATE: // (capset, capset_type)
773 {
774 postCapsetType(&eventBuf, info /* capset_type */);
775 break;
776 }
777
778 case EVENT_CAPSET_DELETE: // (capset)
779 {
780 break;
781 }
782
783 case EVENT_CAPSET_ASSIGN_CAP: // (capset, capno)
784 case EVENT_CAPSET_REMOVE_CAP: // (capset, capno)
785 {
786 postCapNo(&eventBuf, info /* capno */);
787 break;
788 }
789 case EVENT_OSPROCESS_PID: // (capset, pid)
790 case EVENT_OSPROCESS_PPID: // (capset, parent_pid)
791 {
792 postOSProcessId(&eventBuf, info);
793 break;
794 }
795 default:
796 barf("postCapsetEvent: unknown event tag %d", tag);
797 }
798
799 RELEASE_LOCK(&eventBufMutex);
800 }
801
802 void postCapsetStrEvent (EventTypeNum tag,
803 EventCapsetID capset,
804 char *msg)
805 {
806 int strsize = strlen(msg);
807 int size = strsize + sizeof(EventCapsetID);
808 if (size > EVENT_PAYLOAD_SIZE_MAX) {
809 errorBelch("Event size exceeds EVENT_PAYLOAD_SIZE_MAX, bail out");
810 return;
811 }
812
813 ACQUIRE_LOCK(&eventBufMutex);
814
815 if (!hasRoomForVariableEvent(&eventBuf, size)){
816 printAndClearEventBuf(&eventBuf);
817
818 if (!hasRoomForVariableEvent(&eventBuf, size)){
819 errorBelch("Event size exceeds buffer size, bail out");
820 RELEASE_LOCK(&eventBufMutex);
821 return;
822 }
823 }
824
825 postEventHeader(&eventBuf, tag);
826 postPayloadSize(&eventBuf, size);
827 postCapsetID(&eventBuf, capset);
828
829 postBuf(&eventBuf, (StgWord8*) msg, strsize);
830
831 RELEASE_LOCK(&eventBufMutex);
832 }
833
834 void postCapsetVecEvent (EventTypeNum tag,
835 EventCapsetID capset,
836 int argc,
837 char *argv[])
838 {
839 int size = sizeof(EventCapsetID);
840
841 for (int i = 0; i < argc; i++) {
842 // 1 + strlen to account for the trailing \0, used as separator
843 size += 1 + strlen(argv[i]);
844 }
845
846 ACQUIRE_LOCK(&eventBufMutex);
847
848 if (!hasRoomForVariableEvent(&eventBuf, size)){
849 printAndClearEventBuf(&eventBuf);
850
851 if(!hasRoomForVariableEvent(&eventBuf, size)){
852 errorBelch("Event size exceeds buffer size, bail out");
853 RELEASE_LOCK(&eventBufMutex);
854 return;
855 }
856 }
857
858 postEventHeader(&eventBuf, tag);
859 postPayloadSize(&eventBuf, size);
860 postCapsetID(&eventBuf, capset);
861
862 for (int i = 0; i < argc; i++) {
863 // again, 1 + to account for \0
864 postBuf(&eventBuf, (StgWord8*) argv[i], 1 + strlen(argv[i]));
865 }
866
867 RELEASE_LOCK(&eventBufMutex);
868 }
869
870 void postWallClockTime (EventCapsetID capset)
871 {
872 StgWord64 ts;
873 StgWord64 sec;
874 StgWord32 nsec;
875
876 ACQUIRE_LOCK(&eventBufMutex);
877
878 /* The EVENT_WALL_CLOCK_TIME event is intended to allow programs
879 reading the eventlog to match up the event timestamps with wall
880 clock time. The normal event timestamps measure time since the
881 start of the program. To align eventlogs from concurrent
882 processes we need to be able to match up the timestamps. One way
883 to do this is if we know how the timestamps and wall clock time
884 match up (and of course if both processes have sufficiently
885 synchronised clocks).
886
887 So we want to make sure that the timestamp that we generate for
888 this event matches up very closely with the wall clock time.
889 Unfortunately we currently have to use two different APIs to get
890 the elapsed time vs the wall clock time. So to minimise the
891 difference we just call them very close together.
892 */
893
894 getUnixEpochTime(&sec, &nsec); /* Get the wall clock time */
895 ts = time_ns(); /* Get the eventlog timestamp */
896 ensureRoomForEvent(&eventBuf, EVENT_WALL_CLOCK_TIME);
897
898 /* Normally we'd call postEventHeader(), but that generates its own
899 timestamp, so we go one level lower so we can write out the
900 timestamp we already generated above. */
901 postEventTypeNum(&eventBuf, EVENT_WALL_CLOCK_TIME);
902 postWord64(&eventBuf, ts);
903
904 /* EVENT_WALL_CLOCK_TIME (capset, unix_epoch_seconds, nanoseconds) */
905 postCapsetID(&eventBuf, capset);
906 postWord64(&eventBuf, sec);
907 postWord32(&eventBuf, nsec);
908
909 RELEASE_LOCK(&eventBufMutex);
910 }
911
912 /*
913 * Various GC and heap events
914 */
915 void postHeapEvent (Capability *cap,
916 EventTypeNum tag,
917 EventCapsetID heap_capset,
918 W_ info1)
919 {
920 EventsBuf *eb = &capEventBuf[cap->no];
921 ensureRoomForEvent(eb, tag);
922
923 postEventHeader(eb, tag);
924
925 switch (tag) {
926 case EVENT_HEAP_ALLOCATED: // (heap_capset, alloc_bytes)
927 case EVENT_HEAP_SIZE: // (heap_capset, size_bytes)
928 case EVENT_HEAP_LIVE: // (heap_capset, live_bytes)
929 {
930 postCapsetID(eb, heap_capset);
931 postWord64(eb, info1 /* alloc/size/live_bytes */);
932 break;
933 }
934
935 default:
936 barf("postHeapEvent: unknown event tag %d", tag);
937 }
938 }
939
940 void postEventHeapInfo (EventCapsetID heap_capset,
941 uint32_t gens,
942 W_ maxHeapSize,
943 W_ allocAreaSize,
944 W_ mblockSize,
945 W_ blockSize)
946 {
947 ACQUIRE_LOCK(&eventBufMutex);
948 ensureRoomForEvent(&eventBuf, EVENT_HEAP_INFO_GHC);
949
950 postEventHeader(&eventBuf, EVENT_HEAP_INFO_GHC);
951 /* EVENT_HEAP_INFO_GHC (heap_capset, n_generations,
952 max_heap_size, alloc_area_size,
953 mblock_size, block_size) */
954 postCapsetID(&eventBuf, heap_capset);
955 postWord16(&eventBuf, gens);
956 postWord64(&eventBuf, maxHeapSize);
957 postWord64(&eventBuf, allocAreaSize);
958 postWord64(&eventBuf, mblockSize);
959 postWord64(&eventBuf, blockSize);
960
961 RELEASE_LOCK(&eventBufMutex);
962 }
963
964 void postEventGcStats (Capability *cap,
965 EventCapsetID heap_capset,
966 uint32_t gen,
967 W_ copied,
968 W_ slop,
969 W_ fragmentation,
970 uint32_t par_n_threads,
971 W_ par_max_copied,
972 W_ par_tot_copied,
973 W_ par_balanced_copied)
974 {
975 EventsBuf *eb = &capEventBuf[cap->no];
976 ensureRoomForEvent(eb, EVENT_GC_STATS_GHC);
977
978 postEventHeader(eb, EVENT_GC_STATS_GHC);
979 /* EVENT_GC_STATS_GHC (heap_capset, generation,
980 copied_bytes, slop_bytes, frag_bytes,
981 par_n_threads, par_max_copied,
982 par_tot_copied, par_balanced_copied) */
983 postCapsetID(eb, heap_capset);
984 postWord16(eb, gen);
985 postWord64(eb, copied);
986 postWord64(eb, slop);
987 postWord64(eb, fragmentation);
988 postWord32(eb, par_n_threads);
989 postWord64(eb, par_max_copied);
990 postWord64(eb, par_tot_copied);
991 postWord64(eb, par_balanced_copied);
992 }
993
994 void postTaskCreateEvent (EventTaskId taskId,
995 EventCapNo capno,
996 EventKernelThreadId tid)
997 {
998 ACQUIRE_LOCK(&eventBufMutex);
999 ensureRoomForEvent(&eventBuf, EVENT_TASK_CREATE);
1000
1001 postEventHeader(&eventBuf, EVENT_TASK_CREATE);
1002 /* EVENT_TASK_CREATE (taskID, cap, tid) */
1003 postTaskId(&eventBuf, taskId);
1004 postCapNo(&eventBuf, capno);
1005 postKernelThreadId(&eventBuf, tid);
1006
1007 RELEASE_LOCK(&eventBufMutex);
1008 }
1009
1010 void postTaskMigrateEvent (EventTaskId taskId,
1011 EventCapNo capno,
1012 EventCapNo new_capno)
1013 {
1014 ACQUIRE_LOCK(&eventBufMutex);
1015 ensureRoomForEvent(&eventBuf, EVENT_TASK_MIGRATE);
1016
1017 postEventHeader(&eventBuf, EVENT_TASK_MIGRATE);
1018 /* EVENT_TASK_MIGRATE (taskID, cap, new_cap) */
1019 postTaskId(&eventBuf, taskId);
1020 postCapNo(&eventBuf, capno);
1021 postCapNo(&eventBuf, new_capno);
1022
1023 RELEASE_LOCK(&eventBufMutex);
1024 }
1025
1026 void postTaskDeleteEvent (EventTaskId taskId)
1027 {
1028 ACQUIRE_LOCK(&eventBufMutex);
1029 ensureRoomForEvent(&eventBuf, EVENT_TASK_DELETE);
1030
1031 postEventHeader(&eventBuf, EVENT_TASK_DELETE);
1032 /* EVENT_TASK_DELETE (taskID) */
1033 postTaskId(&eventBuf, taskId);
1034
1035 RELEASE_LOCK(&eventBufMutex);
1036 }
1037
1038 void
1039 postEventNoCap (EventTypeNum tag)
1040 {
1041 ACQUIRE_LOCK(&eventBufMutex);
1042 ensureRoomForEvent(&eventBuf, tag);
1043 postEventHeader(&eventBuf, tag);
1044 RELEASE_LOCK(&eventBufMutex);
1045 }
1046
1047 void
1048 postEvent (Capability *cap, EventTypeNum tag)
1049 {
1050 EventsBuf *eb = &capEventBuf[cap->no];
1051 ensureRoomForEvent(eb, tag);
1052 postEventHeader(eb, tag);
1053 }
1054
1055 void
1056 postEventAtTimestamp (Capability *cap, EventTimestamp ts, EventTypeNum tag)
1057 {
1058 EventsBuf *eb = &capEventBuf[cap->no];
1059 ensureRoomForEvent(eb, tag);
1060
1061 /* Normally we'd call postEventHeader(), but that generates its own
1062 timestamp, so we go one level lower so we can write out
1063 the timestamp we received as an argument. */
1064 postEventTypeNum(eb, tag);
1065 postWord64(eb, ts);
1066 }
1067
1068 #define BUF 512
1069
1070 void postLogMsg(EventsBuf *eb, EventTypeNum type, char *msg, va_list ap)
1071 {
1072 char buf[BUF];
1073 uint32_t size = vsnprintf(buf, BUF, msg,ap);
1074 if (size > BUF) {
1075 buf[BUF-1] = '\0';
1076 size = BUF;
1077 }
1078
1079 ensureRoomForVariableEvent(eb, size);
1080
1081 postEventHeader(eb, type);
1082 postPayloadSize(eb, size);
1083 postBuf(eb,(StgWord8*)buf,size);
1084 }
1085
1086 void postMsg(char *msg, va_list ap)
1087 {
1088 ACQUIRE_LOCK(&eventBufMutex);
1089 postLogMsg(&eventBuf, EVENT_LOG_MSG, msg, ap);
1090 RELEASE_LOCK(&eventBufMutex);
1091 }
1092
1093 void postCapMsg(Capability *cap, char *msg, va_list ap)
1094 {
1095 postLogMsg(&capEventBuf[cap->no], EVENT_LOG_MSG, msg, ap);
1096 }
1097
1098 void postUserEvent(Capability *cap, EventTypeNum type, char *msg)
1099 {
1100 const size_t size = strlen(msg);
1101 if (size > EVENT_PAYLOAD_SIZE_MAX) {
1102 errorBelch("Event size exceeds EVENT_PAYLOAD_SIZE_MAX, bail out");
1103 return;
1104 }
1105
1106 EventsBuf *eb = &capEventBuf[cap->no];
1107 if (!hasRoomForVariableEvent(eb, size)){
1108 printAndClearEventBuf(eb);
1109
1110 if (!hasRoomForVariableEvent(eb, size)){
1111 errorBelch("Event size exceeds buffer size, bail out");
1112 return;
1113 }
1114 }
1115
1116 postEventHeader(eb, type);
1117 postPayloadSize(eb, size);
1118 postBuf(eb, (StgWord8*) msg, size);
1119 }
1120
1121 void postUserBinaryEvent(Capability *cap,
1122 EventTypeNum type,
1123 uint8_t *msg,
1124 size_t size)
1125 {
1126 if (size > EVENT_PAYLOAD_SIZE_MAX) {
1127 errorBelch("Event size exceeds EVENT_PAYLOAD_SIZE_MAX, bail out");
1128 return;
1129 }
1130
1131 EventsBuf *eb = &capEventBuf[cap->no];
1132 if (!hasRoomForVariableEvent(eb, size)){
1133 printAndClearEventBuf(eb);
1134
1135 if (!hasRoomForVariableEvent(eb, size)){
1136 errorBelch("Event size exceeds buffer size, bail out");
1137 return;
1138 }
1139 }
1140
1141 postEventHeader(eb, type);
1142 postPayloadSize(eb, size);
1143 postBuf(eb, (StgWord8*) msg, size);
1144 }
1145
1146 void postThreadLabel(Capability *cap,
1147 EventThreadID id,
1148 char *label)
1149 {
1150 const int strsize = strlen(label);
1151 const int size = strsize + sizeof(EventThreadID);
1152 if (size > EVENT_PAYLOAD_SIZE_MAX) {
1153 errorBelch("Event size exceeds EVENT_PAYLOAD_SIZE_MAX, bail out");
1154 return;
1155 }
1156
1157 EventsBuf *eb = &capEventBuf[cap->no];
1158 if (!hasRoomForVariableEvent(eb, size)){
1159 printAndClearEventBuf(eb);
1160
1161 if (!hasRoomForVariableEvent(eb, size)){
1162 errorBelch("Event size exceeds buffer size, bail out");
1163 return;
1164 }
1165 }
1166
1167 postEventHeader(eb, EVENT_THREAD_LABEL);
1168 postPayloadSize(eb, size);
1169 postThreadID(eb, id);
1170 postBuf(eb, (StgWord8*) label, strsize);
1171 }
1172
1173 void postConcUpdRemSetFlush(Capability *cap)
1174 {
1175 EventsBuf *eb = &capEventBuf[cap->no];
1176 ensureRoomForEvent(eb, EVENT_CONC_UPD_REM_SET_FLUSH);
1177 postEventHeader(eb, EVENT_CONC_UPD_REM_SET_FLUSH);
1178 postCapNo(eb, cap->no);
1179 }
1180
1181 void postConcMarkEnd(StgWord32 marked_obj_count)
1182 {
1183 ACQUIRE_LOCK(&eventBufMutex);
1184 ensureRoomForEvent(&eventBuf, EVENT_CONC_MARK_END);
1185 postEventHeader(&eventBuf, EVENT_CONC_MARK_END);
1186 postWord32(&eventBuf, marked_obj_count);
1187 RELEASE_LOCK(&eventBufMutex);
1188 }
1189
1190 void postNonmovingHeapCensus(int log_blk_size,
1191 const struct NonmovingAllocCensus *census)
1192 {
1193 ACQUIRE_LOCK(&eventBufMutex);
1194 postEventHeader(&eventBuf, EVENT_NONMOVING_HEAP_CENSUS);
1195 postWord8(&eventBuf, log_blk_size);
1196 postWord32(&eventBuf, census->n_active_segs);
1197 postWord32(&eventBuf, census->n_filled_segs);
1198 postWord32(&eventBuf, census->n_live_blocks);
1199 RELEASE_LOCK(&eventBufMutex);
1200 }
1201
1202 void closeBlockMarker (EventsBuf *ebuf)
1203 {
1204 if (ebuf->marker)
1205 {
1206 // (type:16, time:64, size:32, end_time:64)
1207
1208 StgInt8* save_pos = ebuf->pos;
1209 ebuf->pos = ebuf->marker + sizeof(EventTypeNum) +
1210 sizeof(EventTimestamp);
1211 postWord32(ebuf, save_pos - ebuf->marker);
1212 postTimestamp(ebuf);
1213 ebuf->pos = save_pos;
1214 ebuf->marker = NULL;
1215 }
1216 }
1217
1218
1219 void postBlockMarker (EventsBuf *eb)
1220 {
1221 ensureRoomForEvent(eb, EVENT_BLOCK_MARKER);
1222
1223 closeBlockMarker(eb);
1224
1225 eb->marker = eb->pos;
1226 postEventHeader(eb, EVENT_BLOCK_MARKER);
1227 postWord32(eb,0); // these get filled in later by closeBlockMarker();
1228 postWord64(eb,0);
1229 postCapNo(eb, eb->capno);
1230 }
1231
1232 static HeapProfBreakdown getHeapProfBreakdown(void)
1233 {
1234 switch (RtsFlags.ProfFlags.doHeapProfile) {
1235 case HEAP_BY_CCS:
1236 return HEAP_PROF_BREAKDOWN_COST_CENTRE;
1237 case HEAP_BY_MOD:
1238 return HEAP_PROF_BREAKDOWN_MODULE;
1239 case HEAP_BY_DESCR:
1240 return HEAP_PROF_BREAKDOWN_CLOSURE_DESCR;
1241 case HEAP_BY_TYPE:
1242 return HEAP_PROF_BREAKDOWN_TYPE_DESCR;
1243 case HEAP_BY_RETAINER:
1244 return HEAP_PROF_BREAKDOWN_RETAINER;
1245 case HEAP_BY_LDV:
1246 return HEAP_PROF_BREAKDOWN_BIOGRAPHY;
1247 case HEAP_BY_CLOSURE_TYPE:
1248 return HEAP_PROF_BREAKDOWN_CLOSURE_TYPE;
1249 default:
1250 barf("getHeapProfBreakdown: unknown heap profiling mode");
1251 }
1252 }
1253
1254 void postHeapProfBegin(StgWord8 profile_id)
1255 {
1256 ACQUIRE_LOCK(&eventBufMutex);
1257 PROFILING_FLAGS *flags = &RtsFlags.ProfFlags;
1258 StgWord modSelector_len =
1259 flags->modSelector ? strlen(flags->modSelector) : 0;
1260 StgWord descrSelector_len =
1261 flags->descrSelector ? strlen(flags->descrSelector) : 0;
1262 StgWord typeSelector_len =
1263 flags->typeSelector ? strlen(flags->typeSelector) : 0;
1264 StgWord ccSelector_len =
1265 flags->ccSelector ? strlen(flags->ccSelector) : 0;
1266 StgWord ccsSelector_len =
1267 flags->ccsSelector ? strlen(flags->ccsSelector) : 0;
1268 StgWord retainerSelector_len =
1269 flags->retainerSelector ? strlen(flags->retainerSelector) : 0;
1270 StgWord bioSelector_len =
1271 flags->bioSelector ? strlen(flags->bioSelector) : 0;
1272 StgWord len =
1273 1+8+4 + modSelector_len + descrSelector_len +
1274 typeSelector_len + ccSelector_len + ccsSelector_len +
1275 retainerSelector_len + bioSelector_len + 7;
1276 ensureRoomForVariableEvent(&eventBuf, len);
1277 postEventHeader(&eventBuf, EVENT_HEAP_PROF_BEGIN);
1278 postPayloadSize(&eventBuf, len);
1279 postWord8(&eventBuf, profile_id);
1280 postWord64(&eventBuf, TimeToNS(flags->heapProfileInterval));
1281 postWord32(&eventBuf, getHeapProfBreakdown());
1282 postString(&eventBuf, flags->modSelector);
1283 postString(&eventBuf, flags->descrSelector);
1284 postString(&eventBuf, flags->typeSelector);
1285 postString(&eventBuf, flags->ccSelector);
1286 postString(&eventBuf, flags->ccsSelector);
1287 postString(&eventBuf, flags->retainerSelector);
1288 postString(&eventBuf, flags->bioSelector);
1289 RELEASE_LOCK(&eventBufMutex);
1290 }
1291
1292 void postHeapProfSampleBegin(StgInt era)
1293 {
1294 ACQUIRE_LOCK(&eventBufMutex);
1295 ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
1296 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
1297 postWord64(&eventBuf, era);
1298 RELEASE_LOCK(&eventBufMutex);
1299 }
1300
1301
1302 void postHeapBioProfSampleBegin(StgInt era, StgWord64 time)
1303 {
1304 ACQUIRE_LOCK(&eventBufMutex);
1305 ensureRoomForEvent(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
1306 postEventHeader(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
1307 postWord64(&eventBuf, era);
1308 postWord64(&eventBuf, time);
1309 RELEASE_LOCK(&eventBufMutex);
1310 }
1311
1312 void postHeapProfSampleEnd(StgInt era)
1313 {
1314 ACQUIRE_LOCK(&eventBufMutex);
1315 ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
1316 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
1317 postWord64(&eventBuf, era);
1318 RELEASE_LOCK(&eventBufMutex);
1319 }
1320
1321 void postHeapProfSampleString(StgWord8 profile_id,
1322 const char *label,
1323 StgWord64 residency)
1324 {
1325 ACQUIRE_LOCK(&eventBufMutex);
1326 StgWord label_len = strlen(label);
1327 StgWord len = 1+8+label_len+1;
1328 ensureRoomForVariableEvent(&eventBuf, len);
1329 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_STRING);
1330 postPayloadSize(&eventBuf, len);
1331 postWord8(&eventBuf, profile_id);
1332 postWord64(&eventBuf, residency);
1333 postString(&eventBuf, label);
1334 RELEASE_LOCK(&eventBufMutex);
1335 }
1336
1337 #if defined(PROFILING)
1338 void postHeapProfCostCentre(StgWord32 ccID,
1339 const char *label,
1340 const char *module,
1341 const char *srcloc,
1342 StgBool is_caf)
1343 {
1344 ACQUIRE_LOCK(&eventBufMutex);
1345 StgWord label_len = strlen(label);
1346 StgWord module_len = strlen(module);
1347 StgWord srcloc_len = strlen(srcloc);
1348 StgWord len = 4+label_len+module_len+srcloc_len+3+1;
1349 ensureRoomForVariableEvent(&eventBuf, len);
1350 postEventHeader(&eventBuf, EVENT_HEAP_PROF_COST_CENTRE);
1351 postPayloadSize(&eventBuf, len);
1352 postWord32(&eventBuf, ccID);
1353 postString(&eventBuf, label);
1354 postString(&eventBuf, module);
1355 postString(&eventBuf, srcloc);
1356 postWord8(&eventBuf, is_caf);
1357 RELEASE_LOCK(&eventBufMutex);
1358 }
1359
1360 void postHeapProfSampleCostCentre(StgWord8 profile_id,
1361 CostCentreStack *stack,
1362 StgWord64 residency)
1363 {
1364 ACQUIRE_LOCK(&eventBufMutex);
1365 StgWord depth = 0;
1366 CostCentreStack *ccs;
1367 for (ccs = stack; ccs != NULL && ccs != CCS_MAIN; ccs = ccs->prevStack)
1368 depth++;
1369 if (depth > 0xff) depth = 0xff;
1370
1371 StgWord len = 1+8+1+depth*4;
1372 ensureRoomForVariableEvent(&eventBuf, len);
1373 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_COST_CENTRE);
1374 postPayloadSize(&eventBuf, len);
1375 postWord8(&eventBuf, profile_id);
1376 postWord64(&eventBuf, residency);
1377 postWord8(&eventBuf, depth);
1378 for (ccs = stack;
1379 depth>0 && ccs != NULL && ccs != CCS_MAIN;
1380 ccs = ccs->prevStack, depth--)
1381 postWord32(&eventBuf, ccs->cc->ccID);
1382 RELEASE_LOCK(&eventBufMutex);
1383 }
1384 #endif /* PROFILING */
1385
1386 void printAndClearEventBuf (EventsBuf *ebuf)
1387 {
1388 closeBlockMarker(ebuf);
1389
1390 if (ebuf->begin != NULL && ebuf->pos != ebuf->begin)
1391 {
1392 size_t elog_size = ebuf->pos - ebuf->begin;
1393 if (!writeEventLog(ebuf->begin, elog_size)) {
1394 debugBelch(
1395 "printAndClearEventLog: could not flush event log"
1396 );
1397 resetEventsBuf(ebuf);
1398 return;
1399 }
1400
1401 resetEventsBuf(ebuf);
1402 flushCount++;
1403
1404 postBlockMarker(ebuf);
1405 }
1406 }
1407
1408 void initEventsBuf(EventsBuf* eb, StgWord64 size, EventCapNo capno)
1409 {
1410 eb->begin = eb->pos = stgMallocBytes(size, "initEventsBuf");
1411 eb->size = size;
1412 eb->marker = NULL;
1413 eb->capno = capno;
1414 }
1415
1416 void resetEventsBuf(EventsBuf* eb)
1417 {
1418 eb->pos = eb->begin;
1419 eb->marker = NULL;
1420 }
1421
1422 StgBool hasRoomForEvent(EventsBuf *eb, EventTypeNum eNum)
1423 {
1424 uint32_t size = sizeof(EventTypeNum) + sizeof(EventTimestamp) + eventTypes[eNum].size;
1425
1426 if (eb->pos + size > eb->begin + eb->size) {
1427 return 0; // Not enough space.
1428 } else {
1429 return 1; // Buf has enough space for the event.
1430 }
1431 }
1432
1433 StgBool hasRoomForVariableEvent(EventsBuf *eb, uint32_t payload_bytes)
1434 {
1435 uint32_t size = sizeof(EventTypeNum) + sizeof(EventTimestamp) +
1436 sizeof(EventPayloadSize) + payload_bytes;
1437
1438 if (eb->pos + size > eb->begin + eb->size) {
1439 return 0; // Not enough space.
1440 } else {
1441 return 1; // Buf has enough space for the event.
1442 }
1443 }
1444
1445 void ensureRoomForEvent(EventsBuf *eb, EventTypeNum tag)
1446 {
1447 if (!hasRoomForEvent(eb, tag)) {
1448 // Flush event buffer to make room for new event.
1449 printAndClearEventBuf(eb);
1450 }
1451 }
1452
1453 int ensureRoomForVariableEvent(EventsBuf *eb, StgWord16 size)
1454 {
1455 if (!hasRoomForVariableEvent(eb, size)) {
1456 // Flush event buffer to make room for new event.
1457 printAndClearEventBuf(eb);
1458 if (!hasRoomForVariableEvent(eb, size))
1459 return 1; // Not enough space
1460 }
1461 return 0;
1462 }
1463
1464
1465 void postEventType(EventsBuf *eb, EventType *et)
1466 {
1467 postInt32(eb, EVENT_ET_BEGIN);
1468 postEventTypeNum(eb, et->etNum);
1469 postWord16(eb, (StgWord16)et->size);
1470 const int desclen = strlen(et->desc);
1471 postWord32(eb, desclen);
1472 for (int d = 0; d < desclen; ++d) {
1473 postInt8(eb, (StgInt8)et->desc[d]);
1474 }
1475 postWord32(eb, 0); // no extensions yet
1476 postInt32(eb, EVENT_ET_END);
1477 }
1478
1479 #endif /* TRACING */