]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/malloctrace.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / malloctrace.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #include "malloctrace.hh"
23 #include <sstream>
24 #include <algorithm>
25
26 using std::string;
27 using std::map;
28 using std::vector;
29
30 MallocTracer* g_mtracer;
31
32 #if 1
33 #include <execinfo.h>
34 vector<void*> MallocTracer::makeBacktrace()
35 {
36 void *array[20]; //only care about last 17 functions (3 taken with tracing support)
37 size_t size = backtrace (array, 20);
38 return vector<void*>(array, array+size);
39 }
40
41
42 extern "C" {
43 extern void *__libc_malloc(size_t size);
44 extern void __libc_free(void* ptr);
45
46 void* malloc (size_t size)
47 {
48 if(!g_mtracer) {
49 void *mem = __libc_malloc(sizeof(MallocTracer));
50 g_mtracer = new(mem) MallocTracer;
51 }
52 return g_mtracer->malloc(size);
53 }
54
55 void free(void* ptr)
56 {
57 if(ptr)
58 g_mtracer->free(ptr);
59 }
60 }
61
62 #endif
63
64 static thread_local bool l_active;
65 void* MallocTracer::malloc(size_t size)
66 {
67 void* ret = __libc_malloc(size);
68 if(!l_active) {
69 l_active=true;
70
71 d_allocflux+=size;
72 d_allocs++;
73 d_totAllocated += size;
74
75
76 std::lock_guard<std::mutex> lock(d_mut);
77 auto& ent=d_stats[makeBacktrace()];
78 ent.count++;
79 ent.sizes[size]++;
80 d_sizes[ret]=size;
81
82 l_active=false;
83 }
84 return ret;
85 }
86
87 void MallocTracer::free(void* ptr)
88 {
89 __libc_free(ptr);
90 if(!l_active) {
91 l_active=true;
92 std::lock_guard<std::mutex> lock(d_mut);
93 auto f = d_sizes.find(ptr);
94 if(f != d_sizes.end()) {
95 d_totAllocated -= f->second;
96 d_sizes.erase(f);
97 }
98 l_active=false;
99 }
100 }
101
102 MallocTracer::allocators_t MallocTracer::topAllocators(int num)
103 {
104 l_active=true;
105 allocators_t ret;
106 for(const auto& e : d_stats) {
107 ret.push_back(make_pair(e.second, e.first));
108 }
109 std::sort(ret.begin(), ret.end(),
110 [](const allocators_t::value_type& a,
111 const allocators_t::value_type& b) {
112 return a.first.count < b.first.count;
113 });
114 if((unsigned int)num > ret.size())
115 ret.clear();
116 else if(num > 0)
117 ret.erase(ret.begin(), ret.begin() + (ret.size() - num));
118 l_active=false;
119 return ret;
120 }
121
122 std::string MallocTracer::topAllocatorsString(int num)
123 {
124 l_active=true;
125 auto raw = topAllocators(num);
126 l_active=true;
127 std::ostringstream ret;
128 for(const auto& e : raw) {
129 ret<<"Called "<<e.first.count<<" times\n";
130 for(const auto& u : e.first.sizes)
131 ret<<u.first<<"b: "<<u.second<<" times, ";
132 ret<<'\n';
133 char** strings = backtrace_symbols(&e.second[0], e.second.size());
134 for(unsigned int i=0; i < e.second.size(); ++i)
135 ret<<strings[i]<<'\n';
136 ret<<"-----\n";
137 }
138
139 string str =ret.str();
140 l_active=false;
141 return str;
142 }
143
144 void MallocTracer::clearAllocators()
145 {
146 l_active=true;
147 std::lock_guard<std::mutex> lock(d_mut);
148 d_stats.clear();
149 l_active=false;
150 }
151