[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
diff --git a/compiler-rt/lib/esan/cache_frag.cpp b/compiler-rt/lib/esan/cache_frag.cpp
index da168dc..af36d90 100644
--- a/compiler-rt/lib/esan/cache_frag.cpp
+++ b/compiler-rt/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 @@
 // 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;
 }