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