Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 1 | //===-- cache_frag.cpp ----------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of EfficiencySanitizer, a family of performance tuners. |
| 11 | // |
| 12 | // This file contains cache fragmentation-specific code. |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "esan.h" |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 16 | #include "esan_flags.h" |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 17 | #include "sanitizer_common/sanitizer_addrhashmap.h" |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 18 | #include "sanitizer_common/sanitizer_common.h" |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 19 | #include "sanitizer_common/sanitizer_placement_new.h" |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 20 | #include <string.h> |
Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 21 | |
| 22 | namespace __esan { |
| 23 | |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 24 | //===-- Struct field access counter runtime -------------------------------===// |
| 25 | |
Qin Zhao | 9e39638 | 2016-05-31 21:27:39 +0000 | [diff] [blame] | 26 | // This should be kept consistent with LLVM's EfficiencySanitizer StructInfo. |
| 27 | struct StructInfo { |
| 28 | const char *StructName; |
Qin Zhao | a4a7220 | 2016-06-10 02:10:34 +0000 | [diff] [blame] | 29 | u32 Size; |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 30 | u32 NumFields; |
Qin Zhao | 7f92eab | 2016-07-07 03:20:24 +0000 | [diff] [blame] | 31 | u32 *FieldOffset; // auxiliary struct field info. |
| 32 | u32 *FieldSize; // auxiliary struct field info. |
| 33 | const char **FieldTypeName; // auxiliary struct field info. |
Qin Zhao | 91ea3fb | 2016-07-02 03:25:55 +0000 | [diff] [blame] | 34 | u64 *FieldCounters; |
| 35 | u64 *ArrayCounter; |
Qin Zhao | 7f92eab | 2016-07-07 03:20:24 +0000 | [diff] [blame] | 36 | bool hasAuxFieldInfo() { return FieldOffset != nullptr; } |
Qin Zhao | 9e39638 | 2016-05-31 21:27:39 +0000 | [diff] [blame] | 37 | }; |
| 38 | |
| 39 | // This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo. |
| 40 | // The tool-specific information per compilation unit (module). |
| 41 | struct CacheFragInfo { |
| 42 | const char *UnitName; |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 43 | u32 NumStructs; |
Qin Zhao | 9e39638 | 2016-05-31 21:27:39 +0000 | [diff] [blame] | 44 | StructInfo *Structs; |
| 45 | }; |
| 46 | |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 47 | struct StructCounter { |
| 48 | StructInfo *Struct; |
Qin Zhao | cd5fe14 | 2016-06-15 17:27:29 +0000 | [diff] [blame] | 49 | u64 Count; // The total access count of the struct. |
| 50 | u64 Ratio; // Difference ratio for the struct layout access. |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 51 | }; |
| 52 | |
| 53 | // We use StructHashMap to keep track of an unique copy of StructCounter. |
| 54 | typedef AddrHashMap<StructCounter, 31051> StructHashMap; |
| 55 | struct Context { |
| 56 | StructHashMap StructMap; |
| 57 | u32 NumStructs; |
| 58 | u64 TotalCount; // The total access count of all structs. |
| 59 | }; |
| 60 | static Context *Ctx; |
| 61 | |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 62 | static void reportStructSummary() { |
| 63 | // FIXME: provide a better struct field access summary report. |
Qin Zhao | cd5fe14 | 2016-06-15 17:27:29 +0000 | [diff] [blame] | 64 | Report("%s: total struct field access count = %llu\n", SanitizerToolName, |
| 65 | Ctx->TotalCount); |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 66 | } |
| 67 | |
| 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) { |
Qin Zhao | cd5fe14 | 2016-06-15 17:27:29 +0000 | [diff] [blame] | 72 | if (Val2 > Val1) { |
| 73 | Swap(Val1, Val2); |
| 74 | } |
| 75 | if (Val2 == 0) |
| 76 | Val2 = 1; |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 77 | return (Val1 / Val2); |
| 78 | } |
| 79 | |
| 80 | static void reportStructCounter(StructHashMap::Handle &Handle) { |
Qin Zhao | cd5fe14 | 2016-06-15 17:27:29 +0000 | [diff] [blame] | 81 | const u32 TypePrintLimit = 512; |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 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) |
| 88 | return; |
| 89 | // Remove the '.' after class/struct during print. |
| 90 | if (strncmp(Struct->StructName, "class.", 6) == 0) { |
| 91 | type = "class"; |
| 92 | start = &Struct->StructName[6]; |
| 93 | } else { |
| 94 | type = "struct"; |
| 95 | start = &Struct->StructName[7]; |
| 96 | } |
| 97 | // Remove the suffixes with '#' during print. |
| 98 | end = strchr(start, '#'); |
| 99 | CHECK(end != nullptr); |
| 100 | Report(" %s %.*s\n", type, end - start, start); |
Qin Zhao | 91ea3fb | 2016-07-02 03:25:55 +0000 | [diff] [blame] | 101 | Report(" size = %u, count = %llu, ratio = %llu, array access = %llu\n", |
| 102 | Struct->Size, Handle->Count, Handle->Ratio, *Struct->ArrayCounter); |
Qin Zhao | 7f92eab | 2016-07-07 03:20:24 +0000 | [diff] [blame] | 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]); |
| 109 | } |
| 110 | } else { |
| 111 | for (u32 i = 0; i < Struct->NumFields; ++i) { |
| 112 | Report(" #%2u: count = %llu\n", i, Struct->FieldCounters[i]); |
| 113 | } |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 114 | } |
| 115 | } |
| 116 | |
| 117 | static void computeStructRatio(StructHashMap::Handle &Handle) { |
| 118 | Handle->Ratio = 0; |
| 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]); |
| 124 | } |
| 125 | Ctx->TotalCount += Handle->Count; |
Qin Zhao | cd5fe14 | 2016-06-15 17:27:29 +0000 | [diff] [blame] | 126 | if (Handle->Ratio >= (u64)getFlags()->report_threshold || |
| 127 | (Verbosity() >= 1 && Handle->Count > 0)) |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 128 | reportStructCounter(Handle); |
| 129 | } |
| 130 | |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 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); |
| 135 | if (H.created()) { |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 136 | VPrintf(2, " Register %s: %u fields\n", Struct->StructName, |
| 137 | Struct->NumFields); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 138 | H->Struct = Struct; |
| 139 | ++Ctx->NumStructs; |
| 140 | } else { |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 141 | VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, |
| 142 | Struct->NumFields); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 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); |
| 153 | if (H.exists()) { |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 154 | VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName, |
| 155 | Struct->NumFields); |
| 156 | // FIXME: we should move this call to finalizeCacheFrag once we can |
| 157 | // iterate over the hash map there. |
| 158 | computeStructRatio(H); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 159 | --Ctx->NumStructs; |
| 160 | } else { |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 161 | VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, |
| 162 | Struct->NumFields); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 163 | } |
| 164 | } |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 165 | static bool Reported = false; |
| 166 | if (Ctx->NumStructs == 0 && !Reported) { |
| 167 | Reported = true; |
| 168 | reportStructSummary(); |
| 169 | } |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 170 | } |
| 171 | |
Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 172 | //===-- Init/exit functions -----------------------------------------------===// |
| 173 | |
| 174 | void processCacheFragCompilationUnitInit(void *Ptr) { |
Qin Zhao | 9e39638 | 2016-05-31 21:27:39 +0000 | [diff] [blame] | 175 | CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 176 | VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, |
| 177 | CacheFrag->UnitName, CacheFrag->NumStructs); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 178 | registerStructInfo(CacheFrag); |
Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | void processCacheFragCompilationUnitExit(void *Ptr) { |
Qin Zhao | 9e39638 | 2016-05-31 21:27:39 +0000 | [diff] [blame] | 182 | CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 183 | VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, |
| 184 | CacheFrag->UnitName, CacheFrag->NumStructs); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 185 | unregisterStructInfo(CacheFrag); |
Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | void initializeCacheFrag() { |
| 189 | VPrintf(2, "in esan::%s\n", __FUNCTION__); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 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]; |
Qin Zhao | bc929e4 | 2016-06-03 20:48:17 +0000 | [diff] [blame] | 193 | Ctx = new (CtxMem) Context(); |
Qin Zhao | 4175a6d | 2016-06-02 18:45:25 +0000 | [diff] [blame] | 194 | Ctx->NumStructs = 0; |
Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | int finalizeCacheFrag() { |
| 198 | VPrintf(2, "in esan::%s\n", __FUNCTION__); |
Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 199 | return 0; |
| 200 | } |
| 201 | |
Derek Bruening | dec4bd0 | 2016-07-09 04:13:25 +0000 | [diff] [blame^] | 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. |
| 206 | } |
| 207 | |
Qin Zhao | 7e4933f | 2016-05-25 17:49:00 +0000 | [diff] [blame] | 208 | } // namespace __esan |