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