xref: /aosp_15_r20/external/compiler-rt/lib/esan/cache_frag.cpp (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- cache_frag.cpp ----------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of EfficiencySanitizer, a family of performance tuners.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // This file contains cache fragmentation-specific code.
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot 
15*7c3d14c8STreehugger Robot #include "esan.h"
16*7c3d14c8STreehugger Robot #include "esan_flags.h"
17*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_addrhashmap.h"
18*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
19*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_placement_new.h"
20*7c3d14c8STreehugger Robot #include <string.h>
21*7c3d14c8STreehugger Robot 
22*7c3d14c8STreehugger Robot namespace __esan {
23*7c3d14c8STreehugger Robot 
24*7c3d14c8STreehugger Robot //===-- Struct field access counter runtime -------------------------------===//
25*7c3d14c8STreehugger Robot 
26*7c3d14c8STreehugger Robot // This should be kept consistent with LLVM's EfficiencySanitizer StructInfo.
27*7c3d14c8STreehugger Robot struct StructInfo {
28*7c3d14c8STreehugger Robot   const char *StructName;
29*7c3d14c8STreehugger Robot   u32 Size;
30*7c3d14c8STreehugger Robot   u32 NumFields;
31*7c3d14c8STreehugger Robot   u32 *FieldOffset;           // auxiliary struct field info.
32*7c3d14c8STreehugger Robot   u32 *FieldSize;             // auxiliary struct field info.
33*7c3d14c8STreehugger Robot   const char **FieldTypeName; // auxiliary struct field info.
34*7c3d14c8STreehugger Robot   u64 *FieldCounters;
35*7c3d14c8STreehugger Robot   u64 *ArrayCounter;
hasAuxFieldInfo__esan::StructInfo36*7c3d14c8STreehugger Robot   bool hasAuxFieldInfo() { return FieldOffset != nullptr; }
37*7c3d14c8STreehugger Robot };
38*7c3d14c8STreehugger Robot 
39*7c3d14c8STreehugger Robot // This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo.
40*7c3d14c8STreehugger Robot // The tool-specific information per compilation unit (module).
41*7c3d14c8STreehugger Robot struct CacheFragInfo {
42*7c3d14c8STreehugger Robot   const char *UnitName;
43*7c3d14c8STreehugger Robot   u32 NumStructs;
44*7c3d14c8STreehugger Robot   StructInfo *Structs;
45*7c3d14c8STreehugger Robot };
46*7c3d14c8STreehugger Robot 
47*7c3d14c8STreehugger Robot struct StructCounter {
48*7c3d14c8STreehugger Robot   StructInfo *Struct;
49*7c3d14c8STreehugger Robot   u64 Count; // The total access count of the struct.
50*7c3d14c8STreehugger Robot   u64 Ratio; // Difference ratio for the struct layout access.
51*7c3d14c8STreehugger Robot };
52*7c3d14c8STreehugger Robot 
53*7c3d14c8STreehugger Robot // We use StructHashMap to keep track of an unique copy of StructCounter.
54*7c3d14c8STreehugger Robot typedef AddrHashMap<StructCounter, 31051> StructHashMap;
55*7c3d14c8STreehugger Robot struct Context {
56*7c3d14c8STreehugger Robot   StructHashMap StructMap;
57*7c3d14c8STreehugger Robot   u32 NumStructs;
58*7c3d14c8STreehugger Robot   u64 TotalCount; // The total access count of all structs.
59*7c3d14c8STreehugger Robot };
60*7c3d14c8STreehugger Robot static Context *Ctx;
61*7c3d14c8STreehugger Robot 
reportStructSummary()62*7c3d14c8STreehugger Robot static void reportStructSummary() {
63*7c3d14c8STreehugger Robot   // FIXME: provide a better struct field access summary report.
64*7c3d14c8STreehugger Robot   Report("%s: total struct field access count = %llu\n", SanitizerToolName,
65*7c3d14c8STreehugger Robot          Ctx->TotalCount);
66*7c3d14c8STreehugger Robot }
67*7c3d14c8STreehugger Robot 
68*7c3d14c8STreehugger Robot // FIXME: we are still exploring proper ways to evaluate the difference between
69*7c3d14c8STreehugger Robot // struct field counts.  Currently, we use a simple formula to calculate the
70*7c3d14c8STreehugger Robot // difference ratio: V1/V2.
computeDifferenceRatio(u64 Val1,u64 Val2)71*7c3d14c8STreehugger Robot static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) {
72*7c3d14c8STreehugger Robot   if (Val2 > Val1) {
73*7c3d14c8STreehugger Robot     Swap(Val1, Val2);
74*7c3d14c8STreehugger Robot   }
75*7c3d14c8STreehugger Robot   if (Val2 == 0)
76*7c3d14c8STreehugger Robot     Val2 = 1;
77*7c3d14c8STreehugger Robot   return (Val1 / Val2);
78*7c3d14c8STreehugger Robot }
79*7c3d14c8STreehugger Robot 
reportStructCounter(StructHashMap::Handle & Handle)80*7c3d14c8STreehugger Robot static void reportStructCounter(StructHashMap::Handle &Handle) {
81*7c3d14c8STreehugger Robot   const u32 TypePrintLimit = 512;
82*7c3d14c8STreehugger Robot   const char *type, *start, *end;
83*7c3d14c8STreehugger Robot   StructInfo *Struct = Handle->Struct;
84*7c3d14c8STreehugger Robot   // Union field address calculation is done via bitcast instead of GEP,
85*7c3d14c8STreehugger Robot   // so the count for union is always 0.
86*7c3d14c8STreehugger Robot   // We skip the union report to avoid confusion.
87*7c3d14c8STreehugger Robot   if (strncmp(Struct->StructName, "union.", 6) == 0)
88*7c3d14c8STreehugger Robot     return;
89*7c3d14c8STreehugger Robot   // Remove the '.' after class/struct during print.
90*7c3d14c8STreehugger Robot   if (strncmp(Struct->StructName, "class.", 6) == 0) {
91*7c3d14c8STreehugger Robot     type = "class";
92*7c3d14c8STreehugger Robot     start = &Struct->StructName[6];
93*7c3d14c8STreehugger Robot   } else {
94*7c3d14c8STreehugger Robot     type = "struct";
95*7c3d14c8STreehugger Robot     start = &Struct->StructName[7];
96*7c3d14c8STreehugger Robot   }
97*7c3d14c8STreehugger Robot   // Remove the suffixes with '#' during print.
98*7c3d14c8STreehugger Robot   end = strchr(start, '#');
99*7c3d14c8STreehugger Robot   CHECK(end != nullptr);
100*7c3d14c8STreehugger Robot   Report("  %s %.*s\n", type, end - start, start);
101*7c3d14c8STreehugger Robot   Report("   size = %u, count = %llu, ratio = %llu, array access = %llu\n",
102*7c3d14c8STreehugger Robot          Struct->Size, Handle->Count, Handle->Ratio, *Struct->ArrayCounter);
103*7c3d14c8STreehugger Robot   if (Struct->hasAuxFieldInfo()) {
104*7c3d14c8STreehugger Robot     for (u32 i = 0; i < Struct->NumFields; ++i) {
105*7c3d14c8STreehugger Robot       Report("   #%2u: offset = %u,\t size = %u,"
106*7c3d14c8STreehugger Robot              "\t count = %llu,\t type = %.*s\n",
107*7c3d14c8STreehugger Robot              i, Struct->FieldOffset[i], Struct->FieldSize[i],
108*7c3d14c8STreehugger Robot              Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeName[i]);
109*7c3d14c8STreehugger Robot     }
110*7c3d14c8STreehugger Robot   } else {
111*7c3d14c8STreehugger Robot     for (u32 i = 0; i < Struct->NumFields; ++i) {
112*7c3d14c8STreehugger Robot       Report("   #%2u: count = %llu\n", i, Struct->FieldCounters[i]);
113*7c3d14c8STreehugger Robot     }
114*7c3d14c8STreehugger Robot   }
115*7c3d14c8STreehugger Robot }
116*7c3d14c8STreehugger Robot 
computeStructRatio(StructHashMap::Handle & Handle)117*7c3d14c8STreehugger Robot static void computeStructRatio(StructHashMap::Handle &Handle) {
118*7c3d14c8STreehugger Robot   Handle->Ratio = 0;
119*7c3d14c8STreehugger Robot   Handle->Count = Handle->Struct->FieldCounters[0];
120*7c3d14c8STreehugger Robot   for (u32 i = 1; i < Handle->Struct->NumFields; ++i) {
121*7c3d14c8STreehugger Robot     Handle->Count += Handle->Struct->FieldCounters[i];
122*7c3d14c8STreehugger Robot     Handle->Ratio += computeDifferenceRatio(
123*7c3d14c8STreehugger Robot         Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]);
124*7c3d14c8STreehugger Robot   }
125*7c3d14c8STreehugger Robot   Ctx->TotalCount += Handle->Count;
126*7c3d14c8STreehugger Robot   if (Handle->Ratio >= (u64)getFlags()->report_threshold ||
127*7c3d14c8STreehugger Robot       (Verbosity() >= 1 && Handle->Count > 0))
128*7c3d14c8STreehugger Robot     reportStructCounter(Handle);
129*7c3d14c8STreehugger Robot }
130*7c3d14c8STreehugger Robot 
registerStructInfo(CacheFragInfo * CacheFrag)131*7c3d14c8STreehugger Robot static void registerStructInfo(CacheFragInfo *CacheFrag) {
132*7c3d14c8STreehugger Robot   for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
133*7c3d14c8STreehugger Robot     StructInfo *Struct = &CacheFrag->Structs[i];
134*7c3d14c8STreehugger Robot     StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters);
135*7c3d14c8STreehugger Robot     if (H.created()) {
136*7c3d14c8STreehugger Robot       VPrintf(2, " Register %s: %u fields\n", Struct->StructName,
137*7c3d14c8STreehugger Robot               Struct->NumFields);
138*7c3d14c8STreehugger Robot       H->Struct = Struct;
139*7c3d14c8STreehugger Robot       ++Ctx->NumStructs;
140*7c3d14c8STreehugger Robot     } else {
141*7c3d14c8STreehugger Robot       VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
142*7c3d14c8STreehugger Robot               Struct->NumFields);
143*7c3d14c8STreehugger Robot     }
144*7c3d14c8STreehugger Robot   }
145*7c3d14c8STreehugger Robot }
146*7c3d14c8STreehugger Robot 
unregisterStructInfo(CacheFragInfo * CacheFrag)147*7c3d14c8STreehugger Robot static void unregisterStructInfo(CacheFragInfo *CacheFrag) {
148*7c3d14c8STreehugger Robot   // FIXME: if the library is unloaded before finalizeCacheFrag, we should
149*7c3d14c8STreehugger Robot   // collect the result for later report.
150*7c3d14c8STreehugger Robot   for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
151*7c3d14c8STreehugger Robot     StructInfo *Struct = &CacheFrag->Structs[i];
152*7c3d14c8STreehugger Robot     StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true);
153*7c3d14c8STreehugger Robot     if (H.exists()) {
154*7c3d14c8STreehugger Robot       VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName,
155*7c3d14c8STreehugger Robot               Struct->NumFields);
156*7c3d14c8STreehugger Robot       // FIXME: we should move this call to finalizeCacheFrag once we can
157*7c3d14c8STreehugger Robot       // iterate over the hash map there.
158*7c3d14c8STreehugger Robot       computeStructRatio(H);
159*7c3d14c8STreehugger Robot       --Ctx->NumStructs;
160*7c3d14c8STreehugger Robot     } else {
161*7c3d14c8STreehugger Robot       VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
162*7c3d14c8STreehugger Robot               Struct->NumFields);
163*7c3d14c8STreehugger Robot     }
164*7c3d14c8STreehugger Robot   }
165*7c3d14c8STreehugger Robot   static bool Reported = false;
166*7c3d14c8STreehugger Robot   if (Ctx->NumStructs == 0 && !Reported) {
167*7c3d14c8STreehugger Robot     Reported = true;
168*7c3d14c8STreehugger Robot     reportStructSummary();
169*7c3d14c8STreehugger Robot   }
170*7c3d14c8STreehugger Robot }
171*7c3d14c8STreehugger Robot 
172*7c3d14c8STreehugger Robot //===-- Init/exit functions -----------------------------------------------===//
173*7c3d14c8STreehugger Robot 
processCacheFragCompilationUnitInit(void * Ptr)174*7c3d14c8STreehugger Robot void processCacheFragCompilationUnitInit(void *Ptr) {
175*7c3d14c8STreehugger Robot   CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
176*7c3d14c8STreehugger Robot   VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
177*7c3d14c8STreehugger Robot           CacheFrag->UnitName, CacheFrag->NumStructs);
178*7c3d14c8STreehugger Robot   registerStructInfo(CacheFrag);
179*7c3d14c8STreehugger Robot }
180*7c3d14c8STreehugger Robot 
processCacheFragCompilationUnitExit(void * Ptr)181*7c3d14c8STreehugger Robot void processCacheFragCompilationUnitExit(void *Ptr) {
182*7c3d14c8STreehugger Robot   CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
183*7c3d14c8STreehugger Robot   VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
184*7c3d14c8STreehugger Robot           CacheFrag->UnitName, CacheFrag->NumStructs);
185*7c3d14c8STreehugger Robot   unregisterStructInfo(CacheFrag);
186*7c3d14c8STreehugger Robot }
187*7c3d14c8STreehugger Robot 
initializeCacheFrag()188*7c3d14c8STreehugger Robot void initializeCacheFrag() {
189*7c3d14c8STreehugger Robot   VPrintf(2, "in esan::%s\n", __FUNCTION__);
190*7c3d14c8STreehugger Robot   // We use placement new to initialize Ctx before C++ static initializaion.
191*7c3d14c8STreehugger Robot   // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap.
192*7c3d14c8STreehugger Robot   static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1];
193*7c3d14c8STreehugger Robot   Ctx = new (CtxMem) Context();
194*7c3d14c8STreehugger Robot   Ctx->NumStructs = 0;
195*7c3d14c8STreehugger Robot }
196*7c3d14c8STreehugger Robot 
finalizeCacheFrag()197*7c3d14c8STreehugger Robot int finalizeCacheFrag() {
198*7c3d14c8STreehugger Robot   VPrintf(2, "in esan::%s\n", __FUNCTION__);
199*7c3d14c8STreehugger Robot   return 0;
200*7c3d14c8STreehugger Robot }
201*7c3d14c8STreehugger Robot 
reportCacheFrag()202*7c3d14c8STreehugger Robot void reportCacheFrag() {
203*7c3d14c8STreehugger Robot   VPrintf(2, "in esan::%s\n", __FUNCTION__);
204*7c3d14c8STreehugger Robot   // FIXME: Not yet implemented.  We need to iterate over all of the
205*7c3d14c8STreehugger Robot   // compilation unit data.
206*7c3d14c8STreehugger Robot }
207*7c3d14c8STreehugger Robot 
208*7c3d14c8STreehugger Robot } // namespace __esan
209