162aa74f8SRafael Auler //===-- instr.cpp -----------------------------------------------*- C++ -*-===// 262aa74f8SRafael Auler // 362aa74f8SRafael Auler // The LLVM Compiler Infrastructure 462aa74f8SRafael Auler // 562aa74f8SRafael Auler // This file is distributed under the University of Illinois Open Source 662aa74f8SRafael Auler // License. See LICENSE.TXT for details. 762aa74f8SRafael Auler // This file contains code that is linked to the final binary with a function 862aa74f8SRafael Auler // that is called at program exit to dump instrumented data collected during 962aa74f8SRafael Auler // execution. 1062aa74f8SRafael Auler // 1162aa74f8SRafael Auler //===----------------------------------------------------------------------===// 1262aa74f8SRafael Auler // 13821480d2SRafael Auler // BOLT runtime instrumentation library for x86 Linux. 1462aa74f8SRafael Auler // 1562aa74f8SRafael Auler //===----------------------------------------------------------------------===// 1662aa74f8SRafael Auler 1762aa74f8SRafael Auler #include <cstdint> 18821480d2SRafael Auler #include <elf.h> 1962aa74f8SRafael Auler 20*cc4b2fb6SRafael Auler //#define ENABLE_DEBUG 21*cc4b2fb6SRafael Auler 22*cc4b2fb6SRafael Auler #ifdef ENABLE_DEBUG 23*cc4b2fb6SRafael Auler #define DEBUG(X) \ 24*cc4b2fb6SRafael Auler { X; } 25*cc4b2fb6SRafael Auler #else 26*cc4b2fb6SRafael Auler #define DEBUG(X) \ 27*cc4b2fb6SRafael Auler {} 28*cc4b2fb6SRafael Auler #endif 29*cc4b2fb6SRafael Auler 30*cc4b2fb6SRafael Auler // All extern declarations here need to be defined by BOLT itself 3162aa74f8SRafael Auler 3262aa74f8SRafael Auler // Counters inserted by instrumentation, incremented during runtime when 3362aa74f8SRafael Auler // points of interest (locations) in the program are reached. 3462aa74f8SRafael Auler extern uint64_t __bolt_instr_locations[]; 35*cc4b2fb6SRafael Auler // Number of call descriptions 36*cc4b2fb6SRafael Auler extern uint32_t __bolt_instr_num_calls; 37*cc4b2fb6SRafael Auler // Number of function descriptions 38*cc4b2fb6SRafael Auler extern uint32_t __bolt_instr_num_funcs; 39*cc4b2fb6SRafael Auler // Filename to dump data to 4062aa74f8SRafael Auler extern char __bolt_instr_filename[]; 4162aa74f8SRafael Auler 42*cc4b2fb6SRafael Auler // Anonymous namespace covering everything but our library entry point 43*cc4b2fb6SRafael Auler namespace { 44*cc4b2fb6SRafael Auler 45*cc4b2fb6SRafael Auler // We use a stack-allocated buffer for string manipulation in some 46*cc4b2fb6SRafael Auler // places with this size. 47*cc4b2fb6SRafael Auler constexpr uint32_t BufSize = 10240; 48*cc4b2fb6SRafael Auler 4962aa74f8SRafael Auler // A location is a function name plus offset. Function name needs to be 5062aa74f8SRafael Auler // retrieved from the string table and is stored as an index to this table. 51821480d2SRafael Auler struct Location { 5262aa74f8SRafael Auler uint32_t FunctionName; 5362aa74f8SRafael Auler uint32_t Offset; 54821480d2SRafael Auler }; 5562aa74f8SRafael Auler 56*cc4b2fb6SRafael Auler struct CallDescription { 57*cc4b2fb6SRafael Auler Location From; 58*cc4b2fb6SRafael Auler Location To; 59*cc4b2fb6SRafael Auler uint32_t Counter; 60*cc4b2fb6SRafael Auler }; 61*cc4b2fb6SRafael Auler 6262aa74f8SRafael Auler // An edge description defines an instrumented edge in the program, fully 6362aa74f8SRafael Auler // identified by where the jump is located and its destination. 64821480d2SRafael Auler struct EdgeDescription { 6562aa74f8SRafael Auler Location From; 66*cc4b2fb6SRafael Auler uint32_t FromNode; 6762aa74f8SRafael Auler Location To; 68*cc4b2fb6SRafael Auler uint32_t ToNode; 69*cc4b2fb6SRafael Auler uint32_t Counter; 70*cc4b2fb6SRafael Auler }; 71*cc4b2fb6SRafael Auler 72*cc4b2fb6SRafael Auler // This description is used for instrumented basic blocks. We only instrument 73*cc4b2fb6SRafael Auler // blocks that are leaves of the spanning tree associated with the CFG. We use 74*cc4b2fb6SRafael Auler // their execution count as a starting point to determine the frequency of the 75*cc4b2fb6SRafael Auler // incoming edge in the spanning tree (the one that is not explictly 76*cc4b2fb6SRafael Auler // instrumented). All other edges (not in the spanning tree) have an associated 77*cc4b2fb6SRafael Auler // counter themselves. We never write a node's counter to the profile, it is 78*cc4b2fb6SRafael Auler // only used for inference of other edges. 79*cc4b2fb6SRafael Auler struct InstrumentedNode { 80*cc4b2fb6SRafael Auler uint32_t Node; 81*cc4b2fb6SRafael Auler uint32_t Counter; 82*cc4b2fb6SRafael Auler }; 83*cc4b2fb6SRafael Auler 84*cc4b2fb6SRafael Auler // General metadata describing a function - number of CFG nodes, leaf nodes and 85*cc4b2fb6SRafael Auler // edges. 86*cc4b2fb6SRafael Auler struct FunctionDescription { 87*cc4b2fb6SRafael Auler uint32_t NumNodes; 88*cc4b2fb6SRafael Auler InstrumentedNode *LeafNodes; 89*cc4b2fb6SRafael Auler uint32_t NumEdges; 90*cc4b2fb6SRafael Auler EdgeDescription *Edges; 91821480d2SRafael Auler }; 9262aa74f8SRafael Auler 93821480d2SRafael Auler // These need to be read from disk. They are generated by BOLT and written to 94821480d2SRafael Auler // an ELF note section in the binary itself. 95821480d2SRafael Auler struct InstrumentationInfo { 96*cc4b2fb6SRafael Auler CallDescription *CallDescriptions; 97*cc4b2fb6SRafael Auler uint8_t *FuncDescriptions; 98821480d2SRafael Auler char *Strings; // String table with function names used in this binary 99821480d2SRafael Auler int FileDesc; // File descriptor for the file on disk backing this 100821480d2SRafael Auler // information in memory via mmap 101*cc4b2fb6SRafael Auler void *MMapPtr; // The mmap ptr 102821480d2SRafael Auler int MMapSize; // The mmap size 103821480d2SRafael Auler }; 10462aa74f8SRafael Auler 10562aa74f8SRafael Auler // Declare some syscall wrappers we use throughout this code to avoid linking 10662aa74f8SRafael Auler // against system libc. 107*cc4b2fb6SRafael Auler uint64_t __open(const char *pathname, uint64_t flags, uint64_t mode) { 10862aa74f8SRafael Auler uint64_t ret; 10962aa74f8SRafael Auler __asm__ __volatile__ ( 11062aa74f8SRafael Auler "movq $2, %%rax\n" 11162aa74f8SRafael Auler "syscall" 11262aa74f8SRafael Auler : "=a"(ret) 11362aa74f8SRafael Auler : "D"(pathname), "S"(flags), "d"(mode) 11462aa74f8SRafael Auler : "cc", "rcx", "r11", "memory"); 11562aa74f8SRafael Auler return ret; 11662aa74f8SRafael Auler } 11762aa74f8SRafael Auler 118*cc4b2fb6SRafael Auler uint64_t __write(uint64_t fd, const void *buf, uint64_t count) { 11962aa74f8SRafael Auler uint64_t ret; 12062aa74f8SRafael Auler __asm__ __volatile__ ( 12162aa74f8SRafael Auler "movq $1, %%rax\n" 12262aa74f8SRafael Auler "syscall\n" 12362aa74f8SRafael Auler : "=a"(ret) 12462aa74f8SRafael Auler : "D"(fd), "S"(buf), "d"(count) 12562aa74f8SRafael Auler : "cc", "rcx", "r11", "memory"); 12662aa74f8SRafael Auler return ret; 12762aa74f8SRafael Auler } 12862aa74f8SRafael Auler 129*cc4b2fb6SRafael Auler uint64_t __lseek(uint64_t fd, uint64_t pos, uint64_t whence) { 130821480d2SRafael Auler uint64_t ret; 131821480d2SRafael Auler __asm__ __volatile__ ( 132821480d2SRafael Auler "movq $8, %%rax\n" 133821480d2SRafael Auler "syscall\n" 134821480d2SRafael Auler : "=a"(ret) 135821480d2SRafael Auler : "D"(fd), "S"(pos), "d"(whence) 136821480d2SRafael Auler : "cc", "rcx", "r11", "memory"); 137821480d2SRafael Auler return ret; 138821480d2SRafael Auler } 139821480d2SRafael Auler 140*cc4b2fb6SRafael Auler int __close(uint64_t fd) { 14162aa74f8SRafael Auler uint64_t ret; 14262aa74f8SRafael Auler __asm__ __volatile__ ( 14362aa74f8SRafael Auler "movq $3, %%rax\n" 14462aa74f8SRafael Auler "syscall\n" 14562aa74f8SRafael Auler : "=a"(ret) 14662aa74f8SRafael Auler : "D"(fd) 14762aa74f8SRafael Auler : "cc", "rcx", "r11", "memory"); 14862aa74f8SRafael Auler return ret; 14962aa74f8SRafael Auler } 15062aa74f8SRafael Auler 151*cc4b2fb6SRafael Auler void *__mmap(uint64_t addr, uint64_t size, uint64_t prot, uint64_t flags, 152*cc4b2fb6SRafael Auler uint64_t fd, uint64_t offset) { 153821480d2SRafael Auler void *ret; 154821480d2SRafael Auler register uint64_t r8 asm("r8") = fd; 155821480d2SRafael Auler register uint64_t r9 asm("r9") = offset; 156821480d2SRafael Auler register uint64_t r10 asm("r10") = flags; 157821480d2SRafael Auler __asm__ __volatile__ ( 158821480d2SRafael Auler "movq $9, %%rax\n" 159821480d2SRafael Auler "syscall\n" 160821480d2SRafael Auler : "=a"(ret) 161821480d2SRafael Auler : "D"(addr), "S"(size), "d"(prot), "r"(r10), "r"(r8), "r"(r9) 162821480d2SRafael Auler : "cc", "rcx", "r11", "memory"); 163821480d2SRafael Auler return ret; 164821480d2SRafael Auler } 165821480d2SRafael Auler 166*cc4b2fb6SRafael Auler uint64_t __munmap(void *addr, uint64_t size) { 167821480d2SRafael Auler uint64_t ret; 168821480d2SRafael Auler __asm__ __volatile__ ( 169821480d2SRafael Auler "movq $11, %%rax\n" 170821480d2SRafael Auler "syscall\n" 171821480d2SRafael Auler : "=a"(ret) 172821480d2SRafael Auler : "D"(addr), "S"(size) 173821480d2SRafael Auler : "cc", "rcx", "r11", "memory"); 174821480d2SRafael Auler return ret; 175821480d2SRafael Auler } 176821480d2SRafael Auler 177*cc4b2fb6SRafael Auler uint64_t __exit(uint64_t code) { 178821480d2SRafael Auler uint64_t ret; 179821480d2SRafael Auler __asm__ __volatile__ ( 180821480d2SRafael Auler "movq $231, %%rax\n" 181821480d2SRafael Auler "syscall\n" 182821480d2SRafael Auler : "=a"(ret) 183821480d2SRafael Auler : "D"(code) 184821480d2SRafael Auler : "cc", "rcx", "r11", "memory"); 185821480d2SRafael Auler return ret; 186821480d2SRafael Auler } 187821480d2SRafael Auler 188821480d2SRafael Auler // Helper functions for writing strings to the .fdata file 189821480d2SRafael Auler 190821480d2SRafael Auler // Write number Num using Base to the buffer in OutBuf, returns a pointer to 191821480d2SRafael Auler // the end of the string. 192*cc4b2fb6SRafael Auler char *intToStr(char *OutBuf, uint64_t Num, uint32_t Base) { 19362aa74f8SRafael Auler const char *Chars = "0123456789abcdef"; 194*cc4b2fb6SRafael Auler char Buf[21]; 19562aa74f8SRafael Auler char *Ptr = Buf; 19662aa74f8SRafael Auler while (Num) { 19762aa74f8SRafael Auler *Ptr++ = *(Chars + (Num % Base)); 19862aa74f8SRafael Auler Num /= Base; 19962aa74f8SRafael Auler } 20062aa74f8SRafael Auler if (Ptr == Buf) { 20162aa74f8SRafael Auler *OutBuf++ = '0'; 20262aa74f8SRafael Auler return OutBuf; 20362aa74f8SRafael Auler } 20462aa74f8SRafael Auler while (Ptr != Buf) { 20562aa74f8SRafael Auler *OutBuf++ = *--Ptr; 20662aa74f8SRafael Auler } 20762aa74f8SRafael Auler return OutBuf; 20862aa74f8SRafael Auler } 20962aa74f8SRafael Auler 210*cc4b2fb6SRafael Auler // Copy Str to OutBuf, returns a pointer to the end of the copied string 211*cc4b2fb6SRafael Auler char *strCopy(char *OutBuf, const char *Str, int32_t Size = BufSize) { 212*cc4b2fb6SRafael Auler while (*Str) { 213821480d2SRafael Auler *OutBuf++ = *Str++; 214*cc4b2fb6SRafael Auler if (--Size <= 0) 215*cc4b2fb6SRafael Auler return OutBuf; 216*cc4b2fb6SRafael Auler } 217821480d2SRafael Auler return OutBuf; 218821480d2SRafael Auler } 219821480d2SRafael Auler 220*cc4b2fb6SRafael Auler void memSet(char *Buf, char C, uint32_t Size) { 221*cc4b2fb6SRafael Auler for (int I = 0; I < Size; ++I) 222*cc4b2fb6SRafael Auler *Buf++ = C; 223*cc4b2fb6SRafael Auler } 224*cc4b2fb6SRafael Auler 225*cc4b2fb6SRafael Auler uint32_t strLen(const char *Str) { 226*cc4b2fb6SRafael Auler uint32_t Size = 0; 227*cc4b2fb6SRafael Auler while (*Str++) 228*cc4b2fb6SRafael Auler ++Size; 229*cc4b2fb6SRafael Auler return Size; 230*cc4b2fb6SRafael Auler } 231*cc4b2fb6SRafael Auler 232*cc4b2fb6SRafael Auler // Print Msg to STDERR and quits with error code 1 233*cc4b2fb6SRafael Auler void reportError(const char *Msg, uint64_t Size) { 234821480d2SRafael Auler __write(2, Msg, Size); 235821480d2SRafael Auler __exit(1); 236821480d2SRafael Auler } 237821480d2SRafael Auler 238*cc4b2fb6SRafael Auler void assert(bool Assertion, const char *Msg) { 239*cc4b2fb6SRafael Auler if (Assertion) 240*cc4b2fb6SRafael Auler return; 241*cc4b2fb6SRafael Auler char Buf[BufSize]; 242*cc4b2fb6SRafael Auler char *Ptr = Buf; 243*cc4b2fb6SRafael Auler Ptr = strCopy(Ptr, "Assertion failed: "); 244*cc4b2fb6SRafael Auler Ptr = strCopy(Ptr, Msg, BufSize - 40); 245*cc4b2fb6SRafael Auler Ptr = strCopy(Ptr, "\n"); 246*cc4b2fb6SRafael Auler reportError(Buf, Ptr - Buf); 247*cc4b2fb6SRafael Auler } 248*cc4b2fb6SRafael Auler 249*cc4b2fb6SRafael Auler void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) { 250*cc4b2fb6SRafael Auler char Buf[BufSize]; 251*cc4b2fb6SRafael Auler char *Ptr = Buf; 252*cc4b2fb6SRafael Auler Ptr = strCopy(Ptr, Msg, BufSize - 23); 253*cc4b2fb6SRafael Auler Ptr = intToStr(Ptr, Num, Base); 254*cc4b2fb6SRafael Auler Ptr = strCopy(Ptr, "\n"); 255*cc4b2fb6SRafael Auler __write(2, Buf, Ptr - Buf); 256*cc4b2fb6SRafael Auler } 257*cc4b2fb6SRafael Auler 258*cc4b2fb6SRafael Auler void report(const char *Msg) { 259*cc4b2fb6SRafael Auler __write(2, Msg, strLen(Msg)); 260*cc4b2fb6SRafael Auler } 261*cc4b2fb6SRafael Auler 262*cc4b2fb6SRafael Auler inline uint64_t alignTo(uint64_t Value, uint64_t Align) { 263*cc4b2fb6SRafael Auler return (Value + Align - 1) / Align * Align; 264*cc4b2fb6SRafael Auler } 265*cc4b2fb6SRafael Auler 266*cc4b2fb6SRafael Auler /// A simple allocator that mmaps a fixed size region and manages this space 267*cc4b2fb6SRafael Auler /// in a stack fashion, meaning you always deallocate the last element that 268*cc4b2fb6SRafael Auler /// was allocated. 269*cc4b2fb6SRafael Auler class BumpPtrAllocator { 270*cc4b2fb6SRafael Auler struct EntryMetadata { 271*cc4b2fb6SRafael Auler uint64_t Magic; 272*cc4b2fb6SRafael Auler uint64_t AllocSize; 273*cc4b2fb6SRafael Auler }; 274*cc4b2fb6SRafael Auler public: 275*cc4b2fb6SRafael Auler void *allocate(uintptr_t Size) { 276*cc4b2fb6SRafael Auler if (StackBase == nullptr) { 277*cc4b2fb6SRafael Auler StackBase = reinterpret_cast<uint8_t *>(__mmap( 278*cc4b2fb6SRafael Auler 0, MAXSIZE, 0x3 /* PROT_READ | PROT_WRITE*/, 279*cc4b2fb6SRafael Auler 0x22 /* MAP_PRIVATE | MAP_ANONYMOUS*/, -1, 0)); 280*cc4b2fb6SRafael Auler StackSize = 0; 281*cc4b2fb6SRafael Auler } 282*cc4b2fb6SRafael Auler Size = alignTo(Size + sizeof(EntryMetadata), 16); 283*cc4b2fb6SRafael Auler uint8_t * AllocAddress = StackBase + StackSize + sizeof(EntryMetadata); 284*cc4b2fb6SRafael Auler auto *M = reinterpret_cast<EntryMetadata *>(StackBase + StackSize); 285*cc4b2fb6SRafael Auler M->Magic = MAGIC; 286*cc4b2fb6SRafael Auler M->AllocSize = Size; 287*cc4b2fb6SRafael Auler StackSize += Size; 288*cc4b2fb6SRafael Auler assert(StackSize < MAXSIZE, "allocator ran out of memory"); 289*cc4b2fb6SRafael Auler return AllocAddress; 290*cc4b2fb6SRafael Auler } 291*cc4b2fb6SRafael Auler 292*cc4b2fb6SRafael Auler void deallocate(void *Ptr) { 293*cc4b2fb6SRafael Auler uint8_t MetadataOffset = sizeof(EntryMetadata); 294*cc4b2fb6SRafael Auler auto *M = reinterpret_cast<EntryMetadata *>( 295*cc4b2fb6SRafael Auler reinterpret_cast<uint8_t *>(Ptr) - MetadataOffset); 296*cc4b2fb6SRafael Auler const uint8_t *StackTop = StackBase + StackSize + MetadataOffset; 297*cc4b2fb6SRafael Auler // Validate size 298*cc4b2fb6SRafael Auler if (Ptr != StackTop - M->AllocSize) { 299*cc4b2fb6SRafael Auler // This could be a pointer returned by operator new [] 300*cc4b2fb6SRafael Auler MetadataOffset += 301*cc4b2fb6SRafael Auler sizeof(uint64_t); // Space for number of elements alloc'ed 302*cc4b2fb6SRafael Auler M = reinterpret_cast<EntryMetadata *>(reinterpret_cast<uint8_t *>(Ptr) - 303*cc4b2fb6SRafael Auler MetadataOffset); 304*cc4b2fb6SRafael Auler assert(Ptr == StackTop - M->AllocSize, 305*cc4b2fb6SRafael Auler "must deallocate the last element alloc'ed"); 306*cc4b2fb6SRafael Auler } 307*cc4b2fb6SRafael Auler assert(M->Magic == MAGIC, "allocator magic is corrupt"); 308*cc4b2fb6SRafael Auler StackSize -= M->AllocSize; 309*cc4b2fb6SRafael Auler } 310*cc4b2fb6SRafael Auler 311*cc4b2fb6SRafael Auler private: 312*cc4b2fb6SRafael Auler static constexpr uint64_t MAGIC = 0x1122334455667788ull; 313*cc4b2fb6SRafael Auler static constexpr uint64_t MAXSIZE = 0xa00000; 314*cc4b2fb6SRafael Auler uint8_t *StackBase{nullptr}; 315*cc4b2fb6SRafael Auler uint64_t StackSize{0}; 316*cc4b2fb6SRafael Auler uint8_t *LastAlloc{nullptr}; 317*cc4b2fb6SRafael Auler }; 318*cc4b2fb6SRafael Auler 319*cc4b2fb6SRafael Auler } // anonymous namespace 320*cc4b2fb6SRafael Auler 321*cc4b2fb6SRafael Auler // User-defined placement new operators. We only use those (as opposed to 322*cc4b2fb6SRafael Auler // overriding the regular operator new) so we can keep our allocator in the 323*cc4b2fb6SRafael Auler // stack instead of in a data section (global). 324*cc4b2fb6SRafael Auler void *operator new(uintptr_t Sz, BumpPtrAllocator &A) { 325*cc4b2fb6SRafael Auler return A.allocate(Sz); 326*cc4b2fb6SRafael Auler } 327*cc4b2fb6SRafael Auler void *operator new (uintptr_t Sz, BumpPtrAllocator &A, char C) { 328*cc4b2fb6SRafael Auler auto *Ptr = reinterpret_cast<char *>(A.allocate(Sz)); 329*cc4b2fb6SRafael Auler memSet(Ptr, C, Sz); 330*cc4b2fb6SRafael Auler return Ptr; 331*cc4b2fb6SRafael Auler } 332*cc4b2fb6SRafael Auler void *operator new [] (uintptr_t Sz, BumpPtrAllocator &A) { 333*cc4b2fb6SRafael Auler return A.allocate(Sz); 334*cc4b2fb6SRafael Auler } 335*cc4b2fb6SRafael Auler void *operator new [] (uintptr_t Sz, BumpPtrAllocator &A, char C) { 336*cc4b2fb6SRafael Auler auto *Ptr = reinterpret_cast<char *>(A.allocate(Sz)); 337*cc4b2fb6SRafael Auler memSet(Ptr, C, Sz); 338*cc4b2fb6SRafael Auler return Ptr; 339*cc4b2fb6SRafael Auler } 340*cc4b2fb6SRafael Auler // Only called during exception unwinding (useless). We must manually dealloc. 341*cc4b2fb6SRafael Auler // C++ language weirdness 342*cc4b2fb6SRafael Auler void operator delete(void *Ptr, BumpPtrAllocator &A) { 343*cc4b2fb6SRafael Auler A.deallocate(Ptr); 344*cc4b2fb6SRafael Auler } 345*cc4b2fb6SRafael Auler 346*cc4b2fb6SRafael Auler namespace { 347*cc4b2fb6SRafael Auler 348821480d2SRafael Auler // Perform a string comparison and returns zero if Str1 matches Str2. Compares 349821480d2SRafael Auler // at most Size characters. 350*cc4b2fb6SRafael Auler int compareStr(const char *Str1, const char *Str2, int Size) { 351821480d2SRafael Auler while (*Str1 == *Str2) { 352821480d2SRafael Auler if (*Str1 == '\0' || --Size == 0) 353821480d2SRafael Auler return 0; 354821480d2SRafael Auler ++Str1; 355821480d2SRafael Auler ++Str2; 356821480d2SRafael Auler } 357821480d2SRafael Auler return 1; 358821480d2SRafael Auler } 359821480d2SRafael Auler 360821480d2SRafael Auler // Write as a string in OutBuf an identifier for the program point at function 361821480d2SRafael Auler // whose name is in the string table index FuncStrIndex plus Offset. 362*cc4b2fb6SRafael Auler char *serializeLoc(const InstrumentationInfo &Info, char *OutBuf, 363*cc4b2fb6SRafael Auler const Location Loc, uint32_t BufSize) { 364821480d2SRafael Auler // fdata location format: Type Name Offset 365821480d2SRafael Auler // Type 1 - regular symbol 366821480d2SRafael Auler OutBuf = strCopy(OutBuf, "1 "); 367821480d2SRafael Auler const char *Str = Info.Strings + Loc.FunctionName; 368*cc4b2fb6SRafael Auler uint32_t Size = 25; 36962aa74f8SRafael Auler while (*Str) { 37062aa74f8SRafael Auler *OutBuf++ = *Str++; 371*cc4b2fb6SRafael Auler if (++Size >= BufSize) 372*cc4b2fb6SRafael Auler break; 37362aa74f8SRafael Auler } 374*cc4b2fb6SRafael Auler assert(!*Str, "buffer overflow, function name too large"); 37562aa74f8SRafael Auler *OutBuf++ = ' '; 376821480d2SRafael Auler OutBuf = intToStr(OutBuf, Loc.Offset, 16); 37762aa74f8SRafael Auler *OutBuf++ = ' '; 37862aa74f8SRafael Auler return OutBuf; 37962aa74f8SRafael Auler } 38062aa74f8SRafael Auler 381821480d2SRafael Auler // Read and map to memory the descriptions written by BOLT into the executable's 382821480d2SRafael Auler // notes section 383*cc4b2fb6SRafael Auler InstrumentationInfo readDescriptions() { 384821480d2SRafael Auler InstrumentationInfo Result; 385821480d2SRafael Auler uint64_t FD = __open("/proc/self/exe", 386821480d2SRafael Auler /*flags=*/0 /*O_RDONLY*/, 387821480d2SRafael Auler /*mode=*/0666); 388*cc4b2fb6SRafael Auler assert(static_cast<int64_t>(FD) > 0, "Failed to open /proc/self/exe"); 389821480d2SRafael Auler Result.FileDesc = FD; 390821480d2SRafael Auler 391821480d2SRafael Auler // mmap our binary to memory 392821480d2SRafael Auler uint64_t Size = __lseek(FD, 0, 2 /*SEEK_END*/); 393821480d2SRafael Auler uint8_t *BinContents = reinterpret_cast<uint8_t *>( 394821480d2SRafael Auler __mmap(0, Size, 0x1 /* PROT_READ*/, 0x2 /* MAP_PRIVATE*/, FD, 0)); 395821480d2SRafael Auler Result.MMapPtr = BinContents; 396821480d2SRafael Auler Result.MMapSize = Size; 397821480d2SRafael Auler Elf64_Ehdr *Hdr = reinterpret_cast<Elf64_Ehdr *>(BinContents); 398821480d2SRafael Auler Elf64_Shdr *Shdr = reinterpret_cast<Elf64_Shdr *>(BinContents + Hdr->e_shoff); 399821480d2SRafael Auler Elf64_Shdr *StringTblHeader = reinterpret_cast<Elf64_Shdr *>( 400821480d2SRafael Auler BinContents + Hdr->e_shoff + Hdr->e_shstrndx * Hdr->e_shentsize); 401821480d2SRafael Auler 402821480d2SRafael Auler // Find .bolt.instr.tables with the data we need and set pointers to it 403821480d2SRafael Auler for (int I = 0; I < Hdr->e_shnum; ++I) { 404821480d2SRafael Auler char *SecName = reinterpret_cast<char *>( 405821480d2SRafael Auler BinContents + StringTblHeader->sh_offset + Shdr->sh_name); 406821480d2SRafael Auler if (compareStr(SecName, ".bolt.instr.tables", 64) != 0) { 407821480d2SRafael Auler Shdr = reinterpret_cast<Elf64_Shdr *>(BinContents + Hdr->e_shoff + 408821480d2SRafael Auler (I + 1) * Hdr->e_shentsize); 409821480d2SRafael Auler continue; 410821480d2SRafael Auler } 411821480d2SRafael Auler // Actual contents of the ELF note start after offset 20 decimal: 412821480d2SRafael Auler // Offset 0: Producer name size (4 bytes) 413821480d2SRafael Auler // Offset 4: Contents size (4 bytes) 414821480d2SRafael Auler // Offset 8: Note type (4 bytes) 415821480d2SRafael Auler // Offset 12: Producer name (BOLT\0) (5 bytes + align to 4-byte boundary) 416821480d2SRafael Auler // Offset 20: Contents 417*cc4b2fb6SRafael Auler uint32_t CallDescSize = 418*cc4b2fb6SRafael Auler *reinterpret_cast<uint32_t *>(BinContents + Shdr->sh_offset + 20); 419*cc4b2fb6SRafael Auler uint32_t FuncDescSize = *reinterpret_cast<uint32_t *>( 420*cc4b2fb6SRafael Auler BinContents + Shdr->sh_offset + 24 + CallDescSize); 421*cc4b2fb6SRafael Auler Result.CallDescriptions = 422*cc4b2fb6SRafael Auler reinterpret_cast<CallDescription *>(BinContents + Shdr->sh_offset + 24); 423*cc4b2fb6SRafael Auler Result.FuncDescriptions = BinContents + Shdr->sh_offset + 28 + CallDescSize; 424*cc4b2fb6SRafael Auler Result.Strings = reinterpret_cast<char *>(BinContents + Shdr->sh_offset + 425*cc4b2fb6SRafael Auler 28 + CallDescSize + FuncDescSize); 426821480d2SRafael Auler return Result; 427821480d2SRafael Auler } 428821480d2SRafael Auler const char ErrMsg[] = 429821480d2SRafael Auler "BOLT instrumentation runtime error: could not find section " 430821480d2SRafael Auler ".bolt.instr.tables\n"; 431821480d2SRafael Auler reportError(ErrMsg, sizeof(ErrMsg)); 432821480d2SRafael Auler return Result; 433821480d2SRafael Auler } 434821480d2SRafael Auler 435*cc4b2fb6SRafael Auler void printStats(const InstrumentationInfo &Info) { 436*cc4b2fb6SRafael Auler char StatMsg[BufSize]; 437*cc4b2fb6SRafael Auler char *StatPtr = StatMsg; 438*cc4b2fb6SRafael Auler StatPtr = strCopy( 439*cc4b2fb6SRafael Auler StatPtr, "\nBOLT INSTRUMENTATION RUNTIME STATISTICS\n\nCallDescSize: "); 440*cc4b2fb6SRafael Auler StatPtr = intToStr(StatPtr, 441*cc4b2fb6SRafael Auler Info.FuncDescriptions - 442*cc4b2fb6SRafael Auler reinterpret_cast<uint8_t *>(Info.CallDescriptions), 443*cc4b2fb6SRafael Auler 10); 444*cc4b2fb6SRafael Auler StatPtr = strCopy(StatPtr, "\nFuncDescSize: "); 445*cc4b2fb6SRafael Auler StatPtr = intToStr( 446*cc4b2fb6SRafael Auler StatPtr, 447*cc4b2fb6SRafael Auler reinterpret_cast<uint8_t *>(Info.Strings) - Info.FuncDescriptions, 10); 448*cc4b2fb6SRafael Auler StatPtr = strCopy(StatPtr, "\n__bolt_instr_num_calls: "); 449*cc4b2fb6SRafael Auler StatPtr = intToStr(StatPtr, __bolt_instr_num_calls, 10); 450*cc4b2fb6SRafael Auler StatPtr = strCopy(StatPtr, "\n__bolt_instr_num_funcs: "); 451*cc4b2fb6SRafael Auler StatPtr = intToStr(StatPtr, __bolt_instr_num_funcs, 10); 452*cc4b2fb6SRafael Auler StatPtr = strCopy(StatPtr, "\n"); 453*cc4b2fb6SRafael Auler __write(2, StatMsg, StatPtr - StatMsg); 454*cc4b2fb6SRafael Auler } 455*cc4b2fb6SRafael Auler 456*cc4b2fb6SRafael Auler /// This is part of a simple CFG representation in memory, where we store 457*cc4b2fb6SRafael Auler /// a dynamically sized array of input and output edges per node, and store 458*cc4b2fb6SRafael Auler /// a dynamically sized array of nodes per graph. We also store the spanning 459*cc4b2fb6SRafael Auler /// tree edges for that CFG in a separate array of nodes in 460*cc4b2fb6SRafael Auler /// \p SpanningTreeNodes, while the regular nodes live in \p CFGNodes. 461*cc4b2fb6SRafael Auler struct Edge { 462*cc4b2fb6SRafael Auler uint32_t Node; // Index in nodes array regarding the destination of this edge 463*cc4b2fb6SRafael Auler uint32_t ID; // Edge index in an array comprising all edges of the graph 464*cc4b2fb6SRafael Auler }; 465*cc4b2fb6SRafael Auler 466*cc4b2fb6SRafael Auler /// A regular graph node or a spanning tree node 467*cc4b2fb6SRafael Auler struct Node { 468*cc4b2fb6SRafael Auler uint32_t NumInEdges{0}; // Input edge count used to size InEdge 469*cc4b2fb6SRafael Auler uint32_t NumOutEdges{0}; // Output edge count used to size OutEdges 470*cc4b2fb6SRafael Auler Edge *InEdges{nullptr}; // Created and managed by \p Graph 471*cc4b2fb6SRafael Auler Edge *OutEdges{nullptr}; // ditto 472*cc4b2fb6SRafael Auler }; 473*cc4b2fb6SRafael Auler 474*cc4b2fb6SRafael Auler /// Main class for CFG representation in memory. Manages object creation and 475*cc4b2fb6SRafael Auler /// destruction, populates an array of CFG nodes as well as corresponding 476*cc4b2fb6SRafael Auler /// spanning tree nodes. 477*cc4b2fb6SRafael Auler struct Graph { 478*cc4b2fb6SRafael Auler uint32_t NumNodes; 479*cc4b2fb6SRafael Auler Node *CFGNodes; 480*cc4b2fb6SRafael Auler Node *SpanningTreeNodes; 481*cc4b2fb6SRafael Auler BumpPtrAllocator &Alloc; 482*cc4b2fb6SRafael Auler 483*cc4b2fb6SRafael Auler /// Reads a list of \p NumEdgeDescs descriptions in \p EdgeDescs and builds 484*cc4b2fb6SRafael Auler /// the graph from it. Allocates several internal dynamic structures that are 485*cc4b2fb6SRafael Auler /// later destroyed by ~Graph() and uses \p Alloc. \p LeafNodes contain all 486*cc4b2fb6SRafael Auler /// spanning tree leaf nodes descriptions (their counters). They are the seed 487*cc4b2fb6SRafael Auler /// used to compute the rest of the missing edge counts in a bottom-up 488*cc4b2fb6SRafael Auler /// traversal of the spanning tree. 489*cc4b2fb6SRafael Auler Graph(BumpPtrAllocator &Alloc, const EdgeDescription *EdgeDescs, 490*cc4b2fb6SRafael Auler uint32_t NumEdgeDescs, const InstrumentedNode *LeafNodes, 491*cc4b2fb6SRafael Auler uint32_t NumLeafNodes); 492*cc4b2fb6SRafael Auler 493*cc4b2fb6SRafael Auler ~Graph(); 494*cc4b2fb6SRafael Auler void dump() const; 495*cc4b2fb6SRafael Auler }; 496*cc4b2fb6SRafael Auler 497*cc4b2fb6SRafael Auler Graph::Graph(BumpPtrAllocator &Alloc, const EdgeDescription *EdgeDescs, 498*cc4b2fb6SRafael Auler uint32_t NumEdgeDescs, const InstrumentedNode *LeafNodes, 499*cc4b2fb6SRafael Auler uint32_t NumLeafNodes) : Alloc(Alloc) { 500*cc4b2fb6SRafael Auler DEBUG(reportNumber("G = 0x", (uint64_t)this, 16)); 501*cc4b2fb6SRafael Auler // First pass to determine number of nodes 502*cc4b2fb6SRafael Auler uint32_t MaxNodes = 0; 503*cc4b2fb6SRafael Auler for (int I = 0; I < NumEdgeDescs; ++I) { 504*cc4b2fb6SRafael Auler if (EdgeDescs[I].FromNode > MaxNodes) 505*cc4b2fb6SRafael Auler MaxNodes = EdgeDescs[I].FromNode; 506*cc4b2fb6SRafael Auler if (EdgeDescs[I].ToNode > MaxNodes) 507*cc4b2fb6SRafael Auler MaxNodes = EdgeDescs[I].ToNode; 508*cc4b2fb6SRafael Auler } 509*cc4b2fb6SRafael Auler for (int I = 0; I < NumLeafNodes; ++I) { 510*cc4b2fb6SRafael Auler if (LeafNodes[I].Node > MaxNodes) 511*cc4b2fb6SRafael Auler MaxNodes = LeafNodes[I].Node; 512*cc4b2fb6SRafael Auler } 513*cc4b2fb6SRafael Auler // No edges? Nothing to do 514*cc4b2fb6SRafael Auler if (!MaxNodes) { 515*cc4b2fb6SRafael Auler CFGNodes = nullptr; 516*cc4b2fb6SRafael Auler SpanningTreeNodes = nullptr; 517*cc4b2fb6SRafael Auler NumNodes = 0; 518*cc4b2fb6SRafael Auler return; 519*cc4b2fb6SRafael Auler } 520*cc4b2fb6SRafael Auler ++MaxNodes; 521*cc4b2fb6SRafael Auler DEBUG(reportNumber("NumNodes = ", MaxNodes, 10)); 522*cc4b2fb6SRafael Auler NumNodes = MaxNodes; 523*cc4b2fb6SRafael Auler 524*cc4b2fb6SRafael Auler // Initial allocations 525*cc4b2fb6SRafael Auler CFGNodes = new (Alloc) Node[MaxNodes]; 526*cc4b2fb6SRafael Auler DEBUG(reportNumber("G->CFGNodes = 0x", (uint64_t)CFGNodes, 16)); 527*cc4b2fb6SRafael Auler SpanningTreeNodes = new (Alloc) Node[MaxNodes]; 528*cc4b2fb6SRafael Auler DEBUG(reportNumber("G->SpanningTreeNodes = 0x", 529*cc4b2fb6SRafael Auler (uint64_t)SpanningTreeNodes, 16)); 530*cc4b2fb6SRafael Auler 531*cc4b2fb6SRafael Auler // Figure out how much to allocate to each vector (in/out edge sets) 532*cc4b2fb6SRafael Auler for (int I = 0; I < NumEdgeDescs; ++I) { 533*cc4b2fb6SRafael Auler CFGNodes[EdgeDescs[I].FromNode].NumOutEdges++; 534*cc4b2fb6SRafael Auler CFGNodes[EdgeDescs[I].ToNode].NumInEdges++; 535*cc4b2fb6SRafael Auler if (EdgeDescs[I].Counter != 0xffffffff) 536*cc4b2fb6SRafael Auler continue; 537*cc4b2fb6SRafael Auler 538*cc4b2fb6SRafael Auler SpanningTreeNodes[EdgeDescs[I].FromNode].NumOutEdges++; 539*cc4b2fb6SRafael Auler SpanningTreeNodes[EdgeDescs[I].ToNode].NumInEdges++; 540*cc4b2fb6SRafael Auler } 541*cc4b2fb6SRafael Auler 542*cc4b2fb6SRafael Auler // Allocate in/out edge sets 543*cc4b2fb6SRafael Auler for (int I = 0; I < MaxNodes; ++I) { 544*cc4b2fb6SRafael Auler if (CFGNodes[I].NumInEdges > 0) 545*cc4b2fb6SRafael Auler CFGNodes[I].InEdges = new (Alloc) Edge[CFGNodes[I].NumInEdges]; 546*cc4b2fb6SRafael Auler if (CFGNodes[I].NumOutEdges > 0) 547*cc4b2fb6SRafael Auler CFGNodes[I].OutEdges = new (Alloc) Edge[CFGNodes[I].NumOutEdges]; 548*cc4b2fb6SRafael Auler if (SpanningTreeNodes[I].NumInEdges > 0) 549*cc4b2fb6SRafael Auler SpanningTreeNodes[I].InEdges = 550*cc4b2fb6SRafael Auler new (Alloc) Edge[SpanningTreeNodes[I].NumInEdges]; 551*cc4b2fb6SRafael Auler if (SpanningTreeNodes[I].NumOutEdges > 0) 552*cc4b2fb6SRafael Auler SpanningTreeNodes[I].OutEdges = 553*cc4b2fb6SRafael Auler new (Alloc) Edge[SpanningTreeNodes[I].NumOutEdges]; 554*cc4b2fb6SRafael Auler CFGNodes[I].NumInEdges = 0; 555*cc4b2fb6SRafael Auler CFGNodes[I].NumOutEdges = 0; 556*cc4b2fb6SRafael Auler SpanningTreeNodes[I].NumInEdges = 0; 557*cc4b2fb6SRafael Auler SpanningTreeNodes[I].NumOutEdges = 0; 558*cc4b2fb6SRafael Auler } 559*cc4b2fb6SRafael Auler 560*cc4b2fb6SRafael Auler // Fill in/out edge sets 561*cc4b2fb6SRafael Auler for (int I = 0; I < NumEdgeDescs; ++I) { 562*cc4b2fb6SRafael Auler const uint32_t Src = EdgeDescs[I].FromNode; 563*cc4b2fb6SRafael Auler const uint32_t Dst = EdgeDescs[I].ToNode; 564*cc4b2fb6SRafael Auler Edge *E = &CFGNodes[Src].OutEdges[CFGNodes[Src].NumOutEdges++]; 565*cc4b2fb6SRafael Auler E->Node = Dst; 566*cc4b2fb6SRafael Auler E->ID = I; 567*cc4b2fb6SRafael Auler 568*cc4b2fb6SRafael Auler E = &CFGNodes[Dst].InEdges[CFGNodes[Dst].NumInEdges++]; 569*cc4b2fb6SRafael Auler E->Node = Src; 570*cc4b2fb6SRafael Auler E->ID = I; 571*cc4b2fb6SRafael Auler 572*cc4b2fb6SRafael Auler if (EdgeDescs[I].Counter != 0xffffffff) 573*cc4b2fb6SRafael Auler continue; 574*cc4b2fb6SRafael Auler 575*cc4b2fb6SRafael Auler E = &SpanningTreeNodes[Src] 576*cc4b2fb6SRafael Auler .OutEdges[SpanningTreeNodes[Src].NumOutEdges++]; 577*cc4b2fb6SRafael Auler E->Node = Dst; 578*cc4b2fb6SRafael Auler E->ID = I; 579*cc4b2fb6SRafael Auler 580*cc4b2fb6SRafael Auler E = &SpanningTreeNodes[Dst] 581*cc4b2fb6SRafael Auler .InEdges[SpanningTreeNodes[Dst].NumInEdges++]; 582*cc4b2fb6SRafael Auler E->Node = Src; 583*cc4b2fb6SRafael Auler E->ID = I; 584*cc4b2fb6SRafael Auler } 585*cc4b2fb6SRafael Auler } 586*cc4b2fb6SRafael Auler 587*cc4b2fb6SRafael Auler Graph::~Graph() { 588*cc4b2fb6SRafael Auler for (int I = NumNodes - 1; I >= 0; --I) { 589*cc4b2fb6SRafael Auler if (SpanningTreeNodes[I].OutEdges) 590*cc4b2fb6SRafael Auler Alloc.deallocate(SpanningTreeNodes[I].OutEdges); 591*cc4b2fb6SRafael Auler if (SpanningTreeNodes[I].InEdges) 592*cc4b2fb6SRafael Auler Alloc.deallocate(SpanningTreeNodes[I].InEdges); 593*cc4b2fb6SRafael Auler if (CFGNodes[I].OutEdges) 594*cc4b2fb6SRafael Auler Alloc.deallocate(CFGNodes[I].OutEdges); 595*cc4b2fb6SRafael Auler if (CFGNodes[I].InEdges) 596*cc4b2fb6SRafael Auler Alloc.deallocate(CFGNodes[I].InEdges); 597*cc4b2fb6SRafael Auler } 598*cc4b2fb6SRafael Auler if (SpanningTreeNodes) 599*cc4b2fb6SRafael Auler Alloc.deallocate(SpanningTreeNodes); 600*cc4b2fb6SRafael Auler if (CFGNodes) 601*cc4b2fb6SRafael Auler Alloc.deallocate(CFGNodes); 602*cc4b2fb6SRafael Auler } 603*cc4b2fb6SRafael Auler 604*cc4b2fb6SRafael Auler void Graph::dump() const { 605*cc4b2fb6SRafael Auler reportNumber("Dumping graph with number of nodes: ", NumNodes, 10); 606*cc4b2fb6SRafael Auler report(" Full graph:\n"); 607*cc4b2fb6SRafael Auler for (int I = 0; I < NumNodes; ++I) { 608*cc4b2fb6SRafael Auler const Node *N = &CFGNodes[I]; 609*cc4b2fb6SRafael Auler reportNumber(" Node #", I, 10); 610*cc4b2fb6SRafael Auler reportNumber(" InEdges total ", N->NumInEdges, 10); 611*cc4b2fb6SRafael Auler for (int J = 0; J < N->NumInEdges; ++J) 612*cc4b2fb6SRafael Auler reportNumber(" ", N->InEdges[J].Node, 10); 613*cc4b2fb6SRafael Auler reportNumber(" OutEdges total ", N->NumOutEdges, 10); 614*cc4b2fb6SRafael Auler for (int J = 0; J < N->NumOutEdges; ++J) 615*cc4b2fb6SRafael Auler reportNumber(" ", N->OutEdges[J].Node, 10); 616*cc4b2fb6SRafael Auler report("\n"); 617*cc4b2fb6SRafael Auler } 618*cc4b2fb6SRafael Auler report(" Spanning tree:\n"); 619*cc4b2fb6SRafael Auler for (int I = 0; I < NumNodes; ++I) { 620*cc4b2fb6SRafael Auler const Node *N = &SpanningTreeNodes[I]; 621*cc4b2fb6SRafael Auler reportNumber(" Node #", I, 10); 622*cc4b2fb6SRafael Auler reportNumber(" InEdges total ", N->NumInEdges, 10); 623*cc4b2fb6SRafael Auler for (int J = 0; J < N->NumInEdges; ++J) 624*cc4b2fb6SRafael Auler reportNumber(" ", N->InEdges[J].Node, 10); 625*cc4b2fb6SRafael Auler reportNumber(" OutEdges total ", N->NumOutEdges, 10); 626*cc4b2fb6SRafael Auler for (int J = 0; J < N->NumOutEdges; ++J) 627*cc4b2fb6SRafael Auler reportNumber(" ", N->OutEdges[J].Node, 10); 628*cc4b2fb6SRafael Auler report("\n"); 629*cc4b2fb6SRafael Auler } 630*cc4b2fb6SRafael Auler } 631*cc4b2fb6SRafael Auler 632*cc4b2fb6SRafael Auler void dumpEdgeFreqs(const uint64_t *EdgeFreqs, const EdgeDescription *EdgeDescs, 633*cc4b2fb6SRafael Auler uint32_t NumEdges) { 634*cc4b2fb6SRafael Auler reportNumber("Dumping edge frequencies for graph with num edges: ", NumEdges, 635*cc4b2fb6SRafael Auler 10); 636*cc4b2fb6SRafael Auler for (int I = 0; I < NumEdges; ++I) { 637*cc4b2fb6SRafael Auler reportNumber("* Src: ", EdgeDescs[I].FromNode, 10); 638*cc4b2fb6SRafael Auler reportNumber(" Dst: ", EdgeDescs[I].ToNode, 10); 639*cc4b2fb6SRafael Auler reportNumber(" Cnt: ", EdgeFreqs[I], 10); 640*cc4b2fb6SRafael Auler } 641*cc4b2fb6SRafael Auler } 642*cc4b2fb6SRafael Auler 643*cc4b2fb6SRafael Auler // Return an array with the frequency of each edge in the function represented 644*cc4b2fb6SRafael Auler // by G. 645*cc4b2fb6SRafael Auler uint64_t *computeEdgeFrequencies(BumpPtrAllocator &Alloc, Graph *G, 646*cc4b2fb6SRafael Auler const EdgeDescription *EdgeDescs, 647*cc4b2fb6SRafael Auler uint32_t NumEdges, 648*cc4b2fb6SRafael Auler const InstrumentedNode *LeafNodes, 649*cc4b2fb6SRafael Auler uint32_t NumLeafNodes, 650*cc4b2fb6SRafael Auler const uint64_t *Counters) { 651*cc4b2fb6SRafael Auler if (G->NumNodes == 0 || NumEdges == 0) 652*cc4b2fb6SRafael Auler return 0; 653*cc4b2fb6SRafael Auler assert(NumLeafNodes > 0, "no leaf node frequency"); 654*cc4b2fb6SRafael Auler 655*cc4b2fb6SRafael Auler uint64_t *EdgeFrequency = new (Alloc, 0) uint64_t [NumEdges]; 656*cc4b2fb6SRafael Auler 657*cc4b2fb6SRafael Auler // Perform a bottom-up, BFS traversal of the spanning tree in G. Edges in the 658*cc4b2fb6SRafael Auler // spanning tree don't have explicit counters. We must infer their value using 659*cc4b2fb6SRafael Auler // a linear combination of other counters (sum of counters of the outgoing 660*cc4b2fb6SRafael Auler // edges minus sum of counters of the incoming edges). 661*cc4b2fb6SRafael Auler uint32_t *Stack = new (Alloc) uint32_t [G->NumNodes]; 662*cc4b2fb6SRafael Auler uint32_t StackTop = 0; 663*cc4b2fb6SRafael Auler enum Status : uint8_t { S_NEW = 0, S_VISITING, S_VISITED }; 664*cc4b2fb6SRafael Auler Status *Visited = new (Alloc, 0) Status[G->NumNodes]; 665*cc4b2fb6SRafael Auler uint64_t *LeafFrequency = new (Alloc, 0) uint64_t[G->NumNodes]; 666*cc4b2fb6SRafael Auler 667*cc4b2fb6SRafael Auler // Setup a fast lookup for frequency of leaf nodes, which have special 668*cc4b2fb6SRafael Auler // basic block frequency instrumentation (they are not edge profiled). 669*cc4b2fb6SRafael Auler uint64_t TotalFreq = 0; 670*cc4b2fb6SRafael Auler for (int I = 0; I < NumLeafNodes; ++I) { 671*cc4b2fb6SRafael Auler LeafFrequency[LeafNodes[I].Node] = Counters[LeafNodes[I].Counter]; 672*cc4b2fb6SRafael Auler DEBUG({ 673*cc4b2fb6SRafael Auler if (Counters[LeafNodes[I].Counter] > 0) { 674*cc4b2fb6SRafael Auler reportNumber("Leaf Node# ", LeafNodes[I].Node, 10); 675*cc4b2fb6SRafael Auler reportNumber(" Counter: ", Counters[LeafNodes[I].Counter], 10); 676*cc4b2fb6SRafael Auler } 677*cc4b2fb6SRafael Auler }); 678*cc4b2fb6SRafael Auler TotalFreq += Counters[LeafNodes[I].Counter]; 679*cc4b2fb6SRafael Auler } 680*cc4b2fb6SRafael Auler // Add all root nodes to the stack 681*cc4b2fb6SRafael Auler for (int I = 0; I < G->NumNodes; ++I) { 682*cc4b2fb6SRafael Auler if (G->SpanningTreeNodes[I].NumInEdges == 0) 683*cc4b2fb6SRafael Auler Stack[StackTop++] = I; 684*cc4b2fb6SRafael Auler } 685*cc4b2fb6SRafael Auler // Empty stack? 686*cc4b2fb6SRafael Auler if (StackTop == 0) { 687*cc4b2fb6SRafael Auler Alloc.deallocate(LeafFrequency); 688*cc4b2fb6SRafael Auler Alloc.deallocate(Visited); 689*cc4b2fb6SRafael Auler Alloc.deallocate(Stack); 690*cc4b2fb6SRafael Auler Alloc.deallocate(EdgeFrequency); 691*cc4b2fb6SRafael Auler return 0; 692*cc4b2fb6SRafael Auler } 693*cc4b2fb6SRafael Auler // Add all known edge counts, will infer the rest 694*cc4b2fb6SRafael Auler for (int I = 0; I < NumEdges; ++I) { 695*cc4b2fb6SRafael Auler const uint32_t C = EdgeDescs[I].Counter; 696*cc4b2fb6SRafael Auler if (C == 0xffffffff) // inferred counter - we will compute its value 697*cc4b2fb6SRafael Auler continue; 698*cc4b2fb6SRafael Auler EdgeFrequency[I] = Counters[C]; 699*cc4b2fb6SRafael Auler TotalFreq += Counters[C]; 700*cc4b2fb6SRafael Auler } 701*cc4b2fb6SRafael Auler 702*cc4b2fb6SRafael Auler // This function is completely cold, there is no point in computing anything 703*cc4b2fb6SRafael Auler // since inferred edges will be zero too. 704*cc4b2fb6SRafael Auler #ifndef ENABLE_DEBUG 705*cc4b2fb6SRafael Auler if (TotalFreq == 0) { 706*cc4b2fb6SRafael Auler Alloc.deallocate(LeafFrequency); 707*cc4b2fb6SRafael Auler Alloc.deallocate(Visited); 708*cc4b2fb6SRafael Auler Alloc.deallocate(Stack); 709*cc4b2fb6SRafael Auler return EdgeFrequency; 710*cc4b2fb6SRafael Auler } 711*cc4b2fb6SRafael Auler #endif 712*cc4b2fb6SRafael Auler 713*cc4b2fb6SRafael Auler while (StackTop > 0) { 714*cc4b2fb6SRafael Auler const uint32_t Cur = Stack[--StackTop]; 715*cc4b2fb6SRafael Auler DEBUG({ 716*cc4b2fb6SRafael Auler if (Visited[Cur] == S_VISITING) 717*cc4b2fb6SRafael Auler report("(visiting) "); 718*cc4b2fb6SRafael Auler else 719*cc4b2fb6SRafael Auler report("(new) "); 720*cc4b2fb6SRafael Auler reportNumber("Cur: ", Cur, 10); 721*cc4b2fb6SRafael Auler }); 722*cc4b2fb6SRafael Auler 723*cc4b2fb6SRafael Auler // This shouldn't happen in a tree 724*cc4b2fb6SRafael Auler assert(Visited[Cur] != S_VISITED, "should not have visited nodes in stack"); 725*cc4b2fb6SRafael Auler if (Visited[Cur] == S_NEW) { 726*cc4b2fb6SRafael Auler Visited[Cur] = S_VISITING; 727*cc4b2fb6SRafael Auler Stack[StackTop++] = Cur; 728*cc4b2fb6SRafael Auler assert(StackTop <= G->NumNodes, "stack grew too large"); 729*cc4b2fb6SRafael Auler for (int I = 0, E = G->SpanningTreeNodes[Cur].NumOutEdges; I < E; ++I) { 730*cc4b2fb6SRafael Auler const uint32_t Succ = G->SpanningTreeNodes[Cur].OutEdges[I].Node; 731*cc4b2fb6SRafael Auler Stack[StackTop++] = Succ; 732*cc4b2fb6SRafael Auler assert(StackTop <= G->NumNodes, "stack grew too large"); 733*cc4b2fb6SRafael Auler } 734*cc4b2fb6SRafael Auler continue; 735*cc4b2fb6SRafael Auler } 736*cc4b2fb6SRafael Auler Visited[Cur] = S_VISITED; 737*cc4b2fb6SRafael Auler 738*cc4b2fb6SRafael Auler // No parent? Reached a tree root, nothing to do. 739*cc4b2fb6SRafael Auler if (G->SpanningTreeNodes[Cur].NumInEdges == 0) 740*cc4b2fb6SRafael Auler continue; 741*cc4b2fb6SRafael Auler 742*cc4b2fb6SRafael Auler assert(G->SpanningTreeNodes[Cur].NumInEdges == 1, "must have 1 parent"); 743*cc4b2fb6SRafael Auler const uint32_t Parent = G->SpanningTreeNodes[Cur].InEdges[0].Node; 744*cc4b2fb6SRafael Auler const uint32_t ParentEdge = G->SpanningTreeNodes[Cur].InEdges[0].ID; 745*cc4b2fb6SRafael Auler 746*cc4b2fb6SRafael Auler // Establish our node frequency based on outgoing edges, which should all be 747*cc4b2fb6SRafael Auler // resolved by now. 748*cc4b2fb6SRafael Auler int64_t CurNodeFreq = LeafFrequency[Cur]; 749*cc4b2fb6SRafael Auler // Not a leaf? 750*cc4b2fb6SRafael Auler if (!CurNodeFreq) { 751*cc4b2fb6SRafael Auler for (int I = 0, E = G->CFGNodes[Cur].NumOutEdges; I != E; ++I) { 752*cc4b2fb6SRafael Auler const uint32_t SuccEdge = G->CFGNodes[Cur].OutEdges[I].ID; 753*cc4b2fb6SRafael Auler CurNodeFreq += EdgeFrequency[SuccEdge]; 754*cc4b2fb6SRafael Auler } 755*cc4b2fb6SRafael Auler } 756*cc4b2fb6SRafael Auler int64_t ParentEdgeFreq = CurNodeFreq; 757*cc4b2fb6SRafael Auler // Calculate parent edge freq. 758*cc4b2fb6SRafael Auler for (int I = 0, E = G->CFGNodes[Cur].NumInEdges; I != E; ++I) { 759*cc4b2fb6SRafael Auler const uint32_t PredEdge = G->CFGNodes[Cur].InEdges[I].ID; 760*cc4b2fb6SRafael Auler ParentEdgeFreq -= EdgeFrequency[PredEdge]; 761*cc4b2fb6SRafael Auler } 762*cc4b2fb6SRafael Auler // Sometimes the conservative CFG that BOLT builds will lead to incorrect 763*cc4b2fb6SRafael Auler // flow computation. For example, in a BB that transitively calls the exit 764*cc4b2fb6SRafael Auler // syscall, BOLT will add a fall-through successor even though it should not 765*cc4b2fb6SRafael Auler // have any successors. So this block execution will likely be wrong. We 766*cc4b2fb6SRafael Auler // tolerate this imperfection since this case should be quite infrequent. 767*cc4b2fb6SRafael Auler if (ParentEdgeFreq < 0) { 768*cc4b2fb6SRafael Auler DEBUG(dumpEdgeFreqs(EdgeFrequency, EdgeDescs, NumEdges)); 769*cc4b2fb6SRafael Auler DEBUG(report("WARNING: incorrect flow")); 770*cc4b2fb6SRafael Auler ParentEdgeFreq = 0; 771*cc4b2fb6SRafael Auler } 772*cc4b2fb6SRafael Auler DEBUG(reportNumber(" Setting freq for ParentEdge: ", ParentEdge, 10)); 773*cc4b2fb6SRafael Auler DEBUG(reportNumber(" with ParentEdgeFreq: ", ParentEdgeFreq, 10)); 774*cc4b2fb6SRafael Auler EdgeFrequency[ParentEdge] = ParentEdgeFreq; 775*cc4b2fb6SRafael Auler } 776*cc4b2fb6SRafael Auler 777*cc4b2fb6SRafael Auler Alloc.deallocate(LeafFrequency); 778*cc4b2fb6SRafael Auler Alloc.deallocate(Visited); 779*cc4b2fb6SRafael Auler Alloc.deallocate(Stack); 780*cc4b2fb6SRafael Auler return EdgeFrequency; 781*cc4b2fb6SRafael Auler } 782*cc4b2fb6SRafael Auler 783*cc4b2fb6SRafael Auler // Write to \p FD all of the edge profiles for function \p FuncDesc. Uses 784*cc4b2fb6SRafael Auler // \p Alloc to allocate helper dynamic structures used to compute profile for 785*cc4b2fb6SRafael Auler // edges that we do not explictly instrument. 786*cc4b2fb6SRafael Auler uint8_t *writeFunctionProfile(int FD, const InstrumentationInfo &Info, 787*cc4b2fb6SRafael Auler uint8_t *FuncDesc, BumpPtrAllocator &Alloc) { 788*cc4b2fb6SRafael Auler uint32_t NumLeafNodes = *reinterpret_cast<uint32_t *>(FuncDesc); 789*cc4b2fb6SRafael Auler DEBUG(reportNumber("NumLeafNodes = ", NumLeafNodes, 10)); 790*cc4b2fb6SRafael Auler InstrumentedNode *LeafNodes = 791*cc4b2fb6SRafael Auler reinterpret_cast<InstrumentedNode *>(FuncDesc + 4); 792*cc4b2fb6SRafael Auler 793*cc4b2fb6SRafael Auler uint32_t NumEdges = *reinterpret_cast<uint32_t *>( 794*cc4b2fb6SRafael Auler FuncDesc + 4 + NumLeafNodes * sizeof(InstrumentedNode)); 795*cc4b2fb6SRafael Auler DEBUG(reportNumber("NumEdges = ", NumEdges, 10)); 796*cc4b2fb6SRafael Auler EdgeDescription *EdgeDescs = reinterpret_cast<EdgeDescription *>( 797*cc4b2fb6SRafael Auler FuncDesc + 8 + NumLeafNodes * sizeof(InstrumentedNode)); 798*cc4b2fb6SRafael Auler 799*cc4b2fb6SRafael Auler uint8_t *next = (FuncDesc + 8 + NumLeafNodes * sizeof(InstrumentedNode) + 800*cc4b2fb6SRafael Auler NumEdges * sizeof(EdgeDescription)); 801*cc4b2fb6SRafael Auler 802*cc4b2fb6SRafael Auler // Skip funcs we know are cold 803*cc4b2fb6SRafael Auler #ifndef ENABLE_DEBUG 804*cc4b2fb6SRafael Auler uint64_t LeafFreq = 0; 805*cc4b2fb6SRafael Auler for (int I = 0; I < NumLeafNodes; ++I) { 806*cc4b2fb6SRafael Auler LeafFreq += __bolt_instr_locations[LeafNodes[I].Counter]; 807*cc4b2fb6SRafael Auler } 808*cc4b2fb6SRafael Auler if (LeafFreq == 0) 809*cc4b2fb6SRafael Auler return next; 810*cc4b2fb6SRafael Auler #endif 811*cc4b2fb6SRafael Auler 812*cc4b2fb6SRafael Auler Graph *G = 813*cc4b2fb6SRafael Auler new (Alloc) Graph(Alloc, EdgeDescs, NumEdges, LeafNodes, NumLeafNodes); 814*cc4b2fb6SRafael Auler DEBUG(G->dump()); 815*cc4b2fb6SRafael Auler uint64_t *Freqs = 816*cc4b2fb6SRafael Auler computeEdgeFrequencies(Alloc, G, EdgeDescs, NumEdges, LeafNodes, 817*cc4b2fb6SRafael Auler NumLeafNodes, __bolt_instr_locations); 818*cc4b2fb6SRafael Auler if (!Freqs) { 819*cc4b2fb6SRafael Auler G->~Graph(); 820*cc4b2fb6SRafael Auler Alloc.deallocate(G); 821*cc4b2fb6SRafael Auler return next; 822*cc4b2fb6SRafael Auler } 823*cc4b2fb6SRafael Auler 824*cc4b2fb6SRafael Auler DEBUG(dumpEdgeFreqs(Freqs, EdgeDescs, NumEdges)); 825*cc4b2fb6SRafael Auler for (int I = 0; I < NumEdges; ++I) { 826*cc4b2fb6SRafael Auler const uint64_t Freq = Freqs[I]; 827*cc4b2fb6SRafael Auler if (Freq == 0) 828*cc4b2fb6SRafael Auler continue; 829*cc4b2fb6SRafael Auler const EdgeDescription *Desc = &EdgeDescs[I]; 830*cc4b2fb6SRafael Auler char LineBuf[BufSize]; 831*cc4b2fb6SRafael Auler char *Ptr = LineBuf; 832*cc4b2fb6SRafael Auler Ptr = serializeLoc(Info, Ptr, Desc->From, BufSize); 833*cc4b2fb6SRafael Auler Ptr = serializeLoc(Info, Ptr, Desc->To, BufSize - (Ptr - LineBuf)); 834*cc4b2fb6SRafael Auler Ptr = strCopy(Ptr, "0 ", BufSize - (Ptr - LineBuf) - 22); 835*cc4b2fb6SRafael Auler Ptr = intToStr(Ptr, Freq, 10); 836*cc4b2fb6SRafael Auler *Ptr++ = '\n'; 837*cc4b2fb6SRafael Auler __write(FD, LineBuf, Ptr - LineBuf); 838*cc4b2fb6SRafael Auler } 839*cc4b2fb6SRafael Auler 840*cc4b2fb6SRafael Auler Alloc.deallocate(Freqs); 841*cc4b2fb6SRafael Auler G->~Graph(); 842*cc4b2fb6SRafael Auler Alloc.deallocate(G); 843*cc4b2fb6SRafael Auler return next; 844*cc4b2fb6SRafael Auler } 845*cc4b2fb6SRafael Auler 846*cc4b2fb6SRafael Auler } // anonymous namespace 847*cc4b2fb6SRafael Auler 848821480d2SRafael Auler // This is the entry point called at program exit. BOLT patches the executable's 849821480d2SRafael Auler // FINI entry in the .dynamic section with the address of this function. Our 850821480d2SRafael Auler // goal here is to flush to disk all instrumentation data in memory, using 851821480d2SRafael Auler // BOLT's fdata format. 85262aa74f8SRafael Auler extern "C" void __bolt_instr_data_dump() { 853821480d2SRafael Auler const InstrumentationInfo Info = readDescriptions(); 854821480d2SRafael Auler 855*cc4b2fb6SRafael Auler DEBUG(printStats(Info)); 856*cc4b2fb6SRafael Auler 857821480d2SRafael Auler uint64_t FD = __open(__bolt_instr_filename, 85862aa74f8SRafael Auler /*flags=*/0x241 /*O_WRONLY|O_TRUNC|O_CREAT*/, 85962aa74f8SRafael Auler /*mode=*/0666); 860*cc4b2fb6SRafael Auler if (static_cast<int64_t>(FD) < 0) { 861*cc4b2fb6SRafael Auler reportNumber("Assertion error: failed to open profile file for writing. " 862*cc4b2fb6SRafael Auler "Error number: 0x", 863*cc4b2fb6SRafael Auler 0 - static_cast<int64_t>(FD), 16); 864*cc4b2fb6SRafael Auler __exit(1); 865*cc4b2fb6SRafael Auler } 86662aa74f8SRafael Auler 867*cc4b2fb6SRafael Auler for (int I = 0, E = __bolt_instr_num_calls; I < E; ++I) { 868*cc4b2fb6SRafael Auler char LineBuf[BufSize]; 86962aa74f8SRafael Auler char *Ptr = LineBuf; 870*cc4b2fb6SRafael Auler 871*cc4b2fb6SRafael Auler CallDescription *Desc = &Info.CallDescriptions[I]; 872*cc4b2fb6SRafael Auler uint64_t HitCount = __bolt_instr_locations[Desc->Counter]; 87362aa74f8SRafael Auler if (!HitCount) 87462aa74f8SRafael Auler continue; 875*cc4b2fb6SRafael Auler Ptr = serializeLoc(Info, Ptr, Desc->From, BufSize); 876*cc4b2fb6SRafael Auler Ptr = serializeLoc(Info, Ptr, Desc->To, BufSize - (Ptr - LineBuf)); 877*cc4b2fb6SRafael Auler Ptr = strCopy(Ptr, "0 ", BufSize - (Ptr - LineBuf) - 25); 87862aa74f8SRafael Auler Ptr = intToStr(Ptr, HitCount, 10); 87962aa74f8SRafael Auler *Ptr++ = '\n'; 880821480d2SRafael Auler __write(FD, LineBuf, Ptr - LineBuf); 88162aa74f8SRafael Auler } 882*cc4b2fb6SRafael Auler 883*cc4b2fb6SRafael Auler BumpPtrAllocator Alloc; 884*cc4b2fb6SRafael Auler uint8_t *FuncDesc = Info.FuncDescriptions; 885*cc4b2fb6SRafael Auler for (int I = 0, E = __bolt_instr_num_funcs; I < E; ++I) { 886*cc4b2fb6SRafael Auler FuncDesc = writeFunctionProfile(FD, Info, FuncDesc, Alloc); 887*cc4b2fb6SRafael Auler DEBUG(reportNumber("FuncDesc now: ", (uint64_t)FuncDesc, 16)); 888*cc4b2fb6SRafael Auler } 889*cc4b2fb6SRafael Auler assert(FuncDesc == (void *)Info.Strings, 890*cc4b2fb6SRafael Auler "FuncDesc ptr must be equal to stringtable"); 891*cc4b2fb6SRafael Auler 892821480d2SRafael Auler __close(FD); 893821480d2SRafael Auler __munmap(Info.MMapPtr, Info.MMapSize); 894821480d2SRafael Auler __close(Info.FileDesc); 89562aa74f8SRafael Auler } 896