[compiler-rt] r271734 - [esan|cfrag] Compute the struct field access difference ratio

Qin Zhao via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 3 13:48:17 PDT 2016


Author: zhaoqin
Date: Fri Jun  3 15:48:17 2016
New Revision: 271734

URL: http://llvm.org/viewvc/llvm-project?rev=271734&view=rev
Log:
[esan|cfrag] Compute the struct field access difference ratio

Summary:
Computes the struct field access variation based on each field access
count.

Adds a flag to control the report thresholds.

Updates struct-simple.cpp with variance report output.

Reviewers: aizatsky

Subscribers: kubabrecka, zhaoqin, llvm-commits, eugenis, vitalybuka, kcc, bruening

Differential Revision: http://reviews.llvm.org/D20914

Modified:
    compiler-rt/trunk/lib/esan/cache_frag.cpp
    compiler-rt/trunk/lib/esan/esan_flags.inc
    compiler-rt/trunk/test/esan/TestCases/struct-simple.cpp
    compiler-rt/trunk/test/esan/TestCases/verbose-simple.c

Modified: compiler-rt/trunk/lib/esan/cache_frag.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/cache_frag.cpp?rev=271734&r1=271733&r2=271734&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/cache_frag.cpp (original)
+++ compiler-rt/trunk/lib/esan/cache_frag.cpp Fri Jun  3 15:48:17 2016
@@ -13,8 +13,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "esan.h"
+#include "esan_flags.h"
 #include "sanitizer_common/sanitizer_addrhashmap.h"
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include <string.h>
 
 namespace __esan {
 
@@ -38,8 +41,8 @@ struct CacheFragInfo {
 
 struct StructCounter {
   StructInfo *Struct;
-  u64 Count;    // The total access count of the struct.
-  u32 Variance; // Variance score for the struct layout access.
+  u64 Count;      // The total access count of the struct.
+  u64 Ratio;      // Difference ratio for the struct layout access.
 };
 
 // We use StructHashMap to keep track of an unique copy of StructCounter.
@@ -51,18 +54,73 @@ struct Context {
 };
 static Context *Ctx;
 
+static void reportStructSummary() {
+  // FIXME: provide a better struct field access summary report.
+  Report("%s: total struct field access count = %llu\n",
+         SanitizerToolName, Ctx->TotalCount);
+}
+
+// FIXME: we are still exploring proper ways to evaluate the difference between
+// struct field counts.  Currently, we use a simple formula to calculate the
+// difference ratio: V1/V2.
+static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) {
+  if (Val2 > Val1) { Swap(Val1, Val2); }
+  if (Val2 == 0) Val2 = 1;
+  return (Val1 / Val2);
+}
+
+static void reportStructCounter(StructHashMap::Handle &Handle) {
+  const char *type, *start, *end;
+  StructInfo *Struct = Handle->Struct;
+  // Union field address calculation is done via bitcast instead of GEP,
+  // so the count for union is always 0.
+  // We skip the union report to avoid confusion.
+  if (strncmp(Struct->StructName, "union.", 6) == 0)
+    return;
+  // Remove the '.' after class/struct during print.
+  if (strncmp(Struct->StructName, "class.", 6) == 0) {
+    type = "class";
+    start = &Struct->StructName[6];
+  } else {
+    type = "struct";
+    start = &Struct->StructName[7];
+  }
+  // Remove the suffixes with '#' during print.
+  end = strchr(start, '#');
+  CHECK(end != nullptr);
+  Report("  %s %.*s\n", type, end - start, start);
+  Report("   count = %llu, ratio = %llu\n", Handle->Count, Handle->Ratio);
+  for (u32 i = 0; i < Struct->NumFields; ++i) {
+    Report("   #%2u: count = %llu,\t type = %s\n", i, Struct->FieldCounters[i],
+           Struct->FieldTypeNames[i]);
+  }
+}
+
+static void computeStructRatio(StructHashMap::Handle &Handle) {
+  Handle->Ratio = 0;
+  Handle->Count = Handle->Struct->FieldCounters[0];
+  for (u32 i = 1; i < Handle->Struct->NumFields; ++i) {
+    Handle->Count += Handle->Struct->FieldCounters[i];
+    Handle->Ratio += computeDifferenceRatio(
+        Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]);
+  }
+  Ctx->TotalCount += Handle->Count;
+  if (Handle->Ratio >= (u64)getFlags()->report_threshold || Verbosity() >= 1)
+    reportStructCounter(Handle);
+}
+
 static void registerStructInfo(CacheFragInfo *CacheFrag) {
   for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
     StructInfo *Struct = &CacheFrag->Structs[i];
     StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters);
     if (H.created()) {
-      VPrintf(2, " Register %s: %u fields\n",
-              Struct->StructName, Struct->NumFields);
+      VPrintf(2, " Register %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
       H->Struct = Struct;
       ++Ctx->NumStructs;
     } else {
-      VPrintf(2, " Duplicated %s: %u fields\n",
-              Struct->StructName, Struct->NumFields);
+      VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
     }
   }
 }
