blob: e3384a982ebde0031da8ad745ce2a6764b1d30a7 [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 const char **FieldTypeNames;
Qin Zhao91ea3fb2016-07-02 03:25:55 +000034 u64 *FieldCounters;
35 u64 *ArrayCounter;
Qin Zhao9e396382016-05-31 21:27:39 +000036};
37
38// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo.
39// The tool-specific information per compilation unit (module).
40struct CacheFragInfo {
41 const char *UnitName;
Qin Zhao4175a6d2016-06-02 18:45:25 +000042 u32 NumStructs;
Qin Zhao9e396382016-05-31 21:27:39 +000043 StructInfo *Structs;
44};
45
Qin Zhao4175a6d2016-06-02 18:45:25 +000046struct StructCounter {
47 StructInfo *Struct;
Qin Zhaocd5fe142016-06-15 17:27:29 +000048 u64 Count; // The total access count of the struct.
49 u64 Ratio; // Difference ratio for the struct layout access.
Qin Zhao4175a6d2016-06-02 18:45:25 +000050};
51
52// We use StructHashMap to keep track of an unique copy of StructCounter.
53typedef AddrHashMap<StructCounter, 31051> StructHashMap;
54struct Context {
55 StructHashMap StructMap;
56 u32 NumStructs;
57 u64 TotalCount; // The total access count of all structs.
58};
59static Context *Ctx;
60
Qin Zhaobc929e42016-06-03 20:48:17 +000061static void reportStructSummary() {
62 // FIXME: provide a better struct field access summary report.
Qin Zhaocd5fe142016-06-15 17:27:29 +000063 Report("%s: total struct field access count = %llu\n", SanitizerToolName,
64 Ctx->TotalCount);
Qin Zhaobc929e42016-06-03 20:48:17 +000065}
66
67// FIXME: we are still exploring proper ways to evaluate the difference between
68// struct field counts. Currently, we use a simple formula to calculate the
69// difference ratio: V1/V2.
70static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) {
Qin Zhaocd5fe142016-06-15 17:27:29 +000071 if (Val2 > Val1) {
72 Swap(Val1, Val2);
73 }
74 if (Val2 == 0)
75 Val2 = 1;
Qin Zhaobc929e42016-06-03 20:48:17 +000076 return (Val1 / Val2);
77}
78
79static void reportStructCounter(StructHashMap::Handle &Handle) {
Qin Zhaocd5fe142016-06-15 17:27:29 +000080 const u32 TypePrintLimit = 512;
Qin Zhaobc929e42016-06-03 20:48:17 +000081 const char *type, *start, *end;
82 StructInfo *Struct = Handle->Struct;
83 // Union field address calculation is done via bitcast instead of GEP,
84 // so the count for union is always 0.
85 // We skip the union report to avoid confusion.
86 if (strncmp(Struct->StructName, "union.", 6) == 0)
87 return;
88 // Remove the '.' after class/struct during print.
89 if (strncmp(Struct->StructName, "class.", 6) == 0) {
90 type = "class";
91 start = &Struct->StructName[6];
92 } else {
93 type = "struct";
94 start = &Struct->StructName[7];
95 }
96 // Remove the suffixes with '#' during print.
97 end = strchr(start, '#');
98 CHECK(end != nullptr);
99 Report(" %s %.*s\n", type, end - start, start);
Qin Zhao91ea3fb2016-07-02 03:25:55 +0000100 Report(" size = %u, count = %llu, ratio = %llu, array access = %llu\n",
101 Struct->Size, Handle->Count, Handle->Ratio, *Struct->ArrayCounter);
Qin Zhaobc929e42016-06-03 20:48:17 +0000102 for (u32 i = 0; i < Struct->NumFields; ++i) {
Qin Zhaoe24bc362016-06-17 04:50:11 +0000103 Report(" #%2u: offset = %u,\t size = %u,\t count = %llu,\t type = %.*s\n",
104 i, Struct->FieldOffsets[i], Struct->FieldSize[i],
105 Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeNames[i]);
Qin Zhaobc929e42016-06-03 20:48:17 +0000106 }
107}
108
109static void computeStructRatio(StructHashMap::Handle &Handle) {
110 Handle->Ratio = 0;
111 Handle->Count = Handle->Struct->FieldCounters[0];
112 for (u32 i = 1; i < Handle->Struct->NumFields; ++i) {
113 Handle->Count += Handle->Struct->FieldCounters[i];
114 Handle->Ratio += computeDifferenceRatio(
115 Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]);
116 }
117 Ctx->TotalCount += Handle->Count;
Qin Zhaocd5fe142016-06-15 17:27:29 +0000118 if (Handle->Ratio >= (u64)getFlags()->report_threshold ||
119 (Verbosity() >= 1 && Handle->Count > 0))
Qin Zhaobc929e42016-06-03 20:48:17 +0000120 reportStructCounter(Handle);
121}
122
Qin Zhao4175a6d2016-06-02 18:45:25 +0000123static void registerStructInfo(CacheFragInfo *CacheFrag) {
124 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
125 StructInfo *Struct = &CacheFrag->Structs[i];
126 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters);
127 if (H.created()) {
Qin Zhaobc929e42016-06-03 20:48:17 +0000128 VPrintf(2, " Register %s: %u fields\n", Struct->StructName,
129 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000130 H->Struct = Struct;
131 ++Ctx->NumStructs;
132 } else {
Qin Zhaobc929e42016-06-03 20:48:17 +0000133 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
134 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000135 }
136 }
137}
138
139static void unregisterStructInfo(CacheFragInfo *CacheFrag) {
140 // FIXME: if the library is unloaded before finalizeCacheFrag, we should
141 // collect the result for later report.
142 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
143 StructInfo *Struct = &CacheFrag->Structs[i];
144 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true);
145 if (H.exists()) {
Qin Zhaobc929e42016-06-03 20:48:17 +0000146 VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName,
147 Struct->NumFields);
148 // FIXME: we should move this call to finalizeCacheFrag once we can
149 // iterate over the hash map there.
150 computeStructRatio(H);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000151 --Ctx->NumStructs;
152 } else {
Qin Zhaobc929e42016-06-03 20:48:17 +0000153 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
154 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000155 }
156 }
Qin Zhaobc929e42016-06-03 20:48:17 +0000157 static bool Reported = false;
158 if (Ctx->NumStructs == 0 && !Reported) {
159 Reported = true;
160 reportStructSummary();
161 }
Qin Zhao4175a6d2016-06-02 18:45:25 +0000162}
163
Qin Zhao7e4933f2016-05-25 17:49:00 +0000164//===-- Init/exit functions -----------------------------------------------===//
165
166void processCacheFragCompilationUnitInit(void *Ptr) {
Qin Zhao9e396382016-05-31 21:27:39 +0000167 CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
Qin Zhaobc929e42016-06-03 20:48:17 +0000168 VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
169 CacheFrag->UnitName, CacheFrag->NumStructs);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000170 registerStructInfo(CacheFrag);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000171}
172
173void processCacheFragCompilationUnitExit(void *Ptr) {
Qin Zhao9e396382016-05-31 21:27:39 +0000174 CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
Qin Zhaobc929e42016-06-03 20:48:17 +0000175 VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
176 CacheFrag->UnitName, CacheFrag->NumStructs);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000177 unregisterStructInfo(CacheFrag);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000178}
179
180void initializeCacheFrag() {
181 VPrintf(2, "in esan::%s\n", __FUNCTION__);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000182 // We use placement new to initialize Ctx before C++ static initializaion.
183 // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap.
184 static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1];
Qin Zhaobc929e42016-06-03 20:48:17 +0000185 Ctx = new (CtxMem) Context();
Qin Zhao4175a6d2016-06-02 18:45:25 +0000186 Ctx->NumStructs = 0;
Qin Zhao7e4933f2016-05-25 17:49:00 +0000187}
188
189int finalizeCacheFrag() {
190 VPrintf(2, "in esan::%s\n", __FUNCTION__);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000191 return 0;
192}
193
194} // namespace __esan