From 61a0f1c5646dad62af289f5f7a5541b2b2b35377 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 14 Mar 2014 08:06:15 +0000 Subject: [PATCH] [sanitizer] partially implement racy fast path in bitset-based deadlock detector llvm-svn: 203904 --- .../lib/sanitizer_common/sanitizer_bvgraph.h | 14 ++++++++++++++ .../sanitizer_common/sanitizer_deadlock_detector.h | 10 ++++++++++ .../sanitizer_deadlock_detector1.cc | 2 ++ .../tests/sanitizer_bvgraph_test.cc | 4 ++++ 4 files changed, 30 insertions(+) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h b/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h index a55757b5d4c9..9a547d3d4b0b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h @@ -60,6 +60,20 @@ class BVGraph { return res; } + // *EXPERIMENTAL* + // Returns true if all edges from=>to exist. + // This function does not use any global state except for 'this' itself, + // and thus can be called from different threads w/o locking. + // This would be racy. + // FIXME: investigate how much we can prove about this race being "benign". + bool hasAllEdges(const BV &from, uptr to) { + for (typename BV::Iterator it(from); it.hasNext(); ) { + uptr idx = it.next(); + if (!v[idx].getBit(to)) return false; + } + return true; + } + // Returns true if the edge from=>to was removed. bool removeEdge(uptr from, uptr to) { return v[from].clearBit(to); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h index 33913137f288..6d4cec86c4ea 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h @@ -172,6 +172,16 @@ class DeadlockDetector { dtls->addLock(cur_idx, current_epoch_); } + // Experimental *racy* fast path function. + // Returns true if all edges from the currently held locks to cur_node exist. + bool hasAllEdges(DeadlockDetectorTLS *dtls, uptr cur_node) { + if (dtls->getEpoch() == nodeToEpoch(cur_node)) { + uptr cur_idx = nodeToIndexUnchecked(cur_node); + return g_.hasAllEdges(dtls->getLocks(current_epoch_), cur_idx); + } + return false; + } + // Adds edges from currently held locks to cur_node, // returns the number of added edges, and puts the sources of added edges // into added_edges[]. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc index 9dbb38f71a10..3f02b3417a22 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc @@ -100,6 +100,7 @@ void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) { DDLogicalThread *lt = cb->lt; if (lt->dd.empty()) return; // This will be the first lock held by lt. + if (dd.hasAllEdges(<->dd, m->id)) return; // We already have all edges. SpinMutexLock lk(&mtx); MutexEnsureID(lt, m); if (dd.isHeld(<->dd, m->id)) @@ -131,6 +132,7 @@ void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) { // Printf("T%p MutexLock: %zx\n", lt, m->id); if (dd.onFirstLock(<->dd, m->id)) return; + // if (dd.hasAllEdges(<->dd, m->id)) return; SpinMutexLock lk(&mtx); MutexEnsureID(lt, m); if (wlock) // Only a recursive rlock may be held. diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc index b7be2a862140..d0f03800fc2d 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc @@ -320,10 +320,14 @@ void RunAddEdgesTest() { from.clear(); from.setBit(1); EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges)); + EXPECT_TRUE(g.hasAllEdges(from, 4)); + EXPECT_FALSE(g.hasAllEdges(from, 5)); EXPECT_EQ(1U, added_edges[0]); from.setBit(2); from.setBit(3); + EXPECT_FALSE(g.hasAllEdges(from, 4)); EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges)); + EXPECT_TRUE(g.hasAllEdges(from, 4)); EXPECT_EQ(2U, added_edges[0]); EXPECT_EQ(3U, added_edges[1]); }