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