blob: 2096bec7569ea3b5259314c33e8cbea3f68a8cf9 [file] [log] [blame]
Qin Zhao7e4933f2016-05-25 17:49:00 +00001//===-- 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 Zhaobc929e42016-06-03 20:48:17 +000016#include "esan_flags.h"
Qin Zhao4175a6d2016-06-02 18:45:25 +000017#include "sanitizer_common/sanitizer_addrhashmap.h"
Qin Zhaobc929e42016-06-03 20:48:17 +000018#include "sanitizer_common/sanitizer_common.h"
Qin Zhao4175a6d2016-06-02 18:45:25 +000019#include "sanitizer_common/sanitizer_placement_new.h"
Qin Zhaobc929e42016-06-03 20:48:17 +000020#include <string.h>
Qin Zhao7e4933f2016-05-25 17:49:00 +000021
22namespace __esan {
23
Qin Zhao4175a6d2016-06-02 18:45:25 +000024//===-- Struct field access counter runtime -------------------------------===//
25
Qin Zhao9e396382016-05-31 21:27:39 +000026// This should be kept consistent with LLVM's EfficiencySanitizer StructInfo.
27struct StructInfo {
28 const char *StructName;
Qin Zhaoa4a72202016-06-10 02:10:34 +000029 u32 Size;
Qin Zhao4175a6d2016-06-02 18:45:25 +000030 u32 NumFields;
Qin Zhaoa4a72202016-06-10 02:10:34 +000031 u32 *FieldOffsets;
Qin Zhaoe24bc362016-06-17 04:50:11 +000032 u32 *FieldSize;
Qin Zhao9e396382016-05-31 21:27:39 +000033 u64 *FieldCounters;
34 const char **FieldTypeNames;
35};
36
37// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo.
38// The tool-specific information per compilation unit (module).
39struct CacheFragInfo {
40 const char *UnitName;
Qin Zhao4175a6d2016-06-02 18:45:25 +000041 u32 NumStructs;
Qin Zhao9e396382016-05-31 21:27:39 +000042 StructInfo *Structs;
43};
44
Qin Zhao4175a6d2016-06-02 18:45:25 +000045struct StructCounter {
46 StructInfo *Struct;
Qin Zhaocd5fe142016-06-15 17:27:29 +000047 u64 Count; // The total access count of the struct.
48 u64 Ratio; // Difference ratio for the struct layout access.
Qin Zhao4175a6d2016-06-02 18:45:25 +000049};
50
51// We use StructHashMap to keep track of an unique copy of StructCounter.
52typedef AddrHashMap<StructCounter, 31051> StructHashMap;
53struct Context {
54 StructHashMap StructMap;
55 u32 NumStructs;
56 u64 TotalCount; // The total access count of all structs.
57};
58static Context *Ctx;
59
Qin Zhaobc929e42016-06-03 20:48:17 +000060static void reportStructSummary() {
61 // FIXME: provide a better struct field access summary report.
Qin Zhaocd5fe142016-06-15 17:27:29 +000062 Report("%s: total struct field access count = %llu\n", SanitizerToolName,
63 Ctx->TotalCount);
Qin Zhaobc929e42016-06-03 20:48:17 +000064}
65
66// FIXME: we are still exploring proper ways to evaluate the difference between
67// struct field counts. Currently, we use a simple formula to calculate the
68// difference ratio: V1/V2.
69static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) {
Qin Zhaocd5fe142016-06-15 17:27:29 +000070 if (Val2 > Val1) {
71 Swap(Val1, Val2);
72 }
73 if (Val2 == 0)
74 Val2 = 1;
Qin Zhaobc929e42016-06-03 20:48:17 +000075 return (Val1 / Val2);
76}
77
78static void reportStructCounter(StructHashMap::Handle &Handle) {
Qin Zhaocd5fe142016-06-15 17:27:29 +000079 const u32 TypePrintLimit = 512;
Qin Zhaobc929e42016-06-03 20:48:17 +000080 const char *type, *start, *end;
81 StructInfo *Struct = Handle->Struct;
82 // Union field address calculation is done via bitcast instead of GEP,
83 // so the count for union is always 0.
84 // We skip the union report to avoid confusion.
85 if (strncmp(Struct->StructName, "union.", 6) == 0)
86 return;
87 // Remove the '.' after class/struct during print.
88 if (strncmp(Struct->StructName, "class.", 6) == 0) {
89 type = "class";
90 start = &Struct->StructName[6];
91 } else {
92 type = "struct";
93 start = &Struct->StructName[7];
94 }
95 // Remove the suffixes with '#' during print.
96 end = strchr(start, '#');
97 CHECK(end != nullptr);
98 Report(" %s %.*s\n", type, end - start, start);
Qin Zhaocd5fe142016-06-15 17:27:29 +000099 Report(" size = %u, count = %llu, ratio = %llu\n", Struct->Size,
100 Handle->Count, Handle->Ratio);
Qin Zhaobc929e42016-06-03 20:48:17 +0000101 for (u32 i = 0; i < Struct->NumFields; ++i) {
Qin Zhaoe24bc362016-06-17 04:50:11 +0000102 Report(" #%2u: offset = %u,\t size = %u,\t count = %llu,\t type = %.*s\n",
103 i, Struct->FieldOffsets[i], Struct->FieldSize[i],
104 Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeNames[i]);
Qin Zhaobc929e42016-06-03 20:48:17 +0000105 }
106}
107
108static void computeStructRatio(StructHashMap::Handle &Handle) {
109 Handle->Ratio = 0;
110 Handle->Count = Handle->Struct->FieldCounters[0];
111 for (u32 i = 1; i < Handle->Struct->NumFields; ++i) {
112 Handle->Count += Handle->Struct->FieldCounters[i];
113 Handle->Ratio += computeDifferenceRatio(
114 Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]);
115 }
116 Ctx->TotalCount += Handle->Count;
Qin Zhaocd5fe142016-06-15 17:27:29 +0000117 if (Handle->Ratio >= (u64)getFlags()->report_threshold ||
118 (Verbosity() >= 1 && Handle->Count > 0))
Qin Zhaobc929e42016-06-03 20:48:17 +0000119 reportStructCounter(Handle);
120}
121
Qin Zhao4175a6d2016-06-02 18:45:25 +0000122static void registerStructInfo(CacheFragInfo *CacheFrag) {
123 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
124 StructInfo *Struct = &CacheFrag->Structs[i];
125 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters);
126 if (H.created()) {
Qin Zhaobc929e42016-06-03 20:48:17 +0000127 VPrintf(2, " Register %s: %u fields\n", Struct->StructName,
128 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000129 H->Struct = Struct;
130 ++Ctx->NumStructs;
131 } else {
Qin Zhaobc929e42016-06-03 20:48:17 +0000132 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
133 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000134 }
135 }
136}
137
138static void unregisterStructInfo(CacheFragInfo *CacheFrag) {
139 // FIXME: if the library is unloaded before finalizeCacheFrag, we should
140 // collect the result for later report.
141 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
142 StructInfo *Struct = &CacheFrag->Structs[i];
143 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true);
144 if (H.exists()) {
Qin Zhaobc929e42016-06-03 20:48:17 +0000145 VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName,
146 Struct->NumFields);
147 // FIXME: we should move this call to finalizeCacheFrag once we can
148 // iterate over the hash map there.
149 computeStructRatio(H);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000150 --Ctx->NumStructs;
151 } else {
Qin Zhaobc929e42016-06-03 20:48:17 +0000152 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
153 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000154 }
155 }
Qin Zhaobc929e42016-06-03 20:48:17 +0000156 static bool Reported = false;
157 if (Ctx->NumStructs == 0 && !Reported) {
158 Reported = true;
159 reportStructSummary();
160 }
Qin Zhao4175a6d2016-06-02 18:45:25 +0000161}
162
Qin Zhao7e4933f2016-05-25 17:49:00 +0000163//===-- Init/exit functions -----------------------------------------------===//
164
165void processCacheFragCompilationUnitInit(void *Ptr) {
Qin Zhao9e396382016-05-31 21:27:39 +0000166 CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
Qin Zhaobc929e42016-06-03 20:48:17 +0000167 VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
168 CacheFrag->UnitName, CacheFrag->NumStructs);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000169 registerStructInfo(CacheFrag);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000170}
171
172void processCacheFragCompilationUnitExit(void *Ptr) {
Qin Zhao9e396382016-05-31 21:27:39 +0000173 CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
Qin Zhaobc929e42016-06-03 20:48:17 +0000174 VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
175 CacheFrag->UnitName, CacheFrag->NumStructs);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000176 unregisterStructInfo(CacheFrag);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000177}
178
179void initializeCacheFrag() {
180 VPrintf(2, "in esan::%s\n", __FUNCTION__);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000181 // We use placement new to initialize Ctx before C++ static initializaion.
182 // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap.
183 static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1];
Qin Zhaobc929e42016-06-03 20:48:17 +0000184 Ctx = new (CtxMem) Context();
Qin Zhao4175a6d2016-06-02 18:45:25 +0000185 Ctx->NumStructs = 0;
Qin Zhao7e4933f2016-05-25 17:49:00 +0000186}
187
188int finalizeCacheFrag() {
189 VPrintf(2, "in esan::%s\n", __FUNCTION__);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000190 return 0;
191}
192
193} // namespace __esan