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