[compiler-rt] r271564 - [esan|cfrag] Add struct info registration

Qin Zhao via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 2 11:45:26 PDT 2016


Author: zhaoqin
Date: Thu Jun  2 13:45:25 2016
New Revision: 271564

URL: http://llvm.org/viewvc/llvm-project?rev=271564&view=rev
Log:
[esan|cfrag] Add struct info registration

Summary:
Adds StructInfo to CacheFragInfo to match the LLVM's EfficiencySanitizer
structs.

Uses StructHashMap to keep track of the struct info used by the app.

Adds registerStructInfo/unregisterStructInfo to add/remove struct infos
to/from StructHashMap.

updates test struct-simple.cpp with more C structs.

Reviewers: aizatsky, filcab

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

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

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

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=271564&r1=271563&r2=271564&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/cache_frag.cpp (original)
+++ compiler-rt/trunk/lib/esan/cache_frag.cpp Thu Jun  2 13:45:25 2016
@@ -13,13 +13,17 @@
 //===----------------------------------------------------------------------===//
 
 #include "esan.h"
+#include "sanitizer_common/sanitizer_addrhashmap.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 
 namespace __esan {
 
+//===-- Struct field access counter runtime -------------------------------===//
+
 // This should be kept consistent with LLVM's EfficiencySanitizer StructInfo.
 struct StructInfo {
   const char *StructName;
-  u32 NumOfFields;
+  u32 NumFields;
   u64 *FieldCounters;
   const char **FieldTypeNames;
 };
@@ -28,32 +32,91 @@ struct StructInfo {
 // The tool-specific information per compilation unit (module).
 struct CacheFragInfo {
   const char *UnitName;
-  u32 NumOfStructs;
+  u32 NumStructs;
   StructInfo *Structs;
 };
 
+struct StructCounter {
+  StructInfo *Struct;
+  u64 Count;    // The total access count of the struct.
+  u32 Variance; // Variance score for the struct layout access.
+};
+
+// We use StructHashMap to keep track of an unique copy of StructCounter.
+typedef AddrHashMap<StructCounter, 31051> StructHashMap;
+struct Context {
+  StructHashMap StructMap;
+  u32 NumStructs;
+  u64 TotalCount; // The total access count of all structs.
+};
+static Context *Ctx;
+
+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);
+      H->Struct = Struct;
+      ++Ctx->NumStructs;
+    } else {
+      VPrintf(2, " Duplicated %s: %u fields\n",
+              Struct->StructName, Struct->NumFields);
+    }
+  }
+}
+
+static void unregisterStructInfo(CacheFragInfo *CacheFrag) {
+  // FIXME: if the library is unloaded before finalizeCacheFrag, we should
+  // collect the result for later report.
+  for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
+    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);
+      --Ctx->NumStructs;
+    } else {
+      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);
+}
+
 //===-- 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->NumOfStructs);
+          __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->NumOfStructs);
+          __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumStructs);
+  unregisterStructInfo(CacheFrag);
 }
 
 void initializeCacheFrag() {
   VPrintf(2, "in esan::%s\n", __FUNCTION__);
+  // 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->NumStructs = 0;
 }
 
 int finalizeCacheFrag() {
   VPrintf(2, "in esan::%s\n", __FUNCTION__);
-  // FIXME: add the cache fragmentation final report.
-  Report("%s is not finished: nothing yet to report\n", SanitizerToolName);
+  reportStructSummary();
   return 0;
 }
 

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=271564&r1=271563&r2=271564&view=diff
==============================================================================
--- compiler-rt/trunk/test/esan/TestCases/struct-simple.cpp (original)
+++ compiler-rt/trunk/test/esan/TestCases/struct-simple.cpp Thu Jun  2 13:45:25 2016
@@ -1,6 +1,7 @@
-// RUN: %clang_esan_frag -O0 %s -DPART -c -o %t-part.o 2>&1
+// RUN: %clang_esan_frag -O0 %s -DPART1 -c -o %t-part1.o 2>&1
+// RUN: %clang_esan_frag -O0 %s -DPART2 -c -o %t-part2.o 2>&1
 // RUN: %clang_esan_frag -O0 %s -DMAIN -c -o %t-main.o 2>&1
