summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2013-03-18 13:55:33 +0000
committerDmitry Vyukov <dvyukov@google.com>2013-03-18 13:55:33 +0000
commit5d72fc796f21fb9714722e0006d72213fb300688 (patch)
tree40e118302835922878ae23d6be85c13116e8b5ae
parentac1f5cafad90d902056f458ce5aec27b87260a52 (diff)
downloadcompiler-rt-5d72fc796f21fb9714722e0006d72213fb300688.tar.gz
compiler-rt-5d72fc796f21fb9714722e0006d72213fb300688.tar.bz2
compiler-rt-5d72fc796f21fb9714722e0006d72213fb300688.tar.xz
tsan: better memory profiler
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@177286 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/tsan/rtl/tsan_platform.h2
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc73
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc20
3 files changed, 80 insertions, 15 deletions
diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h
index 8a17bb9b..d6b331a7 100644
--- a/lib/tsan/rtl/tsan_platform.h
+++ b/lib/tsan/rtl/tsan_platform.h
@@ -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();
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index a1e25293..02a66484 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -42,8 +42,10 @@
#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() {
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index c25530cb..2e9a36b9 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -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);
}