From 1222ad0f487bd4b00f371a580a17ecf494aeb0fb Mon Sep 17 00:00:00 2001 From: bert hubert Date: Mon, 23 Nov 2015 17:09:56 +0100 Subject: [PATCH] simple malloc tracing infra --- pdns/malloctrace.cc | 130 ++++++++++++++++++++++++++++++++++++++++++++ pdns/malloctrace.hh | 40 ++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 pdns/malloctrace.cc create mode 100644 pdns/malloctrace.hh diff --git a/pdns/malloctrace.cc b/pdns/malloctrace.cc new file mode 100644 index 000000000..268580d00 --- /dev/null +++ b/pdns/malloctrace.cc @@ -0,0 +1,130 @@ +#include "malloctrace.hh" +#include +#include + +using std::string; +using std::map; +using std::vector; + +MallocTracer* g_mtracer; + +#if 1 +#include +vector MallocTracer::makeBacktrace() +{ + void *array[20]; //only care about last 17 functions (3 taken with tracing support) + size_t size = backtrace (array, 20); + return vector(array, array+size); +} + + +extern "C" { +extern void *__libc_malloc(size_t size); +extern void __libc_free(void* ptr); + +void* malloc (size_t size) +{ + if(!g_mtracer) { + void *mem = __libc_malloc(sizeof(MallocTracer)); + g_mtracer = new(mem) MallocTracer; + } + return g_mtracer->malloc(size); +} + +void free(void* ptr) +{ + if(ptr) + g_mtracer->free(ptr); +} +} + +#endif + +static thread_local bool l_active; +void* MallocTracer::malloc(size_t size) +{ + void* ret = __libc_malloc(size); + if(!l_active) { + l_active=true; + + d_allocflux+=size; + d_allocs++; + d_totAllocated += size; + + + std::lock_guard lock(d_mut); + auto& ent=d_stats[makeBacktrace()]; + ent.count++; + ent.sizes[size]++; + d_sizes[ret]=size; + + l_active=false; + } + return ret; +} + +void MallocTracer::free(void* ptr) +{ + __libc_free(ptr); + if(!l_active) { + l_active=true; + std::lock_guard lock(d_mut); + auto f = d_sizes.find(ptr); + if(f != d_sizes.end()) { + d_totAllocated -= f->second; + d_sizes.erase(f); + } + l_active=false; + } +} + +MallocTracer::allocators_t MallocTracer::topAllocators(int num) +{ + l_active=true; + allocators_t ret; + for(const auto& e : d_stats) { + ret.push_back(make_pair(e.second, e.first)); + } + std::sort(ret.begin(), ret.end(), + [](const allocators_t::value_type& a, + const allocators_t::value_type& b) { + return a.first.count < b.first.count; + }); + if(num > 0) + ret.erase(ret.begin(), ret.begin() + (ret.size() - num)); + l_active=false; + return ret; +} + +std::string MallocTracer::topAllocatorsString(int num) +{ + l_active=true; + auto raw = topAllocators(num); + l_active=true; + std::ostringstream ret; + for(const auto& e : raw) { + ret<<"Called "< +#include +#include +#include +#include +#include + +/* please do NOT add PowerDNS specific includes/things to this file, we're trying + to make it useful for other projects as well! */ + +/* Goal: you can compile this in safely, but it won't do anything unless PDNS_TRACE_MEMORY is defined. */ + +class MallocTracer +{ +public: + void* malloc (size_t size); + void free(void*); + uint64_t getAllocs(const std::string& = std::string()) const { return d_allocs; } + uint64_t getAllocFlux(const std::string& = std::string()) const { return d_allocflux; } + uint64_t getTotAllocated(const std::string& = std::string()) const { return d_totAllocated; } + + struct AllocStats + { + int count; + std::map sizes; + }; + typedef std::vector > > allocators_t; + allocators_t topAllocators(int num=-1); + std::string topAllocatorsString(int num=-1); +private: + static std::vector makeBacktrace(); + std::atomic d_allocs{0}, d_allocflux{0}, d_totAllocated{0}; + std::map, AllocStats> d_stats; + std::map d_sizes; + std::mutex d_mut; +}; + +extern MallocTracer* g_mtracer; -- 2.40.0