-// RUN: %clang_esan_frag -O0 %t-part.o %t-main.o -o %t 2>&1
+// RUN: %clang_esan_frag -O0 %t-part1.o %t-part2.o %t-main.o -o %t 2>&1
 // RUN: %env_esan_opts=verbosity=2 %run %t 2>&1 | FileCheck %s
 
 // We generate two different object files from this file with different
@@ -10,35 +11,149 @@
 #include <stdio.h>
 
 extern "C" {
-  void part();
+  void part1();
+  void part2();
 }
 
-//===-- compilation unit without main function ----------------------------===//
+//===-- compilation unit part1 without main function ----------------------===//
 
-#ifdef PART
-void part()
+#ifdef PART1
+struct A {
+  int x;
+  int y;
+};
+
+struct B {
+  float m;
+  double n;
+};
+
+union U {
+  float f;
+  double d;
+};
+
+// Same struct in both main and part1.
+struct S {
+  int s1;
+  int s2;
+};
+
+// Different structs with the same name in main and part1.
+struct D {
+  int d1;
+  int d2;
+};
+
+void part1()
 {
+  struct A a;
+  struct B b;
+  union  U u;
+  struct S s;
+  struct D d;
+  for (int i = 0; i < (1 << 11); i++)
+    a.x = 0;
+  a.y = 1;
+  b.m = 2.0;
+  for (int i = 0; i < (1 << 21); i++)
+    b.n = 3.0;
+  u.f = 0.0;
+  u.d = 1.0;
+  s.s1 = 0;
+  d.d1 = 0;
 }
-#endif // PART
+#endif // PART1
+
+//===-- compilation unit part2 without main function ----------------------===//
+#ifdef PART2
+// No struct in this part.
+void part2()
+{
+  // do nothing
+}
+#endif // PART2
 
 //===-- compilation unit with main function -------------------------------===//
 
 #ifdef MAIN
+class C {
+public:
+  struct {
+    int x;
+    int y;
+  } cs;
+  union {
+    float f;
+    double d;
+  } cu;
+  char c[10];
+};
+
+// Same struct in both main and part1.
+struct S {
+  int s1;
+  int s2;
+};
+
+// Different structs with the same name in main and part1.
+struct D {
+  int d1;
+  int d2;
+  int d3;
+};
+
 int main(int argc, char **argv) {
   // CHECK:      in esan::initializeLibrary
   // CHECK:      in esan::initializeCacheFrag
   // CHECK-NEXT: in esan::processCompilationUnitInit
-  // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s)
+  // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
+  // CHECK-NEXT:  Register struct.A#2#11#11: 2 fields
+  // CHECK-NEXT:  Register struct.B#2#3#2:   2 fields
+  // CHECK-NEXT:  Register union.U#1#3:      1 fields
+  // CHECK-NEXT:  Register struct.S#2#11#11: 2 fields
+  // CHECK-NEXT:  Register struct.D#2#11#11: 2 fields
   // CHECK-NEXT: in esan::processCompilationUnitInit
   // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s)
-  part();
+  // CHECK-NEXT: in esan::processCompilationUnitInit
+  // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
+  // CHECK-NEXT:  Register class.C#3#14#13#13:  3 fields
+  // CHECK-NEXT:  Register struct.anon#2#11#11: 2 fields
+  // CHECK-NEXT:  Register union.anon#1#3:      1 fields
+  // CHECK-NEXT:  Duplicated struct.S#2#11#11:  2 fields
+  // CHECK-NEXT:  Register struct.D#3#11#11#11: 3 fields
+  struct C c[2];
+  struct S s;
+  struct D d;
+  c[0].cs.x = 0;
+  c[1].cs.y = 1;
+  c[0].cu.f = 0.0;
+  c[1].cu.d = 1.0;
+  c[0].c[2] = 0;
+  s.s1 = 0;
+  d.d1 = 0;
+  d.d2 = 0;
+  part1();
+  part2();
   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 0 class(es)/struct(s)
+  // 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:  Unregister struct.anon#2#11#11: 2 fields
+  // CHECK-NEXT:  Unregister union.anon#1#3:      1 fields
+  // CHECK-NEXT:  Unregister struct.S#2#11#11:    2 fields
+  // CHECK-NEXT:  Unregister struct.D#3#11#11#11: 3 fields
   // 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:  Unregister struct.B#2#3#2:      2 fields
+  // 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
 }
 #endif // MAIN




More information about the llvm-commits mailing list