tsan: better memory profiler
authorDmitry Vyukov <dvyukov@google.com>
Mon, 18 Mar 2013 13:55:33 +0000 (13:55 +0000)
committerDmitry Vyukov <dvyukov@google.com>
Mon, 18 Mar 2013 13:55:33 +0000 (13:55 +0000)
llvm-svn: 177286

compiler-rt/lib/tsan/rtl/tsan_platform.h
compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
compiler-rt/lib/tsan/rtl/tsan_rtl.cc

index 8a17bb9..d6b331a 100644 (file)
@@ -132,8 +132,8 @@ static inline uptr AlternativeAddress(uptr addr) {
 #endif
 }
 
-uptr GetShadowMemoryConsumption();
 void FlushShadowMemory();
+void WriteMemoryProfile(char *buf, uptr buf_size);
 
 const char *InitializePlatform();
 void FinalizePlatform();
index a1e2529..02a6648 100644 (file)
 #include <dlfcn.h>
 #define __need_res_state
 #include <resolv.h>
+#include <malloc.h>
 
 extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
+extern "C" struct mallinfo __libc_mallinfo();
 
 namespace __tsan {
 
@@ -68,8 +70,75 @@ ScopedInRtl::~ScopedInRtl() {
 }
 #endif
 
-uptr GetShadowMemoryConsumption() {
-  return 0;
+static bool ishex(char c) {
+  return (c >= '0' && c <= '9')
+      || (c >= 'a' && c <= 'f');
+}
+
+static uptr readhex(const char *p) {
+  uptr v = 0;
+  for (; ishex(p[0]); p++) {
+    if (p[0] >= '0' && p[0] <= '9')
+      v = v * 16 + p[0] - '0';
+    else
+      v = v * 16 + p[0] - 'a' + 10;
+  }
+  return v;
+}
+
+static uptr readdec(const char *p) {
+  uptr v = 0;
+  for (; p[0] >= '0' && p[0] <= '9' ; p++)
+    v = v * 10 + p[0] - '0';
+  return v;
+}
+
+void WriteMemoryProfile(char *buf, uptr buf_size) {
+  char *smaps = 0;
+  uptr smaps_cap = 0;
+  uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
+      &smaps, &smaps_cap, 64<<20);
+  uptr mem[6] = {};
+  uptr total = 0;
+  uptr start = 0;
+  bool file = false;
+  const char *pos = smaps;
+  while (pos < smaps + smaps_len) {
+    if (ishex(pos[0])) {
+      start = readhex(pos);
+      for (; *pos != '/' && *pos > '\n'; pos++) {}
+      file = *pos == '/';
+    } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
+      for (; *pos < '0' || *pos > '9'; pos++) {}
+      uptr rss = readdec(pos) * 1024;
+      total += rss;
+      start >>= 40;
+      if (start < 0x10)  // shadow
+        mem[0] += rss;
+      else if (start >= 0x20 && start < 0x30)  // compat modules
+        mem[file ? 1 : 2] += rss;
+      else if (start >= 0x7e)  // modules
+        mem[file ? 1 : 2] += rss;
+      else if (start >= 0x60 && start < 0x62)  // traces
+        mem[3] += rss;
+      else if (start >= 0x7d && start < 0x7e)  // heap
+        mem[4] += rss;
+      else  // other
+        mem[5] += rss;
+    }
+    while (*pos++ != '\n') {}
+  }
+  UnmapOrDie(smaps, smaps_cap);
+  char *buf_pos = buf;
+  char *buf_end = buf + buf_size;
+  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
+      "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
+      total >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
+      mem[3] >> 20, mem[4] >> 20, mem[5] >> 20);
+  struct mallinfo mi = __libc_mallinfo();
+  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
+      "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
+      mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
 }
 
 void FlushShadowMemory() {
index c25530c..2e9a36b 100644 (file)
@@ -93,23 +93,19 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
   , tls_size(tls_size) {
 }
 
-static void WriteMemoryProfile(char *buf, uptr buf_size, int num) {
-  uptr n_threads;
-  uptr n_running_threads;
-  ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
-  uptr threadmem = n_threads * sizeof(ThreadContext) +
-                   n_running_threads * sizeof(ThreadState);
-
-  internal_snprintf(buf, buf_size, "%d: thread=%zuMB(total=%d/live=%d)\n",
-    num, threadmem >> 20, n_threads, n_running_threads);
-}
-
 static void MemoryProfileThread(void *arg) {
   ScopedInRtl in_rtl;
   fd_t fd = (fd_t)(uptr)arg;
+  Context *ctx = CTX();
   for (int i = 0; ; i++) {
     InternalScopedBuffer<char> buf(4096);
-    WriteMemoryProfile(buf.data(), buf.size(), i);
+    uptr n_threads;
+    uptr n_running_threads;
+    ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
+    internal_snprintf(buf.data(), buf.size(), "%d: nthr=%d nlive=%d\n",
+        i, n_threads, n_running_threads);
+    internal_write(fd, buf.data(), internal_strlen(buf.data()));
+    WriteMemoryProfile(buf.data(), buf.size());
     internal_write(fd, buf.data(), internal_strlen(buf.data()));
     SleepForSeconds(1);
   }