[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

llvm-svn: 271564
This commit is contained in:
Qin Zhao 2016-06-02 18:45:25 +00:00
parent d6c5bc2c81
commit 4175a6d580
2 changed files with 194 additions and 16 deletions

View File

@ -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;
}

View File

@ -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