summaryrefslogtreecommitdiff
path: root/lib/tsan
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2012-05-22 11:33:03 +0000
committerDmitry Vyukov <dvyukov@google.com>2012-05-22 11:33:03 +0000
commit26127735454fddae3495794f38189d57dde6510f (patch)
tree62cc5338cb4528534fd34bfa0328881a61bd7f14 /lib/tsan
parent9003eae323f92d68b834f649de17774a21866f0d (diff)
tsan: simple memory profiler
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@157248 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/tsan')
-rw-r--r--lib/tsan/rtl/tsan_flags.cc2
-rw-r--r--lib/tsan/rtl/tsan_flags.h2
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc6
-rw-r--r--lib/tsan/rtl/tsan_mutex.cc2
-rw-r--r--lib/tsan/rtl/tsan_platform.h7
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc10
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc59
-rw-r--r--lib/tsan/rtl/tsan_sync.cc20
-rw-r--r--lib/tsan/rtl/tsan_sync.h6
9 files changed, 110 insertions, 4 deletions
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 95594c40b..5a0b7cec6 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -46,6 +46,7 @@ void InitializeFlags(Flags *f, const char *env) {
f->log_fileno = 2;
f->atexit_sleep_ms = 1000;
f->verbosity = 0;
+ f->profile_memory = "";
// Let a frontend override.
OverrideFlags(f);
@@ -63,6 +64,7 @@ void InitializeFlags(Flags *f, const char *env) {
Flag(env, &f->log_fileno, "log_fileno");
Flag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
Flag(env, &f->verbosity, "verbosity");
+ Flag(env, &f->profile_memory, "profile_memory");
}
static const char *GetFlagValue(const char *env, const char *name,
diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h
index 7a3c4aff2..8e0dc815a 100644
--- a/lib/tsan/rtl/tsan_flags.h
+++ b/lib/tsan/rtl/tsan_flags.h
@@ -46,6 +46,8 @@ struct Flags {
int atexit_sleep_ms;
// Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
int verbosity;
+ // If set, periodically write memory profile to that file.
+ const char *profile_memory;
};
Flags *flags();
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 025912c7c..f67a64677 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -1551,4 +1551,10 @@ const char *internal_strchr(const char *where, char what) {
return (const char*)REAL(strchr)((void*)where, what);
}
+void internal_start_thread(void(*func)(void *arg), void *arg) {
+ void *th;
+ REAL(pthread_create)(&th, 0, (void*(*)(void *arg))func, arg);
+ REAL(pthread_detach)(th);
+}
+
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_mutex.cc b/lib/tsan/rtl/tsan_mutex.cc
index a343a8bc2..e95b195aa 100644
--- a/lib/tsan/rtl/tsan_mutex.cc
+++ b/lib/tsan/rtl/tsan_mutex.cc
@@ -163,7 +163,7 @@ class Backoff {
if (iter_++ < kActiveSpinIters)
proc_yield(kActiveSpinCnt);
else
- sched_yield();
+ internal_yield();
return true;
}
diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h
index 9cfe4763f..61b8a697e 100644
--- a/lib/tsan/rtl/tsan_platform.h
+++ b/lib/tsan/rtl/tsan_platform.h
@@ -64,11 +64,16 @@ static inline uptr ShadowToMem(uptr shadow) {
#endif
}
+uptr GetShadowMemoryConsumption();
+
const char *InitializePlatform();
void FinalizePlatform();
int GetPid();
-void sched_yield();
+void internal_yield();
+void internal_sleep_ms(u32 ms);
+
+void internal_start_thread(void(*func)(void*), void *arg);
typedef int fd_t;
const fd_t kInvalidFd = -1;
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index 96702b48c..8bb2b483c 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -59,6 +59,10 @@ void Die() {
_exit(1);
}
+uptr GetShadowMemoryConsumption() {
+ return 0;
+}
+
static void *my_mmap(void *addr, size_t length, int prot, int flags,
int fd, u64 offset) {
ScopedInRtl in_rtl;
@@ -69,11 +73,15 @@ static void *my_mmap(void *addr, size_t length, int prot, int flags,
# endif
}
-void sched_yield() {
+void internal_yield() {
ScopedInRtl in_rtl;
syscall(__NR_sched_yield);
}
+void internal_sleep_ms(u32 ms) {
+ usleep(ms * 1000);
+}
+
fd_t internal_open(const char *name, bool write) {
ScopedInRtl in_rtl;
return syscall(__NR_open, name,
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 28006f00b..af23edb19 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -79,6 +79,64 @@ ThreadContext::ThreadContext(int tid)
, dead_next() {
}
+static void WriteMemoryProfile(char *buf, uptr buf_size, int num) {
+ uptr shadow = GetShadowMemoryConsumption();
+
+ int nthread = 0;
+ int nlivethread = 0;
+ uptr threadmem = 0;
+ {
+ Lock l(&ctx->thread_mtx);
+ for (unsigned i = 0; i < kMaxTid; i++) {
+ ThreadContext *tctx = ctx->threads[i];
+ if (tctx == 0)
+ continue;
+ nthread += 1;
+ threadmem += sizeof(ThreadContext);
+ if (tctx->status != ThreadStatusRunning)
+ continue;
+ nlivethread += 1;
+ threadmem += sizeof(ThreadState);
+ }
+ }
+
+ uptr nsync = 0;
+ uptr syncmem = CTX()->synctab.GetMemoryConsumption(&nsync);
+
+ Snprintf(buf, buf_size, "%d: shadow=%luMB"
+ " thread=%luMB(total=%d/live=%d)"
+ " sync=%luMB(cnt=%lu)\n",
+ num,
+ shadow >> 20,
+ threadmem >> 20, nthread, nlivethread,
+ syncmem >> 20, nsync);
+}
+
+static void MemoryProfileThread(void *arg) {
+ ScopedInRtl in_rtl;
+ fd_t fd = (fd_t)(uptr)arg;
+ for (int i = 0; ; i++) {
+ InternalScopedBuf<char> buf(4096);
+ WriteMemoryProfile(buf.Ptr(), buf.Size(), i);
+ internal_write(fd, buf.Ptr(), internal_strlen(buf.Ptr()));
+ internal_sleep_ms(1000);
+ }
+}
+
+static void InitializeMemoryProfile() {
+ if (flags()->profile_memory == 0 || flags()->profile_memory[0] == 0)
+ return;
+ InternalScopedBuf<char> filename(4096);
+ Snprintf(filename.Ptr(), filename.Size(), "%s.%d",
+ flags()->profile_memory, GetPid());
+ fd_t fd = internal_open(filename.Ptr(), true);
+ if (fd == kInvalidFd) {
+ Printf("Failed to open memory profile file '%s'\n", &filename[0]);
+ Die();
+ }
+ internal_start_thread(&MemoryProfileThread, (void*)(uptr)fd);
+}
+
void Initialize(ThreadState *thr) {
// Thread safe because done before all threads exist.
static bool is_initialized = false;
@@ -97,6 +155,7 @@ void Initialize(ThreadState *thr) {
ctx->dead_list_tail = 0;
InitializeFlags(&ctx->flags, env);
InitializeSuppressions();
+ InitializeMemoryProfile();
if (ctx->flags.verbosity)
Printf("***** Running under ThreadSanitizer v2 (pid=%d) *****\n", GetPid());
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 0b31ab9ce..2910ead10 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -107,6 +107,26 @@ SyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
return res;
}
+uptr SyncVar::GetMemoryConsumption() {
+ return sizeof(*this)
+ + clock.size() * sizeof(u64)
+ + read_clock.size() * sizeof(u64)
+ + creation_stack.Size() * sizeof(uptr);
+}
+
+uptr SyncTab::GetMemoryConsumption(uptr *nsync) {
+ uptr mem = 0;
+ for (int i = 0; i < kPartCount; i++) {
+ Part *p = &tab_[i];
+ Lock l(&p->mtx);
+ for (SyncVar *s = p->val; s; s = s->next) {
+ *nsync += 1;
+ mem += s->GetMemoryConsumption();
+ }
+ }
+ return mem;
+}
+
int SyncTab::PartIdx(uptr addr) {
return (addr >> 3) % kPartCount;
}
diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h
index 45251f02e..516e46b66 100644
--- a/lib/tsan/rtl/tsan_sync.h
+++ b/lib/tsan/rtl/tsan_sync.h
@@ -52,14 +52,16 @@ struct SyncVar {
Mutex mtx;
const uptr addr;
SyncClock clock;
- StackTrace creation_stack;
SyncClock read_clock; // Used for rw mutexes only.
+ StackTrace creation_stack;
int owner_tid; // Set only by exclusive owners.
int recursion;
bool is_rw;
bool is_recursive;
bool is_broken;
SyncVar *next; // In SyncTab hashtable.
+
+ uptr GetMemoryConsumption();
};
class SyncTab {
@@ -74,6 +76,8 @@ class SyncTab {
// If the SyncVar does not exist, returns 0.
SyncVar* GetAndRemove(ThreadState *thr, uptr pc, uptr addr);
+ uptr GetMemoryConsumption(uptr *nsync);
+
private:
struct Part {
Mutex mtx;