eventlog: Dump cost centre stack on each sample
authorMatthew Pickering <matthewtpickering@gmail.com>
Wed, 9 Oct 2019 13:32:13 +0000 (14:32 +0100)
committerMarge Bot <ben+marge-bot@smart-cactus.org>
Wed, 23 Oct 2019 09:58:58 +0000 (05:58 -0400)
With this change it is possible to reconstruct the timing portion of a
`.prof` file after the fact. By logging the stacks at each time point
a more precise executation trace of the program can be observed rather
than all identical cost centres being identified in the report.

There are two new events:

1. `EVENT_PROF_BEGIN` - emitted at the start of profiling to communicate
the tick interval
2. `EVENT_PROF_SAMPLE_COST_CENTRE` - emitted on each tick to communicate the
current call stack.

Fixes #17322

docs/users_guide/8.10.1-notes.rst
docs/users_guide/eventlog-formats.rst
includes/rts/EventLogFormat.h
rts/ProfHeap.c
rts/Profiling.c
rts/Proftimer.c
rts/Trace.c
rts/Trace.h
rts/eventlog/EventLog.c
rts/eventlog/EventLog.h

index 64c2da2..54046d0 100644 (file)
@@ -166,6 +166,9 @@ Compiler
   the sample start event contains a timestamp of when the census occurred.
   The retainer profiling events are emitted using the standard events.
 
+- The eventlog now logs the cost centre stack on each sample. This enables
+  the `.prof` file to be partially reconstructed from the eventlog.
+
 - Add new flag :ghc-flag:`-fkeep-going` which makes the compiler
   continue as far as it can despite errors.
 
index 27bd37c..a3ed47f 100644 (file)
@@ -134,3 +134,33 @@ A variable-length event encoding a heap sample broken down by,
    * ``Word8``: Profile ID
    * ``Word64``: heap residency in bytes
    * ``String``: type or closure description, or module name
+
+.. _time-profiler-events:
+
+Time profiler event log output
+------------------------------
+
+The time profiling mode enabled by ``-p`` also emits sample events to the eventlog.
+At the start of profiling the tick interval is emitted to the eventlog and then
+on each tick the current cost centre stack is emitted. Together these enable
+a user to construct an approximate track of the executation of their program.
+
+Profile begin event
+^^^^^^^^^^^^^^^^^^^
+
+ * ``EVENT_PROF_BEGIN``
+
+   * ``Word64``: Tick interval, in nanoseconds
+
+
+Tick sample event
+^^^^^^^^^^^^^^^^^^
+
+A variable-length packet encoding a profile sample.
+
+* ``EVENT_PROF_SAMPLE_COST_CENTRE``
+
+  * ``Word32``: Capability
+  * ``Word64``: Current profiling tick
+  * ``Word8``: stack depth
+  * ``Word32[]``: cost centre stack starting with inner-most (cost centre numbers)
index ad983e7..7b989b0 100644 (file)
 #define EVENT_HEAP_PROF_SAMPLE_STRING      164
 #define EVENT_HEAP_PROF_SAMPLE_END         165
 #define EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN   166
+#define EVENT_PROF_SAMPLE_COST_CENTRE      167
+#define EVENT_PROF_BEGIN                   168
 
 #define EVENT_USER_BINARY_MSG              181
 
index 77e0e69..c35b4ba 100644 (file)
@@ -341,18 +341,6 @@ printSample(bool beginSample, StgDouble sampleValue)
     }
 }
 
-static void
-dumpCostCentresToEventLog(void)
-{
-#if defined(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
-}
 
 void freeHeapProfiling (void)
 {
@@ -466,7 +454,6 @@ initHeapProfiling(void)
 #endif
 
     traceHeapProfBegin(0);
-    dumpCostCentresToEventLog();
 }
 
 void
index b91129e..a4247c7 100644 (file)
@@ -25,7 +25,7 @@
 #include <fs_rts.h>
 #include <string.h>
 
-#if defined(DEBUG)
+#if defined(DEBUG) || defined(PROFILING)
 #include "Trace.h"
 #endif
 
@@ -132,6 +132,19 @@ static  void              initProfilingLogFile ( void );
    Initialise the profiling environment
    -------------------------------------------------------------------------- */
 
+static void
+dumpCostCentresToEventLog(void)
+{
+#if defined(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
+}
+
 void initProfiling (void)
 {
     // initialise our arena
@@ -187,8 +200,12 @@ void initProfiling (void)
     if (RtsFlags.CcFlags.doCostCentres) {
         initTimeProfiling();
     }
+
+    dumpCostCentresToEventLog();
 }
 
+
+
 //
 // Should be called after loading any new Haskell code.
 //
@@ -278,6 +295,7 @@ initProfilingLogFile(void)
 void
 initTimeProfiling(void)
 {
+    traceProfBegin();
     /* Start ticking */
     startProfTimer();
 };
index eb4a932..68a73a5 100644 (file)
@@ -12,6 +12,7 @@
 #include "Profiling.h"
 #include "Proftimer.h"
 #include "Capability.h"
