summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2015-12-30 22:32:32 +0100
committerBen Gamari <ben@smart-cactus.org>2016-03-26 01:06:12 +0100
commit436be90ac8616ac504e91da917db67a1c469e6b9 (patch)
tree2be1fcbe0d31009ef89f4fa0e61813b5a3adc089
parent1b4d1201d6fe395db2b268ca111baa69d96ce211 (diff)
downloadhaskell-436be90ac8616ac504e91da917db67a1c469e6b9.tar.gz
Log heap profiler samples to event log
-rw-r--r--includes/rts/EventLogFormat.h7
-rw-r--r--rts/ProfHeap.c32
-rw-r--r--rts/Trace.c43
-rw-r--r--rts/Trace.h19
-rw-r--r--rts/eventlog/EventLog.c183
-rw-r--r--rts/eventlog/EventLog.h20
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,