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