diff options
author | Ben Gamari <ben@smart-cactus.org> | 2015-12-30 22:32:32 +0100 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2016-03-26 01:06:12 +0100 |
commit | 436be90ac8616ac504e91da917db67a1c469e6b9 (patch) | |
tree | 2be1fcbe0d31009ef89f4fa0e61813b5a3adc089 | |
parent | 1b4d1201d6fe395db2b268ca111baa69d96ce211 (diff) | |
download | haskell-436be90ac8616ac504e91da917db67a1c469e6b9.tar.gz |
Log heap profiler samples to event log
-rw-r--r-- | includes/rts/EventLogFormat.h | 7 | ||||
-rw-r--r-- | rts/ProfHeap.c | 32 | ||||
-rw-r--r-- | rts/Trace.c | 43 | ||||
-rw-r--r-- | rts/Trace.h | 19 | ||||
-rw-r--r-- | rts/eventlog/EventLog.c | 183 | ||||
-rw-r--r-- | rts/eventlog/EventLog.h | 20 |
6 files changed, 300 insertions, 4 deletions
diff --git a/includes/rts/EventLogFormat.h b/includes/rts/EventLogFormat.h index 68d0d08f55..75633462c6 100644 --- a/includes/rts/EventLogFormat.h +++ b/includes/rts/EventLogFormat.h @@ -173,12 +173,17 @@ /* Range 140 - 159 is reserved for Perf events. */ +#define EVENT_HEAP_PROF_BEGIN 160 +#define EVENT_HEAP_PROF_COST_CENTRE 161 +#define EVENT_HEAP_PROF_SAMPLE_BEGIN 162 +#define EVENT_HEAP_PROF_SAMPLE_COST_CENTRE 163 +#define EVENT_HEAP_PROF_SAMPLE_STRING 164 /* * The highest event code +1 that ghc itself emits. Note that some event * ranges higher than this are reserved but not currently emitted by ghc. * This must match the size of the EventDesc[] array in EventLog.c */ -#define NUM_GHC_EVENT_TAGS 60 +#define NUM_GHC_EVENT_TAGS 165 #if 0 /* DEPRECATED EVENTS: */ /* we don't actually need to record the thread, it's implicit */ diff --git a/rts/ProfHeap.c b/rts/ProfHeap.c index 819faeb9be..dcfc2bef34 100644 --- a/rts/ProfHeap.c +++ b/rts/ProfHeap.c @@ -19,6 +19,7 @@ #include "LdvProfile.h" #include "Arena.h" #include "Printer.h" +#include "Trace.h" #include "sm/GCThread.h" #include <string.h> @@ -369,6 +370,19 @@ printSample(rtsBool beginSample, StgDouble sampleValue) } } +static void +dumpCostCentresToEventLog(void) +{ +#ifdef PROFILING + CostCentre *cc, *next; + for (cc = CC_LIST; cc != NULL; cc = next) { + next = cc->link; + traceHeapProfCostCentre(cc->ccID, cc->label, cc->module, + cc->srcloc, cc->is_caf); + } +#endif +} + /* -------------------------------------------------------------------------- * Initialize the heap profilier * ----------------------------------------------------------------------- */ @@ -398,7 +412,7 @@ initHeapProfiling(void) } // max_era = 2^LDV_SHIFT - max_era = 1 << LDV_SHIFT; + max_era = 1 << LDV_SHIFT; n_censuses = 32; censuses = stgMallocBytes(sizeof(Census) * n_censuses, "initHeapProfiling"); @@ -435,6 +449,9 @@ initHeapProfiling(void) } #endif + traceHeapProfBegin(0); + dumpCostCentresToEventLog(); + return 0; } @@ -742,10 +759,12 @@ dumpCensus( Census *census ) long count; printSample(rtsTrue, census->time); + traceHeapProfSampleBegin(era); #ifdef PROFILING if (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_LDV) { - fprintf(hp_file, "VOID\t%lu\n", (unsigned long)(census->void_total) * sizeof(W_)); + fprintf(hp_file, "VOID\t%lu\n", + (unsigned long)(census->void_total) * sizeof(W_)); fprintf(hp_file, "LAG\t%lu\n", (unsigned long)(census->not_used - census->void_total) * sizeof(W_)); fprintf(hp_file, "USE\t%lu\n", @@ -786,6 +805,8 @@ dumpCensus( Census *census ) switch (RtsFlags.ProfFlags.doHeapProfile) { case HEAP_BY_CLOSURE_TYPE: fprintf(hp_file, "%s", (char *)ctr->identity); + traceHeapProfSampleString(0, (char *)ctr->identity, + count * sizeof(W_)); break; } #endif @@ -793,12 +814,17 @@ dumpCensus( Census *census ) #ifdef PROFILING switch (RtsFlags.ProfFlags.doHeapProfile) { case HEAP_BY_CCS: - fprint_ccs(hp_file, (CostCentreStack *)ctr->identity, RtsFlags.ProfFlags.ccsLength); + fprint_ccs(hp_file, (CostCentreStack *)ctr->identity, + RtsFlags.ProfFlags.ccsLength); + traceHeapProfSampleCostCentre(0, (CostCentreStack *)ctr->identity, + count * sizeof(W_)); break; case HEAP_BY_MOD: case HEAP_BY_DESCR: case HEAP_BY_TYPE: fprintf(hp_file, "%s", (char *)ctr->identity); + traceHeapProfSampleString(0, (char *)ctr->identity, + count * sizeof(W_)); break; case HEAP_BY_RETAINER: { diff --git a/rts/Trace.c b/rts/Trace.c index d0fa1e57a0..f2ea3d3b10 100644 --- a/rts/Trace.c +++ b/rts/Trace.c @@ -621,6 +621,49 @@ void traceTaskDelete_ (Task *task) } } +void traceHeapProfBegin(StgWord8 profile_id) +{ + if (eventlog_enabled) { + postHeapProfBegin(profile_id); + } +} + +void traceHeapProfSampleBegin(StgInt era) +{ + if (eventlog_enabled) { + postHeapProfSampleBegin(era); + } +} + +void traceHeapProfSampleString(StgWord8 profile_id, + const char *label, StgWord residency) +{ + if (eventlog_enabled) { + postHeapProfSampleString(profile_id, label, residency); + } +} + +#ifdef PROFILING +void traceHeapProfCostCentre(StgWord32 ccID, + const char *label, + const char *module, + const char *srcloc, + StgBool is_caf) +{ + if (eventlog_enabled) { + postHeapProfCostCentre(ccID, label, module, srcloc, is_caf); + } +} + +void traceHeapProfSampleCostCentre(StgWord8 profile_id, + CostCentreStack *stack, StgWord residency) +{ + if (eventlog_enabled) { + postHeapProfSampleCostCentre(profile_id, stack, residency); + } +} +#endif + #ifdef DEBUG static void vtraceCap_stderr(Capability *cap, char *msg, va_list ap) { diff --git a/rts/Trace.h b/rts/Trace.h index e0d6f20c45..52e3389e72 100644 --- a/rts/Trace.h +++ b/rts/Trace.h @@ -275,6 +275,20 @@ void traceTaskMigrate_ (Task *task, void traceTaskDelete_ (Task *task); +void traceHeapProfBegin(StgWord8 profile_id); +void traceHeapProfSampleBegin(StgInt era); +void traceHeapProfSampleString(StgWord8 profile_id, + const char *label, StgWord residency); +#ifdef PROFILING +void traceHeapProfCostCentre(StgWord32 ccID, + const char *label, + const char *module, + const char *srcloc, + StgBool is_caf); +void traceHeapProfSampleCostCentre(StgWord8 profile_id, + CostCentreStack *stack, StgWord residency); +#endif /* PROFILING */ + #else /* !TRACING */ #define traceSchedEvent(cap, tag, tso, other) /* nothing */ @@ -304,6 +318,11 @@ void traceTaskDelete_ (Task *task); #define traceTaskCreate_(taskID, cap) /* nothing */ #define traceTaskMigrate_(taskID, cap, new_cap) /* nothing */ #define traceTaskDelete_(taskID) /* nothing */ +#define traceHeapProfBegin(profile_id) /* nothing */ +#define traceHeapProfCostCentre(ccID, label, module, srcloc, is_caf) /* nothing */ +#define traceHeapProfSampleBegin(era) /* nothing */ +#define traceHeapProfSampleCostCentre(profile_id, stack, residency) /* nothing */ +#define traceHeapProfSampleString(profile_id, label, residency) /* nothing */ #endif /* TRACING */ diff --git a/rts/eventlog/EventLog.c b/rts/eventlog/EventLog.c index db103a7f3c..b9c790da30 100644 --- a/rts/eventlog/EventLog.c +++ b/rts/eventlog/EventLog.c @@ -106,6 +106,11 @@ char *EventDesc[] = { [EVENT_TASK_MIGRATE] = "Task migrate", [EVENT_TASK_DELETE] = "Task delete", [EVENT_HACK_BUG_T9003] = "Empty event for bug #9003", + [EVENT_HEAP_PROF_BEGIN] = "Start of heap profile", + [EVENT_HEAP_PROF_COST_CENTRE] = "Cost center definition", + [EVENT_HEAP_PROF_SAMPLE_BEGIN] = "Start of heap profile sample", + [EVENT_HEAP_PROF_SAMPLE_STRING] = "Heap profile string sample", + [EVENT_HEAP_PROF_SAMPLE_COST_CENTRE] = "Heap profile cost-centre sample", }; // Event type. @@ -164,6 +169,22 @@ static inline void postBuf(EventsBuf *eb, StgWord8 *buf, nat size) eb->pos += size; } +/* Post a null-terminated string to the event log. + * It is the caller's responsibility to ensure that there is + * enough room for strlen(buf)+1 bytes. + */ +static inline void postString(EventsBuf *eb, const char *buf) +{ + if (buf) { + int len = strlen(buf); + ASSERT(eb->begin + eb->size > eb->pos + len); + memcpy(eb->pos, buf, len); + eb->pos += len; + } + *eb->pos = 0; + eb->pos++; +} + static inline StgWord64 time_ns(void) { return TimeToNS(stat_getElapsedTime()); } @@ -209,6 +230,7 @@ static inline void postInt8(EventsBuf *eb, StgInt8 i) static inline void postInt32(EventsBuf *eb, StgInt32 i) { postWord32(eb, (StgWord32)i); } +#define EVENT_SIZE_DYNAMIC (-1) void initEventLogging(void) @@ -429,6 +451,26 @@ initEventLogging(void) eventTypes[t].size = 0; break; + case EVENT_HEAP_PROF_BEGIN: + eventTypes[t].size = EVENT_SIZE_DYNAMIC; + break; + + case EVENT_HEAP_PROF_COST_CENTRE: + eventTypes[t].size = EVENT_SIZE_DYNAMIC; + break; + + case EVENT_HEAP_PROF_SAMPLE_BEGIN: + eventTypes[t].size = 8; + break; + + case EVENT_HEAP_PROF_SAMPLE_STRING: + eventTypes[t].size = EVENT_SIZE_DYNAMIC; + break; + + case EVENT_HEAP_PROF_SAMPLE_COST_CENTRE: + eventTypes[t].size = EVENT_SIZE_DYNAMIC; + break; + default: continue; /* ignore deprecated events */ } @@ -1098,6 +1140,147 @@ void postBlockMarker (EventsBuf *eb) postCapNo(eb, eb->capno); } +typedef enum { + HEAP_PROF_BREAKDOWN_COST_CENTRE = 0x1, + HEAP_PROF_BREAKDOWN_MODULE, + HEAP_PROF_BREAKDOWN_CLOSURE_DESCR, + HEAP_PROF_BREAKDOWN_TYPE_DESCR, + HEAP_PROF_BREAKDOWN_RETAINER, + HEAP_PROF_BREAKDOWN_BIOGRAPHY, +} HeapProfBreakdown; + +static HeapProfBreakdown getHeapProfBreakdown(void) +{ + switch (RtsFlags.ProfFlags.doHeapProfile) { + case HEAP_BY_CCS: + return HEAP_PROF_BREAKDOWN_COST_CENTRE; + case HEAP_BY_MOD: + return HEAP_PROF_BREAKDOWN_MODULE; + case HEAP_BY_DESCR: + return HEAP_PROF_BREAKDOWN_CLOSURE_DESCR; + case HEAP_BY_TYPE: + return HEAP_PROF_BREAKDOWN_TYPE_DESCR; + case HEAP_BY_RETAINER: + return HEAP_PROF_BREAKDOWN_RETAINER; + case HEAP_BY_LDV: + return HEAP_PROF_BREAKDOWN_BIOGRAPHY; + default: + barf("getHeapProfBreakdown called with until heap profiling mode."); + } +} + +void postHeapProfBegin(StgWord8 profile_id) +{ + ACQUIRE_LOCK(&eventBufMutex); + PROFILING_FLAGS *flags = &RtsFlags.ProfFlags; + StgWord modSelector_len = + flags->modSelector ? strlen(flags->modSelector) : 0; + StgWord descrSelector_len = + flags->descrSelector ? strlen(flags->descrSelector) : 0; + StgWord typeSelector_len = + flags->typeSelector ? strlen(flags->typeSelector) : 0; + StgWord ccSelector_len = + flags->ccSelector ? strlen(flags->ccSelector) : 0; + StgWord ccsSelector_len = + flags->ccsSelector ? strlen(flags->ccsSelector) : 0; + StgWord retainerSelector_len = + flags->retainerSelector ? strlen(flags->retainerSelector) : 0; + StgWord bioSelector_len = + flags->bioSelector ? strlen(flags->bioSelector) : 0; + StgWord len = + 1+8+4 + modSelector_len + descrSelector_len + + typeSelector_len + ccSelector_len + ccsSelector_len + + retainerSelector_len + bioSelector_len + 7; + ensureRoomForVariableEvent(&eventBuf, len); + postEventHeader(&eventBuf, EVENT_HEAP_PROF_BEGIN); + postPayloadSize(&eventBuf, len); + postWord8(&eventBuf, profile_id); + postWord64(&eventBuf, TimeToNS(flags->heapProfileInterval)); + postWord32(&eventBuf, getHeapProfBreakdown()); + postString(&eventBuf, flags->modSelector); + postString(&eventBuf, flags->descrSelector); + postString(&eventBuf, flags->typeSelector); + postString(&eventBuf, flags->ccSelector); + postString(&eventBuf, flags->ccsSelector); + postString(&eventBuf, flags->retainerSelector); + postString(&eventBuf, flags->bioSelector); + RELEASE_LOCK(&eventBufMutex); +} + +void postHeapProfSampleBegin(StgInt era) +{ + ACQUIRE_LOCK(&eventBufMutex); + ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN); + postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN); + postWord64(&eventBuf, era); + RELEASE_LOCK(&eventBufMutex); +} + +void postHeapProfSampleString(StgWord8 profile_id, + const char *label, + StgWord64 residency) +{ + ACQUIRE_LOCK(&eventBufMutex); + StgWord label_len = strlen(label); + StgWord len = 1+8+label_len+1; + ensureRoomForVariableEvent(&eventBuf, len); + postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_STRING); + postPayloadSize(&eventBuf, len); + postWord8(&eventBuf, profile_id); + postWord64(&eventBuf, residency); + postString(&eventBuf, label); + RELEASE_LOCK(&eventBufMutex); +} + +#ifdef PROFILING +void postHeapProfCostCentre(StgWord32 ccID, + const char *label, + const char *module, + const char *srcloc, + StgBool is_caf) +{ + ACQUIRE_LOCK(&eventBufMutex); + StgWord label_len = strlen(label); + StgWord module_len = strlen(module); + StgWord srcloc_len = strlen(srcloc); + StgWord len = 4+label_len+module_len+srcloc_len+3+1; + ensureRoomForVariableEvent(&eventBuf, len); + postEventHeader(&eventBuf, EVENT_HEAP_PROF_COST_CENTRE); + postPayloadSize(&eventBuf, len); + postWord32(&eventBuf, ccID); + postString(&eventBuf, label); + postString(&eventBuf, module); + postString(&eventBuf, srcloc); + postWord8(&eventBuf, is_caf); + RELEASE_LOCK(&eventBufMutex); +} + +void postHeapProfSampleCostCentre(StgWord8 profile_id, + CostCentreStack *stack, + StgWord64 residency) +{ + ACQUIRE_LOCK(&eventBufMutex); + StgWord depth = 0; + CostCentreStack *ccs; + for (ccs = stack; ccs != NULL && ccs != CCS_MAIN; ccs = ccs->prevStack) + depth++; + if (depth > 0xff) depth = 0xff; + + StgWord len = 1+8+1+depth*4; + ensureRoomForVariableEvent(&eventBuf, len); + postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_COST_CENTRE); + postPayloadSize(&eventBuf, len); + postWord8(&eventBuf, profile_id); + postWord64(&eventBuf, residency); + postWord8(&eventBuf, depth); + for (ccs = stack; + depth>0 && ccs != NULL && ccs != CCS_MAIN; + ccs = ccs->prevStack, depth--) + postWord32(&eventBuf, ccs->cc->ccID); + RELEASE_LOCK(&eventBufMutex); +} +#endif /* PROFILING */ + void printAndClearEventBuf (EventsBuf *ebuf) { closeBlockMarker(ebuf); diff --git a/rts/eventlog/EventLog.h b/rts/eventlog/EventLog.h index abe7880fe4..df4aac7c71 100644 --- a/rts/eventlog/EventLog.h +++ b/rts/eventlog/EventLog.h @@ -133,6 +133,26 @@ void postTaskMigrateEvent (EventTaskId taskId, void postTaskDeleteEvent (EventTaskId taskId); +void postHeapProfBegin(StgWord8 profile_id); + +void postHeapProfSampleBegin(StgInt era); + +void postHeapProfSampleString(StgWord8 profile_id, + const char *label, + StgWord64 residency); + +#ifdef PROFILING +void postHeapProfCostCentre(StgWord32 ccID, + const char *label, + const char *module, + const char *srcloc, + StgBool is_caf); + +void postHeapProfSampleCostCentre(StgWord8 profile_id, + CostCentreStack *stack, + StgWord64 residency); +#endif /* PROFILING */ + #else /* !TRACING */ INLINE_HEADER void postSchedEvent (Capability *cap STG_UNUSED, |