[compiler-rt] r201210 - [sanitizer] added a bit vector class to be used in a deadlock detector
Kostya Serebryany
kcc at google.com
Tue Feb 11 23:05:25 PST 2014
Author: kcc
Date: Wed Feb 12 01:05:24 2014
New Revision: 201210
URL: http://llvm.org/viewvc/llvm-project?rev=201210&view=rev
Log:
[sanitizer] added a bit vector class to be used in a deadlock detector
Added:
compiler-rt/trunk/lib/sanitizer_common/sanitizer_bitvector.h
compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
Modified:
compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
compiler-rt/trunk/lib/sanitizer_common/tests/CMakeLists.txt
Modified: compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt?rev=201210&r1=201209&r2=201210&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt Wed Feb 12 01:05:24 2014
@@ -44,6 +44,7 @@ set(SANITIZER_HEADERS
sanitizer_atomic.h
sanitizer_atomic_clang.h
sanitizer_atomic_msvc.h
+ sanitizer_bitvector.h
sanitizer_common.h
sanitizer_common_interceptors.inc
sanitizer_common_interceptors_ioctl.inc
Added: compiler-rt/trunk/lib/sanitizer_common/sanitizer_bitvector.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_bitvector.h?rev=201210&view=auto
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_bitvector.h (added)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_bitvector.h Wed Feb 12 01:05:24 2014
@@ -0,0 +1,143 @@
+//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Specializer BitVector implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BITVECTOR_H
+#define SANITIZER_BITVECTOR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+// Fixed size bit vector based on a single basic integer.
+template <class basic_int_t = uptr>
+class BasicBitVector {
+ public:
+ enum SizeEnum { kSize = sizeof(basic_int_t) * 8 };
+ uptr size() const { return kSize; }
+ // No CTOR.
+ void clear() { bits_ = 0; }
+ bool empty() const { return bits_ == 0; }
+ void setBit(uptr idx) { bits_ |= mask(idx); }
+ void clearBit(uptr idx) { bits_ &= ~mask(idx); }
+ bool getBit(uptr idx) const { return bits_ & mask(idx); }
+ uptr getAndClearFirstOne() {
+ CHECK(!empty());
+ // FIXME: change to LeastSignificantSetBitIndex?
+ uptr idx = MostSignificantSetBitIndex(bits_);
+ clearBit(idx);
+ return idx;
+ }
+
+ private:
+ basic_int_t mask(uptr idx) const {
+ CHECK_LE(idx, size());
+ return (basic_int_t)1UL << idx;
+ }
+ basic_int_t bits_;
+};
+
+// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
+// The implementation is optimized for a sparse bit vector, i.e. the one
+// that has few set bits.
+template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
+class TwoLevelBitVector {
+ // This is essentially a 2-level bit vector.
+ // Set bit in the first level BV indicates that there are set bits
+ // in the corresponding BV of the second level.
+ // This structure allows O(kLevel1Size) time for clear() and empty(),
+ // as well fast handling of sparse BVs.
+ public:
+ enum SizeEnum { kSize = BV::kSize * BV::kSize * kLevel1Size };
+ // No CTOR.
+ uptr size() const { return kSize; }
+ void clear() {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ l1_[i].clear();
+ }
+ bool empty() {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ if (!l1_[i].empty())
+ return false;
+ return true;
+ }
+ void setBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ if (!l1_[i0].getBit(i1)) {
+ l1_[i0].setBit(i1);
+ l2_[i0][i1].clear();
+ }
+ l2_[i0][i1].setBit(i2);
+ // Printf("%s: %zd => %zd %zd %zd\n", __FUNCTION__, idx, i0, i1, i2);
+ }
+ void clearBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ if (l1_[i0].getBit(i1)) {
+ l2_[i0][i1].clearBit(i2);
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ }
+ bool getBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ // Printf("%s: %zd => %zd %zd %zd\n", __FUNCTION__, idx, i0, i1, i2);
+ return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
+ }
+ uptr getAndClearFirstOne() {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ if (l1_[i0].empty()) continue;
+ uptr i1 = l1_[i0].getAndClearFirstOne();
+ uptr i2 = l2_[i0][i1].getAndClearFirstOne();
+ if (!l2_[i0][i1].empty())
+ l1_[i0].setBit(i1);
+ uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
+ // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
+ return res;
+ }
+ CHECK(0);
+ return 0;
+ }
+
+ private:
+ void check(uptr idx) { CHECK_LE(idx, size()); }
+ uptr idx0(uptr idx) {
+ uptr res = idx / (BV::kSize * BV::kSize);
+ CHECK_LE(res, kLevel1Size);
+ return res;
+ }
+ uptr idx1(uptr idx) {
+ uptr res = (idx / BV::kSize) % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+ uptr idx2(uptr idx) {
+ uptr res = idx % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+
+ BV l1_[kLevel1Size];
+ BV l2_[kLevel1Size][BV::kSize];
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BITVECTOR_H
Modified: compiler-rt/trunk/lib/sanitizer_common/tests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/CMakeLists.txt?rev=201210&r1=201209&r2=201210&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/tests/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/sanitizer_common/tests/CMakeLists.txt Wed Feb 12 01:05:24 2014
@@ -3,6 +3,7 @@ include(CompilerRTCompile)
set(SANITIZER_UNITTESTS
sanitizer_allocator_test.cc
sanitizer_atomic_test.cc
+ sanitizer_bitvector_test.cc
sanitizer_common_test.cc
sanitizer_flags_test.cc
sanitizer_format_interceptor_test.cc
Added: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc?rev=201210&view=auto
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc (added)
+++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc Wed Feb 12 01:05:24 2014
@@ -0,0 +1,91 @@
+//===-- sanitizer_bitvector_test.cc ---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// Tests for sanitizer_bitvector.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bitvector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+template <class BV>
+void TestBitVector(uptr expected_size) {
+ BV bv;
+ EXPECT_EQ(expected_size, BV::kSize);
+ bv.clear();
+ EXPECT_TRUE(bv.empty());
+ bv.setBit(13);
+ EXPECT_FALSE(bv.empty());
+ EXPECT_FALSE(bv.getBit(12));
+ EXPECT_FALSE(bv.getBit(14));
+ EXPECT_TRUE(bv.getBit(13));
+ bv.clearBit(13);
+ EXPECT_FALSE(bv.getBit(13));
+
+ // test random bits
+ bv.clear();
+ set<uptr> s;
+ for (uptr it = 0; it < 1000; it++) {
+ uptr bit = ((uptr)my_rand() % bv.size());
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ switch (my_rand() % 2) {
+ case 0:
+ bv.setBit(bit);
+ s.insert(bit);
+ break;
+ case 1:
+ bv.clearBit(bit);
+ s.erase(bit);
+ break;
+ }
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ }
+
+ // test getAndClearFirstOne.
+ vector<uptr>bits(bv.size());
+ for (uptr it = 0; it < 30; it++) {
+ // iota
+ for (size_t j = 0; j < bits.size(); j++) bits[j] = j;
+ random_shuffle(bits.begin(), bits.end());
+ uptr n_bits = ((uptr)my_rand() % bv.size()) + 1;
+ EXPECT_TRUE(n_bits > 0 && n_bits <= bv.size());
+ bv.clear();
+ set<uptr> s(bits.begin(), bits.begin() + n_bits);
+ for (uptr i = 0; i < n_bits; i++) {
+ bv.setBit(bits[i]);
+ s.insert(bits[i]);
+ }
+ while (!bv.empty()) {
+ uptr idx = bv.getAndClearFirstOne();
+ EXPECT_TRUE(s.erase(idx));
+ }
+ EXPECT_TRUE(s.empty());
+ }
+}
+
+TEST(SanitizerCommon, BasicBitVector) {
+ TestBitVector<BasicBitVector<> >(SANITIZER_WORDSIZE);
+}
+
+TEST(SanitizerCommon, TwoLevelBitVector) {
+ uptr ws = SANITIZER_WORDSIZE;
+ TestBitVector<TwoLevelBitVector<> >(ws * ws);
+ TestBitVector<TwoLevelBitVector<2> >(ws * ws * 2);
+ TestBitVector<TwoLevelBitVector<3> >(ws * ws * 3);
+}
More information about the llvm-commits
mailing list