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