+#include "Trace.h"
 
 #if defined(PROFILING)
 static bool do_prof_ticks = false;       // enable profiling ticks
@@ -77,6 +78,7 @@ handleProfTick(void)
         uint32_t n;
         for (n=0; n < n_capabilities; n++) {
             capabilities[n]->r.rCCCS->time_ticks++;
+            traceProfSampleCostCentre(capabilities[n], capabilities[n]->r.rCCCS, total_ticks);
         }
     }
 #endif
index de647f7..c8a951a 100644 (file)
@@ -656,6 +656,7 @@ void traceHeapProfCostCentre(StgWord32 ccID,
     }
 }
 
+// This one is for .hp samples
 void traceHeapProfSampleCostCentre(StgWord8 profile_id,
                                    CostCentreStack *stack, StgWord residency)
 {
@@ -663,6 +664,21 @@ void traceHeapProfSampleCostCentre(StgWord8 profile_id,
         postHeapProfSampleCostCentre(profile_id, stack, residency);
     }
 }
+
+// This one is for .prof samples
+void traceProfSampleCostCentre(Capability *cap,
+                               CostCentreStack *stack, StgWord tick)
+{
+    if (eventlog_enabled) {
+        postProfSampleCostCentre(cap, stack, tick);
+    }
+}
+void traceProfBegin(void)
+{
+    if (eventlog_enabled) {
+        postProfBegin();
+    }
+}
 #endif
 
 #if defined(DEBUG)
index d3bb226..b7db0ca 100644 (file)
@@ -301,6 +301,10 @@ void traceHeapProfCostCentre(StgWord32 ccID,
                              StgBool is_caf);
 void traceHeapProfSampleCostCentre(StgWord8 profile_id,
                                    CostCentreStack *stack, StgWord residency);
+
+void traceProfSampleCostCentre(Capability *cap,
+                               CostCentreStack *stack, StgWord ticks);
+void traceProfBegin(void);
 #endif /* PROFILING */
 
 void flushTrace(void);
index 5c6a1ca..6d7b487 100644 (file)
@@ -107,6 +107,8 @@ char *EventDesc[] = {
   [EVENT_HEAP_PROF_SAMPLE_END]    = "End 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_PROF_SAMPLE_COST_CENTRE] = "Time profile cost-centre stack",
+  [EVENT_PROF_BEGIN] = "Start of a time profile",
   [EVENT_USER_BINARY_MSG]     = "User binary message"
 };
 
@@ -442,6 +444,14 @@ init_event_types(void)
             eventTypes[t].size = EVENT_SIZE_DYNAMIC;
             break;
 
+        case EVENT_PROF_SAMPLE_COST_CENTRE:
+            eventTypes[t].size = EVENT_SIZE_DYNAMIC;
+            break;
+
+        case EVENT_PROF_BEGIN:
+            eventTypes[t].size = 8;
+            break;
+
         case EVENT_USER_BINARY_MSG:
             eventTypes[t].size = EVENT_SIZE_DYNAMIC;
             break;
@@ -1312,6 +1322,44 @@ void postHeapProfSampleCostCentre(StgWord8 profile_id,
         postWord32(&eventBuf, ccs->cc->ccID);
     RELEASE_LOCK(&eventBufMutex);
 }
+
+
+void postProfSampleCostCentre(Capability *cap,
+                              CostCentreStack *stack,
+                              StgWord64 tick)
+{
+    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 = 4+8+1+depth*4;
+    ensureRoomForVariableEvent(&eventBuf, len);
+    postEventHeader(&eventBuf, EVENT_PROF_SAMPLE_COST_CENTRE);
+    postPayloadSize(&eventBuf, len);
+    postWord32(&eventBuf, cap->no);
+    postWord64(&eventBuf, tick);
+    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);
+}
+
+// This event is output at the start of profiling so the tick interval can
+// be reported. Once the tick interval is reported the total executation time
+// can be calculuated from how many samples there are.
+void postProfBegin(void)
+{
+    ACQUIRE_LOCK(&eventBufMutex);
+    postEventHeader(&eventBuf, EVENT_PROF_BEGIN);
+    // The interval that each tick was sampled, in nanoseconds
+    postWord64(&eventBuf, TimeToNS(RtsFlags.MiscFlags.tickInterval));
+    RELEASE_LOCK(&eventBufMutex);
+}
 #endif /* PROFILING */
 
 void printAndClearEventBuf (EventsBuf *ebuf)
index d8a614b..ec9a5f3 100644 (file)
@@ -157,6 +157,11 @@ void postHeapProfCostCentre(StgWord32 ccID,
 void postHeapProfSampleCostCentre(StgWord8 profile_id,
                                   CostCentreStack *stack,
                                   StgWord64 residency);
+
+void postProfSampleCostCentre(Capability *cap,
+                              CostCentreStack *stack,
+                              StgWord64 ticks);
+void postProfBegin(void);
 #endif /* PROFILING */
 
 #else /* !TRACING */