summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/esan/cache_frag.cpp75
-rw-r--r--test/esan/TestCases/struct-simple.cpp135
2 files changed, 194 insertions, 16 deletions
diff --git a/lib/esan/cache_frag.cpp b/lib/esan/cache_frag.cpp
index da168dc0c..af36d90bb 100644
--- a/lib/esan/cache_frag.cpp
+++ b/lib/esan/cache_frag.cpp
@@ -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;
}
diff --git a/test/esan/TestCases/struct-simple.cpp b/test/esan/TestCases/struct-simple.cpp
index f1dd38534..560f79cb6 100644
--- a/test/esan/TestCases/struct-simple.cpp
+++ b/test/esan/TestCases/struct-simple.cpp
@@ -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 // PART1
+
+//===-- compilation unit part2 without main function ----------------------===//
+#ifdef PART2
+// No struct in this part.
+void part2()
{
+ // do nothing
}
-#endif // PART
+#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