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