[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