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