1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/LinuxMallocProfiling.cpp - malloc/new tracing ---------===//
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // The Subzero Code Generator
4*03ce13f7SAndroid Build Coastguard Worker //
5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker ///
10*03ce13f7SAndroid Build Coastguard Worker /// \file
11*03ce13f7SAndroid Build Coastguard Worker /// \brief malloc/new/...caller tracing.
12*03ce13f7SAndroid Build Coastguard Worker ///
13*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #include "LinuxMallocProfiling.h"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #ifdef ALLOW_LINUX_MALLOC_PROFILE
18*03ce13f7SAndroid Build Coastguard Worker
19*03ce13f7SAndroid Build Coastguard Worker #include <dlfcn.h>
20*03ce13f7SAndroid Build Coastguard Worker #include <malloc.h>
21*03ce13f7SAndroid Build Coastguard Worker #include <unordered_map>
22*03ce13f7SAndroid Build Coastguard Worker
23*03ce13f7SAndroid Build Coastguard Worker extern "C" void *__libc_malloc(size_t size);
24*03ce13f7SAndroid Build Coastguard Worker
25*03ce13f7SAndroid Build Coastguard Worker namespace {
26*03ce13f7SAndroid Build Coastguard Worker // The Callers structure allocates memory, which would perturb the tracing.
27*03ce13f7SAndroid Build Coastguard Worker // InAllocatorFunction is true when we are tracing a new/malloc/...
28*03ce13f7SAndroid Build Coastguard Worker bool InAllocatorFunction = false;
29*03ce13f7SAndroid Build Coastguard Worker
30*03ce13f7SAndroid Build Coastguard Worker // Keep track of the number of times a particular call site address invoked an
31*03ce13f7SAndroid Build Coastguard Worker // allocator. NOTE: this is not thread safe, so the user must invoke with
32*03ce13f7SAndroid Build Coastguard Worker // --threads=0 to enable profiling.
33*03ce13f7SAndroid Build Coastguard Worker using MallocMap = std::unordered_map<void *, uint64_t>;
34*03ce13f7SAndroid Build Coastguard Worker MallocMap *Callers;
35*03ce13f7SAndroid Build Coastguard Worker
internalAllocator(size_t size,void * caller)36*03ce13f7SAndroid Build Coastguard Worker void *internalAllocator(size_t size, void *caller) {
37*03ce13f7SAndroid Build Coastguard Worker if (Callers != nullptr && !InAllocatorFunction) {
38*03ce13f7SAndroid Build Coastguard Worker InAllocatorFunction = true;
39*03ce13f7SAndroid Build Coastguard Worker ++(*Callers)[caller];
40*03ce13f7SAndroid Build Coastguard Worker InAllocatorFunction = false;
41*03ce13f7SAndroid Build Coastguard Worker }
42*03ce13f7SAndroid Build Coastguard Worker return __libc_malloc(size);
43*03ce13f7SAndroid Build Coastguard Worker }
44*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
45*03ce13f7SAndroid Build Coastguard Worker
46*03ce13f7SAndroid Build Coastguard Worker // new, new[], and malloc are all defined as weak symbols to allow them to be
47*03ce13f7SAndroid Build Coastguard Worker // overridden by user code. This gives us a convenient place to hook allocation
48*03ce13f7SAndroid Build Coastguard Worker // tracking, to record the IP of the caller, which we get from the call to
49*03ce13f7SAndroid Build Coastguard Worker // __builtin_return_address.
operator new(size_t size)50*03ce13f7SAndroid Build Coastguard Worker void *operator new(size_t size) {
51*03ce13f7SAndroid Build Coastguard Worker void *caller = __builtin_return_address(0);
52*03ce13f7SAndroid Build Coastguard Worker return internalAllocator(size, caller);
53*03ce13f7SAndroid Build Coastguard Worker }
54*03ce13f7SAndroid Build Coastguard Worker
operator new[](size_t size)55*03ce13f7SAndroid Build Coastguard Worker void *operator new[](size_t size) {
56*03ce13f7SAndroid Build Coastguard Worker void *caller = __builtin_return_address(0);
57*03ce13f7SAndroid Build Coastguard Worker return internalAllocator(size, caller);
58*03ce13f7SAndroid Build Coastguard Worker }
59*03ce13f7SAndroid Build Coastguard Worker
malloc(size_t size)60*03ce13f7SAndroid Build Coastguard Worker extern "C" void *malloc(size_t size) {
61*03ce13f7SAndroid Build Coastguard Worker void *caller = __builtin_return_address(0);
62*03ce13f7SAndroid Build Coastguard Worker return internalAllocator(size, caller);
63*03ce13f7SAndroid Build Coastguard Worker }
64*03ce13f7SAndroid Build Coastguard Worker
65*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
66*03ce13f7SAndroid Build Coastguard Worker
LinuxMallocProfiling(size_t NumThreads,Ostream * Ls)67*03ce13f7SAndroid Build Coastguard Worker LinuxMallocProfiling::LinuxMallocProfiling(size_t NumThreads, Ostream *Ls)
68*03ce13f7SAndroid Build Coastguard Worker : Ls(Ls) {
69*03ce13f7SAndroid Build Coastguard Worker if (NumThreads != 0) {
70*03ce13f7SAndroid Build Coastguard Worker *Ls << "NOTE: Malloc profiling is not thread safe. Use --threads=0 to "
71*03ce13f7SAndroid Build Coastguard Worker "enable.\n";
72*03ce13f7SAndroid Build Coastguard Worker return;
73*03ce13f7SAndroid Build Coastguard Worker }
74*03ce13f7SAndroid Build Coastguard Worker Callers = new MallocMap();
75*03ce13f7SAndroid Build Coastguard Worker }
76*03ce13f7SAndroid Build Coastguard Worker
~LinuxMallocProfiling()77*03ce13f7SAndroid Build Coastguard Worker LinuxMallocProfiling::~LinuxMallocProfiling() {
78*03ce13f7SAndroid Build Coastguard Worker if (Callers == nullptr) {
79*03ce13f7SAndroid Build Coastguard Worker return;
80*03ce13f7SAndroid Build Coastguard Worker }
81*03ce13f7SAndroid Build Coastguard Worker for (const auto &C : *Callers) {
82*03ce13f7SAndroid Build Coastguard Worker Dl_info dli;
83*03ce13f7SAndroid Build Coastguard Worker dladdr(C.first, &dli);
84*03ce13f7SAndroid Build Coastguard Worker
85*03ce13f7SAndroid Build Coastguard Worker *Ls << C.second << " ";
86*03ce13f7SAndroid Build Coastguard Worker if (dli.dli_sname == NULL) {
87*03ce13f7SAndroid Build Coastguard Worker *Ls << C.first;
88*03ce13f7SAndroid Build Coastguard Worker } else {
89*03ce13f7SAndroid Build Coastguard Worker *Ls << dli.dli_sname;
90*03ce13f7SAndroid Build Coastguard Worker }
91*03ce13f7SAndroid Build Coastguard Worker *Ls << "\n";
92*03ce13f7SAndroid Build Coastguard Worker }
93*03ce13f7SAndroid Build Coastguard Worker delete Callers;
94*03ce13f7SAndroid Build Coastguard Worker Callers = nullptr;
95*03ce13f7SAndroid Build Coastguard Worker }
96*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
97*03ce13f7SAndroid Build Coastguard Worker
98*03ce13f7SAndroid Build Coastguard Worker #else // !ALLOW_LINUX_MALLOC_PROFILE
99*03ce13f7SAndroid Build Coastguard Worker
100*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
101*03ce13f7SAndroid Build Coastguard Worker
LinuxMallocProfiling(size_t NumThreads,Ostream * Ls)102*03ce13f7SAndroid Build Coastguard Worker LinuxMallocProfiling::LinuxMallocProfiling(size_t NumThreads, Ostream *Ls) {
103*03ce13f7SAndroid Build Coastguard Worker (void)NumThreads;
104*03ce13f7SAndroid Build Coastguard Worker (void)Ls;
105*03ce13f7SAndroid Build Coastguard Worker }
106*03ce13f7SAndroid Build Coastguard Worker
~LinuxMallocProfiling()107*03ce13f7SAndroid Build Coastguard Worker LinuxMallocProfiling::~LinuxMallocProfiling() {}
108*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
109*03ce13f7SAndroid Build Coastguard Worker
110*03ce13f7SAndroid Build Coastguard Worker #endif // ALLOW_LINUX_MALLOC_PROFILE
111