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