Move GC tracing into a separate trace class
[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 #ifdef 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 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 // PID of the process that writes to event_log_filename (#4512)
30 static pid_t event_log_pid = -1;
31
32 static char *event_log_filename = NULL;
33
34 // File for logging events
35 FILE *event_log_file = NULL;
36
37 #define EVENT_LOG_SIZE 2 * (1024 * 1024) // 2MB
38
39 static int flushCount;
40
41 // Struct for record keeping of buffer to store event types and events.
42 typedef struct _EventsBuf {
43 StgInt8 *begin;
44 StgInt8 *pos;
45 StgInt8 *marker;
46 StgWord64 size;
47 EventCapNo capno; // which capability this buffer belongs to, or -1
48 } EventsBuf;
49
50 EventsBuf *capEventBuf; // one EventsBuf for each Capability
51
52 EventsBuf eventBuf; // an EventsBuf not associated with any Capability
53 #ifdef THREADED_RTS
54 Mutex eventBufMutex; // protected by this mutex
55 #endif
56
57 char *EventDesc[] = {
58 [EVENT_CREATE_THREAD] = "Create thread",
59 [EVENT_RUN_THREAD] = "Run thread",
60 [EVENT_STOP_THREAD] = "Stop thread",
61 [EVENT_THREAD_RUNNABLE] = "Thread runnable",
62 [EVENT_MIGRATE_THREAD] = "Migrate thread",
63 [EVENT_RUN_SPARK] = "Run spark",
64 [EVENT_STEAL_SPARK] = "Steal spark",
65 [EVENT_SHUTDOWN] = "Shutdown",
66 [EVENT_THREAD_WAKEUP] = "Wakeup thread",
67 [EVENT_GC_START] = "Starting GC",
68 [EVENT_GC_END] = "Finished GC",
69 [EVENT_REQUEST_SEQ_GC] = "Request sequential GC",
70 [EVENT_REQUEST_PAR_GC] = "Request parallel GC",
71 [EVENT_CREATE_SPARK_THREAD] = "Create spark thread",
72 [EVENT_LOG_MSG] = "Log message",
73 [EVENT_USER_MSG] = "User message",
74 [EVENT_STARTUP] = "Startup",
75 [EVENT_GC_IDLE] = "GC idle",
76 [EVENT_GC_WORK] = "GC working",
77 [EVENT_GC_DONE] = "GC done",
78 [EVENT_BLOCK_MARKER] = "Block marker",
79 [EVENT_CAPSET_CREATE] = "Create capability set",
80 [EVENT_CAPSET_DELETE] = "Delete capability set",
81 [EVENT_CAPSET_ASSIGN_CAP] = "Add capability to capability set",
82 [EVENT_CAPSET_REMOVE_CAP] = "Remove capability from capability set",
83 [EVENT_RTS_IDENTIFIER] = "RTS name and version",
84 [EVENT_PROGRAM_ARGS] = "Program arguments",
85 [EVENT_PROGRAM_ENV] = "Program environment variables",
86 [EVENT_OSPROCESS_PID] = "Process ID",
87 [EVENT_OSPROCESS_PPID] = "Parent process ID",
88 [EVENT_SPARK_COUNTERS] = "Spark counters"
89 };
90
91 // Event type.
92
93 typedef struct _EventType {
94 EventTypeNum etNum; // Event Type number.
95 nat size; // size of the payload in bytes
96 char *desc; // Description
97 } EventType;
98
99 EventType eventTypes[NUM_EVENT_TAGS];
100
101 static void initEventsBuf(EventsBuf* eb, StgWord64 size, EventCapNo capno);
102 static void resetEventsBuf(EventsBuf* eb);
103 static void printAndClearEventBuf (EventsBuf *eventsBuf);
104
105 static void postEventType(EventsBuf *eb, EventType *et);
106
107 static void postLogMsg(EventsBuf *eb, EventTypeNum type, char *msg, va_list ap);
108
109 static void postBlockMarker(EventsBuf *eb);
110 static void closeBlockMarker(EventsBuf *ebuf);
111
112 static StgBool hasRoomForEvent(EventsBuf *eb, EventTypeNum eNum);
113 static StgBool hasRoomForVariableEvent(EventsBuf *eb, nat payload_bytes);
114
115 static inline void postWord8(EventsBuf *eb, StgWord8 i)
116 {
117 *(eb->pos++) = i;
118 }
119
120 static inline void postWord16(EventsBuf *eb, StgWord16 i)
121 {
122 postWord8(eb, (StgWord8)(i >> 8));
123 postWord8(eb, (StgWord8)i);
124 }
125
126 static inline void postWord32(EventsBuf *eb, StgWord32 i)
127 {
128 postWord16(eb, (StgWord16)(i >> 16));
129 postWord16(eb, (StgWord16)i);
130 }
131
132 static inline void postWord64(EventsBuf *eb, StgWord64 i)
133 {
134 postWord32(eb, (StgWord32)(i >> 32));
135 postWord32(eb, (StgWord32)i);
136 }
137
138 static inline void postBuf(EventsBuf *eb, StgWord8 *buf, nat size)
139 {
140 memcpy(eb->pos, buf, size);
141 eb->pos += size;
142 }
143
144 static inline StgWord64 time_ns(void)
145 { return stat_getElapsedTime() * (1000000000LL/TICKS_PER_SECOND); }
146
147 static inline void postEventTypeNum(EventsBuf *eb, EventTypeNum etNum)
148 { postWord16(eb, etNum); }
149
150 static inline void postTimestamp(EventsBuf *eb)
151 { postWord64(eb, time_ns()); }
152
153 static inline void postThreadID(EventsBuf *eb, EventThreadID id)
154 { postWord32(eb,id); }
155
156 static inline void postCapNo(EventsBuf *eb, EventCapNo no)
157 { postWord16(eb,no); }
158
159 static inline void postCapsetID(EventsBuf *eb, EventCapsetID id)
160 { postWord32(eb,id); }
161
162 static inline void postCapsetType(EventsBuf *eb, EventCapsetType type)
163 { postWord16(eb,type); }
164
165 static inline void postPayloadSize(EventsBuf *eb, EventPayloadSize size)
166 { postWord16(eb,size); }
167
168 static inline void postEventHeader(EventsBuf *eb, EventTypeNum type)
169 {
170 postEventTypeNum(eb, type);
171 postTimestamp(eb);
172 }
173
174 static inline void postInt8(EventsBuf *eb, StgInt8 i)
175 { postWord8(eb, (StgWord8)i); }
176
177 static inline void postInt16(EventsBuf *eb, StgInt16 i)
178 { postWord16(eb, (StgWord16)i); }
179
180 static inline void postInt32(EventsBuf *eb, StgInt32 i)
181 { postWord32(eb, (StgWord32)i); }
182
183 static inline void postInt64(EventsBuf *eb, StgInt64 i)
184 { postWord64(eb, (StgWord64)i); }
185
186
187 void
188 initEventLogging(void)
189 {
190 StgWord8 t, c;
191 nat n_caps;
192
193 event_log_filename = stgMallocBytes(strlen(prog_name)
194 + 10 /* .%d */
195 + 10 /* .eventlog */,
196 "initEventLogging");
197
198 if (sizeof(EventDesc) / sizeof(char*) != NUM_EVENT_TAGS) {
199 barf("EventDesc array has the wrong number of elements");
200 }
201
202 if (event_log_pid == -1) { // #4512
203 // Single process
204 sprintf(event_log_filename, "%s.eventlog", prog_name);
205 event_log_pid = getpid();
206 } else {
207 // Forked process, eventlog already started by the parent
208 // before fork
209 event_log_pid = getpid();
210 sprintf(event_log_filename, "%s.%d.eventlog", prog_name, event_log_pid);
211 }
212
213 /* Open event log file for writing. */
214 if ((event_log_file = fopen(event_log_filename, "wb")) == NULL) {
215 sysErrorBelch("initEventLogging: can't open %s", event_log_filename);
216 stg_exit(EXIT_FAILURE);
217 }
218
219 /*
220 * Allocate buffer(s) to store events.
221 * Create buffer large enough for the header begin marker, all event
222 * types, and header end marker to prevent checking if buffer has room
223 * for each of these steps, and remove the need to flush the buffer to
224 * disk during initialization.
225 *
226 * Use a single buffer to store the header with event types, then flush
227 * the buffer so all buffers are empty for writing events.
228 */
229 #ifdef THREADED_RTS
230 // XXX n_capabilities hasn't been initislised yet
231 n_caps = RtsFlags.ParFlags.nNodes;
232 #else
233 n_caps = 1;
234 #endif
235 capEventBuf = stgMallocBytes(n_caps * sizeof(EventsBuf),"initEventLogging");
236
237 for (c = 0; c < n_caps; ++c) {
238 // Init buffer for events.
239 initEventsBuf(&capEventBuf[c], EVENT_LOG_SIZE, c);
240 }
241 initEventsBuf(&eventBuf, EVENT_LOG_SIZE, (EventCapNo)(-1));
242
243 // Write in buffer: the header begin marker.
244 postInt32(&eventBuf, EVENT_HEADER_BEGIN);
245
246 // Mark beginning of event types in the header.
247 postInt32(&eventBuf, EVENT_HET_BEGIN);
248 for (t = 0; t < NUM_EVENT_TAGS; ++t) {
249
250 eventTypes[t].etNum = t;
251 eventTypes[t].desc = EventDesc[t];
252
253 switch (t) {
254 case EVENT_CREATE_THREAD: // (cap, thread)
255 case EVENT_RUN_THREAD: // (cap, thread)
256 case EVENT_THREAD_RUNNABLE: // (cap, thread)
257 case EVENT_RUN_SPARK: // (cap, thread)
258 case EVENT_CREATE_SPARK_THREAD: // (cap, spark_thread)
259 eventTypes[t].size = sizeof(EventThreadID);
260 break;
261
262 case EVENT_MIGRATE_THREAD: // (cap, thread, new_cap)
263 case EVENT_STEAL_SPARK: // (cap, thread, victim_cap)
264 case EVENT_THREAD_WAKEUP: // (cap, thread, other_cap)
265 eventTypes[t].size =
266 sizeof(EventThreadID) + sizeof(EventCapNo);
267 break;
268
269 case EVENT_STOP_THREAD: // (cap, thread, status)
270 eventTypes[t].size =
271 sizeof(EventThreadID) + sizeof(StgWord16) + sizeof(EventThreadID);
272 break;
273
274 case EVENT_STARTUP: // (cap count)
275 eventTypes[t].size = sizeof(EventCapNo);
276 break;
277
278 case EVENT_CAPSET_CREATE: // (capset, capset_type)
279 eventTypes[t].size =
280 sizeof(EventCapsetID) + sizeof(EventCapsetType);
281 break;
282
283 case EVENT_CAPSET_DELETE: // (capset)
284 eventTypes[t].size = sizeof(EventCapsetID);
285 break;
286
287 case EVENT_CAPSET_ASSIGN_CAP: // (capset, cap)
288 case EVENT_CAPSET_REMOVE_CAP:
289 eventTypes[t].size =
290 sizeof(EventCapsetID) + sizeof(EventCapNo);
291 break;
292
293 case EVENT_OSPROCESS_PID: // (cap, pid)
294 case EVENT_OSPROCESS_PPID:
295 eventTypes[t].size =
296 sizeof(EventCapsetID) + sizeof(StgWord32);
297 break;
298
299 case EVENT_SHUTDOWN: // (cap)
300 case EVENT_REQUEST_SEQ_GC: // (cap)
301 case EVENT_REQUEST_PAR_GC: // (cap)
302 case EVENT_GC_START: // (cap)
303 case EVENT_GC_END: // (cap)
304 case EVENT_GC_IDLE:
305 case EVENT_GC_WORK:
306 case EVENT_GC_DONE:
307 eventTypes[t].size = 0;
308 break;
309
310 case EVENT_LOG_MSG: // (msg)
311 case EVENT_USER_MSG: // (msg)
312 case EVENT_RTS_IDENTIFIER: // (capset, str)
313 case EVENT_PROGRAM_ARGS: // (capset, strvec)
314 case EVENT_PROGRAM_ENV: // (capset, strvec)
315 eventTypes[t].size = 0xffff;
316 break;
317
318 case EVENT_SPARK_COUNTERS: // (cap, 7*counter)
319 eventTypes[t].size = 7 * sizeof(StgWord64);
320 break;
321
322 case EVENT_BLOCK_MARKER:
323 eventTypes[t].size = sizeof(StgWord32) + sizeof(EventTimestamp) +
324 sizeof(EventCapNo);
325 break;
326
327 default:
328 continue; /* ignore deprecated events */
329 }
330
331 // Write in buffer: the start event type.
332 postEventType(&eventBuf, &eventTypes[t]);
333 }
334
335 // Mark end of event types in the header.
336 postInt32(&eventBuf, EVENT_HET_END);
337
338 // Write in buffer: the header end marker.
339 postInt32(&eventBuf, EVENT_HEADER_END);
340
341 // Prepare event buffer for events (data).
342 postInt32(&eventBuf, EVENT_DATA_BEGIN);
343
344 // Flush capEventBuf with header.
345 /*
346 * Flush header and data begin marker to the file, thus preparing the
347 * file to have events written to it.
348 */
349 printAndClearEventBuf(&eventBuf);
350
351 for (c = 0; c < n_caps; ++c) {
352 postBlockMarker(&capEventBuf[c]);
353 }
354
355 #ifdef THREADED_RTS
356 initMutex(&eventBufMutex);
357 #endif
358 }
359
360 void
361 endEventLogging(void)
362 {
363 nat c;
364
365 // Flush all events remaining in the buffers.
366 for (c = 0; c < n_capabilities; ++c) {
367 printAndClearEventBuf(&capEventBuf[c]);
368 }
369 printAndClearEventBuf(&eventBuf);
370 resetEventsBuf(&eventBuf); // we don't want the block marker
371
372 // Mark end of events (data).
373 postEventTypeNum(&eventBuf, EVENT_DATA_END);
374
375 // Flush the end of data marker.
376 printAndClearEventBuf(&eventBuf);
377
378 if (event_log_file != NULL) {
379 fclose(event_log_file);
380 }
381 }
382
383 void
384 freeEventLogging(void)
385 {
386 StgWord8 c;
387
388 // Free events buffer.
389 for (c = 0; c < n_capabilities; ++c) {
390 if (capEventBuf[c].begin != NULL)
391 stgFree(capEventBuf[c].begin);
392 }
393 if (capEventBuf != NULL) {
394 stgFree(capEventBuf);
395 }
396 if (event_log_filename != NULL) {
397 stgFree(event_log_filename);
398 }
399 }
400
401 void
402 flushEventLog(void)
403 {
404 if (event_log_file != NULL) {
405 fflush(event_log_file);
406 }
407 }
408
409 void
410 abortEventLogging(void)
411 {
412 freeEventLogging();
413 if (event_log_file != NULL) {
414 fclose(event_log_file);
415 }
416 }
417 /*
418 * Post an event message to the capability's eventlog buffer.
419 * If the buffer is full, prints out the buffer and clears it.
420 */
421 void
422 postSchedEvent (Capability *cap,
423 EventTypeNum tag,
424 StgThreadID thread,
425 StgWord info1,
426 StgWord info2)
427 {
428 EventsBuf *eb;
429
430 eb = &capEventBuf[cap->no];
431
432 if (!hasRoomForEvent(eb, tag)) {
433 // Flush event buffer to make room for new event.
434 printAndClearEventBuf(eb);
435 }
436
437 postEventHeader(eb, tag);
438
439 switch (tag) {
440 case EVENT_CREATE_THREAD: // (cap, thread)
441 case EVENT_RUN_THREAD: // (cap, thread)
442 case EVENT_THREAD_RUNNABLE: // (cap, thread)
443 case EVENT_RUN_SPARK: // (cap, thread)
444 {
445 postThreadID(eb,thread);
446 break;
447 }
448
449 case EVENT_CREATE_SPARK_THREAD: // (cap, spark_thread)
450 {
451 postThreadID(eb,info1 /* spark_thread */);
452 break;
453 }
454
455 case EVENT_MIGRATE_THREAD: // (cap, thread, new_cap)
456 case EVENT_STEAL_SPARK: // (cap, thread, victim_cap)
457 case EVENT_THREAD_WAKEUP: // (cap, thread, other_cap)
458 {
459 postThreadID(eb,thread);
460 postCapNo(eb,info1 /* new_cap | victim_cap | other_cap */);
461 break;
462 }
463
464 case EVENT_STOP_THREAD: // (cap, thread, status)
465 {
466 postThreadID(eb,thread);
467 postWord16(eb,info1 /* status */);
468 postThreadID(eb,info2 /* blocked on thread */);
469 break;
470 }
471
472 case EVENT_SHUTDOWN: // (cap)
473 {
474 break;
475 }
476
477 default:
478 barf("postSchedEvent: unknown event tag %d", tag);
479 }
480 }
481
482 void
483 postSparkCountersEvent (Capability *cap,
484 SparkCounters counters,
485 StgWord remaining)
486 {
487 EventsBuf *eb;
488
489 eb = &capEventBuf[cap->no];
490
491 if (!hasRoomForEvent(eb, EVENT_SPARK_COUNTERS)) {
492 // Flush event buffer to make room for new event.
493 printAndClearEventBuf(eb);
494 }
495
496 postEventHeader(eb, EVENT_SPARK_COUNTERS);
497 postWord64(eb,counters.created);
498 postWord64(eb,counters.dud);
499 postWord64(eb,counters.overflowed);
500 postWord64(eb,counters.converted);
501 postWord64(eb,counters.gcd);
502 postWord64(eb,counters.fizzled);
503 postWord64(eb,remaining);
504 }
505
506 void postCapsetModifyEvent (EventTypeNum tag,
507 EventCapsetID capset,
508 StgWord32 other)
509 {
510 ACQUIRE_LOCK(&eventBufMutex);
511
512 if (!hasRoomForEvent(&eventBuf, tag)) {
513 // Flush event buffer to make room for new event.
514 printAndClearEventBuf(&eventBuf);
515 }
516
517 postEventHeader(&eventBuf, tag);
518 postCapsetID(&eventBuf, capset);
519
520 switch (tag) {
521 case EVENT_CAPSET_CREATE: // (capset, capset_type)
522 {
523 postCapsetType(&eventBuf, other /* capset_type */);
524 break;
525 }
526
527 case EVENT_CAPSET_DELETE: // (capset)
528 {
529 break;
530 }
531
532 case EVENT_CAPSET_ASSIGN_CAP: // (capset, capno)
533 case EVENT_CAPSET_REMOVE_CAP: // (capset, capno)
534 {
535 postCapNo(&eventBuf, other /* capno */);
536 break;
537 }
538 case EVENT_OSPROCESS_PID: // (capset, pid)
539 case EVENT_OSPROCESS_PPID: // (capset, parent_pid)
540 {
541 postWord32(&eventBuf, other);
542 break;
543 }
544 default:
545 barf("postCapsetModifyEvent: unknown event tag %d", tag);
546 }
547
548 RELEASE_LOCK(&eventBufMutex);
549 }
550
551 void postCapsetStrEvent (EventTypeNum tag,
552 EventCapsetID capset,
553 char *msg)
554 {
555 int strsize = strlen(msg);
556 int size = strsize + sizeof(EventCapsetID);
557
558 ACQUIRE_LOCK(&eventBufMutex);
559
560 if (!hasRoomForVariableEvent(&eventBuf, size)){
561 printAndClearEventBuf(&eventBuf);
562
563 if (!hasRoomForVariableEvent(&eventBuf, size)){
564 // Event size exceeds buffer size, bail out:
565 RELEASE_LOCK(&eventBufMutex);
566 return;
567 }
568 }
569
570 postEventHeader(&eventBuf, tag);
571 postPayloadSize(&eventBuf, size);
572 postCapsetID(&eventBuf, capset);
573
574 postBuf(&eventBuf, (StgWord8*) msg, strsize);
575
576 RELEASE_LOCK(&eventBufMutex);
577 }
578
579 void postCapsetVecEvent (EventTypeNum tag,
580 EventCapsetID capset,
581 int argc,
582 char *argv[])
583 {
584 int i, size = sizeof(EventCapsetID);
585
586 for (i = 0; i < argc; i++) {
587 // 1 + strlen to account for the trailing \0, used as separator
588 size += 1 + strlen(argv[i]);
589 }
590
591 ACQUIRE_LOCK(&eventBufMutex);
592
593 if (!hasRoomForVariableEvent(&eventBuf, size)){
594 printAndClearEventBuf(&eventBuf);
595
596 if(!hasRoomForVariableEvent(&eventBuf, size)){
597 // Event size exceeds buffer size, bail out:
598 RELEASE_LOCK(&eventBufMutex);
599 return;
600 }
601 }
602
603 postEventHeader(&eventBuf, tag);
604 postPayloadSize(&eventBuf, size);
605 postCapsetID(&eventBuf, capset);
606
607 for( i = 0; i < argc; i++ ) {
608 // again, 1 + to account for \0
609 postBuf(&eventBuf, (StgWord8*) argv[i], 1 + strlen(argv[i]));
610 }
611
612 RELEASE_LOCK(&eventBufMutex);
613 }
614
615 void
616 postEvent (Capability *cap, EventTypeNum tag)
617 {
618 EventsBuf *eb;
619
620 eb = &capEventBuf[cap->no];
621
622 if (!hasRoomForEvent(eb, tag)) {
623 // Flush event buffer to make room for new event.
624 printAndClearEventBuf(eb);
625 }
626
627 postEventHeader(eb, tag);
628 }
629
630 #define BUF 512
631
632 void postLogMsg(EventsBuf *eb, EventTypeNum type, char *msg, va_list ap)
633 {
634 char buf[BUF];
635 nat size;
636
637 size = vsnprintf(buf,BUF,msg,ap);
638 if (size > BUF) {
639 buf[BUF-1] = '\0';
640 size = BUF;
641 }
642
643 if (!hasRoomForVariableEvent(eb, size)) {
644 // Flush event buffer to make room for new event.
645 printAndClearEventBuf(eb);
646 }
647
648 postEventHeader(eb, type);
649 postPayloadSize(eb, size);
650 postBuf(eb,(StgWord8*)buf,size);
651 }
652
653 void postMsg(char *msg, va_list ap)
654 {
655 ACQUIRE_LOCK(&eventBufMutex);
656 postLogMsg(&eventBuf, EVENT_LOG_MSG, msg, ap);
657 RELEASE_LOCK(&eventBufMutex);
658 }
659
660 void postCapMsg(Capability *cap, char *msg, va_list ap)
661 {
662 postLogMsg(&capEventBuf[cap->no], EVENT_LOG_MSG, msg, ap);
663 }
664
665 void postUserMsg(Capability *cap, char *msg, va_list ap)
666 {
667 postLogMsg(&capEventBuf[cap->no], EVENT_USER_MSG, msg, ap);
668 }
669
670 void postEventStartup(EventCapNo n_caps)
671 {
672 ACQUIRE_LOCK(&eventBufMutex);
673
674 if (!hasRoomForEvent(&eventBuf, EVENT_STARTUP)) {
675 // Flush event buffer to make room for new event.
676 printAndClearEventBuf(&eventBuf);
677 }
678
679 // Post a STARTUP event with the number of capabilities
680 postEventHeader(&eventBuf, EVENT_STARTUP);
681 postCapNo(&eventBuf, n_caps);
682
683 RELEASE_LOCK(&eventBufMutex);
684 }
685
686 void closeBlockMarker (EventsBuf *ebuf)
687 {
688 StgInt8* save_pos;
689
690 if (ebuf->marker)
691 {
692 // (type:16, time:64, size:32, end_time:64)
693
694 save_pos = ebuf->pos;
695 ebuf->pos = ebuf->marker + sizeof(EventTypeNum) +
696 sizeof(EventTimestamp);
697 postWord32(ebuf, save_pos - ebuf->marker);
698 postTimestamp(ebuf);
699 ebuf->pos = save_pos;
700 ebuf->marker = NULL;
701 }
702 }
703
704
705 void postBlockMarker (EventsBuf *eb)
706 {
707 if (!hasRoomForEvent(eb, EVENT_BLOCK_MARKER)) {
708 printAndClearEventBuf(eb);
709 }
710
711 closeBlockMarker(eb);
712
713 eb->marker = eb->pos;
714 postEventHeader(eb, EVENT_BLOCK_MARKER);
715 postWord32(eb,0); // these get filled in later by closeBlockMarker();
716 postWord64(eb,0);
717 postCapNo(eb, eb->capno);
718 }
719
720 void printAndClearEventBuf (EventsBuf *ebuf)
721 {
722 StgWord64 numBytes = 0, written = 0;
723
724 closeBlockMarker(ebuf);
725
726 if (ebuf->begin != NULL && ebuf->pos != ebuf->begin)
727 {
728 numBytes = ebuf->pos - ebuf->begin;
729
730 written = fwrite(ebuf->begin, 1, numBytes, event_log_file);
731 if (written != numBytes) {
732 debugBelch(
733 "printAndClearEventLog: fwrite() failed, written=%" FMT_Word64
734 " doesn't match numBytes=%" FMT_Word64, written, numBytes);
735 return;
736 }
737
738 resetEventsBuf(ebuf);
739 flushCount++;
740
741 postBlockMarker(ebuf);
742 }
743 }
744
745 void initEventsBuf(EventsBuf* eb, StgWord64 size, EventCapNo capno)
746 {
747 eb->begin = eb->pos = stgMallocBytes(size, "initEventsBuf");
748 eb->size = size;
749 eb->marker = NULL;
750 eb->capno = capno;
751 }
752
753 void resetEventsBuf(EventsBuf* eb)
754 {
755 eb->pos = eb->begin;
756 eb->marker = NULL;
757 }
758
759 StgBool hasRoomForEvent(EventsBuf *eb, EventTypeNum eNum)
760 {
761 nat size;
762
763 size = sizeof(EventTypeNum) + sizeof(EventTimestamp) + eventTypes[eNum].size;
764
765 if (eb->pos + size > eb->begin + eb->size) {
766 return 0; // Not enough space.
767 } else {
768 return 1; // Buf has enough space for the event.
769 }
770 }
771
772 StgBool hasRoomForVariableEvent(EventsBuf *eb, nat payload_bytes)
773 {
774 nat size;
775
776 size = sizeof(EventTypeNum) + sizeof(EventTimestamp) +
777 sizeof(EventPayloadSize) + payload_bytes;
778
779 if (eb->pos + size > eb->begin + eb->size) {
780 return 0; // Not enough space.
781 } else {
782 return 1; // Buf has enough space for the event.
783 }
784 }
785
786 void postEventType(EventsBuf *eb, EventType *et)
787 {
788 StgWord8 d;
789 nat desclen;
790
791 postInt32(eb, EVENT_ET_BEGIN);
792 postEventTypeNum(eb, et->etNum);
793 postWord16(eb, (StgWord16)et->size);
794 desclen = strlen(et->desc);
795 postWord32(eb, desclen);
796 for (d = 0; d < desclen; ++d) {
797 postInt8(eb, (StgInt8)et->desc[d]);
798 }
799 postWord32(eb, 0); // no extensions yet
800 postInt32(eb, EVENT_ET_END);
801 }
802
803 #endif /* TRACING */