@@ -74,34 +132,37 @@ static void unregisterStructInfo(CacheFr
     StructInfo *Struct = &CacheFrag->Structs[i];
     StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true);
     if (H.exists()) {
-      VPrintf(2, " Unregister %s: %u fields\n",
-              Struct->StructName, Struct->NumFields);
+      VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
+      // FIXME: we should move this call to finalizeCacheFrag once we can
+      // iterate over the hash map there.
+      computeStructRatio(H);
       --Ctx->NumStructs;
     } else {
-      VPrintf(2, " Duplicated %s: %u fields\n",
-              Struct->StructName, Struct->NumFields);
+      VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
     }
   }
-}
-
-static void reportStructSummary() {
-  // FIXME: iterate StructHashMap and generate the final report.
-  Report("%s is not finished: nothing yet to report\n", SanitizerToolName);
+  static bool Reported = false;
+  if (Ctx->NumStructs == 0 && !Reported) {
+    Reported = true;
+    reportStructSummary();
+  }
 }
 
 //===-- Init/exit functions -----------------------------------------------===//
 
 void processCacheFragCompilationUnitInit(void *Ptr) {
   CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
-  VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n",
-          __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumStructs);
+  VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
+          CacheFrag->UnitName, CacheFrag->NumStructs);
   registerStructInfo(CacheFrag);
 }
 
 void processCacheFragCompilationUnitExit(void *Ptr) {
   CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
-  VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n",
-          __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumStructs);
+  VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
+          CacheFrag->UnitName, CacheFrag->NumStructs);
   unregisterStructInfo(CacheFrag);
 }
 
@@ -110,13 +171,12 @@ void initializeCacheFrag() {
   // We use placement new to initialize Ctx before C++ static initializaion.
   // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap.
   static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1];
-  Ctx = new(CtxMem) Context();
+  Ctx = new (CtxMem) Context();
   Ctx->NumStructs = 0;
 }
 
 int finalizeCacheFrag() {
   VPrintf(2, "in esan::%s\n", __FUNCTION__);
-  reportStructSummary();
   return 0;
 }
 

