]> granicus.if.org Git - pdns/commitdiff
simple malloc tracing infra
authorbert hubert <bert.hubert@powerdns.com>
Mon, 23 Nov 2015 16:09:56 +0000 (17:09 +0100)
committerbert hubert <bert.hubert@powerdns.com>
Mon, 23 Nov 2015 16:09:56 +0000 (17:09 +0100)
pdns/malloctrace.cc [new file with mode: 0644]
pdns/malloctrace.hh [new file with mode: 0644]

diff --git a/pdns/malloctrace.cc b/pdns/malloctrace.cc
new file mode 100644 (file)
index 0000000..268580d
--- /dev/null
@@ -0,0 +1,130 @@
+#include "malloctrace.hh"
+#include <sstream>
+#include <algorithm>
+
+using std::string;
+using std::map;
+using std::vector;
+
+MallocTracer* g_mtracer;
+
+#if 1
+#include <execinfo.h>
+vector<void*> MallocTracer::makeBacktrace()
+{
+  void *array[20]; //only care about last 17 functions (3 taken with tracing support)
+  size_t size = backtrace (array, 20);
+  return vector<void*>(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<std::mutex> 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<std::mutex> 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 "<<e.first.count<<" times\n";
+    for(const auto& u : e.first.sizes) 
+      ret<<u.first<<"b: "<<u.second<<" times, ";
+    ret<<'\n';
+    char** strings = backtrace_symbols(&e.second[0], e.second.size());
+    for(unsigned int i=0; i < e.second.size(); ++i)
+      ret<<strings[i]<<'\n';
+    ret<<"-----\n";
+  }
+
+  string str =ret.str();
+  l_active=false;
+  return str;
+}
+
+/*
+char **strings;
+  size_t i;
+  strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
+
+  for (i = 0; i < size; i++) //skip useless functions
+    ret+=strings[i]+string("\n");
+  return ret;
+*/
+
diff --git a/pdns/malloctrace.hh b/pdns/malloctrace.hh
new file mode 100644 (file)
index 0000000..83d23b2
--- /dev/null
@@ -0,0 +1,40 @@
+#pragma once
+#include <string>
+#include <atomic>
+#include <stdint.h>
+#include <mutex>
+#include <map>
+#include <vector>
+
+/* 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<unsigned int, unsigned int> sizes;
+  };
+  typedef std::vector<std::pair<MallocTracer::AllocStats, 
+                               std::vector<void*> > > allocators_t;
+  allocators_t topAllocators(int num=-1);
+  std::string topAllocatorsString(int num=-1);
+private:
+  static std::vector<void*> makeBacktrace();
+  std::atomic<uint64_t> d_allocs{0}, d_allocflux{0}, d_totAllocated{0};
+  std::map<std::vector<void*>, AllocStats> d_stats;
+  std::map<void*, size_t> d_sizes;
+  std::mutex d_mut;
+};
+
+extern MallocTracer* g_mtracer;