1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 2008-2009
5 * Support for fast binary event logging.
7 * ---------------------------------------------------------------------------*/
13 #include "Capability.h"
20 static char *event_log_filename = NULL;
22 // File for logging events
23 FILE *event_log_file = NULL;
25 #define EVENT_LOG_SIZE 2 * (1024 * 1024) // 2MB
27 static int flushCount;
29 // Struct for record keeping of buffer to store event types and events.
30 typedef struct _EventsBuf {
50 "Request sequential GC",
51 "Request parallel GC",
58 typedef struct _EventType {
59 EventTypeNum etNum; // Event Type number.
60 nat size; // size of the payload in bytes
61 char *desc; // Description
64 EventType eventTypes[NUM_EVENT_TAGS];
66 static void printAndClearEventBuf (EventsBuf *eventsBuf);
67 static void initEventsBuf(EventsBuf* eb, StgWord64 size);
68 static void resetEventsBuf(EventsBuf* eb);
70 static void beginHeader(EventsBuf *eb);
71 static void endHeader(EventsBuf *eb);
73 static void beginData(EventsBuf *eb);
74 static void endData(EventsBuf *eb);
76 static void beginEventTypes(EventsBuf *eb);
77 static void endEventTypes(EventsBuf *eb);
79 static void postEventType(EventsBuf *eb, EventType *et);
81 static StgBool hasRoomForEvent(EventsBuf *eb, EventTypeNum eNum);
83 static inline void postWord8(EventsBuf *eb, StgWord8 i)
88 static inline void postWord16(EventsBuf *eb, StgWord16 i)
90 postWord8(eb, (StgWord8)(i >> 8));
91 postWord8(eb, (StgWord8)i);
94 static inline void postWord32(EventsBuf *eb, StgWord32 i)
96 postWord16(eb, (StgWord16)(i >> 16));
97 postWord16(eb, (StgWord16)i);
100 static inline void postWord64(EventsBuf *eb, StgWord64 i)
102 postWord32(eb, (StgWord32)(i >> 32));
103 postWord32(eb, (StgWord32)i);
106 static inline void postEventTypeNum(EventsBuf *eb, EventTypeNum etNum)
107 { postWord16(eb, etNum); }
109 static inline void postEventTypeID(EventsBuf *eb, StgWord16 etID)
110 { postWord16(eb, etID); }
112 static inline void postTimestamp(EventsBuf *eb, Timestamp t)
113 { postWord64(eb,t); }
115 static inline void postThreadID(EventsBuf *eb, ThreadID id)
116 { postWord32(eb,id); }
118 static inline void postCapNo(EventsBuf *eb, CapNo no)
119 { postWord16(eb,no); }
121 static inline void postInt8(EventsBuf *eb, StgInt8 i)
122 { postWord8(eb, (StgWord8)i); }
124 static inline void postInt16(EventsBuf *eb, StgInt16 i)
125 { postWord16(eb, (StgWord16)i); }
127 static inline void postInt32(EventsBuf *eb, StgInt32 i)
128 { postWord32(eb, (StgWord32)i); }
130 static inline void postInt64(EventsBuf *eb, StgInt64 i)
131 { postWord64(eb, (StgWord64)i); }
135 initEventLogging(void)
139 debugTrace(DEBUG_eventlog, "intiEventLog: start");
141 event_log_filename = stgMallocBytes(strlen(prog_name) + 9,
144 if (sizeof(EventDesc) / sizeof(char*) != NUM_EVENT_TAGS) {
145 barf("EventDesc array has the wrong number of elements");
148 sprintf(event_log_filename, "%s.eventlog", prog_name);
150 /* Open event log file for writing. */
151 if ((event_log_file = fopen(event_log_filename, "wb")) == NULL) {
152 sysErrorBelch("initEventLoggin: can't open %s", event_log_filename);
153 stg_exit(EXIT_FAILURE);
157 * Allocate buffer(s) to store events.
158 * Create buffer large enough for the header begin marker, all event
159 * types, and header end marker to prevent checking if buffer has room
160 * for each of these steps, and remove the need to flush the buffer to
161 * disk during initialization.
163 * Use a single buffer to store the header with event types, then flush
164 * the buffer so all buffers are empty for writing events.
166 eventsBuf = stgMallocBytes(n_capabilities * sizeof(EventsBuf),"initEventLogging");
168 for (c = 0; c < n_capabilities; ++c) {
169 // Init buffer for events.
170 initEventsBuf(&eventsBuf[c], EVENT_LOG_SIZE);
173 // Write in buffer: the header begin marker.
174 beginHeader(&eventsBuf[0]);
176 // Mark beginning of event types in the header.
177 beginEventTypes(&eventsBuf[0]);
178 for (t = 0; t < NUM_EVENT_TAGS; ++t) {
180 eventTypes[t].etNum = t;
181 eventTypes[t].desc = EventDesc[t];
184 case EVENT_CREATE_THREAD: // (cap, thread)
185 case EVENT_RUN_THREAD: // (cap, thread)
186 case EVENT_THREAD_RUNNABLE: // (cap, thread)
187 case EVENT_CREATE_SPARK: // (cap, thread)
188 case EVENT_RUN_SPARK: // (cap, thread)
189 eventTypes[t].size = sizeof(CapNo) + sizeof(ThreadID);
192 case EVENT_SPARK_TO_THREAD: // (cap, thread, spark_thread)
194 sizeof(CapNo) + sizeof(ThreadID) + sizeof(ThreadID);
197 case EVENT_MIGRATE_THREAD: // (cap, thread, new_cap)
198 case EVENT_STEAL_SPARK: // (cap, thread, victim_cap)
199 case EVENT_THREAD_WAKEUP: // (cap, thread, other_cap)
201 sizeof(CapNo) + sizeof(ThreadID) + sizeof(CapNo);
204 case EVENT_STOP_THREAD: // (cap, thread, status)
206 sizeof(CapNo) + sizeof(ThreadID) + sizeof(StgWord16);
209 case EVENT_SHUTDOWN: // (cap)
210 case EVENT_REQUEST_SEQ_GC: // (cap)
211 case EVENT_REQUEST_PAR_GC: // (cap)
212 case EVENT_GC_START: // (cap)
213 case EVENT_GC_END: // (cap)
214 eventTypes[t].size = sizeof(CapNo);
218 // Write in buffer: the start event type.
219 postEventType(&eventsBuf[0], &eventTypes[t]);
222 // Mark end of event types in the header.
223 endEventTypes(&eventsBuf[0]);
225 // Write in buffer: the header end marker.
226 endHeader(&eventsBuf[0]);
228 // Prepare event buffer for events (data).
229 beginData(&eventsBuf[0]);
231 // Flush eventsBuf with header.
233 * Flush header and data begin marker to the file, thus preparing the
234 * file to have events written to it.
236 printAndClearEventBuf(&eventsBuf[0]);
238 debugTrace(DEBUG_eventlog, "initEventLog: finish");
242 endEventLogging(void)
246 debugTrace(DEBUG_eventlog,"endEventLog: start");
248 // Flush all events remaining in the buffers.
249 for (c = 0; c < n_capabilities; ++c) {
250 printAndClearEventBuf(&eventsBuf[c]);
253 // Mark end of events (data).
254 endData(&eventsBuf[0]);
256 // Flush the end of data marker.
257 printAndClearEventBuf(&eventsBuf[0]);
259 if (event_log_file != NULL) {
260 fclose(event_log_file);
263 debugTrace(DEBUG_eventlog,"endEventLog: finish");
267 freeEventLogging(void)
271 debugTrace(DEBUG_eventlog,"freeEventLog: start");
273 // Free events buffer.
274 for (c = 0; c < n_capabilities; ++c) {
275 if (eventsBuf[c].begin != NULL)
276 stgFree(eventsBuf[c].begin);
278 if (eventsBuf != NULL) {
281 if (event_log_filename != NULL) {
282 stgFree(event_log_filename);
285 debugTrace(DEBUG_eventlog,"freeEventLog: finish");
289 * Post an event message to the capability's eventlog buffer.
290 * If the buffer is full, prints out the buffer and clears it.
293 postEvent_(Capability *cap, EventTypeNum tag, StgThreadID thread, StgWord64 other)
297 debugTrace(DEBUG_eventlog,"postEvent: start");
299 eb = &eventsBuf[cap->no];
301 if (!hasRoomForEvent(eb, tag)) {
302 // Flush event buffer to make room for new event.
303 printAndClearEventBuf(eb);
306 postEventTypeNum(eb, tag);
307 postTimestamp(eb, stat_getElapsedTime() * (1000000000LL/TICKS_PER_SECOND));
308 postCapNo(eb, cap->no);
311 case EVENT_CREATE_THREAD: // (cap, thread)
312 case EVENT_RUN_THREAD: // (cap, thread)
313 case EVENT_THREAD_RUNNABLE: // (cap, thread)
314 case EVENT_CREATE_SPARK: // (cap, thread)
315 case EVENT_RUN_SPARK: // (cap, thread)
317 postThreadID(eb,thread);
321 case EVENT_SPARK_TO_THREAD: // (cap, thread, spark_thread)
323 postThreadID(eb,thread);
324 postThreadID(eb,other /* spark_thread */);
328 case EVENT_MIGRATE_THREAD: // (cap, thread, new_cap)
329 case EVENT_STEAL_SPARK: // (cap, thread, victim_cap)
330 case EVENT_THREAD_WAKEUP: // (cap, thread, other_cap)
332 postThreadID(eb,thread);
333 postCapNo(eb,other /* new_cap | victim_cap | other_cap */);
337 case EVENT_STOP_THREAD: // (cap, thread, status)
339 postThreadID(eb,thread);
340 postWord16(eb,other /* status */);
344 case EVENT_SHUTDOWN: // (cap)
345 case EVENT_REQUEST_SEQ_GC: // (cap)
346 case EVENT_REQUEST_PAR_GC: // (cap)
347 case EVENT_GC_START: // (cap)
348 case EVENT_GC_END: // (cap)
354 barf("postEvent: unknown event tag %d", tag);
357 debugTrace(DEBUG_eventlog,"postEvent: finish");
360 static void printAndClearEventBuf (EventsBuf *eventsBuf)
362 StgWord64 numBytes = 0, written = 0;
364 if (eventsBuf->begin != NULL && eventsBuf->pos != eventsBuf->begin)
366 numBytes = eventsBuf->pos - eventsBuf->begin;
368 debugTrace(DEBUG_eventlog,
369 "printAndEventLog: numbytes %" FMT_Word64
370 " bytes to fwrite()",
373 written = fwrite(eventsBuf->begin, 1, numBytes, event_log_file);
374 if (written != numBytes) {
376 "printAndClearEventLog: fwrite() failed, written=%" FMT_Word64
377 " doesn't match numBytes=%" FMT_Word64, written, numBytes);
381 debugTrace(DEBUG_eventlog,
382 "printAndClearEventLog: fwrite(): %" FMT_Word64
383 " bytes written", written);
385 resetEventsBuf(eventsBuf);
391 printAndClearEventLog(Capability *cap)
393 debugTrace(DEBUG_eventlog,"printAndClearEventLog: start");
395 printAndClearEventBuf(&eventsBuf[cap->no]);
397 debugTrace(DEBUG_eventlog,"printAndClearEventLog: finish");
400 /* -----------------------------------------------------------------------------
401 Actual event generation below here
402 -------------------------------------------------------------------------- */
404 void initEventsBuf(EventsBuf* eb, StgWord64 size)
406 eb->begin = eb->pos = malloc(size);
410 void resetEventsBuf(EventsBuf* eb)
415 // N.B.: Assuming buffer contains enough space for the header begin marker.
416 void beginHeader(EventsBuf *eb)
418 postInt32(eb, EVENT_HEADER_BEGIN);
421 // N.B.: Assuming buffer contains enough space for the header end marker.
422 void endHeader(EventsBuf *eb)
424 postInt32(eb, EVENT_HEADER_END);
427 void beginData(EventsBuf *eb)
429 postInt32(eb, EVENT_DATA_BEGIN);
432 void endData(EventsBuf *eb)
434 postEventTypeNum(eb, EVENT_DATA_END);
437 void beginEventTypes(EventsBuf *eb)
439 postInt32(eb, EVENT_HET_BEGIN);
442 void endEventTypes(EventsBuf *eb)
444 postInt32(eb, EVENT_HET_END);
447 StgBool hasRoomForEvent(EventsBuf *eb, EventTypeNum eNum)
451 size += sizeof(EventTypeNum) + sizeof(Timestamp) + eventTypes[eNum].size;
453 if (eb->pos + size > eb->begin + eb->size) {
454 return 0; // Not enough space.
456 return 1; // Buf has enough space for the event.
460 static void postEventType(EventsBuf *eb, EventType *et)
465 postInt32(eb, EVENT_ET_BEGIN);
466 postEventTypeNum(eb, et->etNum);
467 postWord16(eb, (StgWord16)et->size);
468 desclen = strlen(et->desc);
469 postWord32(eb, desclen);
470 for (d = 0; d < desclen; ++d) {
471 postInt8(eb, (StgInt8)et->desc[d]);
473 postWord32(eb, 0); // no extensions yet
474 postInt32(eb, EVENT_ET_END);
477 #endif /* EVENTLOG */