Modified: compiler-rt/trunk/lib/esan/esan_flags.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/esan_flags.inc?rev=271734&r1=271733&r2=271734&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/esan_flags.inc (original)
+++ compiler-rt/trunk/lib/esan/esan_flags.inc Fri Jun  3 15:48:17 2016
@@ -45,3 +45,12 @@ ESAN_FLAG(int, sample_freq, 20,
 // Number N samples number N-1 every (1 << snapshot_step) instance of N-1.
 ESAN_FLAG(int, snapshot_step, 2, "Working set tool: the log of the sampling "
           "performed for the next-higher-frequency snapshot series.")
+
+//===----------------------------------------------------------------------===//
+// Cache Fragmentation tool options
+//===----------------------------------------------------------------------===//
+
+// The difference information of a struct is reported if the struct's difference
+// score is greater than the report_threshold.
+ESAN_FLAG(int, report_threshold, 1<<10, "Cache-frag tool: the struct difference"
+          " score threshold for reporting.")

Modified: compiler-rt/trunk/test/esan/TestCases/struct-simple.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/esan/TestCases/struct-simple.cpp?rev=271734&r1=271733&r2=271734&view=diff
==============================================================================
--- compiler-rt/trunk/test/esan/TestCases/struct-simple.cpp (original)
+++ compiler-rt/trunk/test/esan/TestCases/struct-simple.cpp Fri Jun  3 15:48:17 2016
@@ -138,22 +138,52 @@ int main(int argc, char **argv) {
   return 0;
   // CHECK:      in esan::finalizeLibrary
   // CHECK-NEXT: in esan::finalizeCacheFrag
-  // CHECK-NEXT: {{.*}}EfficiencySanitizer is not finished: nothing yet to report
   // CHECK-NEXT: in esan::processCompilationUnitExit
   // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
   // CHECK-NEXT:  Unregister class.C#3#14#13#13:  3 fields
+  // CHECK-NEXT:   {{.*}} class C
+  // CHECK-NEXT:   {{.*}}  count = 5, ratio = 3
+  // CHECK-NEXT:   {{.*}}  # 0: count = 2, type = %struct.anon = type { i32, i32 }
+  // CHECK-NEXT:   {{.*}}  # 1: count = 2, type = %union.anon = type { double }
+  // CHECK-NEXT:   {{.*}}  # 2: count = 1, type = [10 x i8]
   // CHECK-NEXT:  Unregister struct.anon#2#11#11: 2 fields
+  // CHECK-NEXT:   {{.*}} struct anon
+  // CHECK-NEXT:   {{.*}}  count = 2, ratio = 1
+  // CHECK-NEXT:   {{.*}}  # 0: count = 1, type = i32
+  // CHECK-NEXT:   {{.*}}  # 1: count = 1, type = i32
   // CHECK-NEXT:  Unregister union.anon#1#3:      1 fields
   // CHECK-NEXT:  Unregister struct.S#2#11#11:    2 fields
+  // CHECK-NEXT:   {{.*}} struct S
+  // CHECK-NEXT:   {{.*}}  count = 2, ratio = 2
+  // CHECK-NEXT:   {{.*}}  # 0: count = 2, type = i32
+  // CHECK-NEXT:   {{.*}}  # 1: count = 0, type = i32
   // CHECK-NEXT:  Unregister struct.D#3#11#11#11: 3 fields
+  // CHECK-NEXT:   {{.*}} struct D
+  // CHECK-NEXT:   {{.*}}  count = 2, ratio = 2
+  // CHECK-NEXT:   {{.*}}  # 0: count = 1, type = i32
+  // CHECK-NEXT:   {{.*}}  # 1: count = 1, type = i32
+  // CHECK-NEXT:   {{.*}}  # 2: count = 0, type = i32
   // CHECK-NEXT: in esan::processCompilationUnitExit
   // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s)
   // CHECK-NEXT: in esan::processCompilationUnitExit
   // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
   // CHECK-NEXT:  Unregister struct.A#2#11#11:    2 fields
+  // CHECK-NEXT:   {{.*}} struct A
+  // CHECK-NEXT:   {{.*}}  count = 2049, ratio = 2048
+  // CHECK-NEXT:   {{.*}}  # 0: count = 2048, type = i32
+  // CHECK-NEXT:   {{.*}}  # 1: count = 1, type = i32
   // CHECK-NEXT:  Unregister struct.B#2#3#2:      2 fields
+  // CHECK-NEXT:   {{.*}} struct B
+  // CHECK-NEXT:   {{.*}}  count = 2097153, ratio = 2097152
+  // CHECK-NEXT:   {{.*}}  # 0: count = 1, type = float
+  // CHECK-NEXT:   {{.*}}  # 1: count = 2097152, type = double
   // CHECK-NEXT:  Unregister union.U#1#3:         1 fields
   // CHECK-NEXT:  Duplicated struct.S#2#11#11:    2 fields
   // CHECK-NEXT:  Unregister struct.D#2#11#11:    2 fields
+  // CHECK-NEXT:   {{.*}} struct D
+  // CHECK-NEXT:   {{.*}}  count = 1, ratio = 1
+  // CHECK-NEXT:   {{.*}}  # 0: count = 1, type = i32
+  // CHECK-NEXT:   {{.*}}  # 1: count = 0, type = i32
+  // CHECK-NEXT: {{.*}}EfficiencySanitizer: total struct field access count = 2099214
 }
 #endif // MAIN

Modified: compiler-rt/trunk/test/esan/TestCases/verbose-simple.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/esan/TestCases/verbose-simple.c?rev=271734&r1=271733&r2=271734&view=diff
==============================================================================
--- compiler-rt/trunk/test/esan/TestCases/verbose-simple.c (original)
+++ compiler-rt/trunk/test/esan/TestCases/verbose-simple.c Fri Jun  3 15:48:17 2016
@@ -9,6 +9,6 @@ int main(int argc, char **argv) {
   // CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
   // CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
   // CHECK-NEXT: in esan::finalizeLibrary
-  // CHECK-NEXT: ==verbose-simple{{.*}}EfficiencySanitizer is not finished: nothing yet to report
+  // CHECK-NEXT: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0
   return 0;
 }




More information about the llvm-commits mailing list