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 //
13*16a497c6SRafael Auler // BOLT runtime instrumentation library for x86 Linux. Currently, BOLT does
14*16a497c6SRafael Auler // not support linking modules with dependencies on one another into the final
15*16a497c6SRafael Auler // binary (TODO?), which means this library has to be self-contained in a single
16*16a497c6SRafael Auler // module.
17*16a497c6SRafael Auler //
18*16a497c6SRafael Auler // All extern declarations here need to be defined by BOLT itself. Those will be
19*16a497c6SRafael Auler // undefined symbols that BOLT needs to resolve by emitting these symbols with
20*16a497c6SRafael Auler // MCStreamer. Currently, Passes/Instrumentation.cpp is the pass responsible
21*16a497c6SRafael Auler // for defining the symbols here and these two files have a tight coupling: one
22*16a497c6SRafael Auler // working statically when you run BOLT and another during program runtime when
23*16a497c6SRafael Auler // you run an instrumented binary. The main goal here is to output an fdata file
24*16a497c6SRafael Auler // (BOLT profile) with the instrumentation counters inserted by the static pass.
25*16a497c6SRafael Auler // Counters for indirect calls are an exception, as we can't know them
26*16a497c6SRafael Auler // statically. These counters are created and managed here. To allow this, we
27*16a497c6SRafael Auler // need a minimal framework for allocating memory dynamically. We provide this
28*16a497c6SRafael Auler // with the BumpPtrAllocator class (not LLVM's, but our own version of it).
29*16a497c6SRafael Auler //
30*16a497c6SRafael Auler // Since this code is intended to be inserted into any executable, we decided to
31*16a497c6SRafael Auler // make it standalone and do not depend on any external libraries (i.e. language
32*16a497c6SRafael Auler // support libraries, such as glibc or stdc++). To allow this, we provide a few
33*16a497c6SRafael Auler // light implementations of common OS interacting functionalities using direct
34*16a497c6SRafael Auler // syscall wrappers. Our simple allocator doesn't manage deallocations that
35*16a497c6SRafael Auler // fragment the memory space, so it's stack based. This is the minimal framework
36*16a497c6SRafael Auler // provided here to allow processing instrumented counters and writing fdata.
37*16a497c6SRafael Auler //
38*16a497c6SRafael Auler // In the C++ idiom used here, we never use or rely on constructors or
39*16a497c6SRafael Auler // destructors for global objects. That's because those need support from the
40*16a497c6SRafael Auler // linker in initialization/finalization code, and we want to keep our linker
41*16a497c6SRafael Auler // very simple. Similarly, we don't create any global objects that are zero
42*16a497c6SRafael Auler // initialized, since those would need to go .bss, which our simple linker also
43*16a497c6SRafael Auler // don't support (TODO?).
4462aa74f8SRafael Auler //
4562aa74f8SRafael Auler //===----------------------------------------------------------------------===//
4662aa74f8SRafael Auler 
4762aa74f8SRafael Auler #include <cstdint>
48ba31344fSRafael Auler 
49ba31344fSRafael Auler #include "config.h"
50ba31344fSRafael Auler #ifdef HAVE_ELF_H
51821480d2SRafael Auler #include <elf.h>
52ba31344fSRafael Auler #endif
5362aa74f8SRafael Auler 
54*16a497c6SRafael Auler // Enables a very verbose logging to stderr useful when debugging
55cc4b2fb6SRafael Auler //#define ENABLE_DEBUG
56cc4b2fb6SRafael Auler 
57cc4b2fb6SRafael Auler #ifdef ENABLE_DEBUG
58cc4b2fb6SRafael Auler #define DEBUG(X)                                                               \
59cc4b2fb6SRafael Auler   { X; }
60cc4b2fb6SRafael Auler #else
61cc4b2fb6SRafael Auler #define DEBUG(X)                                                               \
62cc4b2fb6SRafael Auler   {}
63cc4b2fb6SRafael Auler #endif
64cc4b2fb6SRafael Auler 
65*16a497c6SRafael Auler // Main counters inserted by instrumentation, incremented during runtime when
66*16a497c6SRafael Auler // points of interest (locations) in the program are reached. Those are direct
67*16a497c6SRafael Auler // calls and direct and indirect branches (local ones). There are also counters
68*16a497c6SRafael Auler // for basic block execution if they are a spanning tree leaf and need to be
69*16a497c6SRafael Auler // counted in order to infer the execution count of other edges of the CFG.
7062aa74f8SRafael Auler extern uint64_t __bolt_instr_locations[];
71*16a497c6SRafael Auler extern uint32_t __bolt_num_counters;
72*16a497c6SRafael Auler // Descriptions are serialized metadata about binary functions written by BOLT,
73*16a497c6SRafael Auler // so we have a minimal understanding about the program structure. For a
74*16a497c6SRafael Auler // reference on the exact format of this metadata, see *Description structs,
75*16a497c6SRafael Auler // Location, IntrumentedNode and EntryNode.
76*16a497c6SRafael Auler // Number of indirect call site descriptions
77*16a497c6SRafael Auler extern uint32_t __bolt_instr_num_ind_calls;
78*16a497c6SRafael Auler // Number of indirect call target descriptions
79*16a497c6SRafael Auler extern uint32_t __bolt_instr_num_ind_targets;
80cc4b2fb6SRafael Auler // Number of function descriptions
81cc4b2fb6SRafael Auler extern uint32_t __bolt_instr_num_funcs;
82*16a497c6SRafael Auler // Time to sleep across dumps (when we write the fdata profile to disk)
83*16a497c6SRafael Auler extern uint32_t __bolt_instr_sleep_time;
84cc4b2fb6SRafael Auler // Filename to dump data to
8562aa74f8SRafael Auler extern char __bolt_instr_filename[];
86*16a497c6SRafael Auler // If true, append current PID to the fdata filename when creating it so
87*16a497c6SRafael Auler // different invocations of the same program can be differentiated.
88*16a497c6SRafael Auler extern bool __bolt_instr_use_pid;
89*16a497c6SRafael Auler // Functions that will be used to instrument indirect calls. BOLT static pass
90*16a497c6SRafael Auler // will identify indirect calls and modify them to load the address in these
91*16a497c6SRafael Auler // trampolines and call this address instead. BOLT can't use direct calls to
92*16a497c6SRafael Auler // our handlers because our addresses here are not known at analysis time. We
93*16a497c6SRafael Auler // only support resolving dependencies from this file to the output of BOLT,
94*16a497c6SRafael Auler // *not* the other way around.
95*16a497c6SRafael Auler // TODO: We need better linking support to make that happen.
96*16a497c6SRafael Auler extern void (*__bolt_trampoline_ind_call)();
97*16a497c6SRafael Auler extern void (*__bolt_trampoline_ind_tailcall)();
98*16a497c6SRafael Auler // Function pointers to init/fini routines in the binary, so we can resume
99*16a497c6SRafael Auler // regular execution of these functions that we hooked
100*16a497c6SRafael Auler extern void (*__bolt_instr_init_ptr)();
101*16a497c6SRafael Auler extern void (*__bolt_instr_fini_ptr)();
10262aa74f8SRafael Auler 
103cc4b2fb6SRafael Auler // Anonymous namespace covering everything but our library entry point
104cc4b2fb6SRafael Auler namespace {
105cc4b2fb6SRafael Auler 
106*16a497c6SRafael Auler // We use a stack-allocated buffer for string manipulation in many pieces of
107*16a497c6SRafael Auler // this code, including the code that prints each line of the fdata file. This
108*16a497c6SRafael Auler // buffer needs to accomodate large function names, but shouldn't be arbitrarily
109*16a497c6SRafael Auler // large (dynamically allocated) for simplicity of our memory space usage.
110cc4b2fb6SRafael Auler constexpr uint32_t BufSize = 10240;
111cc4b2fb6SRafael Auler 
11262aa74f8SRafael Auler // Declare some syscall wrappers we use throughout this code to avoid linking
11362aa74f8SRafael Auler // against system libc.
114cc4b2fb6SRafael Auler uint64_t __open(const char *pathname, uint64_t flags, uint64_t mode) {
11562aa74f8SRafael Auler   uint64_t ret;
11662aa74f8SRafael Auler   __asm__ __volatile__ (
11762aa74f8SRafael Auler           "movq $2, %%rax\n"
11862aa74f8SRafael Auler           "syscall"
11962aa74f8SRafael Auler           : "=a"(ret)
12062aa74f8SRafael Auler           : "D"(pathname), "S"(flags), "d"(mode)
12162aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
12262aa74f8SRafael Auler   return ret;
12362aa74f8SRafael Auler }
12462aa74f8SRafael Auler 
125cc4b2fb6SRafael Auler uint64_t __write(uint64_t fd, const void *buf, uint64_t count) {
12662aa74f8SRafael Auler   uint64_t ret;
12762aa74f8SRafael Auler   __asm__ __volatile__ (
12862aa74f8SRafael Auler           "movq $1, %%rax\n"
12962aa74f8SRafael Auler           "syscall\n"
13062aa74f8SRafael Auler           : "=a"(ret)
13162aa74f8SRafael Auler           : "D"(fd), "S"(buf), "d"(count)
13262aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
13362aa74f8SRafael Auler   return ret;
13462aa74f8SRafael Auler }
13562aa74f8SRafael Auler 
136cc4b2fb6SRafael Auler uint64_t __lseek(uint64_t fd, uint64_t pos, uint64_t whence) {
137821480d2SRafael Auler   uint64_t ret;
138821480d2SRafael Auler   __asm__ __volatile__ (
139821480d2SRafael Auler           "movq $8, %%rax\n"
140821480d2SRafael Auler           "syscall\n"
141821480d2SRafael Auler           : "=a"(ret)
142821480d2SRafael Auler           : "D"(fd), "S"(pos), "d"(whence)
143821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
144821480d2SRafael Auler   return ret;
145821480d2SRafael Auler }
146821480d2SRafael Auler 
147cc4b2fb6SRafael Auler int __close(uint64_t fd) {
14862aa74f8SRafael Auler   uint64_t ret;
14962aa74f8SRafael Auler   __asm__ __volatile__ (
15062aa74f8SRafael Auler           "movq $3, %%rax\n"
15162aa74f8SRafael Auler           "syscall\n"
15262aa74f8SRafael Auler           : "=a"(ret)
15362aa74f8SRafael Auler           : "D"(fd)
15462aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
15562aa74f8SRafael Auler   return ret;
15662aa74f8SRafael Auler }
15762aa74f8SRafael Auler 
158*16a497c6SRafael Auler struct timespec {
159*16a497c6SRafael Auler   uint64_t tv_sec; /* seconds */
160*16a497c6SRafael Auler   uint64_t tv_nsec;  /* nanoseconds */
161*16a497c6SRafael Auler };
162*16a497c6SRafael Auler 
163*16a497c6SRafael Auler uint64_t __nanosleep(const timespec *req, timespec *rem) {
164*16a497c6SRafael Auler   uint64_t ret;
165*16a497c6SRafael Auler   __asm__ __volatile__ (
166*16a497c6SRafael Auler           "movq $35, %%rax\n"
167*16a497c6SRafael Auler           "syscall\n"
168*16a497c6SRafael Auler           : "=a"(ret)
169*16a497c6SRafael Auler           : "D"(req), "S"(rem)
170*16a497c6SRafael Auler           : "cc", "rcx", "r11", "memory");
171*16a497c6SRafael Auler   return ret;
172*16a497c6SRafael Auler }
173*16a497c6SRafael Auler 
174*16a497c6SRafael Auler int64_t __fork() {
175*16a497c6SRafael Auler   uint64_t ret;
176*16a497c6SRafael Auler   __asm__ __volatile__("movq $57, %%rax\n"
177*16a497c6SRafael Auler                        "syscall\n"
178*16a497c6SRafael Auler                        : "=a"(ret)
179*16a497c6SRafael Auler                        :
180*16a497c6SRafael Auler                        : "cc", "rcx", "r11", "memory");
181*16a497c6SRafael Auler   return ret;
182*16a497c6SRafael Auler }
183*16a497c6SRafael Auler 
184cc4b2fb6SRafael Auler void *__mmap(uint64_t addr, uint64_t size, uint64_t prot, uint64_t flags,
185cc4b2fb6SRafael Auler              uint64_t fd, uint64_t offset) {
186821480d2SRafael Auler   void *ret;
187821480d2SRafael Auler   register uint64_t r8 asm("r8") = fd;
188821480d2SRafael Auler   register uint64_t r9 asm("r9") = offset;
189821480d2SRafael Auler   register uint64_t r10 asm("r10") = flags;
190821480d2SRafael Auler   __asm__ __volatile__ (
191821480d2SRafael Auler           "movq $9, %%rax\n"
192821480d2SRafael Auler           "syscall\n"
193821480d2SRafael Auler           : "=a"(ret)
194821480d2SRafael Auler           : "D"(addr), "S"(size), "d"(prot), "r"(r10), "r"(r8), "r"(r9)
195821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
196821480d2SRafael Auler   return ret;
197821480d2SRafael Auler }
198821480d2SRafael Auler 
199cc4b2fb6SRafael Auler uint64_t __munmap(void *addr, uint64_t size) {
200821480d2SRafael Auler   uint64_t ret;
201821480d2SRafael Auler   __asm__ __volatile__ (
202821480d2SRafael Auler           "movq $11, %%rax\n"
203821480d2SRafael Auler           "syscall\n"
204821480d2SRafael Auler           : "=a"(ret)
205821480d2SRafael Auler           : "D"(addr), "S"(size)
206821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
207821480d2SRafael Auler   return ret;
208821480d2SRafael Auler }
209821480d2SRafael Auler 
210*16a497c6SRafael Auler uint64_t __getpid() {
211*16a497c6SRafael Auler   uint64_t ret;
212*16a497c6SRafael Auler   __asm__ __volatile__ (
213*16a497c6SRafael Auler           "movq $39, %%rax\n"
214*16a497c6SRafael Auler           "syscall\n"
215*16a497c6SRafael Auler           : "=a"(ret)
216*16a497c6SRafael Auler           :
217*16a497c6SRafael Auler           : "cc", "rcx", "r11", "memory");
218*16a497c6SRafael Auler   return ret;
219*16a497c6SRafael Auler }
220*16a497c6SRafael Auler 
221*16a497c6SRafael Auler uint64_t __getppid() {
222*16a497c6SRafael Auler   uint64_t ret;
223*16a497c6SRafael Auler   __asm__ __volatile__ (
224*16a497c6SRafael Auler           "movq $110, %%rax\n"
225*16a497c6SRafael Auler           "syscall\n"
226*16a497c6SRafael Auler           : "=a"(ret)
227*16a497c6SRafael Auler           :
228*16a497c6SRafael Auler           : "cc", "rcx", "r11", "memory");
229*16a497c6SRafael Auler   return ret;
230*16a497c6SRafael Auler }
231*16a497c6SRafael Auler 
232cc4b2fb6SRafael Auler uint64_t __exit(uint64_t code) {
233821480d2SRafael Auler   uint64_t ret;
234821480d2SRafael Auler   __asm__ __volatile__ (
235821480d2SRafael Auler           "movq $231, %%rax\n"
236821480d2SRafael Auler           "syscall\n"
237821480d2SRafael Auler           : "=a"(ret)
238821480d2SRafael Auler           : "D"(code)
239821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
240821480d2SRafael Auler   return ret;
241821480d2SRafael Auler }
242821480d2SRafael Auler 
243*16a497c6SRafael Auler // Helper functions for writing strings to the .fdata file. We intentionally
244*16a497c6SRafael Auler // avoid using libc names (lowercase memset) to make it clear it is our impl.
245821480d2SRafael Auler 
246*16a497c6SRafael Auler /// Write number Num using Base to the buffer in OutBuf, returns a pointer to
247*16a497c6SRafael Auler /// the end of the string.
248cc4b2fb6SRafael Auler char *intToStr(char *OutBuf, uint64_t Num, uint32_t Base) {
24962aa74f8SRafael Auler   const char *Chars = "0123456789abcdef";
250cc4b2fb6SRafael Auler   char Buf[21];
25162aa74f8SRafael Auler   char *Ptr = Buf;
25262aa74f8SRafael Auler   while (Num) {
25362aa74f8SRafael Auler     *Ptr++ = *(Chars + (Num % Base));
25462aa74f8SRafael Auler     Num /= Base;
25562aa74f8SRafael Auler   }
25662aa74f8SRafael Auler   if (Ptr == Buf) {
25762aa74f8SRafael Auler     *OutBuf++ = '0';
25862aa74f8SRafael Auler     return OutBuf;
25962aa74f8SRafael Auler   }
26062aa74f8SRafael Auler   while (Ptr != Buf) {
26162aa74f8SRafael Auler     *OutBuf++ = *--Ptr;
26262aa74f8SRafael Auler   }
26362aa74f8SRafael Auler   return OutBuf;
26462aa74f8SRafael Auler }
26562aa74f8SRafael Auler 
266*16a497c6SRafael Auler /// Copy Str to OutBuf, returns a pointer to the end of the copied string
267cc4b2fb6SRafael Auler char *strCopy(char *OutBuf, const char *Str, int32_t Size = BufSize) {
268cc4b2fb6SRafael Auler   while (*Str) {
269821480d2SRafael Auler     *OutBuf++ = *Str++;
270cc4b2fb6SRafael Auler     if (--Size <= 0)
271cc4b2fb6SRafael Auler       return OutBuf;
272cc4b2fb6SRafael Auler   }
273821480d2SRafael Auler   return OutBuf;
274821480d2SRafael Auler }
275821480d2SRafael Auler 
276cc4b2fb6SRafael Auler void memSet(char *Buf, char C, uint32_t Size) {
277cc4b2fb6SRafael Auler   for (int I = 0; I < Size; ++I)
278cc4b2fb6SRafael Auler     *Buf++ = C;
279cc4b2fb6SRafael Auler }
280cc4b2fb6SRafael Auler 
281cc4b2fb6SRafael Auler uint32_t strLen(const char *Str) {
282cc4b2fb6SRafael Auler   uint32_t Size = 0;
283cc4b2fb6SRafael Auler   while (*Str++)
284cc4b2fb6SRafael Auler     ++Size;
285cc4b2fb6SRafael Auler   return Size;
286cc4b2fb6SRafael Auler }
287cc4b2fb6SRafael Auler 
288cc4b2fb6SRafael Auler void reportError(const char *Msg, uint64_t Size) {
289821480d2SRafael Auler   __write(2, Msg, Size);
290821480d2SRafael Auler   __exit(1);
291821480d2SRafael Auler }
292821480d2SRafael Auler 
293cc4b2fb6SRafael Auler void assert(bool Assertion, const char *Msg) {
294cc4b2fb6SRafael Auler   if (Assertion)
295cc4b2fb6SRafael Auler     return;
296cc4b2fb6SRafael Auler   char Buf[BufSize];
297cc4b2fb6SRafael Auler   char *Ptr = Buf;
298cc4b2fb6SRafael Auler   Ptr = strCopy(Ptr, "Assertion failed: ");
299cc4b2fb6SRafael Auler   Ptr = strCopy(Ptr, Msg, BufSize - 40);
300cc4b2fb6SRafael Auler   Ptr = strCopy(Ptr, "\n");
301cc4b2fb6SRafael Auler   reportError(Buf, Ptr - Buf);
302cc4b2fb6SRafael Auler }
303cc4b2fb6SRafael Auler 
304cc4b2fb6SRafael Auler void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
305cc4b2fb6SRafael Auler   char Buf[BufSize];
306cc4b2fb6SRafael Auler   char *Ptr = Buf;
307cc4b2fb6SRafael Auler   Ptr = strCopy(Ptr, Msg, BufSize - 23);
308cc4b2fb6SRafael Auler   Ptr = intToStr(Ptr, Num, Base);
309cc4b2fb6SRafael Auler   Ptr = strCopy(Ptr, "\n");
310cc4b2fb6SRafael Auler   __write(2, Buf, Ptr - Buf);
311cc4b2fb6SRafael Auler }
312cc4b2fb6SRafael Auler 
313cc4b2fb6SRafael Auler void report(const char *Msg) {
314cc4b2fb6SRafael Auler   __write(2, Msg, strLen(Msg));
315cc4b2fb6SRafael Auler }
316cc4b2fb6SRafael Auler 
317*16a497c6SRafael Auler /// 1B mutex accessed by lock xchg
318*16a497c6SRafael Auler class Mutex {
319*16a497c6SRafael Auler   volatile bool InUse{false};
320*16a497c6SRafael Auler public:
321*16a497c6SRafael Auler   bool acquire() {
322*16a497c6SRafael Auler     bool Result = true;
323*16a497c6SRafael Auler     asm volatile("lock; xchg %0, %1"
324*16a497c6SRafael Auler                  : "+m"(InUse), "=r"(Result)
325*16a497c6SRafael Auler                  :
326*16a497c6SRafael Auler                  : "cc");
327*16a497c6SRafael Auler     return !Result;
328*16a497c6SRafael Auler   }
329*16a497c6SRafael Auler   void release() {
330*16a497c6SRafael Auler     InUse = false;
331*16a497c6SRafael Auler   }
332*16a497c6SRafael Auler };
333*16a497c6SRafael Auler 
334*16a497c6SRafael Auler /// RAII wrapper for Mutex
335*16a497c6SRafael Auler class Lock {
336*16a497c6SRafael Auler   Mutex &M;
337*16a497c6SRafael Auler public:
338*16a497c6SRafael Auler   Lock(Mutex &M) : M(M) {
339*16a497c6SRafael Auler     while (!M.acquire()) {}
340*16a497c6SRafael Auler   }
341*16a497c6SRafael Auler   ~Lock() {
342*16a497c6SRafael Auler     M.release();
343*16a497c6SRafael Auler   }
344*16a497c6SRafael Auler };
345*16a497c6SRafael Auler 
346cc4b2fb6SRafael Auler inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
347cc4b2fb6SRafael Auler   return (Value + Align - 1) / Align * Align;
348cc4b2fb6SRafael Auler }
349cc4b2fb6SRafael Auler 
350cc4b2fb6SRafael Auler /// A simple allocator that mmaps a fixed size region and manages this space
351cc4b2fb6SRafael Auler /// in a stack fashion, meaning you always deallocate the last element that
352*16a497c6SRafael Auler /// was allocated. In practice, we don't need to deallocate individual elements.
353*16a497c6SRafael Auler /// We monotonically increase our usage and then deallocate everything once we
354*16a497c6SRafael Auler /// are done processing something.
355cc4b2fb6SRafael Auler class BumpPtrAllocator {
356*16a497c6SRafael Auler   /// This is written before each allocation and act as a canary to detect when
357*16a497c6SRafael Auler   /// a bug caused our program to cross allocation boundaries.
358cc4b2fb6SRafael Auler   struct EntryMetadata {
359cc4b2fb6SRafael Auler     uint64_t Magic;
360cc4b2fb6SRafael Auler     uint64_t AllocSize;
361cc4b2fb6SRafael Auler   };
362cc4b2fb6SRafael Auler public:
363cc4b2fb6SRafael Auler   void *allocate(uintptr_t Size) {
364*16a497c6SRafael Auler     Lock L(M);
365cc4b2fb6SRafael Auler     if (StackBase == nullptr) {
366*16a497c6SRafael Auler       StackBase = reinterpret_cast<uint8_t *>(
367*16a497c6SRafael Auler           __mmap(0, MaxSize, 0x3 /* PROT_READ | PROT_WRITE*/,
368*16a497c6SRafael Auler                  Shared ? 0x21 /*MAP_SHARED | MAP_ANONYMOUS*/
369*16a497c6SRafael Auler                         : 0x22 /* MAP_PRIVATE | MAP_ANONYMOUS*/,
370*16a497c6SRafael Auler                  -1, 0));
371cc4b2fb6SRafael Auler       StackSize = 0;
372cc4b2fb6SRafael Auler     }
373cc4b2fb6SRafael Auler     Size = alignTo(Size + sizeof(EntryMetadata), 16);
374cc4b2fb6SRafael Auler     uint8_t * AllocAddress = StackBase + StackSize + sizeof(EntryMetadata);
375cc4b2fb6SRafael Auler     auto *M = reinterpret_cast<EntryMetadata *>(StackBase + StackSize);
376*16a497c6SRafael Auler     M->Magic = Magic;
377cc4b2fb6SRafael Auler     M->AllocSize = Size;
378cc4b2fb6SRafael Auler     StackSize += Size;
379*16a497c6SRafael Auler     assert(StackSize < MaxSize, "allocator ran out of memory");
380cc4b2fb6SRafael Auler     return AllocAddress;
381cc4b2fb6SRafael Auler   }
382cc4b2fb6SRafael Auler 
383*16a497c6SRafael Auler #ifdef DEBUG
384*16a497c6SRafael Auler   /// Element-wise deallocation is only used for debugging to catch memory
385*16a497c6SRafael Auler   /// bugs by checking magic bytes. Ordinarily, we reset the allocator once
386*16a497c6SRafael Auler   /// we are done with it. Reset is done with clear(). There's no need
387*16a497c6SRafael Auler   /// to deallocate each element individually.
388cc4b2fb6SRafael Auler   void deallocate(void *Ptr) {
389*16a497c6SRafael Auler     Lock L(M);
390cc4b2fb6SRafael Auler     uint8_t MetadataOffset = sizeof(EntryMetadata);
391cc4b2fb6SRafael Auler     auto *M = reinterpret_cast<EntryMetadata *>(
392cc4b2fb6SRafael Auler         reinterpret_cast<uint8_t *>(Ptr) - MetadataOffset);
393cc4b2fb6SRafael Auler     const uint8_t *StackTop = StackBase + StackSize + MetadataOffset;
394cc4b2fb6SRafael Auler     // Validate size
395cc4b2fb6SRafael Auler     if (Ptr != StackTop - M->AllocSize) {
396*16a497c6SRafael Auler       // Failed validation, check if it is a pointer returned by operator new []
397cc4b2fb6SRafael Auler       MetadataOffset +=
398cc4b2fb6SRafael Auler           sizeof(uint64_t); // Space for number of elements alloc'ed
399cc4b2fb6SRafael Auler       M = reinterpret_cast<EntryMetadata *>(reinterpret_cast<uint8_t *>(Ptr) -
400cc4b2fb6SRafael Auler                                             MetadataOffset);
401*16a497c6SRafael Auler       // Ok, it failed both checks if this assertion fails. Stop the program, we
402*16a497c6SRafael Auler       // have a memory bug.
403cc4b2fb6SRafael Auler       assert(Ptr == StackTop - M->AllocSize,
404cc4b2fb6SRafael Auler              "must deallocate the last element alloc'ed");
405cc4b2fb6SRafael Auler     }
406*16a497c6SRafael Auler     assert(M->Magic == Magic, "allocator magic is corrupt");
407cc4b2fb6SRafael Auler     StackSize -= M->AllocSize;
408cc4b2fb6SRafael Auler   }
409*16a497c6SRafael Auler #else
410*16a497c6SRafael Auler   void deallocate(void *) {}
411*16a497c6SRafael Auler #endif
412*16a497c6SRafael Auler 
413*16a497c6SRafael Auler   void clear() {
414*16a497c6SRafael Auler     Lock L(M);
415*16a497c6SRafael Auler     StackSize = 0;
416*16a497c6SRafael Auler   }
417*16a497c6SRafael Auler 
418*16a497c6SRafael Auler   /// Set mmap reservation size (only relevant before first allocation)
419*16a497c6SRafael Auler   void setMaxSize(uint64_t Size) {
420*16a497c6SRafael Auler     MaxSize = Size;
421*16a497c6SRafael Auler   }
422*16a497c6SRafael Auler 
423*16a497c6SRafael Auler   /// Set mmap reservation privacy (only relevant before first allocation)
424*16a497c6SRafael Auler   void setShared(bool S) {
425*16a497c6SRafael Auler     Shared = S;
426*16a497c6SRafael Auler   }
427*16a497c6SRafael Auler 
428*16a497c6SRafael Auler   void destroy() {
429*16a497c6SRafael Auler     if (StackBase == nullptr)
430*16a497c6SRafael Auler       return;
431*16a497c6SRafael Auler     __munmap(StackBase, MaxSize);
432*16a497c6SRafael Auler   }
433cc4b2fb6SRafael Auler 
434cc4b2fb6SRafael Auler private:
435*16a497c6SRafael Auler   static constexpr uint64_t Magic = 0x1122334455667788ull;
436*16a497c6SRafael Auler   uint64_t MaxSize = 0xa00000;
437cc4b2fb6SRafael Auler   uint8_t *StackBase{nullptr};
438cc4b2fb6SRafael Auler   uint64_t StackSize{0};
439*16a497c6SRafael Auler   bool Shared{false};
440*16a497c6SRafael Auler   Mutex M;
441cc4b2fb6SRafael Auler };
442cc4b2fb6SRafael Auler 
443*16a497c6SRafael Auler /// Used for allocating indirect call instrumentation counters. Initialized by
444*16a497c6SRafael Auler /// __bolt_instr_setup, our initialization routine.
445*16a497c6SRafael Auler BumpPtrAllocator GlobalAlloc;
446*16a497c6SRafael Auler 
447cc4b2fb6SRafael Auler } // anonymous namespace
448cc4b2fb6SRafael Auler 
449cc4b2fb6SRafael Auler // User-defined placement new operators. We only use those (as opposed to
450cc4b2fb6SRafael Auler // overriding the regular operator new) so we can keep our allocator in the
451cc4b2fb6SRafael Auler // stack instead of in a data section (global).
452cc4b2fb6SRafael Auler void *operator new(uintptr_t Sz, BumpPtrAllocator &A) {
453cc4b2fb6SRafael Auler   return A.allocate(Sz);
454cc4b2fb6SRafael Auler }
455cc4b2fb6SRafael Auler void *operator new(uintptr_t Sz, BumpPtrAllocator &A, char C) {
456cc4b2fb6SRafael Auler   auto *Ptr = reinterpret_cast<char *>(A.allocate(Sz));
457cc4b2fb6SRafael Auler   memSet(Ptr, C, Sz);
458cc4b2fb6SRafael Auler   return Ptr;
459cc4b2fb6SRafael Auler }
460cc4b2fb6SRafael Auler void *operator new[](uintptr_t Sz, BumpPtrAllocator &A) {
461cc4b2fb6SRafael Auler   return A.allocate(Sz);
462cc4b2fb6SRafael Auler }
463cc4b2fb6SRafael Auler void *operator new[](uintptr_t Sz, BumpPtrAllocator &A, char C) {
464cc4b2fb6SRafael Auler   auto *Ptr = reinterpret_cast<char *>(A.allocate(Sz));
465cc4b2fb6SRafael Auler   memSet(Ptr, C, Sz);
466cc4b2fb6SRafael Auler   return Ptr;
467cc4b2fb6SRafael Auler }
468cc4b2fb6SRafael Auler // Only called during exception unwinding (useless). We must manually dealloc.
469cc4b2fb6SRafael Auler // C++ language weirdness
470cc4b2fb6SRafael Auler void operator delete(void *Ptr, BumpPtrAllocator &A) {
471cc4b2fb6SRafael Auler   A.deallocate(Ptr);
472cc4b2fb6SRafael Auler }
473cc4b2fb6SRafael Auler 
474cc4b2fb6SRafael Auler namespace {
475cc4b2fb6SRafael Auler 
476*16a497c6SRafael Auler /// Basic key-val atom stored in our hash
477*16a497c6SRafael Auler struct SimpleHashTableEntryBase {
478*16a497c6SRafael Auler   uint64_t Key;
479*16a497c6SRafael Auler   uint64_t Val;
480*16a497c6SRafael Auler };
481*16a497c6SRafael Auler 
482*16a497c6SRafael Auler /// This hash table implementation starts by allocating a table of size
483*16a497c6SRafael Auler /// InitialSize. When conflicts happen in this main table, it resolves
484*16a497c6SRafael Auler /// them by chaining a new table of size IncSize. It never reallocs as our
485*16a497c6SRafael Auler /// allocator doesn't support it. The key is intended to be function pointers.
486*16a497c6SRafael Auler /// There's no clever hash function (it's just x mod size, size being prime).
487*16a497c6SRafael Auler /// I never tuned the coefficientes in the modular equation (TODO)
488*16a497c6SRafael Auler /// This is used for indirect calls (each call site has one of this, so it
489*16a497c6SRafael Auler /// should have a small footprint) and for tallying call counts globally for
490*16a497c6SRafael Auler /// each target to check if we missed the origin of some calls (this one is a
491*16a497c6SRafael Auler /// large instantiation of this template, since it is global for all call sites)
492*16a497c6SRafael Auler template <typename T = SimpleHashTableEntryBase, uint32_t InitialSize = 7,
493*16a497c6SRafael Auler           uint32_t IncSize = 7>
494*16a497c6SRafael Auler class SimpleHashTable {
495*16a497c6SRafael Auler public:
496*16a497c6SRafael Auler   using MapEntry = T;
497*16a497c6SRafael Auler 
498*16a497c6SRafael Auler   /// Increment by 1 the value of \p Key. If it is not in this table, it will be
499*16a497c6SRafael Auler   /// added to the table and its value set to 1.
500*16a497c6SRafael Auler   void incrementVal(uint64_t Key, BumpPtrAllocator &Alloc) {
501*16a497c6SRafael Auler     ++get(Key, Alloc).Val;
502*16a497c6SRafael Auler   }
503*16a497c6SRafael Auler 
504*16a497c6SRafael Auler   /// Basic member accessing interface. Here we pass the allocator explicitly to
505*16a497c6SRafael Auler   /// avoid storing a pointer to it as part of this table (remember there is one
506*16a497c6SRafael Auler   /// hash for each indirect call site, so we wan't to minimize our footprint).
507*16a497c6SRafael Auler   MapEntry &get(uint64_t Key, BumpPtrAllocator &Alloc) {
508*16a497c6SRafael Auler     Lock L(M);
509*16a497c6SRafael Auler     if (TableRoot)
510*16a497c6SRafael Auler       return getEntry(TableRoot, Key, Key, Alloc, 0);
511*16a497c6SRafael Auler     return firstAllocation(Key, Alloc);
512*16a497c6SRafael Auler   }
513*16a497c6SRafael Auler 
514*16a497c6SRafael Auler   /// Traverses all elements in the table
515*16a497c6SRafael Auler   template <typename... Args>
516*16a497c6SRafael Auler   void forEachElement(void (*Callback)(MapEntry &, Args...), Args... args) {
517*16a497c6SRafael Auler     if (!TableRoot)
518*16a497c6SRafael Auler       return;
519*16a497c6SRafael Auler     return forEachElement(Callback, InitialSize, TableRoot, args...);
520*16a497c6SRafael Auler   }
521*16a497c6SRafael Auler 
522*16a497c6SRafael Auler   void resetCounters();
523*16a497c6SRafael Auler 
524*16a497c6SRafael Auler private:
525*16a497c6SRafael Auler   constexpr static uint64_t VacantMarker = 0;
526*16a497c6SRafael Auler   constexpr static uint64_t FollowUpTableMarker = 0x8000000000000000ull;
527*16a497c6SRafael Auler 
528*16a497c6SRafael Auler   MapEntry *TableRoot{nullptr};
529*16a497c6SRafael Auler   Mutex M;
530*16a497c6SRafael Auler 
531*16a497c6SRafael Auler   template <typename... Args>
532*16a497c6SRafael Auler   void forEachElement(void (*Callback)(MapEntry &, Args...),
533*16a497c6SRafael Auler                       uint32_t NumEntries, MapEntry *Entries, Args... args) {
534*16a497c6SRafael Auler     for (int I = 0; I < NumEntries; ++I) {
535*16a497c6SRafael Auler       auto &Entry = Entries[I];
536*16a497c6SRafael Auler       if (Entry.Key == VacantMarker)
537*16a497c6SRafael Auler         continue;
538*16a497c6SRafael Auler       if (Entry.Key & FollowUpTableMarker) {
539*16a497c6SRafael Auler         forEachElement(Callback, IncSize,
540*16a497c6SRafael Auler                        reinterpret_cast<MapEntry *>(Entry.Key &
541*16a497c6SRafael Auler                                                     ~FollowUpTableMarker),
542*16a497c6SRafael Auler                        args...);
543*16a497c6SRafael Auler         continue;
544*16a497c6SRafael Auler       }
545*16a497c6SRafael Auler       Callback(Entry, args...);
546*16a497c6SRafael Auler     }
547*16a497c6SRafael Auler   }
548*16a497c6SRafael Auler 
549*16a497c6SRafael Auler   MapEntry &firstAllocation(uint64_t Key, BumpPtrAllocator &Alloc) {
550*16a497c6SRafael Auler     TableRoot = new (Alloc, 0) MapEntry[InitialSize];
551*16a497c6SRafael Auler     auto &Entry = TableRoot[Key % InitialSize];
552*16a497c6SRafael Auler     Entry.Key = Key;
553*16a497c6SRafael Auler     return Entry;
554*16a497c6SRafael Auler   }
555*16a497c6SRafael Auler 
556*16a497c6SRafael Auler   MapEntry &getEntry(MapEntry *Entries, uint64_t Key, uint64_t Selector,
557*16a497c6SRafael Auler                      BumpPtrAllocator &Alloc, int CurLevel) {
558*16a497c6SRafael Auler     const uint32_t NumEntries = CurLevel == 0 ? InitialSize : IncSize;
559*16a497c6SRafael Auler     uint64_t Remainder = Selector / NumEntries;
560*16a497c6SRafael Auler     Selector = Selector % NumEntries;
561*16a497c6SRafael Auler     auto &Entry = Entries[Selector];
562*16a497c6SRafael Auler 
563*16a497c6SRafael Auler     // A hit
564*16a497c6SRafael Auler     if (Entry.Key == Key) {
565*16a497c6SRafael Auler       return Entry;
566*16a497c6SRafael Auler     }
567*16a497c6SRafael Auler 
568*16a497c6SRafael Auler     // Vacant - add new entry
569*16a497c6SRafael Auler     if (Entry.Key == VacantMarker) {
570*16a497c6SRafael Auler       Entry.Key = Key;
571*16a497c6SRafael Auler       return Entry;
572*16a497c6SRafael Auler     }
573*16a497c6SRafael Auler 
574*16a497c6SRafael Auler     // Defer to the next level
575*16a497c6SRafael Auler     if (Entry.Key & FollowUpTableMarker) {
576*16a497c6SRafael Auler       return getEntry(
577*16a497c6SRafael Auler           reinterpret_cast<MapEntry *>(Entry.Key & ~FollowUpTableMarker),
578*16a497c6SRafael Auler           Key, Remainder, Alloc, CurLevel + 1);
579*16a497c6SRafael Auler     }
580*16a497c6SRafael Auler 
581*16a497c6SRafael Auler     // Conflict - create the next level
582*16a497c6SRafael Auler     MapEntry *NextLevelTbl = new (Alloc, 0) MapEntry[IncSize];
583*16a497c6SRafael Auler     uint64_t CurEntrySelector = Entry.Key / InitialSize;
584*16a497c6SRafael Auler     for (int I = 0; I < CurLevel; ++I)
585*16a497c6SRafael Auler       CurEntrySelector /= IncSize;
586*16a497c6SRafael Auler     CurEntrySelector = CurEntrySelector % IncSize;
587*16a497c6SRafael Auler     NextLevelTbl[CurEntrySelector] = Entry;
588*16a497c6SRafael Auler     Entry.Key = reinterpret_cast<uint64_t>(NextLevelTbl) | FollowUpTableMarker;
589*16a497c6SRafael Auler     return getEntry(NextLevelTbl, Key, Remainder, Alloc, CurLevel + 1);
590*16a497c6SRafael Auler   }
591*16a497c6SRafael Auler };
592*16a497c6SRafael Auler 
593*16a497c6SRafael Auler template <typename T> void resetIndCallCounter(T &Entry) {
594*16a497c6SRafael Auler   Entry.Val = 0;
595*16a497c6SRafael Auler }
596*16a497c6SRafael Auler 
597*16a497c6SRafael Auler template <typename T, uint32_t X, uint32_t Y>
598*16a497c6SRafael Auler void SimpleHashTable<T, X, Y>::resetCounters() {
599*16a497c6SRafael Auler   Lock L(M);
600*16a497c6SRafael Auler   forEachElement(resetIndCallCounter);
601*16a497c6SRafael Auler }
602*16a497c6SRafael Auler 
603*16a497c6SRafael Auler /// Represents a hash table mapping a function target address to its counter.
604*16a497c6SRafael Auler using IndirectCallHashTable = SimpleHashTable<>;
605*16a497c6SRafael Auler 
606*16a497c6SRafael Auler /// Initialize with number 1 instead of 0 so we don't go into .bss. This is the
607*16a497c6SRafael Auler /// global array of all hash tables storing indirect call destinations happening
608*16a497c6SRafael Auler /// during runtime, one table per call site.
609*16a497c6SRafael Auler IndirectCallHashTable *GlobalIndCallCounters{
610*16a497c6SRafael Auler     reinterpret_cast<IndirectCallHashTable *>(1)};
611*16a497c6SRafael Auler 
612*16a497c6SRafael Auler /// Don't allow reentrancy in the fdata writing phase - only one thread writes
613*16a497c6SRafael Auler /// it
614*16a497c6SRafael Auler Mutex *GlobalWriteProfileMutex{reinterpret_cast<Mutex *>(1)};
615*16a497c6SRafael Auler 
616*16a497c6SRafael Auler /// Store number of calls in additional to target address (Key) and frequency
617*16a497c6SRafael Auler /// as perceived by the basic block counter (Val).
618*16a497c6SRafael Auler struct CallFlowEntryBase : public SimpleHashTableEntryBase {
619*16a497c6SRafael Auler   uint64_t Calls;
620*16a497c6SRafael Auler };
621*16a497c6SRafael Auler 
622*16a497c6SRafael Auler using CallFlowHashTableBase = SimpleHashTable<CallFlowEntryBase, 11939, 233>;
623*16a497c6SRafael Auler 
624*16a497c6SRafael Auler /// This is a large table indexing all possible call targets (indirect and
625*16a497c6SRafael Auler /// direct ones). The goal is to find mismatches between number of calls (for
626*16a497c6SRafael Auler /// those calls we were able to track) and the entry basic block counter of the
627*16a497c6SRafael Auler /// callee. In most cases, these two should be equal. If not, there are two
628*16a497c6SRafael Auler /// possible scenarios here:
629*16a497c6SRafael Auler ///
630*16a497c6SRafael Auler ///  * Entry BB has higher frequency than all known calls to this function.
631*16a497c6SRafael Auler ///    In this case, we have dynamic library code or any uninstrumented code
632*16a497c6SRafael Auler ///    calling this function. We will write the profile for these untracked
633*16a497c6SRafael Auler ///    calls as having source "0 [unknown] 0" in the fdata file.
634*16a497c6SRafael Auler ///
635*16a497c6SRafael Auler ///  * Number of known calls is higher than the frequency of entry BB
636*16a497c6SRafael Auler ///    This only happens when there is no counter for the entry BB / callee
637*16a497c6SRafael Auler ///    function is not simple (in BOLT terms). We don't do anything special
638*16a497c6SRafael Auler ///    here and just ignore those (we still report all calls to the non-simple
639*16a497c6SRafael Auler ///    function, though).
640*16a497c6SRafael Auler ///
641*16a497c6SRafael Auler class CallFlowHashTable : public CallFlowHashTableBase {
642*16a497c6SRafael Auler public:
643*16a497c6SRafael Auler   CallFlowHashTable(BumpPtrAllocator &Alloc) : Alloc(Alloc) {}
644*16a497c6SRafael Auler 
645*16a497c6SRafael Auler   MapEntry &get(uint64_t Key) { return CallFlowHashTableBase::get(Key, Alloc); }
646*16a497c6SRafael Auler 
647*16a497c6SRafael Auler private:
648*16a497c6SRafael Auler   // Different than the hash table for indirect call targets, we do store the
649*16a497c6SRafael Auler   // allocator here since there is only one call flow hash and space overhead
650*16a497c6SRafael Auler   // is negligible.
651*16a497c6SRafael Auler   BumpPtrAllocator &Alloc;
652*16a497c6SRafael Auler };
653*16a497c6SRafael Auler 
654*16a497c6SRafael Auler ///
655*16a497c6SRafael Auler /// Description metadata emitted by BOLT to describe the program - refer to
656*16a497c6SRafael Auler /// Passes/Instrumentation.cpp - Instrumentation::emitTablesAsELFNote()
657*16a497c6SRafael Auler ///
658*16a497c6SRafael Auler struct Location {
659*16a497c6SRafael Auler   uint32_t FunctionName;
660*16a497c6SRafael Auler   uint32_t Offset;
661*16a497c6SRafael Auler };
662*16a497c6SRafael Auler 
663*16a497c6SRafael Auler struct CallDescription {
664*16a497c6SRafael Auler   Location From;
665*16a497c6SRafael Auler   uint32_t FromNode;
666*16a497c6SRafael Auler   Location To;
667*16a497c6SRafael Auler   uint32_t Counter;
668*16a497c6SRafael Auler   uint64_t TargetAddress;
669*16a497c6SRafael Auler };
670*16a497c6SRafael Auler 
671*16a497c6SRafael Auler using IndCallDescription = Location;
672*16a497c6SRafael Auler 
673*16a497c6SRafael Auler struct IndCallTargetDescription {
674*16a497c6SRafael Auler   Location Loc;
675*16a497c6SRafael Auler   uint64_t Address;
676*16a497c6SRafael Auler };
677*16a497c6SRafael Auler 
678*16a497c6SRafael Auler struct EdgeDescription {
679*16a497c6SRafael Auler   Location From;
680*16a497c6SRafael Auler   uint32_t FromNode;
681*16a497c6SRafael Auler   Location To;
682*16a497c6SRafael Auler   uint32_t ToNode;
683*16a497c6SRafael Auler   uint32_t Counter;
684*16a497c6SRafael Auler };
685*16a497c6SRafael Auler 
686*16a497c6SRafael Auler struct InstrumentedNode {
687*16a497c6SRafael Auler   uint32_t Node;
688*16a497c6SRafael Auler   uint32_t Counter;
689*16a497c6SRafael Auler };
690*16a497c6SRafael Auler 
691*16a497c6SRafael Auler struct EntryNode {
692*16a497c6SRafael Auler   uint64_t Node;
693*16a497c6SRafael Auler   uint64_t Address;
694*16a497c6SRafael Auler };
695*16a497c6SRafael Auler 
696*16a497c6SRafael Auler struct FunctionDescription {
697*16a497c6SRafael Auler   uint32_t NumLeafNodes;
698*16a497c6SRafael Auler   const InstrumentedNode *LeafNodes;
699*16a497c6SRafael Auler   uint32_t NumEdges;
700*16a497c6SRafael Auler   const EdgeDescription *Edges;
701*16a497c6SRafael Auler   uint32_t NumCalls;
702*16a497c6SRafael Auler   const CallDescription *Calls;
703*16a497c6SRafael Auler   uint32_t NumEntryNodes;
704*16a497c6SRafael Auler   const EntryNode *EntryNodes;
705*16a497c6SRafael Auler 
706*16a497c6SRafael Auler   /// Constructor will parse the serialized function metadata written by BOLT
707*16a497c6SRafael Auler   FunctionDescription(const uint8_t *FuncDesc);
708*16a497c6SRafael Auler 
709*16a497c6SRafael Auler   uint64_t getSize() const {
710*16a497c6SRafael Auler     return 16 + NumLeafNodes * sizeof(InstrumentedNode) +
711*16a497c6SRafael Auler            NumEdges * sizeof(EdgeDescription) +
712*16a497c6SRafael Auler            NumCalls * sizeof(CallDescription) +
713*16a497c6SRafael Auler            NumEntryNodes * sizeof(EntryNode);
714*16a497c6SRafael Auler   }
715*16a497c6SRafael Auler };
716*16a497c6SRafael Auler 
717*16a497c6SRafael Auler /// The context is created when the fdata profile needs to be written to disk
718*16a497c6SRafael Auler /// and we need to interpret our runtime counters. It contains pointers to the
719*16a497c6SRafael Auler /// mmaped binary (only the BOLT written metadata section). Deserialization
720*16a497c6SRafael Auler /// should be straightforward as most data is POD or an array of POD elements.
721*16a497c6SRafael Auler /// This metadata is used to reconstruct function CFGs.
722*16a497c6SRafael Auler struct ProfileWriterContext {
723*16a497c6SRafael Auler   IndCallDescription *IndCallDescriptions;
724*16a497c6SRafael Auler   IndCallTargetDescription *IndCallTargets;
725*16a497c6SRafael Auler   uint8_t *FuncDescriptions;
726*16a497c6SRafael Auler   char *Strings;  // String table with function names used in this binary
727*16a497c6SRafael Auler   int FileDesc;   // File descriptor for the file on disk backing this
728*16a497c6SRafael Auler                   // information in memory via mmap
729*16a497c6SRafael Auler   void *MMapPtr;  // The mmap ptr
730*16a497c6SRafael Auler   int MMapSize;   // The mmap size
731*16a497c6SRafael Auler 
732*16a497c6SRafael Auler   /// Hash table storing all possible call destinations to detect untracked
733*16a497c6SRafael Auler   /// calls and correctly report them as [unknown] in output fdata.
734*16a497c6SRafael Auler   CallFlowHashTable *CallFlowTable;
735*16a497c6SRafael Auler 
736*16a497c6SRafael Auler   /// Lookup the sorted indirect call target vector to fetch function name and
737*16a497c6SRafael Auler   /// offset for an arbitrary function pointer.
738*16a497c6SRafael Auler   const IndCallTargetDescription *lookupIndCallTarget(uint64_t Target) const;
739*16a497c6SRafael Auler };
740*16a497c6SRafael Auler 
741*16a497c6SRafael Auler /// Perform a string comparison and returns zero if Str1 matches Str2. Compares
742*16a497c6SRafael Auler /// at most Size characters.
743cc4b2fb6SRafael Auler int compareStr(const char *Str1, const char *Str2, int Size) {
744821480d2SRafael Auler   while (*Str1 == *Str2) {
745821480d2SRafael Auler     if (*Str1 == '\0' || --Size == 0)
746821480d2SRafael Auler       return 0;
747821480d2SRafael Auler     ++Str1;
748821480d2SRafael Auler     ++Str2;
749821480d2SRafael Auler   }
750821480d2SRafael Auler   return 1;
751821480d2SRafael Auler }
752821480d2SRafael Auler 
753*16a497c6SRafael Auler /// Output Location to the fdata file
754*16a497c6SRafael Auler char *serializeLoc(const ProfileWriterContext &Ctx, char *OutBuf,
755cc4b2fb6SRafael Auler                    const Location Loc, uint32_t BufSize) {
756821480d2SRafael Auler   // fdata location format: Type Name Offset
757821480d2SRafael Auler   // Type 1 - regular symbol
758821480d2SRafael Auler   OutBuf = strCopy(OutBuf, "1 ");
759*16a497c6SRafael Auler   const char *Str = Ctx.Strings + Loc.FunctionName;
760cc4b2fb6SRafael Auler   uint32_t Size = 25;
76162aa74f8SRafael Auler   while (*Str) {
76262aa74f8SRafael Auler     *OutBuf++ = *Str++;
763cc4b2fb6SRafael Auler     if (++Size >= BufSize)
764cc4b2fb6SRafael Auler       break;
76562aa74f8SRafael Auler   }
766cc4b2fb6SRafael Auler   assert(!*Str, "buffer overflow, function name too large");
76762aa74f8SRafael Auler   *OutBuf++ = ' ';
768821480d2SRafael Auler   OutBuf = intToStr(OutBuf, Loc.Offset, 16);
76962aa74f8SRafael Auler   *OutBuf++ = ' ';
77062aa74f8SRafael Auler   return OutBuf;
77162aa74f8SRafael Auler }
77262aa74f8SRafael Auler 
773*16a497c6SRafael Auler /// Read and deserialize a function description written by BOLT. \p FuncDesc
774*16a497c6SRafael Auler /// points at the beginning of the function metadata structure in the file.
775*16a497c6SRafael Auler /// See Instrumentation::emitTablesAsELFNote()
776*16a497c6SRafael Auler FunctionDescription::FunctionDescription(const uint8_t *FuncDesc) {
777*16a497c6SRafael Auler   NumLeafNodes = *reinterpret_cast<const uint32_t *>(FuncDesc);
778*16a497c6SRafael Auler   DEBUG(reportNumber("NumLeafNodes = ", NumLeafNodes, 10));
779*16a497c6SRafael Auler   LeafNodes = reinterpret_cast<const InstrumentedNode *>(FuncDesc + 4);
780*16a497c6SRafael Auler 
781*16a497c6SRafael Auler   NumEdges = *reinterpret_cast<const uint32_t *>(
782*16a497c6SRafael Auler       FuncDesc + 4 + NumLeafNodes * sizeof(InstrumentedNode));
783*16a497c6SRafael Auler   DEBUG(reportNumber("NumEdges = ", NumEdges, 10));
784*16a497c6SRafael Auler   Edges = reinterpret_cast<const EdgeDescription *>(
785*16a497c6SRafael Auler       FuncDesc + 8 + NumLeafNodes * sizeof(InstrumentedNode));
786*16a497c6SRafael Auler 
787*16a497c6SRafael Auler   NumCalls = *reinterpret_cast<const uint32_t *>(
788*16a497c6SRafael Auler       FuncDesc + 8 + NumLeafNodes * sizeof(InstrumentedNode) +
789*16a497c6SRafael Auler       NumEdges * sizeof(EdgeDescription));
790*16a497c6SRafael Auler   DEBUG(reportNumber("NumCalls = ", NumCalls, 10));
791*16a497c6SRafael Auler   Calls = reinterpret_cast<const CallDescription *>(
792*16a497c6SRafael Auler       FuncDesc + 12 + NumLeafNodes * sizeof(InstrumentedNode) +
793*16a497c6SRafael Auler       NumEdges * sizeof(EdgeDescription));
794*16a497c6SRafael Auler   NumEntryNodes = *reinterpret_cast<const uint32_t *>(
795*16a497c6SRafael Auler       FuncDesc + 12 + NumLeafNodes * sizeof(InstrumentedNode) +
796*16a497c6SRafael Auler       NumEdges * sizeof(EdgeDescription) + NumCalls * sizeof(CallDescription));
797*16a497c6SRafael Auler   DEBUG(reportNumber("NumEntryNodes = ", NumEntryNodes, 10));
798*16a497c6SRafael Auler   EntryNodes = reinterpret_cast<const EntryNode *>(
799*16a497c6SRafael Auler       FuncDesc + 16 + NumLeafNodes * sizeof(InstrumentedNode) +
800*16a497c6SRafael Auler       NumEdges * sizeof(EdgeDescription) + NumCalls * sizeof(CallDescription));
801*16a497c6SRafael Auler }
802*16a497c6SRafael Auler 
803*16a497c6SRafael Auler /// Read and mmap descriptions written by BOLT from the executable's notes
804*16a497c6SRafael Auler /// section
805ba31344fSRafael Auler #ifdef HAVE_ELF_H
806*16a497c6SRafael Auler ProfileWriterContext readDescriptions() {
807*16a497c6SRafael Auler   ProfileWriterContext Result;
808821480d2SRafael Auler   uint64_t FD = __open("/proc/self/exe",
809821480d2SRafael Auler                        /*flags=*/0 /*O_RDONLY*/,
810821480d2SRafael Auler                        /*mode=*/0666);
811cc4b2fb6SRafael Auler   assert(static_cast<int64_t>(FD) > 0, "Failed to open /proc/self/exe");
812821480d2SRafael Auler   Result.FileDesc = FD;
813821480d2SRafael Auler 
814821480d2SRafael Auler   // mmap our binary to memory
815821480d2SRafael Auler   uint64_t Size = __lseek(FD, 0, 2 /*SEEK_END*/);
816821480d2SRafael Auler   uint8_t *BinContents = reinterpret_cast<uint8_t *>(
817821480d2SRafael Auler       __mmap(0, Size, 0x1 /* PROT_READ*/, 0x2 /* MAP_PRIVATE*/, FD, 0));
818821480d2SRafael Auler   Result.MMapPtr = BinContents;
819821480d2SRafael Auler   Result.MMapSize = Size;
820821480d2SRafael Auler   Elf64_Ehdr *Hdr = reinterpret_cast<Elf64_Ehdr *>(BinContents);
821821480d2SRafael Auler   Elf64_Shdr *Shdr = reinterpret_cast<Elf64_Shdr *>(BinContents + Hdr->e_shoff);
822821480d2SRafael Auler   Elf64_Shdr *StringTblHeader = reinterpret_cast<Elf64_Shdr *>(
823821480d2SRafael Auler       BinContents + Hdr->e_shoff + Hdr->e_shstrndx * Hdr->e_shentsize);
824821480d2SRafael Auler 
825821480d2SRafael Auler   // Find .bolt.instr.tables with the data we need and set pointers to it
826821480d2SRafael Auler   for (int I = 0; I < Hdr->e_shnum; ++I) {
827821480d2SRafael Auler     char *SecName = reinterpret_cast<char *>(
828821480d2SRafael Auler         BinContents + StringTblHeader->sh_offset + Shdr->sh_name);
829821480d2SRafael Auler     if (compareStr(SecName, ".bolt.instr.tables", 64) != 0) {
830821480d2SRafael Auler       Shdr = reinterpret_cast<Elf64_Shdr *>(BinContents + Hdr->e_shoff +
831821480d2SRafael Auler                                             (I + 1) * Hdr->e_shentsize);
832821480d2SRafael Auler       continue;
833821480d2SRafael Auler     }
834821480d2SRafael Auler     // Actual contents of the ELF note start after offset 20 decimal:
835821480d2SRafael Auler     // Offset 0: Producer name size (4 bytes)
836821480d2SRafael Auler     // Offset 4: Contents size (4 bytes)
837821480d2SRafael Auler     // Offset 8: Note type (4 bytes)
838821480d2SRafael Auler     // Offset 12: Producer name (BOLT\0) (5 bytes + align to 4-byte boundary)
839821480d2SRafael Auler     // Offset 20: Contents
840*16a497c6SRafael Auler     uint32_t IndCallDescSize =
841cc4b2fb6SRafael Auler         *reinterpret_cast<uint32_t *>(BinContents + Shdr->sh_offset + 20);
842*16a497c6SRafael Auler     uint32_t IndCallTargetDescSize = *reinterpret_cast<uint32_t *>(
843*16a497c6SRafael Auler         BinContents + Shdr->sh_offset + 24 + IndCallDescSize);
844*16a497c6SRafael Auler     uint32_t FuncDescSize =
845*16a497c6SRafael Auler         *reinterpret_cast<uint32_t *>(BinContents + Shdr->sh_offset + 28 +
846*16a497c6SRafael Auler                                       IndCallDescSize + IndCallTargetDescSize);
847*16a497c6SRafael Auler     Result.IndCallDescriptions = reinterpret_cast<IndCallDescription *>(
848*16a497c6SRafael Auler         BinContents + Shdr->sh_offset + 24);
849*16a497c6SRafael Auler     Result.IndCallTargets = reinterpret_cast<IndCallTargetDescription *>(
850*16a497c6SRafael Auler         BinContents + Shdr->sh_offset + 28 + IndCallDescSize);
851*16a497c6SRafael Auler     Result.FuncDescriptions = BinContents + Shdr->sh_offset + 32 +
852*16a497c6SRafael Auler                               IndCallDescSize + IndCallTargetDescSize;
853*16a497c6SRafael Auler     Result.Strings = reinterpret_cast<char *>(
854*16a497c6SRafael Auler         BinContents + Shdr->sh_offset + 32 + IndCallDescSize +
855*16a497c6SRafael Auler         IndCallTargetDescSize + FuncDescSize);
856821480d2SRafael Auler     return Result;
857821480d2SRafael Auler   }
858821480d2SRafael Auler   const char ErrMsg[] =
859821480d2SRafael Auler       "BOLT instrumentation runtime error: could not find section "
860821480d2SRafael Auler       ".bolt.instr.tables\n";
861821480d2SRafael Auler   reportError(ErrMsg, sizeof(ErrMsg));
862821480d2SRafael Auler   return Result;
863821480d2SRafael Auler }
864ba31344fSRafael Auler #else
865*16a497c6SRafael Auler ProfileWriterContext readDescriptions() {
866*16a497c6SRafael Auler   ProfileWriterContext Result;
867ba31344fSRafael Auler   const char ErrMsg[] =
868ba31344fSRafael Auler     "BOLT instrumentation runtime error: unsupported binary format.\n";
869ba31344fSRafael Auler   reportError(ErrMsg, sizeof(ErrMsg));
870ba31344fSRafael Auler   return Result;
871ba31344fSRafael Auler }
872ba31344fSRafael Auler #endif
873821480d2SRafael Auler 
874*16a497c6SRafael Auler /// Debug by printing overall metadata global numbers to check it is sane
875*16a497c6SRafael Auler void printStats(const ProfileWriterContext &Ctx) {
876cc4b2fb6SRafael Auler   char StatMsg[BufSize];
877cc4b2fb6SRafael Auler   char *StatPtr = StatMsg;
878*16a497c6SRafael Auler   StatPtr =
879*16a497c6SRafael Auler       strCopy(StatPtr,
880*16a497c6SRafael Auler               "\nBOLT INSTRUMENTATION RUNTIME STATISTICS\n\nIndCallDescSize: ");
881cc4b2fb6SRafael Auler   StatPtr = intToStr(StatPtr,
882*16a497c6SRafael Auler                      Ctx.FuncDescriptions -
883*16a497c6SRafael Auler                          reinterpret_cast<uint8_t *>(Ctx.IndCallDescriptions),
884cc4b2fb6SRafael Auler                      10);
885cc4b2fb6SRafael Auler   StatPtr = strCopy(StatPtr, "\nFuncDescSize: ");
886cc4b2fb6SRafael Auler   StatPtr = intToStr(
887cc4b2fb6SRafael Auler       StatPtr,
888*16a497c6SRafael Auler       reinterpret_cast<uint8_t *>(Ctx.Strings) - Ctx.FuncDescriptions, 10);
889*16a497c6SRafael Auler   StatPtr = strCopy(StatPtr, "\n__bolt_instr_num_ind_calls: ");
890*16a497c6SRafael Auler   StatPtr = intToStr(StatPtr, __bolt_instr_num_ind_calls, 10);
891cc4b2fb6SRafael Auler   StatPtr = strCopy(StatPtr, "\n__bolt_instr_num_funcs: ");
892cc4b2fb6SRafael Auler   StatPtr = intToStr(StatPtr, __bolt_instr_num_funcs, 10);
893cc4b2fb6SRafael Auler   StatPtr = strCopy(StatPtr, "\n");
894cc4b2fb6SRafael Auler   __write(2, StatMsg, StatPtr - StatMsg);
895cc4b2fb6SRafael Auler }
896cc4b2fb6SRafael Auler 
897cc4b2fb6SRafael Auler /// This is part of a simple CFG representation in memory, where we store
898cc4b2fb6SRafael Auler /// a dynamically sized array of input and output edges per node, and store
899cc4b2fb6SRafael Auler /// a dynamically sized array of nodes per graph. We also store the spanning
900cc4b2fb6SRafael Auler /// tree edges for that CFG in a separate array of nodes in
901cc4b2fb6SRafael Auler /// \p SpanningTreeNodes, while the regular nodes live in \p CFGNodes.
902cc4b2fb6SRafael Auler struct Edge {
903cc4b2fb6SRafael Auler   uint32_t Node; // Index in nodes array regarding the destination of this edge
904cc4b2fb6SRafael Auler   uint32_t ID;   // Edge index in an array comprising all edges of the graph
905cc4b2fb6SRafael Auler };
906cc4b2fb6SRafael Auler 
907cc4b2fb6SRafael Auler /// A regular graph node or a spanning tree node
908cc4b2fb6SRafael Auler struct Node {
909cc4b2fb6SRafael Auler   uint32_t NumInEdges{0};  // Input edge count used to size InEdge
910cc4b2fb6SRafael Auler   uint32_t NumOutEdges{0}; // Output edge count used to size OutEdges
911cc4b2fb6SRafael Auler   Edge *InEdges{nullptr};  // Created and managed by \p Graph
912cc4b2fb6SRafael Auler   Edge *OutEdges{nullptr}; // ditto
913cc4b2fb6SRafael Auler };
914cc4b2fb6SRafael Auler 
915cc4b2fb6SRafael Auler /// Main class for CFG representation in memory. Manages object creation and
916cc4b2fb6SRafael Auler /// destruction, populates an array of CFG nodes as well as corresponding
917cc4b2fb6SRafael Auler /// spanning tree nodes.
918cc4b2fb6SRafael Auler struct Graph {
919cc4b2fb6SRafael Auler   uint32_t NumNodes;
920cc4b2fb6SRafael Auler   Node *CFGNodes;
921cc4b2fb6SRafael Auler   Node *SpanningTreeNodes;
922*16a497c6SRafael Auler   uint64_t *EdgeFreqs;
923*16a497c6SRafael Auler   uint64_t *CallFreqs;
924cc4b2fb6SRafael Auler   BumpPtrAllocator &Alloc;
925*16a497c6SRafael Auler   const FunctionDescription &D;
926cc4b2fb6SRafael Auler 
927*16a497c6SRafael Auler   /// Reads a list of edges from function description \p D and builds
928cc4b2fb6SRafael Auler   /// the graph from it. Allocates several internal dynamic structures that are
929*16a497c6SRafael Auler   /// later destroyed by ~Graph() and uses \p Alloc. D.LeafNodes contain all
930cc4b2fb6SRafael Auler   /// spanning tree leaf nodes descriptions (their counters). They are the seed
931cc4b2fb6SRafael Auler   /// used to compute the rest of the missing edge counts in a bottom-up
932cc4b2fb6SRafael Auler   /// traversal of the spanning tree.
933*16a497c6SRafael Auler   Graph(BumpPtrAllocator &Alloc, const FunctionDescription &D,
934*16a497c6SRafael Auler         const uint64_t *Counters, ProfileWriterContext &Ctx);
935cc4b2fb6SRafael Auler   ~Graph();
936cc4b2fb6SRafael Auler   void dump() const;
937*16a497c6SRafael Auler 
938*16a497c6SRafael Auler private:
939*16a497c6SRafael Auler   void computeEdgeFrequencies(const uint64_t *Counters,
940*16a497c6SRafael Auler                               ProfileWriterContext &Ctx);
941*16a497c6SRafael Auler   void dumpEdgeFreqs() const;
942cc4b2fb6SRafael Auler };
943cc4b2fb6SRafael Auler 
944*16a497c6SRafael Auler Graph::Graph(BumpPtrAllocator &Alloc, const FunctionDescription &D,
945*16a497c6SRafael Auler              const uint64_t *Counters, ProfileWriterContext &Ctx)
946*16a497c6SRafael Auler     : Alloc(Alloc), D(D) {
947cc4b2fb6SRafael Auler   DEBUG(reportNumber("G = 0x", (uint64_t)this, 16));
948cc4b2fb6SRafael Auler   // First pass to determine number of nodes
949*16a497c6SRafael Auler   int32_t MaxNodes = -1;
950*16a497c6SRafael Auler   CallFreqs = nullptr;
951*16a497c6SRafael Auler   EdgeFreqs = nullptr;
952*16a497c6SRafael Auler   for (int I = 0; I < D.NumEdges; ++I) {
953*16a497c6SRafael Auler     if (static_cast<int32_t>(D.Edges[I].FromNode) > MaxNodes)
954*16a497c6SRafael Auler       MaxNodes = D.Edges[I].FromNode;
955*16a497c6SRafael Auler     if (static_cast<int32_t>(D.Edges[I].ToNode) > MaxNodes)
956*16a497c6SRafael Auler       MaxNodes = D.Edges[I].ToNode;
957cc4b2fb6SRafael Auler   }
958*16a497c6SRafael Auler   for (int I = 0; I < D.NumLeafNodes; ++I) {
959*16a497c6SRafael Auler     if (static_cast<int32_t>(D.LeafNodes[I].Node) > MaxNodes)
960*16a497c6SRafael Auler       MaxNodes = D.LeafNodes[I].Node;
961cc4b2fb6SRafael Auler   }
962*16a497c6SRafael Auler   for (int I = 0; I < D.NumCalls; ++I) {
963*16a497c6SRafael Auler     if (static_cast<int32_t>(D.Calls[I].FromNode) > MaxNodes)
964*16a497c6SRafael Auler       MaxNodes = D.Calls[I].FromNode;
965*16a497c6SRafael Auler   }
966*16a497c6SRafael Auler   // No nodes? Nothing to do
967*16a497c6SRafael Auler   if (MaxNodes < 0) {
968*16a497c6SRafael Auler     DEBUG(report("No nodes!\n"));
969cc4b2fb6SRafael Auler     CFGNodes = nullptr;
970cc4b2fb6SRafael Auler     SpanningTreeNodes = nullptr;
971cc4b2fb6SRafael Auler     NumNodes = 0;
972cc4b2fb6SRafael Auler     return;
973cc4b2fb6SRafael Auler   }
974cc4b2fb6SRafael Auler   ++MaxNodes;
975cc4b2fb6SRafael Auler   DEBUG(reportNumber("NumNodes = ", MaxNodes, 10));
976*16a497c6SRafael Auler   NumNodes = static_cast<uint32_t>(MaxNodes);
977cc4b2fb6SRafael Auler 
978cc4b2fb6SRafael Auler   // Initial allocations
979cc4b2fb6SRafael Auler   CFGNodes = new (Alloc) Node[MaxNodes];
980cc4b2fb6SRafael Auler   DEBUG(reportNumber("G->CFGNodes = 0x", (uint64_t)CFGNodes, 16));
981cc4b2fb6SRafael Auler   SpanningTreeNodes = new (Alloc) Node[MaxNodes];
982cc4b2fb6SRafael Auler   DEBUG(reportNumber("G->SpanningTreeNodes = 0x",
983cc4b2fb6SRafael Auler                      (uint64_t)SpanningTreeNodes, 16));
984cc4b2fb6SRafael Auler 
985cc4b2fb6SRafael Auler   // Figure out how much to allocate to each vector (in/out edge sets)
986*16a497c6SRafael Auler   for (int I = 0; I < D.NumEdges; ++I) {
987*16a497c6SRafael Auler     CFGNodes[D.Edges[I].FromNode].NumOutEdges++;
988*16a497c6SRafael Auler     CFGNodes[D.Edges[I].ToNode].NumInEdges++;
989*16a497c6SRafael Auler     if (D.Edges[I].Counter != 0xffffffff)
990cc4b2fb6SRafael Auler       continue;
991cc4b2fb6SRafael Auler 
992*16a497c6SRafael Auler     SpanningTreeNodes[D.Edges[I].FromNode].NumOutEdges++;
993*16a497c6SRafael Auler     SpanningTreeNodes[D.Edges[I].ToNode].NumInEdges++;
994cc4b2fb6SRafael Auler   }
995cc4b2fb6SRafael Auler 
996cc4b2fb6SRafael Auler   // Allocate in/out edge sets
997cc4b2fb6SRafael Auler   for (int I = 0; I < MaxNodes; ++I) {
998cc4b2fb6SRafael Auler     if (CFGNodes[I].NumInEdges > 0)
999cc4b2fb6SRafael Auler       CFGNodes[I].InEdges = new (Alloc) Edge[CFGNodes[I].NumInEdges];
1000cc4b2fb6SRafael Auler     if (CFGNodes[I].NumOutEdges > 0)
1001cc4b2fb6SRafael Auler       CFGNodes[I].OutEdges = new (Alloc) Edge[CFGNodes[I].NumOutEdges];
1002cc4b2fb6SRafael Auler     if (SpanningTreeNodes[I].NumInEdges > 0)
1003cc4b2fb6SRafael Auler       SpanningTreeNodes[I].InEdges =
1004cc4b2fb6SRafael Auler           new (Alloc) Edge[SpanningTreeNodes[I].NumInEdges];
1005cc4b2fb6SRafael Auler     if (SpanningTreeNodes[I].NumOutEdges > 0)
1006cc4b2fb6SRafael Auler       SpanningTreeNodes[I].OutEdges =
1007cc4b2fb6SRafael Auler           new (Alloc) Edge[SpanningTreeNodes[I].NumOutEdges];
1008cc4b2fb6SRafael Auler     CFGNodes[I].NumInEdges = 0;
1009cc4b2fb6SRafael Auler     CFGNodes[I].NumOutEdges = 0;
1010cc4b2fb6SRafael Auler     SpanningTreeNodes[I].NumInEdges = 0;
1011cc4b2fb6SRafael Auler     SpanningTreeNodes[I].NumOutEdges = 0;
1012cc4b2fb6SRafael Auler   }
1013cc4b2fb6SRafael Auler 
1014cc4b2fb6SRafael Auler   // Fill in/out edge sets
1015*16a497c6SRafael Auler   for (int I = 0; I < D.NumEdges; ++I) {
1016*16a497c6SRafael Auler     const uint32_t Src = D.Edges[I].FromNode;
1017*16a497c6SRafael Auler     const uint32_t Dst = D.Edges[I].ToNode;
1018cc4b2fb6SRafael Auler     Edge *E = &CFGNodes[Src].OutEdges[CFGNodes[Src].NumOutEdges++];
1019cc4b2fb6SRafael Auler     E->Node = Dst;
1020cc4b2fb6SRafael Auler     E->ID = I;
1021cc4b2fb6SRafael Auler 
1022cc4b2fb6SRafael Auler     E = &CFGNodes[Dst].InEdges[CFGNodes[Dst].NumInEdges++];
1023cc4b2fb6SRafael Auler     E->Node = Src;
1024cc4b2fb6SRafael Auler     E->ID = I;
1025cc4b2fb6SRafael Auler 
1026*16a497c6SRafael Auler     if (D.Edges[I].Counter != 0xffffffff)
1027cc4b2fb6SRafael Auler       continue;
1028cc4b2fb6SRafael Auler 
1029cc4b2fb6SRafael Auler     E = &SpanningTreeNodes[Src]
1030cc4b2fb6SRafael Auler              .OutEdges[SpanningTreeNodes[Src].NumOutEdges++];
1031cc4b2fb6SRafael Auler     E->Node = Dst;
1032cc4b2fb6SRafael Auler     E->ID = I;
1033cc4b2fb6SRafael Auler 
1034cc4b2fb6SRafael Auler     E = &SpanningTreeNodes[Dst]
1035cc4b2fb6SRafael Auler              .InEdges[SpanningTreeNodes[Dst].NumInEdges++];
1036cc4b2fb6SRafael Auler     E->Node = Src;
1037cc4b2fb6SRafael Auler     E->ID = I;
1038cc4b2fb6SRafael Auler   }
1039*16a497c6SRafael Auler 
1040*16a497c6SRafael Auler   computeEdgeFrequencies(Counters, Ctx);
1041cc4b2fb6SRafael Auler }
1042cc4b2fb6SRafael Auler 
1043cc4b2fb6SRafael Auler Graph::~Graph() {
1044*16a497c6SRafael Auler   if (CallFreqs)
1045*16a497c6SRafael Auler     Alloc.deallocate(CallFreqs);
1046*16a497c6SRafael Auler   if (EdgeFreqs)
1047*16a497c6SRafael Auler     Alloc.deallocate(EdgeFreqs);
1048cc4b2fb6SRafael Auler   for (int I = NumNodes - 1; I >= 0; --I) {
1049cc4b2fb6SRafael Auler     if (SpanningTreeNodes[I].OutEdges)
1050cc4b2fb6SRafael Auler       Alloc.deallocate(SpanningTreeNodes[I].OutEdges);
1051cc4b2fb6SRafael Auler     if (SpanningTreeNodes[I].InEdges)
1052cc4b2fb6SRafael Auler       Alloc.deallocate(SpanningTreeNodes[I].InEdges);
1053cc4b2fb6SRafael Auler     if (CFGNodes[I].OutEdges)
1054cc4b2fb6SRafael Auler       Alloc.deallocate(CFGNodes[I].OutEdges);
1055cc4b2fb6SRafael Auler     if (CFGNodes[I].InEdges)
1056cc4b2fb6SRafael Auler       Alloc.deallocate(CFGNodes[I].InEdges);
1057cc4b2fb6SRafael Auler   }
1058cc4b2fb6SRafael Auler   if (SpanningTreeNodes)
1059cc4b2fb6SRafael Auler     Alloc.deallocate(SpanningTreeNodes);
1060cc4b2fb6SRafael Auler   if (CFGNodes)
1061cc4b2fb6SRafael Auler     Alloc.deallocate(CFGNodes);
1062cc4b2fb6SRafael Auler }
1063cc4b2fb6SRafael Auler 
1064cc4b2fb6SRafael Auler void Graph::dump() const {
1065cc4b2fb6SRafael Auler   reportNumber("Dumping graph with number of nodes: ", NumNodes, 10);
1066cc4b2fb6SRafael Auler   report("  Full graph:\n");
1067cc4b2fb6SRafael Auler   for (int I = 0; I < NumNodes; ++I) {
1068cc4b2fb6SRafael Auler     const Node *N = &CFGNodes[I];
1069cc4b2fb6SRafael Auler     reportNumber("    Node #", I, 10);
1070cc4b2fb6SRafael Auler     reportNumber("      InEdges total ", N->NumInEdges, 10);
1071cc4b2fb6SRafael Auler     for (int J = 0; J < N->NumInEdges; ++J)
1072cc4b2fb6SRafael Auler       reportNumber("        ", N->InEdges[J].Node, 10);
1073cc4b2fb6SRafael Auler     reportNumber("      OutEdges total ", N->NumOutEdges, 10);
1074cc4b2fb6SRafael Auler     for (int J = 0; J < N->NumOutEdges; ++J)
1075cc4b2fb6SRafael Auler       reportNumber("        ", N->OutEdges[J].Node, 10);
1076cc4b2fb6SRafael Auler     report("\n");
1077cc4b2fb6SRafael Auler   }
1078cc4b2fb6SRafael Auler   report("  Spanning tree:\n");
1079cc4b2fb6SRafael Auler   for (int I = 0; I < NumNodes; ++I) {
1080cc4b2fb6SRafael Auler     const Node *N = &SpanningTreeNodes[I];
1081cc4b2fb6SRafael Auler     reportNumber("    Node #", I, 10);
1082cc4b2fb6SRafael Auler     reportNumber("      InEdges total ", N->NumInEdges, 10);
1083cc4b2fb6SRafael Auler     for (int J = 0; J < N->NumInEdges; ++J)
1084cc4b2fb6SRafael Auler       reportNumber("        ", N->InEdges[J].Node, 10);
1085cc4b2fb6SRafael Auler     reportNumber("      OutEdges total ", N->NumOutEdges, 10);
1086cc4b2fb6SRafael Auler     for (int J = 0; J < N->NumOutEdges; ++J)
1087cc4b2fb6SRafael Auler       reportNumber("        ", N->OutEdges[J].Node, 10);
1088cc4b2fb6SRafael Auler     report("\n");
1089cc4b2fb6SRafael Auler   }
1090cc4b2fb6SRafael Auler }
1091cc4b2fb6SRafael Auler 
1092*16a497c6SRafael Auler void Graph::dumpEdgeFreqs() const {
1093*16a497c6SRafael Auler   reportNumber(
1094*16a497c6SRafael Auler       "Dumping edge frequencies for graph with num edges: ", D.NumEdges, 10);
1095*16a497c6SRafael Auler   for (int I = 0; I < D.NumEdges; ++I) {
1096*16a497c6SRafael Auler     reportNumber("* Src: ", D.Edges[I].FromNode, 10);
1097*16a497c6SRafael Auler     reportNumber("  Dst: ", D.Edges[I].ToNode, 10);
1098cc4b2fb6SRafael Auler     reportNumber("    Cnt: ", EdgeFreqs[I], 10);
1099cc4b2fb6SRafael Auler   }
1100cc4b2fb6SRafael Auler }
1101cc4b2fb6SRafael Auler 
1102*16a497c6SRafael Auler /// Auxiliary map structure for fast lookups of which calls map to each node of
1103*16a497c6SRafael Auler /// the function CFG
1104*16a497c6SRafael Auler struct NodeToCallsMap {
1105*16a497c6SRafael Auler   struct MapEntry {
1106*16a497c6SRafael Auler     uint32_t NumCalls;
1107*16a497c6SRafael Auler     uint32_t *Calls;
1108*16a497c6SRafael Auler   };
1109*16a497c6SRafael Auler   MapEntry *Entries;
1110*16a497c6SRafael Auler   BumpPtrAllocator &Alloc;
1111*16a497c6SRafael Auler   const uint32_t NumNodes;
1112cc4b2fb6SRafael Auler 
1113*16a497c6SRafael Auler   NodeToCallsMap(BumpPtrAllocator &Alloc, const FunctionDescription &D,
1114*16a497c6SRafael Auler                  uint32_t NumNodes)
1115*16a497c6SRafael Auler       : Alloc(Alloc), NumNodes(NumNodes) {
1116*16a497c6SRafael Auler     Entries = new (Alloc, 0) MapEntry[NumNodes];
1117*16a497c6SRafael Auler     for (int I = 0; I < D.NumCalls; ++I) {
1118*16a497c6SRafael Auler       DEBUG(reportNumber("Registering call in node ", D.Calls[I].FromNode, 10));
1119*16a497c6SRafael Auler       ++Entries[D.Calls[I].FromNode].NumCalls;
1120*16a497c6SRafael Auler     }
1121*16a497c6SRafael Auler     for (int I = 0; I < NumNodes; ++I) {
1122*16a497c6SRafael Auler       Entries[I].Calls = Entries[I].NumCalls ? new (Alloc)
1123*16a497c6SRafael Auler                                                    uint32_t[Entries[I].NumCalls]
1124*16a497c6SRafael Auler                                              : nullptr;
1125*16a497c6SRafael Auler       Entries[I].NumCalls = 0;
1126*16a497c6SRafael Auler     }
1127*16a497c6SRafael Auler     for (int I = 0; I < D.NumCalls; ++I) {
1128*16a497c6SRafael Auler       auto &Entry = Entries[D.Calls[I].FromNode];
1129*16a497c6SRafael Auler       Entry.Calls[Entry.NumCalls++] = I;
1130*16a497c6SRafael Auler     }
1131*16a497c6SRafael Auler   }
1132*16a497c6SRafael Auler 
1133*16a497c6SRafael Auler   /// Set the frequency of all calls in node \p NodeID to Freq. However, if
1134*16a497c6SRafael Auler   /// the calls have their own counters and do not depend on the basic block
1135*16a497c6SRafael Auler   /// counter, this means they have landing pads and throw exceptions. In this
1136*16a497c6SRafael Auler   /// case, set their frequency with their counters and return the maximum
1137*16a497c6SRafael Auler   /// value observed in such counters. This will be used as the new frequency
1138*16a497c6SRafael Auler   /// at basic block entry. This is used to fix the CFG edge frequencies in the
1139*16a497c6SRafael Auler   /// presence of exceptions.
1140*16a497c6SRafael Auler   uint64_t visitAllCallsIn(uint32_t NodeID, uint64_t Freq, uint64_t *CallFreqs,
1141*16a497c6SRafael Auler                            const FunctionDescription &D,
1142*16a497c6SRafael Auler                            const uint64_t *Counters,
1143*16a497c6SRafael Auler                            ProfileWriterContext &Ctx) const {
1144*16a497c6SRafael Auler     const auto &Entry = Entries[NodeID];
1145*16a497c6SRafael Auler     uint64_t MaxValue = 0ull;
1146*16a497c6SRafael Auler     for (int I = 0, E = Entry.NumCalls; I != E; ++I) {
1147*16a497c6SRafael Auler       const auto CallID = Entry.Calls[I];
1148*16a497c6SRafael Auler       DEBUG(reportNumber("  Setting freq for call ID: ", CallID, 10));
1149*16a497c6SRafael Auler       auto &CallDesc = D.Calls[CallID];
1150*16a497c6SRafael Auler       if (CallDesc.Counter == 0xffffffff) {
1151*16a497c6SRafael Auler         CallFreqs[CallID] = Freq;
1152*16a497c6SRafael Auler         DEBUG(reportNumber("  with : ", Freq, 10));
1153*16a497c6SRafael Auler       } else {
1154*16a497c6SRafael Auler         const auto CounterVal = Counters[CallDesc.Counter];
1155*16a497c6SRafael Auler         CallFreqs[CallID] = CounterVal;
1156*16a497c6SRafael Auler         MaxValue = CounterVal > MaxValue ? CounterVal : MaxValue;
1157*16a497c6SRafael Auler         DEBUG(reportNumber("  with (private counter) : ", CounterVal, 10));
1158*16a497c6SRafael Auler       }
1159*16a497c6SRafael Auler       DEBUG(reportNumber("  Address: 0x", CallDesc.TargetAddress, 16));
1160*16a497c6SRafael Auler       if (CallFreqs[CallID] > 0)
1161*16a497c6SRafael Auler         Ctx.CallFlowTable->get(CallDesc.TargetAddress).Calls +=
1162*16a497c6SRafael Auler             CallFreqs[CallID];
1163*16a497c6SRafael Auler     }
1164*16a497c6SRafael Auler     return MaxValue;
1165*16a497c6SRafael Auler   }
1166*16a497c6SRafael Auler 
1167*16a497c6SRafael Auler   ~NodeToCallsMap() {
1168*16a497c6SRafael Auler     for (int I = NumNodes - 1; I >= 0; --I) {
1169*16a497c6SRafael Auler       if (Entries[I].Calls)
1170*16a497c6SRafael Auler         Alloc.deallocate(Entries[I].Calls);
1171*16a497c6SRafael Auler     }
1172*16a497c6SRafael Auler     Alloc.deallocate(Entries);
1173*16a497c6SRafael Auler   }
1174*16a497c6SRafael Auler };
1175*16a497c6SRafael Auler 
1176*16a497c6SRafael Auler /// Fill an array with the frequency of each edge in the function represented
1177*16a497c6SRafael Auler /// by G, as well as another array for each call.
1178*16a497c6SRafael Auler void Graph::computeEdgeFrequencies(const uint64_t *Counters,
1179*16a497c6SRafael Auler                                    ProfileWriterContext &Ctx) {
1180*16a497c6SRafael Auler   if (NumNodes == 0)
1181*16a497c6SRafael Auler     return;
1182*16a497c6SRafael Auler 
1183*16a497c6SRafael Auler   EdgeFreqs = D.NumEdges ? new (Alloc, 0) uint64_t [D.NumEdges] : nullptr;
1184*16a497c6SRafael Auler   CallFreqs = D.NumCalls ? new (Alloc, 0) uint64_t [D.NumCalls] : nullptr;
1185*16a497c6SRafael Auler 
1186*16a497c6SRafael Auler   // Setup a lookup for calls present in each node (BB)
1187*16a497c6SRafael Auler   NodeToCallsMap *CallMap = new (Alloc) NodeToCallsMap(Alloc, D, NumNodes);
1188cc4b2fb6SRafael Auler 
1189cc4b2fb6SRafael Auler   // Perform a bottom-up, BFS traversal of the spanning tree in G. Edges in the
1190cc4b2fb6SRafael Auler   // spanning tree don't have explicit counters. We must infer their value using
1191cc4b2fb6SRafael Auler   // a linear combination of other counters (sum of counters of the outgoing
1192cc4b2fb6SRafael Auler   // edges minus sum of counters of the incoming edges).
1193*16a497c6SRafael Auler   uint32_t *Stack = new (Alloc) uint32_t [NumNodes];
1194cc4b2fb6SRafael Auler   uint32_t StackTop = 0;
1195cc4b2fb6SRafael Auler   enum Status : uint8_t { S_NEW = 0, S_VISITING, S_VISITED };
1196*16a497c6SRafael Auler   Status *Visited = new (Alloc, 0) Status[NumNodes];
1197*16a497c6SRafael Auler   uint64_t *LeafFrequency = new (Alloc, 0) uint64_t[NumNodes];
1198*16a497c6SRafael Auler   uint64_t *EntryAddress = new (Alloc, 0) uint64_t[NumNodes];
1199cc4b2fb6SRafael Auler 
1200cc4b2fb6SRafael Auler   // Setup a fast lookup for frequency of leaf nodes, which have special
1201cc4b2fb6SRafael Auler   // basic block frequency instrumentation (they are not edge profiled).
1202*16a497c6SRafael Auler   for (int I = 0; I < D.NumLeafNodes; ++I) {
1203*16a497c6SRafael Auler     LeafFrequency[D.LeafNodes[I].Node] = Counters[D.LeafNodes[I].Counter];
1204cc4b2fb6SRafael Auler     DEBUG({
1205*16a497c6SRafael Auler       if (Counters[D.LeafNodes[I].Counter] > 0) {
1206*16a497c6SRafael Auler         reportNumber("Leaf Node# ", D.LeafNodes[I].Node, 10);
1207*16a497c6SRafael Auler         reportNumber("     Counter: ", Counters[D.LeafNodes[I].Counter], 10);
1208cc4b2fb6SRafael Auler       }
1209cc4b2fb6SRafael Auler     });
1210*16a497c6SRafael Auler   }
1211*16a497c6SRafael Auler   for (int I = 0; I < D.NumEntryNodes; ++I) {
1212*16a497c6SRafael Auler     EntryAddress[D.EntryNodes[I].Node] = D.EntryNodes[I].Address;
1213*16a497c6SRafael Auler     DEBUG({
1214*16a497c6SRafael Auler         reportNumber("Entry Node# ", D.EntryNodes[I].Node, 10);
1215*16a497c6SRafael Auler         reportNumber("      Address: ", D.EntryNodes[I].Address, 16);
1216*16a497c6SRafael Auler     });
1217cc4b2fb6SRafael Auler   }
1218cc4b2fb6SRafael Auler   // Add all root nodes to the stack
1219*16a497c6SRafael Auler   for (int I = 0; I < NumNodes; ++I) {
1220*16a497c6SRafael Auler     if (SpanningTreeNodes[I].NumInEdges == 0)
1221cc4b2fb6SRafael Auler       Stack[StackTop++] = I;
1222cc4b2fb6SRafael Auler   }
1223cc4b2fb6SRafael Auler   // Empty stack?
1224cc4b2fb6SRafael Auler   if (StackTop == 0) {
1225*16a497c6SRafael Auler     DEBUG(report("Empty stack!\n"));
1226*16a497c6SRafael Auler     Alloc.deallocate(EntryAddress);
1227cc4b2fb6SRafael Auler     Alloc.deallocate(LeafFrequency);
1228cc4b2fb6SRafael Auler     Alloc.deallocate(Visited);
1229cc4b2fb6SRafael Auler     Alloc.deallocate(Stack);
1230*16a497c6SRafael Auler     CallMap->~NodeToCallsMap();
1231*16a497c6SRafael Auler     Alloc.deallocate(CallMap);
1232*16a497c6SRafael Auler     if (CallFreqs)
1233*16a497c6SRafael Auler       Alloc.deallocate(CallFreqs);
1234*16a497c6SRafael Auler     if (EdgeFreqs)
1235*16a497c6SRafael Auler       Alloc.deallocate(EdgeFreqs);
1236*16a497c6SRafael Auler     EdgeFreqs = nullptr;
1237*16a497c6SRafael Auler     CallFreqs = nullptr;
1238*16a497c6SRafael Auler     return;
1239cc4b2fb6SRafael Auler   }
1240cc4b2fb6SRafael Auler   // Add all known edge counts, will infer the rest
1241*16a497c6SRafael Auler   for (int I = 0; I < D.NumEdges; ++I) {
1242*16a497c6SRafael Auler     const uint32_t C = D.Edges[I].Counter;
1243cc4b2fb6SRafael Auler     if (C == 0xffffffff) // inferred counter - we will compute its value
1244cc4b2fb6SRafael Auler       continue;
1245*16a497c6SRafael Auler     EdgeFreqs[I] = Counters[C];
1246cc4b2fb6SRafael Auler   }
1247cc4b2fb6SRafael Auler 
1248cc4b2fb6SRafael Auler   while (StackTop > 0) {
1249cc4b2fb6SRafael Auler     const uint32_t Cur = Stack[--StackTop];
1250cc4b2fb6SRafael Auler     DEBUG({
1251cc4b2fb6SRafael Auler       if (Visited[Cur] == S_VISITING)
1252cc4b2fb6SRafael Auler         report("(visiting) ");
1253cc4b2fb6SRafael Auler       else
1254cc4b2fb6SRafael Auler         report("(new) ");
1255cc4b2fb6SRafael Auler       reportNumber("Cur: ", Cur, 10);
1256cc4b2fb6SRafael Auler     });
1257cc4b2fb6SRafael Auler 
1258cc4b2fb6SRafael Auler     // This shouldn't happen in a tree
1259cc4b2fb6SRafael Auler     assert(Visited[Cur] != S_VISITED, "should not have visited nodes in stack");
1260cc4b2fb6SRafael Auler     if (Visited[Cur] == S_NEW) {
1261cc4b2fb6SRafael Auler       Visited[Cur] = S_VISITING;
1262cc4b2fb6SRafael Auler       Stack[StackTop++] = Cur;
1263*16a497c6SRafael Auler       assert(StackTop <= NumNodes, "stack grew too large");
1264*16a497c6SRafael Auler       for (int I = 0, E = SpanningTreeNodes[Cur].NumOutEdges; I < E; ++I) {
1265*16a497c6SRafael Auler         const uint32_t Succ = SpanningTreeNodes[Cur].OutEdges[I].Node;
1266cc4b2fb6SRafael Auler         Stack[StackTop++] = Succ;
1267*16a497c6SRafael Auler         assert(StackTop <= NumNodes, "stack grew too large");
1268cc4b2fb6SRafael Auler      }
1269cc4b2fb6SRafael Auler       continue;
1270cc4b2fb6SRafael Auler     }
1271cc4b2fb6SRafael Auler     Visited[Cur] = S_VISITED;
1272cc4b2fb6SRafael Auler 
1273cc4b2fb6SRafael Auler     // Establish our node frequency based on outgoing edges, which should all be
1274cc4b2fb6SRafael Auler     // resolved by now.
1275cc4b2fb6SRafael Auler     int64_t CurNodeFreq = LeafFrequency[Cur];
1276cc4b2fb6SRafael Auler     // Not a leaf?
1277cc4b2fb6SRafael Auler     if (!CurNodeFreq) {
1278*16a497c6SRafael Auler       for (int I = 0, E = CFGNodes[Cur].NumOutEdges; I != E; ++I) {
1279*16a497c6SRafael Auler         const uint32_t SuccEdge = CFGNodes[Cur].OutEdges[I].ID;
1280*16a497c6SRafael Auler         CurNodeFreq += EdgeFreqs[SuccEdge];
1281cc4b2fb6SRafael Auler       }
1282cc4b2fb6SRafael Auler     }
1283*16a497c6SRafael Auler     if (CurNodeFreq < 0)
1284*16a497c6SRafael Auler       CurNodeFreq = 0;
1285*16a497c6SRafael Auler 
1286*16a497c6SRafael Auler     const uint64_t CallFreq = CallMap->visitAllCallsIn(
1287*16a497c6SRafael Auler         Cur, CurNodeFreq > 0 ? CurNodeFreq : 0, CallFreqs, D, Counters, Ctx);
1288*16a497c6SRafael Auler 
1289*16a497c6SRafael Auler     // Exception handling affected our output flow? Fix with calls info
1290*16a497c6SRafael Auler     DEBUG({
1291*16a497c6SRafael Auler       if (CallFreq > CurNodeFreq)
1292*16a497c6SRafael Auler         report("Bumping node frequency with call info\n");
1293*16a497c6SRafael Auler     });
1294*16a497c6SRafael Auler     CurNodeFreq = CallFreq > CurNodeFreq ? CallFreq : CurNodeFreq;
1295*16a497c6SRafael Auler 
1296*16a497c6SRafael Auler     if (CurNodeFreq > 0) {
1297*16a497c6SRafael Auler       if (uint64_t Addr = EntryAddress[Cur]) {
1298*16a497c6SRafael Auler         DEBUG(
1299*16a497c6SRafael Auler             reportNumber("  Setting flow at entry point address 0x", Addr, 16));
1300*16a497c6SRafael Auler         DEBUG(reportNumber("  with: ", CurNodeFreq, 10));
1301*16a497c6SRafael Auler         Ctx.CallFlowTable->get(Addr).Val = CurNodeFreq;
1302*16a497c6SRafael Auler       }
1303*16a497c6SRafael Auler     }
1304*16a497c6SRafael Auler 
1305*16a497c6SRafael Auler     // No parent? Reached a tree root, limit to call frequency updating.
1306*16a497c6SRafael Auler     if (SpanningTreeNodes[Cur].NumInEdges == 0) {
1307*16a497c6SRafael Auler       continue;
1308*16a497c6SRafael Auler     }
1309*16a497c6SRafael Auler 
1310*16a497c6SRafael Auler     assert(SpanningTreeNodes[Cur].NumInEdges == 1, "must have 1 parent");
1311*16a497c6SRafael Auler     const uint32_t Parent = SpanningTreeNodes[Cur].InEdges[0].Node;
1312*16a497c6SRafael Auler     const uint32_t ParentEdge = SpanningTreeNodes[Cur].InEdges[0].ID;
1313*16a497c6SRafael Auler 
1314cc4b2fb6SRafael Auler     // Calculate parent edge freq.
1315*16a497c6SRafael Auler     int64_t ParentEdgeFreq = CurNodeFreq;
1316*16a497c6SRafael Auler     for (int I = 0, E = CFGNodes[Cur].NumInEdges; I != E; ++I) {
1317*16a497c6SRafael Auler       const uint32_t PredEdge = CFGNodes[Cur].InEdges[I].ID;
1318*16a497c6SRafael Auler       ParentEdgeFreq -= EdgeFreqs[PredEdge];
1319cc4b2fb6SRafael Auler     }
1320*16a497c6SRafael Auler 
1321cc4b2fb6SRafael Auler     // Sometimes the conservative CFG that BOLT builds will lead to incorrect
1322cc4b2fb6SRafael Auler     // flow computation. For example, in a BB that transitively calls the exit
1323cc4b2fb6SRafael Auler     // syscall, BOLT will add a fall-through successor even though it should not
1324cc4b2fb6SRafael Auler     // have any successors. So this block execution will likely be wrong. We
1325cc4b2fb6SRafael Auler     // tolerate this imperfection since this case should be quite infrequent.
1326cc4b2fb6SRafael Auler     if (ParentEdgeFreq < 0) {
1327*16a497c6SRafael Auler       DEBUG(dumpEdgeFreqs());
1328cc4b2fb6SRafael Auler       DEBUG(report("WARNING: incorrect flow"));
1329cc4b2fb6SRafael Auler       ParentEdgeFreq = 0;
1330cc4b2fb6SRafael Auler     }
1331cc4b2fb6SRafael Auler     DEBUG(reportNumber("  Setting freq for ParentEdge: ", ParentEdge, 10));
1332cc4b2fb6SRafael Auler     DEBUG(reportNumber("  with ParentEdgeFreq: ", ParentEdgeFreq, 10));
1333*16a497c6SRafael Auler     EdgeFreqs[ParentEdge] = ParentEdgeFreq;
1334cc4b2fb6SRafael Auler   }
1335cc4b2fb6SRafael Auler 
1336*16a497c6SRafael Auler   Alloc.deallocate(EntryAddress);
1337cc4b2fb6SRafael Auler   Alloc.deallocate(LeafFrequency);
1338cc4b2fb6SRafael Auler   Alloc.deallocate(Visited);
1339cc4b2fb6SRafael Auler   Alloc.deallocate(Stack);
1340*16a497c6SRafael Auler   CallMap->~NodeToCallsMap();
1341*16a497c6SRafael Auler   Alloc.deallocate(CallMap);
1342*16a497c6SRafael Auler   DEBUG(dumpEdgeFreqs());
1343cc4b2fb6SRafael Auler }
1344cc4b2fb6SRafael Auler 
1345*16a497c6SRafael Auler /// Write to \p FD all of the edge profiles for function \p FuncDesc. Uses
1346*16a497c6SRafael Auler /// \p Alloc to allocate helper dynamic structures used to compute profile for
1347*16a497c6SRafael Auler /// edges that we do not explictly instrument.
1348*16a497c6SRafael Auler const uint8_t *writeFunctionProfile(int FD, ProfileWriterContext &Ctx,
1349*16a497c6SRafael Auler                                     const uint8_t *FuncDesc,
1350*16a497c6SRafael Auler                                     BumpPtrAllocator &Alloc) {
1351*16a497c6SRafael Auler   const FunctionDescription F(FuncDesc);
1352*16a497c6SRafael Auler   const uint8_t *next = FuncDesc + F.getSize();
1353cc4b2fb6SRafael Auler 
1354cc4b2fb6SRafael Auler   // Skip funcs we know are cold
1355cc4b2fb6SRafael Auler #ifndef ENABLE_DEBUG
1356*16a497c6SRafael Auler   uint64_t CountersFreq = 0;
1357*16a497c6SRafael Auler   for (int I = 0; I < F.NumLeafNodes; ++I) {
1358*16a497c6SRafael Auler     CountersFreq += __bolt_instr_locations[F.LeafNodes[I].Counter];
1359cc4b2fb6SRafael Auler   }
1360*16a497c6SRafael Auler   if (CountersFreq == 0) {
1361*16a497c6SRafael Auler     for (int I = 0; I < F.NumEdges; ++I) {
1362*16a497c6SRafael Auler       const uint32_t C = F.Edges[I].Counter;
1363*16a497c6SRafael Auler       if (C == 0xffffffff)
1364*16a497c6SRafael Auler         continue;
1365*16a497c6SRafael Auler       CountersFreq += __bolt_instr_locations[C];
1366*16a497c6SRafael Auler     }
1367*16a497c6SRafael Auler     if (CountersFreq == 0) {
1368*16a497c6SRafael Auler       for (int I = 0; I < F.NumCalls; ++I) {
1369*16a497c6SRafael Auler         const uint32_t C = F.Calls[I].Counter;
1370*16a497c6SRafael Auler         if (C == 0xffffffff)
1371*16a497c6SRafael Auler           continue;
1372*16a497c6SRafael Auler         CountersFreq += __bolt_instr_locations[C];
1373*16a497c6SRafael Auler       }
1374*16a497c6SRafael Auler       if (CountersFreq == 0)
1375cc4b2fb6SRafael Auler         return next;
1376*16a497c6SRafael Auler     }
1377*16a497c6SRafael Auler   }
1378cc4b2fb6SRafael Auler #endif
1379cc4b2fb6SRafael Auler 
1380*16a497c6SRafael Auler   Graph *G = new (Alloc) Graph(Alloc, F, __bolt_instr_locations, Ctx);
1381cc4b2fb6SRafael Auler   DEBUG(G->dump());
1382*16a497c6SRafael Auler   if (!G->EdgeFreqs && !G->CallFreqs) {
1383cc4b2fb6SRafael Auler     G->~Graph();
1384cc4b2fb6SRafael Auler     Alloc.deallocate(G);
1385cc4b2fb6SRafael Auler     return next;
1386cc4b2fb6SRafael Auler   }
1387cc4b2fb6SRafael Auler 
1388*16a497c6SRafael Auler   for (int I = 0; I < F.NumEdges; ++I) {
1389*16a497c6SRafael Auler     const uint64_t Freq = G->EdgeFreqs[I];
1390cc4b2fb6SRafael Auler     if (Freq == 0)
1391cc4b2fb6SRafael Auler       continue;
1392*16a497c6SRafael Auler     const EdgeDescription *Desc = &F.Edges[I];
1393cc4b2fb6SRafael Auler     char LineBuf[BufSize];
1394cc4b2fb6SRafael Auler     char *Ptr = LineBuf;
1395*16a497c6SRafael Auler     Ptr = serializeLoc(Ctx, Ptr, Desc->From, BufSize);
1396*16a497c6SRafael Auler     Ptr = serializeLoc(Ctx, Ptr, Desc->To, BufSize - (Ptr - LineBuf));
1397cc4b2fb6SRafael Auler     Ptr = strCopy(Ptr, "0 ", BufSize - (Ptr - LineBuf) - 22);
1398cc4b2fb6SRafael Auler     Ptr = intToStr(Ptr, Freq, 10);
1399cc4b2fb6SRafael Auler     *Ptr++ = '\n';
1400cc4b2fb6SRafael Auler     __write(FD, LineBuf, Ptr - LineBuf);
1401cc4b2fb6SRafael Auler   }
1402cc4b2fb6SRafael Auler 
1403*16a497c6SRafael Auler   for (int I = 0; I < F.NumCalls; ++I) {
1404*16a497c6SRafael Auler     const uint64_t Freq = G->CallFreqs[I];
1405*16a497c6SRafael Auler     if (Freq == 0)
1406*16a497c6SRafael Auler       continue;
1407*16a497c6SRafael Auler     char LineBuf[BufSize];
1408*16a497c6SRafael Auler     char *Ptr = LineBuf;
1409*16a497c6SRafael Auler     const CallDescription *Desc = &F.Calls[I];
1410*16a497c6SRafael Auler     Ptr = serializeLoc(Ctx, Ptr, Desc->From, BufSize);
1411*16a497c6SRafael Auler     Ptr = serializeLoc(Ctx, Ptr, Desc->To, BufSize - (Ptr - LineBuf));
1412*16a497c6SRafael Auler     Ptr = strCopy(Ptr, "0 ", BufSize - (Ptr - LineBuf) - 25);
1413*16a497c6SRafael Auler     Ptr = intToStr(Ptr, Freq, 10);
1414*16a497c6SRafael Auler     *Ptr++ = '\n';
1415*16a497c6SRafael Auler     __write(FD, LineBuf, Ptr - LineBuf);
1416*16a497c6SRafael Auler   }
1417*16a497c6SRafael Auler 
1418cc4b2fb6SRafael Auler   G->~Graph();
1419cc4b2fb6SRafael Auler   Alloc.deallocate(G);
1420cc4b2fb6SRafael Auler   return next;
1421cc4b2fb6SRafael Auler }
1422cc4b2fb6SRafael Auler 
1423*16a497c6SRafael Auler const IndCallTargetDescription *
1424*16a497c6SRafael Auler ProfileWriterContext::lookupIndCallTarget(uint64_t Target) const {
1425*16a497c6SRafael Auler   uint32_t B = 0;
1426*16a497c6SRafael Auler   uint32_t E = __bolt_instr_num_ind_targets;
1427*16a497c6SRafael Auler   if (E == 0)
1428*16a497c6SRafael Auler     return nullptr;
1429*16a497c6SRafael Auler   do {
1430*16a497c6SRafael Auler     uint32_t I = (E - B) / 2 + B;
1431*16a497c6SRafael Auler     if (IndCallTargets[I].Address == Target)
1432*16a497c6SRafael Auler       return &IndCallTargets[I];
1433*16a497c6SRafael Auler     if (IndCallTargets[I].Address < Target)
1434*16a497c6SRafael Auler       B = I + 1;
1435*16a497c6SRafael Auler     else
1436*16a497c6SRafael Auler       E = I;
1437*16a497c6SRafael Auler   } while (B < E);
1438*16a497c6SRafael Auler   return nullptr;
1439cc4b2fb6SRafael Auler }
144062aa74f8SRafael Auler 
1441*16a497c6SRafael Auler /// Write a single indirect call <src, target> pair to the fdata file
1442*16a497c6SRafael Auler void visitIndCallCounter(IndirectCallHashTable::MapEntry &Entry,
1443*16a497c6SRafael Auler                          int FD, int CallsiteID,
1444*16a497c6SRafael Auler                          ProfileWriterContext *Ctx) {
1445*16a497c6SRafael Auler   if (Entry.Val == 0)
1446*16a497c6SRafael Auler     return;
1447*16a497c6SRafael Auler   DEBUG(reportNumber("Target func 0x", Entry.Key, 16));
1448*16a497c6SRafael Auler   DEBUG(reportNumber("Target freq: ", Entry.Val, 10));
1449*16a497c6SRafael Auler   const IndCallDescription *CallsiteDesc =
1450*16a497c6SRafael Auler       &Ctx->IndCallDescriptions[CallsiteID];
1451*16a497c6SRafael Auler   const IndCallTargetDescription *TargetDesc =
1452*16a497c6SRafael Auler       Ctx->lookupIndCallTarget(Entry.Key);
1453*16a497c6SRafael Auler   if (!TargetDesc) {
1454*16a497c6SRafael Auler     DEBUG(report("Failed to lookup indirect call target\n"));
1455cc4b2fb6SRafael Auler     char LineBuf[BufSize];
145662aa74f8SRafael Auler     char *Ptr = LineBuf;
1457*16a497c6SRafael Auler     Ptr = serializeLoc(*Ctx, Ptr, *CallsiteDesc, BufSize);
1458*16a497c6SRafael Auler     Ptr = strCopy(Ptr, "0 [unknown] 0 0 ", BufSize - (Ptr - LineBuf) - 40);
1459*16a497c6SRafael Auler     Ptr = intToStr(Ptr, Entry.Val, 10);
1460*16a497c6SRafael Auler     *Ptr++ = '\n';
1461*16a497c6SRafael Auler     __write(FD, LineBuf, Ptr - LineBuf);
1462*16a497c6SRafael Auler     return;
1463*16a497c6SRafael Auler   }
1464*16a497c6SRafael Auler   Ctx->CallFlowTable->get(TargetDesc->Address).Calls += Entry.Val;
1465*16a497c6SRafael Auler   char LineBuf[BufSize];
1466*16a497c6SRafael Auler   char *Ptr = LineBuf;
1467*16a497c6SRafael Auler   Ptr = serializeLoc(*Ctx, Ptr, *CallsiteDesc, BufSize);
1468*16a497c6SRafael Auler   Ptr = serializeLoc(*Ctx, Ptr, TargetDesc->Loc, BufSize - (Ptr - LineBuf));
1469cc4b2fb6SRafael Auler   Ptr = strCopy(Ptr, "0 ", BufSize - (Ptr - LineBuf) - 25);
1470*16a497c6SRafael Auler   Ptr = intToStr(Ptr, Entry.Val, 10);
147162aa74f8SRafael Auler   *Ptr++ = '\n';
1472821480d2SRafael Auler   __write(FD, LineBuf, Ptr - LineBuf);
147362aa74f8SRafael Auler }
1474cc4b2fb6SRafael Auler 
1475*16a497c6SRafael Auler /// Write to \p FD all of the indirect call profiles.
1476*16a497c6SRafael Auler void writeIndirectCallProfile(int FD, ProfileWriterContext &Ctx) {
1477*16a497c6SRafael Auler   for (int I = 0; I < __bolt_instr_num_ind_calls; ++I) {
1478*16a497c6SRafael Auler     DEBUG(reportNumber("IndCallsite #", I, 10));
1479*16a497c6SRafael Auler     GlobalIndCallCounters[I].forEachElement(visitIndCallCounter, FD, I, &Ctx);
1480*16a497c6SRafael Auler   }
1481*16a497c6SRafael Auler }
1482*16a497c6SRafael Auler 
1483*16a497c6SRafael Auler /// Check a single call flow for a callee versus all known callers. If there are
1484*16a497c6SRafael Auler /// less callers than what the callee expects, write the difference with source
1485*16a497c6SRafael Auler /// [unknown] in the profile.
1486*16a497c6SRafael Auler void visitCallFlowEntry(CallFlowHashTable::MapEntry &Entry, int FD,
1487*16a497c6SRafael Auler                         ProfileWriterContext *Ctx) {
1488*16a497c6SRafael Auler   DEBUG(reportNumber("Call flow entry address: 0x", Entry.Key, 16));
1489*16a497c6SRafael Auler   DEBUG(reportNumber("Calls: ", Entry.Calls, 10));
1490*16a497c6SRafael Auler   DEBUG(reportNumber("Reported entry frequency: ", Entry.Val, 10));
1491*16a497c6SRafael Auler   DEBUG({
1492*16a497c6SRafael Auler     if (Entry.Calls > Entry.Val)
1493*16a497c6SRafael Auler       report("  More calls than expected!\n");
1494*16a497c6SRafael Auler   });
1495*16a497c6SRafael Auler   if (Entry.Val <= Entry.Calls)
1496*16a497c6SRafael Auler     return;
1497*16a497c6SRafael Auler   DEBUG(reportNumber(
1498*16a497c6SRafael Auler       "  Balancing calls with traffic: ", Entry.Val - Entry.Calls, 10));
1499*16a497c6SRafael Auler   const IndCallTargetDescription *TargetDesc =
1500*16a497c6SRafael Auler       Ctx->lookupIndCallTarget(Entry.Key);
1501*16a497c6SRafael Auler   if (!TargetDesc) {
1502*16a497c6SRafael Auler     // There is probably something wrong with this callee and this should be
1503*16a497c6SRafael Auler     // investigated, but I don't want to assert and lose all data collected.
1504*16a497c6SRafael Auler     DEBUG(report("WARNING: failed to look up call target!\n"));
1505*16a497c6SRafael Auler     return;
1506*16a497c6SRafael Auler   }
1507*16a497c6SRafael Auler   char LineBuf[BufSize];
1508*16a497c6SRafael Auler   char *Ptr = LineBuf;
1509*16a497c6SRafael Auler   Ptr = strCopy(Ptr, "0 [unknown] 0 ", BufSize);
1510*16a497c6SRafael Auler   Ptr = serializeLoc(*Ctx, Ptr, TargetDesc->Loc, BufSize - (Ptr - LineBuf));
1511*16a497c6SRafael Auler   Ptr = strCopy(Ptr, "0 ", BufSize - (Ptr - LineBuf) - 25);
1512*16a497c6SRafael Auler   Ptr = intToStr(Ptr, Entry.Val - Entry.Calls, 10);
1513*16a497c6SRafael Auler   *Ptr++ = '\n';
1514*16a497c6SRafael Auler   __write(FD, LineBuf, Ptr - LineBuf);
1515*16a497c6SRafael Auler }
1516*16a497c6SRafael Auler 
1517*16a497c6SRafael Auler /// Open fdata file for writing and return a valid file descriptor, aborting
1518*16a497c6SRafael Auler /// program upon failure.
1519*16a497c6SRafael Auler int openProfile() {
1520*16a497c6SRafael Auler   // Build the profile name string by appending our PID
1521*16a497c6SRafael Auler   char Buf[BufSize];
1522*16a497c6SRafael Auler   char *Ptr = Buf;
1523*16a497c6SRafael Auler   uint64_t PID = __getpid();
1524*16a497c6SRafael Auler   Ptr = strCopy(Buf, __bolt_instr_filename, BufSize);
1525*16a497c6SRafael Auler   if (__bolt_instr_use_pid) {
1526*16a497c6SRafael Auler     Ptr = strCopy(Ptr, ".", BufSize - (Ptr - Buf + 1));
1527*16a497c6SRafael Auler     Ptr = intToStr(Ptr, PID, 10);
1528*16a497c6SRafael Auler     Ptr = strCopy(Ptr, ".fdata", BufSize - (Ptr - Buf + 1));
1529*16a497c6SRafael Auler   }
1530*16a497c6SRafael Auler   *Ptr++ = '\0';
1531*16a497c6SRafael Auler   uint64_t FD = __open(Buf,
1532*16a497c6SRafael Auler                        /*flags=*/0x241 /*O_WRONLY|O_TRUNC|O_CREAT*/,
1533*16a497c6SRafael Auler                        /*mode=*/0666);
1534*16a497c6SRafael Auler   if (static_cast<int64_t>(FD) < 0) {
1535*16a497c6SRafael Auler     report("Error while trying to open profile file for writing: ");
1536*16a497c6SRafael Auler     report(Buf);
1537*16a497c6SRafael Auler     reportNumber("\nFailed with error number: 0x",
1538*16a497c6SRafael Auler                  0 - static_cast<int64_t>(FD), 16);
1539*16a497c6SRafael Auler     __exit(1);
1540*16a497c6SRafael Auler   }
1541*16a497c6SRafael Auler   return FD;
1542*16a497c6SRafael Auler }
1543*16a497c6SRafael Auler 
1544*16a497c6SRafael Auler } // anonymous namespace
1545*16a497c6SRafael Auler 
1546*16a497c6SRafael Auler /// Reset all counters in case you want to start profiling a new phase of your
1547*16a497c6SRafael Auler /// program independently of prior phases.
1548*16a497c6SRafael Auler /// The address of this function is printed by BOLT and this can be called by
1549*16a497c6SRafael Auler /// any attached debugger during runtime. There is a useful oneliner for gdb:
1550*16a497c6SRafael Auler ///
1551*16a497c6SRafael Auler ///   gdb -p $(pgrep -xo PROCESSNAME) -ex 'p ((void(*)())0xdeadbeef)()' \
1552*16a497c6SRafael Auler ///     -ex 'set confirm off' -ex quit
1553*16a497c6SRafael Auler ///
1554*16a497c6SRafael Auler /// Where 0xdeadbeef is this function address and PROCESSNAME your binary file
1555*16a497c6SRafael Auler /// name.
1556*16a497c6SRafael Auler extern "C" void __bolt_instr_clear_counters() {
1557*16a497c6SRafael Auler   memSet(reinterpret_cast<char *>(__bolt_instr_locations), 0,
1558*16a497c6SRafael Auler          __bolt_num_counters * 8);
1559*16a497c6SRafael Auler   for (int I = 0; I < __bolt_instr_num_ind_calls; ++I) {
1560*16a497c6SRafael Auler     GlobalIndCallCounters[I].resetCounters();
1561*16a497c6SRafael Auler   }
1562*16a497c6SRafael Auler }
1563*16a497c6SRafael Auler 
1564*16a497c6SRafael Auler /// This is the entry point for profile writing.
1565*16a497c6SRafael Auler /// There are three ways of getting here:
1566*16a497c6SRafael Auler ///
1567*16a497c6SRafael Auler ///  * Program execution ended, finalization methods are running and BOLT
1568*16a497c6SRafael Auler ///    hooked into FINI from your binary dynamic section;
1569*16a497c6SRafael Auler ///  * You used the sleep timer option and during initialization we forked
1570*16a497c6SRafael Auler ///    a separete process that will call this function periodically;
1571*16a497c6SRafael Auler ///  * BOLT prints this function address so you can attach a debugger and
1572*16a497c6SRafael Auler ///    call this function directly to get your profile written to disk
1573*16a497c6SRafael Auler ///    on demand.
1574*16a497c6SRafael Auler ///
1575*16a497c6SRafael Auler extern "C" void __bolt_instr_data_dump() {
1576*16a497c6SRafael Auler   // Already dumping
1577*16a497c6SRafael Auler   if (!GlobalWriteProfileMutex->acquire())
1578*16a497c6SRafael Auler     return;
1579*16a497c6SRafael Auler 
1580*16a497c6SRafael Auler   BumpPtrAllocator HashAlloc;
1581*16a497c6SRafael Auler   HashAlloc.setMaxSize(0x6400000);
1582*16a497c6SRafael Auler   ProfileWriterContext Ctx = readDescriptions();
1583*16a497c6SRafael Auler   Ctx.CallFlowTable = new (HashAlloc, 0) CallFlowHashTable(HashAlloc);
1584*16a497c6SRafael Auler 
1585*16a497c6SRafael Auler   DEBUG(printStats(Ctx));
1586*16a497c6SRafael Auler 
1587*16a497c6SRafael Auler   int FD = openProfile();
1588*16a497c6SRafael Auler 
1589cc4b2fb6SRafael Auler   BumpPtrAllocator Alloc;
1590*16a497c6SRafael Auler   const uint8_t *FuncDesc = Ctx.FuncDescriptions;
1591cc4b2fb6SRafael Auler   for (int I = 0, E = __bolt_instr_num_funcs; I < E; ++I) {
1592*16a497c6SRafael Auler     FuncDesc = writeFunctionProfile(FD, Ctx, FuncDesc, Alloc);
1593*16a497c6SRafael Auler     Alloc.clear();
1594cc4b2fb6SRafael Auler     DEBUG(reportNumber("FuncDesc now: ", (uint64_t)FuncDesc, 16));
1595cc4b2fb6SRafael Auler   }
1596*16a497c6SRafael Auler   assert(FuncDesc == (void *)Ctx.Strings,
1597cc4b2fb6SRafael Auler          "FuncDesc ptr must be equal to stringtable");
1598cc4b2fb6SRafael Auler 
1599*16a497c6SRafael Auler   writeIndirectCallProfile(FD, Ctx);
1600*16a497c6SRafael Auler   Ctx.CallFlowTable->forEachElement(visitCallFlowEntry, FD, &Ctx);
1601*16a497c6SRafael Auler 
1602821480d2SRafael Auler   __close(FD);
1603*16a497c6SRafael Auler   __munmap(Ctx.MMapPtr, Ctx.MMapSize);
1604*16a497c6SRafael Auler   __close(Ctx.FileDesc);
1605*16a497c6SRafael Auler   HashAlloc.destroy();
1606*16a497c6SRafael Auler   GlobalWriteProfileMutex->release();
1607*16a497c6SRafael Auler   DEBUG(report("Finished writing profile.\n"));
1608*16a497c6SRafael Auler }
1609*16a497c6SRafael Auler 
1610*16a497c6SRafael Auler /// Event loop for our child process spawned during setup to dump profile data
1611*16a497c6SRafael Auler /// at user-specified intervals
1612*16a497c6SRafael Auler void watchProcess() {
1613*16a497c6SRafael Auler   timespec ts, rem;
1614*16a497c6SRafael Auler   uint64_t Ellapsed = 0ull;
1615*16a497c6SRafael Auler   ts.tv_sec = 1;
1616*16a497c6SRafael Auler   ts.tv_nsec = 0;
1617*16a497c6SRafael Auler   while (1) {
1618*16a497c6SRafael Auler     __nanosleep(&ts, &rem);
1619*16a497c6SRafael Auler     // This means our parent process died, so no need for us to keep dumping.
1620*16a497c6SRafael Auler     // Notice that make and some systems will wait until all child processes
1621*16a497c6SRafael Auler     // of a command finishes before proceeding, so it is important to exit as
1622*16a497c6SRafael Auler     // early as possible once our parent dies.
1623*16a497c6SRafael Auler     if (__getppid() == 1) {
1624*16a497c6SRafael Auler       break;
1625*16a497c6SRafael Auler     }
1626*16a497c6SRafael Auler     if (++Ellapsed < __bolt_instr_sleep_time)
1627*16a497c6SRafael Auler       continue;
1628*16a497c6SRafael Auler     Ellapsed = 0;
1629*16a497c6SRafael Auler     __bolt_instr_data_dump();
1630*16a497c6SRafael Auler     __bolt_instr_clear_counters();
1631*16a497c6SRafael Auler   }
1632*16a497c6SRafael Auler   DEBUG(report("My parent process is dead, bye!\n"));
1633*16a497c6SRafael Auler   __exit(0);
1634*16a497c6SRafael Auler }
1635*16a497c6SRafael Auler 
1636*16a497c6SRafael Auler extern "C" void __bolt_instr_indirect_call();
1637*16a497c6SRafael Auler extern "C" void __bolt_instr_indirect_tailcall();
1638*16a497c6SRafael Auler 
1639*16a497c6SRafael Auler /// Initialization code
1640*16a497c6SRafael Auler extern "C" void __bolt_instr_setup() {
1641*16a497c6SRafael Auler   const uint64_t CountersStart =
1642*16a497c6SRafael Auler       reinterpret_cast<uint64_t>(&__bolt_instr_locations[0]);
1643*16a497c6SRafael Auler   const uint64_t CountersEnd = alignTo(
1644*16a497c6SRafael Auler       reinterpret_cast<uint64_t>(&__bolt_instr_locations[__bolt_num_counters]),
1645*16a497c6SRafael Auler       0x1000);
1646*16a497c6SRafael Auler   DEBUG(reportNumber("replace mmap start: ", CountersStart, 16));
1647*16a497c6SRafael Auler   DEBUG(reportNumber("replace mmap stop: ", CountersEnd, 16));
1648*16a497c6SRafael Auler   assert (CountersEnd > CountersStart, "no counters");
1649*16a497c6SRafael Auler   // Maps our counters to be shared instead of private, so we keep counting for
1650*16a497c6SRafael Auler   // forked processes
1651*16a497c6SRafael Auler   __mmap(CountersStart, CountersEnd - CountersStart,
1652*16a497c6SRafael Auler          0x3 /*PROT_READ|PROT_WRITE*/,
1653*16a497c6SRafael Auler          0x31 /*MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED*/, -1, 0);
1654*16a497c6SRafael Auler 
1655*16a497c6SRafael Auler   __bolt_trampoline_ind_call = __bolt_instr_indirect_call;
1656*16a497c6SRafael Auler   __bolt_trampoline_ind_tailcall = __bolt_instr_indirect_tailcall;
1657*16a497c6SRafael Auler   // Conservatively reserve 100MiB shared pages
1658*16a497c6SRafael Auler   GlobalAlloc.setMaxSize(0x6400000);
1659*16a497c6SRafael Auler   GlobalAlloc.setShared(true);
1660*16a497c6SRafael Auler   GlobalWriteProfileMutex = new (GlobalAlloc, 0) Mutex();
1661*16a497c6SRafael Auler   if (__bolt_instr_num_ind_calls > 0)
1662*16a497c6SRafael Auler     GlobalIndCallCounters =
1663*16a497c6SRafael Auler         new (GlobalAlloc, 0) IndirectCallHashTable[__bolt_instr_num_ind_calls];
1664*16a497c6SRafael Auler 
1665*16a497c6SRafael Auler   if (__bolt_instr_sleep_time != 0) {
1666*16a497c6SRafael Auler     if (auto PID = __fork())
1667*16a497c6SRafael Auler       return;
1668*16a497c6SRafael Auler     watchProcess();
1669*16a497c6SRafael Auler   }
1670*16a497c6SRafael Auler }
1671*16a497c6SRafael Auler 
1672*16a497c6SRafael Auler extern "C" void instrumentIndirectCall(uint64_t Target, uint64_t IndCallID) {
1673*16a497c6SRafael Auler   GlobalIndCallCounters[IndCallID].incrementVal(Target, GlobalAlloc);
1674*16a497c6SRafael Auler }
1675*16a497c6SRafael Auler 
1676*16a497c6SRafael Auler #define SAVE_ALL                                                               \
1677*16a497c6SRafael Auler   "push %%rax\n"                                                               \
1678*16a497c6SRafael Auler   "push %%rbx\n"                                                               \
1679*16a497c6SRafael Auler   "push %%rcx\n"                                                               \
1680*16a497c6SRafael Auler   "push %%rdx\n"                                                               \
1681*16a497c6SRafael Auler   "push %%rdi\n"                                                               \
1682*16a497c6SRafael Auler   "push %%rsi\n"                                                               \
1683*16a497c6SRafael Auler   "push %%rbp\n"                                                               \
1684*16a497c6SRafael Auler   "push %%r8\n"                                                                \
1685*16a497c6SRafael Auler   "push %%r9\n"                                                                \
1686*16a497c6SRafael Auler   "push %%r10\n"                                                               \
1687*16a497c6SRafael Auler   "push %%r11\n"                                                               \
1688*16a497c6SRafael Auler   "push %%r12\n"                                                               \
1689*16a497c6SRafael Auler   "push %%r13\n"                                                               \
1690*16a497c6SRafael Auler   "push %%r14\n"                                                               \
1691*16a497c6SRafael Auler   "push %%r15\n"
1692*16a497c6SRafael Auler 
1693*16a497c6SRafael Auler #define RESTORE_ALL                                                            \
1694*16a497c6SRafael Auler   "pop %%r15\n"                                                                \
1695*16a497c6SRafael Auler   "pop %%r14\n"                                                                \
1696*16a497c6SRafael Auler   "pop %%r13\n"                                                                \
1697*16a497c6SRafael Auler   "pop %%r12\n"                                                                \
1698*16a497c6SRafael Auler   "pop %%r11\n"                                                                \
1699*16a497c6SRafael Auler   "pop %%r10\n"                                                                \
1700*16a497c6SRafael Auler   "pop %%r9\n"                                                                 \
1701*16a497c6SRafael Auler   "pop %%r8\n"                                                                 \
1702*16a497c6SRafael Auler   "pop %%rbp\n"                                                                \
1703*16a497c6SRafael Auler   "pop %%rsi\n"                                                                \
1704*16a497c6SRafael Auler   "pop %%rdi\n"                                                                \
1705*16a497c6SRafael Auler   "pop %%rdx\n"                                                                \
1706*16a497c6SRafael Auler   "pop %%rcx\n"                                                                \
1707*16a497c6SRafael Auler   "pop %%rbx\n"                                                                \
1708*16a497c6SRafael Auler   "pop %%rax\n"
1709*16a497c6SRafael Auler 
1710*16a497c6SRafael Auler /// We receive as in-stack arguments the identifier of the indirect call site
1711*16a497c6SRafael Auler /// as well as the target address for the call
1712*16a497c6SRafael Auler extern "C" __attribute((naked)) void __bolt_instr_indirect_call()
1713*16a497c6SRafael Auler {
1714*16a497c6SRafael Auler   __asm__ __volatile__(SAVE_ALL
1715*16a497c6SRafael Auler                        "mov 0x88(%%rsp), %%rdi\n"
1716*16a497c6SRafael Auler                        "mov 0x80(%%rsp), %%rsi\n"
1717*16a497c6SRafael Auler                        "call instrumentIndirectCall\n"
1718*16a497c6SRafael Auler                        RESTORE_ALL
1719*16a497c6SRafael Auler                        "pop %%rdi\n"
1720*16a497c6SRafael Auler                        "add $16, %%rsp\n"
1721*16a497c6SRafael Auler                        "xchg (%%rsp), %%rdi\n"
1722*16a497c6SRafael Auler                        "jmp *-8(%%rsp)\n"
1723*16a497c6SRafael Auler                        :::);
1724*16a497c6SRafael Auler }
1725*16a497c6SRafael Auler 
1726*16a497c6SRafael Auler extern "C" __attribute((naked)) void __bolt_instr_indirect_tailcall()
1727*16a497c6SRafael Auler {
1728*16a497c6SRafael Auler   __asm__ __volatile__(SAVE_ALL
1729*16a497c6SRafael Auler                        "mov 0x80(%%rsp), %%rdi\n"
1730*16a497c6SRafael Auler                        "mov 0x78(%%rsp), %%rsi\n"
1731*16a497c6SRafael Auler                        "call instrumentIndirectCall\n"
1732*16a497c6SRafael Auler                        RESTORE_ALL
1733*16a497c6SRafael Auler                        "add $16, %%rsp\n"
1734*16a497c6SRafael Auler                        "pop %%rdi\n"
1735*16a497c6SRafael Auler                        "jmp *-16(%%rsp)\n"
1736*16a497c6SRafael Auler                        :::);
1737*16a497c6SRafael Auler }
1738*16a497c6SRafael Auler 
1739*16a497c6SRafael Auler /// This is hooking ELF's entry, it needs to save all machine state.
1740*16a497c6SRafael Auler extern "C" __attribute((naked)) void __bolt_instr_start()
1741*16a497c6SRafael Auler {
1742*16a497c6SRafael Auler   __asm__ __volatile__(SAVE_ALL
1743*16a497c6SRafael Auler                        "call __bolt_instr_setup\n"
1744*16a497c6SRafael Auler                        RESTORE_ALL
1745*16a497c6SRafael Auler                        "jmp *__bolt_instr_init_ptr\n"
1746*16a497c6SRafael Auler                        :::);
1747*16a497c6SRafael Auler }
1748*16a497c6SRafael Auler 
1749*16a497c6SRafael Auler /// This is hooking into ELF's DT_FINI
1750*16a497c6SRafael Auler extern "C" void __bolt_instr_fini() {
1751*16a497c6SRafael Auler   __bolt_instr_fini_ptr();
1752*16a497c6SRafael Auler   if (__bolt_instr_sleep_time == 0)
1753*16a497c6SRafael Auler     __bolt_instr_data_dump();
1754*16a497c6SRafael Auler   DEBUG(report("Finished.\n"));
175562aa74f8SRafael Auler }
1756