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