blob: a68598f1f93ad627b4278e5d8280803f22f9fc67 [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 Zhao9e396382016-05-31 21:27:39 +000032 u64 *FieldCounters;
33 const char **FieldTypeNames;
34};
35
36// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo.
37// The tool-specific information per compilation unit (module).
38struct CacheFragInfo {
39 const char *UnitName;
Qin Zhao4175a6d2016-06-02 18:45:25 +000040 u32 NumStructs;
Qin Zhao9e396382016-05-31 21:27:39 +000041 StructInfo *Structs;
42};
43
Qin Zhao4175a6d2016-06-02 18:45:25 +000044struct StructCounter {
45 StructInfo *Struct;
Qin Zhaobc929e42016-06-03 20:48:17 +000046 u64 Count; // The total access count of the struct.
47 u64 Ratio; // Difference ratio for the struct layout access.
Qin Zhao4175a6d2016-06-02 18:45:25 +000048};
49
50// We use StructHashMap to keep track of an unique copy of StructCounter.
51typedef AddrHashMap<StructCounter, 31051> StructHashMap;
52struct Context {
53 StructHashMap StructMap;
54 u32 NumStructs;
55 u64 TotalCount; // The total access count of all structs.
56};
57static Context *Ctx;
58
Qin Zhaobc929e42016-06-03 20:48:17 +000059static void reportStructSummary() {
60 // FIXME: provide a better struct field access summary report.
61 Report("%s: total struct field access count = %llu\n",
62 SanitizerToolName, Ctx->TotalCount);
63}
64
65// FIXME: we are still exploring proper ways to evaluate the difference between
66// struct field counts. Currently, we use a simple formula to calculate the
67// difference ratio: V1/V2.
68static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) {
69 if (Val2 > Val1) { Swap(Val1, Val2); }
70 if (Val2 == 0) Val2 = 1;
71 return (Val1 / Val2);
72}
73
74static void reportStructCounter(StructHashMap::Handle &Handle) {
75 const char *type, *start, *end;
76 StructInfo *Struct = Handle->Struct;
77 // Union field address calculation is done via bitcast instead of GEP,
78 // so the count for union is always 0.
79 // We skip the union report to avoid confusion.
80 if (strncmp(Struct->StructName, "union.", 6) == 0)
81 return;
82 // Remove the '.' after class/struct during print.
83 if (strncmp(Struct->StructName, "class.", 6) == 0) {
84 type = "class";
85 start = &Struct->StructName[6];
86 } else {
87 type = "struct";
88 start = &Struct->StructName[7];
89 }
90 // Remove the suffixes with '#' during print.
91 end = strchr(start, '#');
92 CHECK(end != nullptr);
93 Report(" %s %.*s\n", type, end - start, start);
Qin Zhaoa4a72202016-06-10 02:10:34 +000094 Report(" size = %u, count = %llu, ratio = %llu\n",
95 Struct->Size, Handle->Count, Handle->Ratio);
Qin Zhaobc929e42016-06-03 20:48:17 +000096 for (u32 i = 0; i < Struct->NumFields; ++i) {
Qin Zhaoa4a72202016-06-10 02:10:34 +000097 Report(" #%2u: offset = %u,\t count = %llu,\t type = %s\n", i,
98 Struct->FieldOffsets[i], Struct->FieldCounters[i],
Qin Zhaobc929e42016-06-03 20:48:17 +000099 Struct->FieldTypeNames[i]);
100 }
101}
102
103static void computeStructRatio(StructHashMap::Handle &Handle) {
104 Handle->Ratio = 0;
105 Handle->Count = Handle->Struct->FieldCounters[0];
106 for (u32 i = 1; i < Handle->Struct->NumFields; ++i) {
107 Handle->Count += Handle->Struct->FieldCounters[i];
108 Handle->Ratio += computeDifferenceRatio(
109 Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]);
110 }
111 Ctx->TotalCount += Handle->Count;
112 if (Handle->Ratio >= (u64)getFlags()->report_threshold || Verbosity() >= 1)
113 reportStructCounter(Handle);
114}
115
Qin Zhao4175a6d2016-06-02 18:45:25 +0000116static void registerStructInfo(CacheFragInfo *CacheFrag) {
117 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
118 StructInfo *Struct = &CacheFrag->Structs[i];
119 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters);
120 if (H.created()) {
Qin Zhaobc929e42016-06-03 20:48:17 +0000121 VPrintf(2, " Register %s: %u fields\n", Struct->StructName,
122 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000123 H->Struct = Struct;
124 ++Ctx->NumStructs;
125 } else {
Qin Zhaobc929e42016-06-03 20:48:17 +0000126 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
127 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000128 }
129 }
130}
131
132static void unregisterStructInfo(CacheFragInfo *CacheFrag) {
133 // FIXME: if the library is unloaded before finalizeCacheFrag, we should
134 // collect the result for later report.
135 for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
136 StructInfo *Struct = &CacheFrag->Structs[i];
137 StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true);
138 if (H.exists()) {
Qin Zhaobc929e42016-06-03 20:48:17 +0000139 VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName,
140 Struct->NumFields);
141 // FIXME: we should move this call to finalizeCacheFrag once we can
142 // iterate over the hash map there.
143 computeStructRatio(H);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000144 --Ctx->NumStructs;
145 } else {
Qin Zhaobc929e42016-06-03 20:48:17 +0000146 VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
147 Struct->NumFields);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000148 }
149 }
Qin Zhaobc929e42016-06-03 20:48:17 +0000150 static bool Reported = false;
151 if (Ctx->NumStructs == 0 && !Reported) {
152 Reported = true;
153 reportStructSummary();
154 }
Qin Zhao4175a6d2016-06-02 18:45:25 +0000155}
156
Qin Zhao7e4933f2016-05-25 17:49:00 +0000157//===-- Init/exit functions -----------------------------------------------===//
158
159void processCacheFragCompilationUnitInit(void *Ptr) {
Qin Zhao9e396382016-05-31 21:27:39 +0000160 CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
Qin Zhaobc929e42016-06-03 20:48:17 +0000161 VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
162 CacheFrag->UnitName, CacheFrag->NumStructs);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000163 registerStructInfo(CacheFrag);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000164}
165
166void processCacheFragCompilationUnitExit(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 unregisterStructInfo(CacheFrag);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000171}
172
173void initializeCacheFrag() {
174 VPrintf(2, "in esan::%s\n", __FUNCTION__);
Qin Zhao4175a6d2016-06-02 18:45:25 +0000175 // We use placement new to initialize Ctx before C++ static initializaion.
176 // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap.
177 static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1];
Qin Zhaobc929e42016-06-03 20:48:17 +0000178 Ctx = new (CtxMem) Context();
Qin Zhao4175a6d2016-06-02 18:45:25 +0000179 Ctx->NumStructs = 0;
Qin Zhao7e4933f2016-05-25 17:49:00 +0000180}
181
182int finalizeCacheFrag() {
183 VPrintf(2, "in esan::%s\n", __FUNCTION__);
Qin Zhao7e4933f2016-05-25 17:49:00 +0000184 return 0;
185}
186
187} // namespace __esan