Bug 394307

Summary: Add macro to extract current instruction count for peak load monitoring
Product: [Developer tools] valgrind Reporter: Jonas Josefsson <jonjo442>
Component: callgrindAssignee: Josef Weidendorfer <josef.weidendorfer>
Status: REPORTED ---    
Severity: normal CC: josef.weidendorfer, jseward
Priority: NOR    
Version First Reported In: unspecified   
Target Milestone: ---   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed/Implemented In:
Sentry Crash Report:

Description Jonas Josefsson 2018-05-16 06:18:35 UTC
In order to use callgrind to find load peaks, it is necessary to extract the current instruction count from the running program. Currently callgrind just gives the total instruction count which can give information about a mean load but it cannot be used to find peak loads.

I've made a modification to callgrind that adds a macro that does this:

diff --git a/callgrind/callgrind.h b/callgrind/callgrind.h
index f078cc82b..6d3c40951 100644
--- a/callgrind/callgrind.h
+++ b/callgrind/callgrind.h
@@ -78,7 +78,8 @@ typedef
       VG_USERREQ__TOGGLE_COLLECT,
       VG_USERREQ__DUMP_STATS_AT,
       VG_USERREQ__START_INSTRUMENTATION,
-      VG_USERREQ__STOP_INSTRUMENTATION
+      VG_USERREQ__STOP_INSTRUMENTATION,
+      VG_USERREQ__GET_TOTAL_COSTS
    } Vg_CallgrindClientRequest;
 
 /* Dump current state of cost centers, and zero them afterwards */
@@ -126,4 +127,10 @@ typedef
   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STOP_INSTRUMENTATION,  \
                                   0, 0, 0, 0, 0)
 
+#define CALLGRIND_GET_TOTAL_COSTS(rValue)                        \
+  VALGRIND_DO_CLIENT_REQUEST(rValue, 0, VG_USERREQ__GET_TOTAL_COSTS,  \
+                                  0, 0, 0, 0, 0)
+
 #endif /* __CALLGRIND_H */
diff --git a/callgrind/main.c b/callgrind/main.c
index ab4927296..dd59cc208 100644
--- a/callgrind/main.c
+++ b/callgrind/main.c
@@ -1661,6 +1661,20 @@ Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
      }
      break;
 
+  case VG_USERREQ__GET_TOTAL_COSTS:
+     {
+        #define UWORD_MAX (~(UWord)0)
+        ULong Ir_total;
+
+        Ir_total = CLG_(current_state).cost[ fullOffset(EG_IR) ];
+        
+        if (Ir_total > UWORD_MAX) // ULong is 64 bits, UWord might be 32 bit
+          Ir_total = UWORD_MAX;
+
+        *ret = ((UWord) Ir_total);
+     }
+     break;
+
    case VG_USERREQ__ZERO_STATS:
      CLG_(zero_all_cost)(True);
       *ret = 0;                 /* meaningless */
(END)


This can be used to track the peak load of a function in the following way:

// Some kind of main loop
unsigned long MaxInstCount = 0;
while(1) 
{
    unsigned long PostInstCount, PreInstCount;

    CALLGRIND_ZERO_STATS;
    CALLGRIND_START_INSTRUMENTATION;

    CALLGRIND_GET_TOTAL_COSTS(PreInstCount);

    // Execute function to monitor
    Execute_Something();

    CALLGRIND_GET_TOTAL_COSTS(PostInstCount);
    
    PostInstCount -= PreInstCount;

    // Find max and dump callgrind stats.
    if (PostInstCount > MaxInstCount)
    {    
         MaxInstCount = PostInstCount;
         CALLGRIND_DUMP_STATS;
    }

    // Write execution time and some other parameters to InstructionFetchLog.txt.
    fprintf(InstructionFetchLog, "%u,%u\n", PostInstCount, SomeInterestingStateInfo);

    // Stop intrumentation
    CALLGRIND_STOP_INSTRUMENTATION;
}