//===-- cache_frag.cpp ----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // This file contains cache fragmentation-specific code. //===----------------------------------------------------------------------===// #include "esan.h" #include "sanitizer_common/sanitizer_addrhashmap.h" #include "sanitizer_common/sanitizer_placement_new.h" namespace __esan { //===-- Struct field access counter runtime -------------------------------===// // This should be kept consistent with LLVM's EfficiencySanitizer StructInfo. struct StructInfo { const char *StructName; u32 NumFields; u64 *FieldCounters; const char **FieldTypeNames; }; // This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo. // The tool-specific information per compilation unit (module). struct CacheFragInfo { const char *UnitName; u32 NumStructs; StructInfo *Structs; }; struct StructCounter { StructInfo *Struct; u64 Count; // The total access count of the struct. u32 Variance; // Variance score for the struct layout access. }; // We use StructHashMap to keep track of an unique copy of StructCounter. typedef AddrHashMap StructHashMap; struct Context { StructHashMap StructMap; u32 NumStructs; u64 TotalCount; // The total access count of all structs. }; static Context *Ctx; static void registerStructInfo(CacheFragInfo *CacheFrag) { for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { StructInfo *Struct = &CacheFrag->Structs[i]; StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters); if (H.created()) { VPrintf(2, " Register %s: %u fields\n", Struct->StructName, Struct->NumFields); H->Struct = Struct; ++Ctx->NumStructs; } else { VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, Struct->NumFields); } } } static void unregisterStructInfo(CacheFragInfo *CacheFrag) { // FIXME: if the library is unloaded before finalizeCacheFrag, we should // collect the result for later report. for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { StructInfo *Struct = &CacheFrag->Structs[i]; StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true); if (H.exists()) { VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName, Struct->NumFields); --Ctx->NumStructs; } else { VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, Struct->NumFields); } } } static void reportStructSummary() { // FIXME: iterate StructHashMap and generate the final report. Report("%s is not finished: nothing yet to report\n", SanitizerToolName); } //===-- Init/exit functions -----------------------------------------------===// void processCacheFragCompilationUnitInit(void *Ptr) { CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumStructs); registerStructInfo(CacheFrag); } void processCacheFragCompilationUnitExit(void *Ptr) { CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumStructs); unregisterStructInfo(CacheFrag); } void initializeCacheFrag() { VPrintf(2, "in esan::%s\n", __FUNCTION__); // We use placement new to initialize Ctx before C++ static initializaion. // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap. static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1]; Ctx = new(CtxMem) Context(); Ctx->NumStructs = 0; } int finalizeCacheFrag() { VPrintf(2, "in esan::%s\n", __FUNCTION__); reportStructSummary(); return 0; } } // namespace __esan