a9bb6035237eac0ef71fb5805d36c5023807d3c0
[ghc.git] / rts / eventlog / EventLog.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 2008-2009
4 *
5 * Support for fast binary event logging.
6 *
7 * ---------------------------------------------------------------------------*/
8
9 #include "PosixSource.h"
10 #include "Rts.h"
11
12 #if defined(TRACING)
13
14 #include "Trace.h"
15 #include "Capability.h"
16 #include "RtsUtils.h"
17 #include "Stats.h"
18 #include "EventLog.h"
19
20 #include <string.h>
21 #include <stdio.h>
22 #if defined(HAVE_SYS_TYPES_H)
23 #include <sys/types.h>
24 #endif
25 #if defined(HAVE_UNISTD_H)
26 #include <unistd.h>
27 #endif
28
29 static const EventLogWriter *event_log_writer;
30
31 #define EVENT_LOG_SIZE 2 * (1024 * 1024) // 2MB
32
33 static int flushCount;
34
35 // Struct for record keeping of buffer to store event types and events.
36 typedef struct _EventsBuf {
37 StgInt8 *begin;
38 StgInt8 *pos;
39 StgInt8 *marker;
40 StgWord64 size;
41 EventCapNo capno; // which capability this buffer belongs to, or -1
42 } EventsBuf;
43
44 EventsBuf *capEventBuf; // one EventsBuf for each Capability
45
46 EventsBuf eventBuf; // an EventsBuf not associated with any Capability
47 #if defined(THREADED_RTS)
48 Mutex eventBufMutex; // protected by this mutex
49 #endif
50
51 char *EventDesc[] = {
52 [EVENT_CREATE_THREAD] = "Create thread",
53 [EVENT_RUN_THREAD] = "Run thread",
54 [EVENT_STOP_THREAD] = "Stop thread",
55 [EVENT_THREAD_RUNNABLE] = "Thread runnable",
56 [EVENT_MIGRATE_THREAD] = "Migrate thread",
57 [EVENT_THREAD_WAKEUP] = "Wakeup thread",
58 [EVENT_THREAD_LABEL] = "Thread label",
59 [EVENT_CAP_CREATE] = "Create capability",
60 [EVENT_CAP_DELETE] = "Delete capability",
61 [EVENT_CAP_DISABLE] = "Disable capability",
62 [EVENT_CAP_ENABLE] = "Enable capability",
63 [EVENT_GC_START] = "Starting GC",
64 [EVENT_GC_END] = "Finished GC",
65 [EVENT_REQUEST_SEQ_GC] = "Request sequential GC",
66 [EVENT_REQUEST_PAR_GC] = "Request parallel GC",
67 [EVENT_GC_GLOBAL_SYNC] = "Synchronise stop-the-world GC",
68 [EVENT_GC_STATS_GHC] = "GC statistics",
69 [EVENT_HEAP_INFO_GHC] = "Heap static parameters",
70 [EVENT_HEAP_ALLOCATED] = "Total heap mem ever allocated",
71 [EVENT_HEAP_SIZE] = "Current heap size",
72 [EVENT_HEAP_LIVE] = "Current heap live data",
73 [EVENT_CREATE_SPARK_THREAD] = "Create spark thread",
74 [EVENT_LOG_MSG] = "Log message",
75 [EVENT_USER_MSG] = "User message",
76 [EVENT_USER_MARKER] = "User marker",
77 [EVENT_GC_IDLE] = "GC idle",
78 [EVENT_GC_WORK] = "GC working",
79 [EVENT_GC_DONE] = "GC done",
80 [EVENT_BLOCK_MARKER] = "Block marker",
81 [EVENT_CAPSET_CREATE] = "Create capability set",
82 [EVENT_CAPSET_DELETE] = "Delete capability set",
83 [EVENT_CAPSET_ASSIGN_CAP] = "Add capability to capability set",
84 [EVENT_CAPSET_REMOVE_CAP] = "Remove capability from capability set",
85 [EVENT_RTS_IDENTIFIER] = "RTS name and version",
86 [EVENT_PROGRAM_ARGS] = "Program arguments",
87 [EVENT_PROGRAM_ENV] = "Program environment variables",
88 [EVENT_OSPROCESS_PID] = "Process ID",
89 [EVENT_OSPROCESS_PPID] = "Parent process ID",
90 [EVENT_WALL_CLOCK_TIME] = "Wall clock time",
91 [EVENT_SPARK_COUNTERS] = "Spark counters",
92 [EVENT_SPARK_CREATE] = "Spark create",
93 [EVENT_SPARK_DUD] = "Spark dud",
94 [EVENT_SPARK_OVERFLOW] = "Spark overflow",
95 [EVENT_SPARK_RUN] = "Spark run",
96 [EVENT_SPARK_STEAL] = "Spark steal",
97 [EVENT_SPARK_FIZZLE] = "Spark fizzle",
98 [EVENT_SPARK_GC] = "Spark GC",
99 [EVENT_TASK_CREATE] = "Task create",
100 [EVENT_TASK_MIGRATE] = "Task migrate",
101 [EVENT_TASK_DELETE] = "Task delete",
102 [EVENT_HACK_BUG_T9003] = "Empty event for bug #9003",
103 [EVENT_HEAP_PROF_BEGIN] = "Start of heap profile",
104 [EVENT_HEAP_PROF_COST_CENTRE] = "Cost center definition",
105 [EVENT_HEAP_PROF_SAMPLE_BEGIN] = "Start of heap profile sample",
106 [EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN] = "Start of heap profile (biographical) sample",
107 [EVENT_HEAP_PROF_SAMPLE_END] = "End of heap profile sample",
108 [EVENT_HEAP_PROF_SAMPLE_STRING] = "Heap profile string sample",
109 [EVENT_HEAP_PROF_SAMPLE_COST_CENTRE] = "Heap profile cost-centre sample",
110 [EVENT_USER_BINARY_MSG] = "User binary message",
111 [EVENT_CONC_MARK_BEGIN] = "Begin concurrent mark phase",
112 [EVENT_CONC_MARK_END] = "End concurrent mark phase",
113 [EVENT_CONC_SYNC_BEGIN] = "Begin concurrent GC synchronisation",
114 [EVENT_CONC_SYNC_END] = "End concurrent GC synchronisation",
115 [EVENT_CONC_SWEEP_BEGIN] = "Begin concurrent sweep",
116 [EVENT_CONC_SWEEP_END] = "End concurrent sweep",
117 [EVENT_CONC_UPD_REM_SET_FLUSH] = "Update remembered set flushed"
118 };
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_BIO_PROF_SAMPLE_BEGIN:
437 eventTypes[t].size = 16;
438 break;
439
440 case EVENT_HEAP_PROF_SAMPLE_END:
441 eventTypes[t].size = 8;
442 break;
443
444 case EVENT_HEAP_PROF_SAMPLE_STRING:
445 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
446 break;
447
448 case EVENT_HEAP_PROF_SAMPLE_COST_CENTRE:
449 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
450 break;
451
452 case EVENT_USER_BINARY_MSG:
453 eventTypes[t].size = EVENT_SIZE_DYNAMIC;
454 break;
455
456 case EVENT_CONC_MARK_BEGIN:
457 case EVENT_CONC_SYNC_BEGIN:
458 case EVENT_CONC_SYNC_END:
459 case EVENT_CONC_SWEEP_BEGIN:
460 case EVENT_CONC_SWEEP_END:
461 eventTypes[t].size = 0;
462 break;
463
464 case EVENT_CONC_MARK_END:
465 eventTypes[t].size = 4;
466 break;
467
468 case EVENT_CONC_UPD_REM_SET_FLUSH: // (cap)
469 eventTypes[t].size =
470 sizeof(EventCapNo);
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 closeBlockMarker (EventsBuf *ebuf)
1186 {
1187 if (ebuf->marker)
1188 {
1189 // (type:16, time:64, size:32, end_time:64)
1190
1191 StgInt8* save_pos = ebuf->pos;
1192 ebuf->pos = ebuf->marker + sizeof(EventTypeNum) +
1193 sizeof(EventTimestamp);
1194 postWord32(ebuf, save_pos - ebuf->marker);
1195 postTimestamp(ebuf);
1196 ebuf->pos = save_pos;
1197 ebuf->marker = NULL;
1198 }
1199 }
1200
1201
1202 void postBlockMarker (EventsBuf *eb)
1203 {
1204 ensureRoomForEvent(eb, EVENT_BLOCK_MARKER);
1205
1206 closeBlockMarker(eb);
1207
1208 eb->marker = eb->pos;
1209 postEventHeader(eb, EVENT_BLOCK_MARKER);
1210 postWord32(eb,0); // these get filled in later by closeBlockMarker();
1211 postWord64(eb,0);
1212 postCapNo(eb, eb->capno);
1213 }
1214
1215 static HeapProfBreakdown getHeapProfBreakdown(void)
1216 {
1217 switch (RtsFlags.ProfFlags.doHeapProfile) {
1218 case HEAP_BY_CCS:
1219 return HEAP_PROF_BREAKDOWN_COST_CENTRE;
1220 case HEAP_BY_MOD:
1221 return HEAP_PROF_BREAKDOWN_MODULE;
1222 case HEAP_BY_DESCR:
1223 return HEAP_PROF_BREAKDOWN_CLOSURE_DESCR;
1224 case HEAP_BY_TYPE:
1225 return HEAP_PROF_BREAKDOWN_TYPE_DESCR;
1226 case HEAP_BY_RETAINER:
1227 return HEAP_PROF_BREAKDOWN_RETAINER;
1228 case HEAP_BY_LDV:
1229 return HEAP_PROF_BREAKDOWN_BIOGRAPHY;
1230 case HEAP_BY_CLOSURE_TYPE:
1231 return HEAP_PROF_BREAKDOWN_CLOSURE_TYPE;
1232 default:
1233 barf("getHeapProfBreakdown: unknown heap profiling mode");
1234 }
1235 }
1236
1237 void postHeapProfBegin(StgWord8 profile_id)
1238 {
1239 ACQUIRE_LOCK(&eventBufMutex);
1240 PROFILING_FLAGS *flags = &RtsFlags.ProfFlags;
1241 StgWord modSelector_len =
1242 flags->modSelector ? strlen(flags->modSelector) : 0;
1243 StgWord descrSelector_len =
1244 flags->descrSelector ? strlen(flags->descrSelector) : 0;
1245 StgWord typeSelector_len =
1246 flags->typeSelector ? strlen(flags->typeSelector) : 0;
1247 StgWord ccSelector_len =
1248 flags->ccSelector ? strlen(flags->ccSelector) : 0;
1249 StgWord ccsSelector_len =
1250 flags->ccsSelector ? strlen(flags->ccsSelector) : 0;
1251 StgWord retainerSelector_len =
1252 flags->retainerSelector ? strlen(flags->retainerSelector) : 0;
1253 StgWord bioSelector_len =
1254 flags->bioSelector ? strlen(flags->bioSelector) : 0;
1255 StgWord len =
1256 1+8+4 + modSelector_len + descrSelector_len +
1257 typeSelector_len + ccSelector_len + ccsSelector_len +
1258 retainerSelector_len + bioSelector_len + 7;
1259 ensureRoomForVariableEvent(&eventBuf, len);
1260 postEventHeader(&eventBuf, EVENT_HEAP_PROF_BEGIN);
1261 postPayloadSize(&eventBuf, len);
1262 postWord8(&eventBuf, profile_id);
1263 postWord64(&eventBuf, TimeToNS(flags->heapProfileInterval));
1264 postWord32(&eventBuf, getHeapProfBreakdown());
1265 postString(&eventBuf, flags->modSelector);
1266 postString(&eventBuf, flags->descrSelector);
1267 postString(&eventBuf, flags->typeSelector);
1268 postString(&eventBuf, flags->ccSelector);
1269 postString(&eventBuf, flags->ccsSelector);
1270 postString(&eventBuf, flags->retainerSelector);
1271 postString(&eventBuf, flags->bioSelector);
1272 RELEASE_LOCK(&eventBufMutex);
1273 }
1274
1275 void postHeapProfSampleBegin(StgInt era)
1276 {
1277 ACQUIRE_LOCK(&eventBufMutex);
1278 ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
1279 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
1280 postWord64(&eventBuf, era);
1281 RELEASE_LOCK(&eventBufMutex);
1282 }
1283
1284
1285 void postHeapBioProfSampleBegin(StgInt era, StgWord64 time)
1286 {
1287 ACQUIRE_LOCK(&eventBufMutex);
1288 ensureRoomForEvent(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
1289 postEventHeader(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
1290 postWord64(&eventBuf, era);
1291 postWord64(&eventBuf, time);
1292 RELEASE_LOCK(&eventBufMutex);
1293 }
1294
1295 void postHeapProfSampleEnd(StgInt era)
1296 {
1297 ACQUIRE_LOCK(&eventBufMutex);
1298 ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
1299 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
1300 postWord64(&eventBuf, era);
1301 RELEASE_LOCK(&eventBufMutex);
1302 }
1303
1304 void postHeapProfSampleString(StgWord8 profile_id,
1305 const char *label,
1306 StgWord64 residency)
1307 {
1308 ACQUIRE_LOCK(&eventBufMutex);
1309 StgWord label_len = strlen(label);
1310 StgWord len = 1+8+label_len+1;
1311 ensureRoomForVariableEvent(&eventBuf, len);
1312 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_STRING);
1313 postPayloadSize(&eventBuf, len);
1314 postWord8(&eventBuf, profile_id);
1315 postWord64(&eventBuf, residency);
1316 postString(&eventBuf, label);
1317 RELEASE_LOCK(&eventBufMutex);
1318 }
1319
1320 #if defined(PROFILING)
1321 void postHeapProfCostCentre(StgWord32 ccID,
1322 const char *label,
1323 const char *module,
1324 const char *srcloc,
1325 StgBool is_caf)
1326 {
1327 ACQUIRE_LOCK(&eventBufMutex);
1328 StgWord label_len = strlen(label);
1329 StgWord module_len = strlen(module);
1330 StgWord srcloc_len = strlen(srcloc);
1331 StgWord len = 4+label_len+module_len+srcloc_len+3+1;
1332 ensureRoomForVariableEvent(&eventBuf, len);
1333 postEventHeader(&eventBuf, EVENT_HEAP_PROF_COST_CENTRE);
1334 postPayloadSize(&eventBuf, len);
1335 postWord32(&eventBuf, ccID);
1336 postString(&eventBuf, label);
1337 postString(&eventBuf, module);
1338 postString(&eventBuf, srcloc);
1339 postWord8(&eventBuf, is_caf);
1340 RELEASE_LOCK(&eventBufMutex);
1341 }
1342
1343 void postHeapProfSampleCostCentre(StgWord8 profile_id,
1344 CostCentreStack *stack,
1345 StgWord64 residency)
1346 {
1347 ACQUIRE_LOCK(&eventBufMutex);
1348 StgWord depth = 0;
1349 CostCentreStack *ccs;
1350 for (ccs = stack; ccs != NULL && ccs != CCS_MAIN; ccs = ccs->prevStack)
1351 depth++;
1352 if (depth > 0xff) depth = 0xff;
1353
1354 StgWord len = 1+8+1+depth*4;
1355 ensureRoomForVariableEvent(&eventBuf, len);
1356 postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_COST_CENTRE);
1357 postPayloadSize(&eventBuf, len);
1358 postWord8(&eventBuf, profile_id);
1359 postWord64(&eventBuf, residency);
1360 postWord8(&eventBuf, depth);
1361 for (ccs = stack;
1362 depth>0 && ccs != NULL && ccs != CCS_MAIN;
1363 ccs = ccs->prevStack, depth--)
1364 postWord32(&eventBuf, ccs->cc->ccID);
1365 RELEASE_LOCK(&eventBufMutex);
1366 }
1367 #endif /* PROFILING */
1368
1369 void printAndClearEventBuf (EventsBuf *ebuf)
1370 {
1371 closeBlockMarker(ebuf);
1372
1373 if (ebuf->begin != NULL && ebuf->pos != ebuf->begin)
1374 {
1375 size_t elog_size = ebuf->pos - ebuf->begin;
1376 if (!writeEventLog(ebuf->begin, elog_size)) {
1377 debugBelch(
1378 "printAndClearEventLog: could not flush event log"
1379 );
1380 resetEventsBuf(ebuf);
1381 return;
1382 }
1383
1384 resetEventsBuf(ebuf);
1385 flushCount++;
1386
1387 postBlockMarker(ebuf);
1388 }
1389 }
1390
1391 void initEventsBuf(EventsBuf* eb, StgWord64 size, EventCapNo capno)
1392 {
1393 eb->begin = eb->pos = stgMallocBytes(size, "initEventsBuf");
1394 eb->size = size;
1395 eb->marker = NULL;
1396 eb->capno = capno;
1397 }
1398
1399 void resetEventsBuf(EventsBuf* eb)
1400 {
1401 eb->pos = eb->begin;
1402 eb->marker = NULL;
1403 }
1404
1405 StgBool hasRoomForEvent(EventsBuf *eb, EventTypeNum eNum)
1406 {
1407 uint32_t size = sizeof(EventTypeNum) + sizeof(EventTimestamp) + eventTypes[eNum].size;
1408
1409 if (eb->pos + size > eb->begin + eb->size) {
1410 return 0; // Not enough space.
1411 } else {
1412 return 1; // Buf has enough space for the event.
1413 }
1414 }
1415
1416 StgBool hasRoomForVariableEvent(EventsBuf *eb, uint32_t payload_bytes)
1417 {
1418 uint32_t size = sizeof(EventTypeNum) + sizeof(EventTimestamp) +
1419 sizeof(EventPayloadSize) + payload_bytes;
1420
1421 if (eb->pos + size > eb->begin + eb->size) {
1422 return 0; // Not enough space.
1423 } else {
1424 return 1; // Buf has enough space for the event.
1425 }
1426 }
1427
1428 void ensureRoomForEvent(EventsBuf *eb, EventTypeNum tag)
1429 {
1430 if (!hasRoomForEvent(eb, tag)) {
1431 // Flush event buffer to make room for new event.
1432 printAndClearEventBuf(eb);
1433 }
1434 }
1435
1436 int ensureRoomForVariableEvent(EventsBuf *eb, StgWord16 size)
1437 {
1438 if (!hasRoomForVariableEvent(eb, size)) {
1439 // Flush event buffer to make room for new event.
1440 printAndClearEventBuf(eb);
1441 if (!hasRoomForVariableEvent(eb, size))
1442 return 1; // Not enough space
1443 }
1444 return 0;
1445 }
1446
1447
1448 void postEventType(EventsBuf *eb, EventType *et)
1449 {
1450 postInt32(eb, EVENT_ET_BEGIN);
1451 postEventTypeNum(eb, et->etNum);
1452 postWord16(eb, (StgWord16)et->size);
1453 const int desclen = strlen(et->desc);
1454 postWord32(eb, desclen);
1455 for (int d = 0; d < desclen; ++d) {
1456 postInt8(eb, (StgInt8)et->desc[d]);
1457 }
1458 postWord32(eb, 0); // no extensions yet
1459 postInt32(eb, EVENT_ET_END);
1460 }
1461
1462 #endif /* TRACING */