1 //===-- cache_frag.cpp ----------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of EfficiencySanitizer, a family of performance tuners.
12 // This file contains cache fragmentation-specific code.
13 //===----------------------------------------------------------------------===//
16 #include "esan_flags.h"
17 #include "sanitizer_common/sanitizer_addrhashmap.h"
18 #include "sanitizer_common/sanitizer_common.h"
19 #include "sanitizer_common/sanitizer_placement_new.h"
24 //===-- Struct field access counter runtime -------------------------------===//
26 // This should be kept consistent with LLVM's EfficiencySanitizer StructInfo.
28 const char *StructName;
31 u32 *FieldOffset; // auxiliary struct field info.
32 u32 *FieldSize; // auxiliary struct field info.
33 const char **FieldTypeName; // auxiliary struct field info.
36 bool hasAuxFieldInfo() { return FieldOffset != nullptr; }
39 // This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo.
40 // The tool-specific information per compilation unit (module).
41 struct CacheFragInfo {
47 struct StructCounter {
49 u64 Count; // The total access count of the struct.
50 u64 Ratio; // Difference ratio for the struct layout access.
53 // We use StructHashMap to keep track of an unique copy of StructCounter.
54 typedef AddrHashMap<StructCounter, 31051> StructHashMap;
56 StructHashMap StructMap;
58 u64 TotalCount; // The total access count of all structs.
62 static void reportStructSummary() {
63 // FIXME: provide a better struct field access summary report.
64 Report("%s: total struct field access count = %llu\n", SanitizerToolName,
68 // FIXME: we are still exploring proper ways to evaluate the difference between
69 // struct field counts. Currently, we use a simple formula to calculate the
70 // difference ratio: V1/V2.
71 static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) {
80 static void reportStructCounter(StructHashMap::Handle &Handle) {
81 const u32 TypePrintLimit = 512;
82 const char *type, *start, *end;
83 StructInfo *Struct = Handle->Struct;
84 // Union field address calculation is done via bitcast instead of GEP,
85 // so the count for union is always 0.
86 // We skip the union report to avoid confusion.
87 if (strncmp(Struct->StructName, "union.", 6) == 0)
89 // Remove the '.' after class/struct during print.
90 if (strncmp(Struct->StructName, "class.", 6) == 0) {
92 start = &Struct->StructName[6];
95 start = &Struct->StructName[7];
97 // Remove the suffixes with '$' during print.
98 end = strchr(start, '$');
99 CHECK(end != nullptr);
100 Report(" %s %.*s\n", type, end - start, start);
101 Report(" size = %u, count = %llu, ratio = %llu, array access = %llu\n",
102 Struct->Size, Handle->Count, Handle->Ratio, *Struct->ArrayCounter);
103 if (Struct->hasAuxFieldInfo()) {
104 for (u32 i = 0; i < Struct->NumFields; ++i) {
105 Report(" #%2u: offset = %u,\t size = %u,"
106 "\t count = %llu,\t type = %.*s\n",
107 i, Struct->FieldOffset[i], Struct->FieldSize[i],
108 Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeName[i]);
111 for (u32 i = 0; i < Struct->NumFields; ++i) {
112 Report(" #%2u: count = %llu\n", i, Struct->FieldCounters[i]);
117 static void computeStructRatio(StructHashMap::Handle &Handle) {
119 Handle->Count = Handle->Struct->FieldCounters[0];
120 for (u32 i = 1; i < Handle->Struct->NumFields; ++i) {
121 Handle->Count += Handle->Struct->FieldCounters[i];
122 Handle->Ratio += computeDifferenceRatio(
123 Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]);
125 Ctx->TotalCount += Handle->Count;
126 if (Handle->Ratio >= (u64)getFlags()->report_threshold ||
127 (Verbosity() >= 1 && Handle->Count > 0))
128 reportStructCounter(Handle);
131 static void registerStructInfo(CacheFragInfo *CacheFrag) {
132 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
133 StructInfo *Struct = &CacheFrag->Structs[i];
134 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters);
136 VPrintf(2, " Register %s: %u fields\n", Struct->StructName,
141 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
147 static void unregisterStructInfo(CacheFragInfo *CacheFrag) {
148 // FIXME: if the library is unloaded before finalizeCacheFrag, we should
149 // collect the result for later report.
150 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
151 StructInfo *Struct = &CacheFrag->Structs[i];
152 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true);
154 VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName,
156 // FIXME: we should move this call to finalizeCacheFrag once we can
157 // iterate over the hash map there.
158 computeStructRatio(H);
161 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
165 static bool Reported = false;
166 if (Ctx->NumStructs == 0 && !Reported) {
168 reportStructSummary();
172 //===-- Init/exit functions -----------------------------------------------===//
174 void processCacheFragCompilationUnitInit(void *Ptr) {
175 CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
176 VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
177 CacheFrag->UnitName, CacheFrag->NumStructs);
178 registerStructInfo(CacheFrag);
181 void processCacheFragCompilationUnitExit(void *Ptr) {
182 CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
183 VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
184 CacheFrag->UnitName, CacheFrag->NumStructs);
185 unregisterStructInfo(CacheFrag);
188 void initializeCacheFrag() {
189 VPrintf(2, "in esan::%s\n", __FUNCTION__);
190 // We use placement new to initialize Ctx before C++ static initializaion.
191 // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap.
192 static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1];
193 Ctx = new (CtxMem) Context();
197 int finalizeCacheFrag() {
198 VPrintf(2, "in esan::%s\n", __FUNCTION__);
202 void reportCacheFrag() {
203 VPrintf(2, "in esan::%s\n", __FUNCTION__);
204 // FIXME: Not yet implemented. We need to iterate over all of the
205 // compilation unit data.
208 } // namespace __esan