[compiler-rt] d194705 - [sanitizer] Add a ForEach callback interface for AddrHashMap.
Snehasish Kumar via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 11 11:31:36 PST 2021
Author: Snehasish Kumar
Date: 2021-11-11T11:29:36-08:00
New Revision: d19470540a0769313d219295f245975af5589edb
URL: https://github.com/llvm/llvm-project/commit/d19470540a0769313d219295f245975af5589edb
DIFF: https://github.com/llvm/llvm-project/commit/d19470540a0769313d219295f245975af5589edb.diff
LOG: [sanitizer] Add a ForEach callback interface for AddrHashMap.
This change adds a ForEach method to the AddrHashMap class which can
then be used to iterate over all the key value pairs in the hash map.
I intend to use this in an upcoming change to the memprof runtime.
Added a unit test to cover basic insertion and the ForEach callback.
Differential Revision: https://reviews.llvm.org/D111368
Added:
compiler-rt/lib/sanitizer_common/tests/sanitizer_addrhashmap_test.cpp
Modified:
compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
Removed:
################################################################################
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h b/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
index 73b48cb27ddca..7e2fa91089f13 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
@@ -39,6 +39,11 @@ namespace __sanitizer {
// the current thread has exclusive access to the data
// if !h.exists() then the element never existed
// }
+// {
+// Map::Handle h(&m, addr, false, true);
+// this will create a new element or return a handle to an existing element
+// if !h.created() this thread does *not* have exclusive access to the data
+// }
template<typename T, uptr kSize>
class AddrHashMap {
private:
@@ -89,6 +94,12 @@ class AddrHashMap {
bool create_;
};
+ typedef void (*ForEachCallback)(const uptr key, const T &val, void *arg);
+ // ForEach acquires a lock on each bucket while iterating over
+ // elements. Note that this only ensures that the structure of the hashmap is
+ // unchanged, there may be a data race to the element itself.
+ void ForEach(ForEachCallback cb, void *arg);
+
private:
friend class Handle;
Bucket *table_;
@@ -98,6 +109,33 @@ class AddrHashMap {
uptr calcHash(uptr addr);
};
+template <typename T, uptr kSize>
+void AddrHashMap<T, kSize>::ForEach(ForEachCallback cb, void *arg) {
+ for (uptr n = 0; n < kSize; n++) {
+ Bucket *bucket = &table_[n];
+
+ ReadLock lock(&bucket->mtx);
+
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &bucket->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_acquire);
+ if (addr1 != 0)
+ cb(addr1, c->val, arg);
+ }
+
+ // Iterate over any additional cells.
+ if (AddBucket *add =
+ (AddBucket *)atomic_load(&bucket->add, memory_order_acquire)) {
+ for (uptr i = 0; i < add->size; i++) {
+ Cell *c = &add->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_acquire);
+ if (addr1 != 0)
+ cb(addr1, c->val, arg);
+ }
+ }
+ }
+}
+
template<typename T, uptr kSize>
AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) {
map_ = map;
diff --git a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
index e982992af07a1..d689d60d06f2f 100644
--- a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
@@ -9,6 +9,7 @@ if(APPLE)
endif()
set(SANITIZER_UNITTESTS
+ sanitizer_addrhashmap_test.cpp
sanitizer_allocator_test.cpp
sanitizer_atomic_test.cpp
sanitizer_bitvector_test.cpp
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_addrhashmap_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_addrhashmap_test.cpp
new file mode 100644
index 0000000000000..8c7574eb326af
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_addrhashmap_test.cpp
@@ -0,0 +1,62 @@
+//===-- sanitizer_addrhashmap_test.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_addrhashmap.h"
+
+#include <unordered_map>
+
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+struct Value {
+ int payload;
+ inline bool operator==(const Value& rhs) const {
+ return payload == rhs.payload;
+ }
+};
+
+using MapTy = AddrHashMap<Value, 11>;
+using HandleTy = MapTy::Handle;
+using RefMapTy = std::unordered_map<uptr, Value>;
+
+static void ExistsInReferenceMap(const uptr key, const Value& val, void* arg) {
+ RefMapTy* ref = reinterpret_cast<RefMapTy*>(arg);
+ const RefMapTy::iterator iter = ref->find(key);
+ ASSERT_NE(iter, ref->end());
+ EXPECT_EQ(iter->second, val);
+ ref->erase(iter);
+}
+
+TEST(AddrHashMap, Basic) {
+ // Use a reference implementation to compare with.
+ RefMapTy reference_map{
+ {0x1000, {1}},
+ {0x2000, {2}},
+ {0x3000, {3}},
+ };
+
+ MapTy m;
+
+ for (const auto& key_val : reference_map) {
+ const uptr key = key_val.first;
+ const Value val = key_val.second;
+
+ // Insert all the elements.
+ {
+ HandleTy h(&m, key);
+ ASSERT_TRUE(h.created());
+ h->payload = val.payload;
+ }
+ }
+
+ // Now check that all the elements are present.
+ m.ForEach(ExistsInReferenceMap, &reference_map);
+ EXPECT_TRUE(reference_map.empty());
+}
+
+} // namespace __sanitizer
More information about the llvm-commits
mailing list