1 | //===-- sanitizer_flat_map_test.cpp ---------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "sanitizer_common/sanitizer_flat_map.h" |
10 | |
11 | #include "gtest/gtest.h" |
12 | #include "sanitizer_common/tests/sanitizer_pthread_wrappers.h" |
13 | |
14 | using namespace __sanitizer; |
15 | |
16 | namespace { |
17 | |
18 | struct TestStruct { |
19 | int data[125] = {}; |
20 | TestStruct(uptr v = 0) { data[11] = v; } |
21 | bool operator==(const TestStruct &other) const { |
22 | return 0 == memcmp(data, other.data, sizeof(data)); |
23 | } |
24 | }; |
25 | |
26 | template <typename T> |
27 | class FlatMapTest : public ::testing::Test {}; |
28 | |
29 | using FlatMapTestTypes = ::testing::Types<u8, u64, TestStruct>; |
30 | TYPED_TEST_SUITE(FlatMapTest, FlatMapTestTypes, ); |
31 | |
32 | TYPED_TEST(FlatMapTest, TwoLevelByteMap) { |
33 | const u64 kSize1 = 1 << 6, kSize2 = 1 << 12; |
34 | const u64 n = kSize1 * kSize2; |
35 | TwoLevelMap<TypeParam, kSize1, kSize2> m; |
36 | m.Init(); |
37 | |
38 | m[7] = {10}; |
39 | for (u64 i = 0; i < kSize2; ++i) { |
40 | EXPECT_TRUE(m.contains(i)); |
41 | } |
42 | EXPECT_FALSE(m.contains(kSize2)); |
43 | |
44 | for (u64 i = 0; i < n; i += 7) { |
45 | m[i] = TypeParam((i % 100) + 1); |
46 | } |
47 | for (u64 j = 0; j < n; j++) { |
48 | EXPECT_TRUE(m.contains(j)); |
49 | if (j % 7) |
50 | EXPECT_EQ(m[j], TypeParam()); |
51 | else |
52 | EXPECT_EQ(m[j], TypeParam((j % 100) + 1)); |
53 | } |
54 | |
55 | m.TestOnlyUnmap(); |
56 | } |
57 | |
58 | template <typename TypeParam, typename AddressSpaceView> |
59 | using TestMapASVT = TwoLevelMap<TypeParam, 1 << 8, 1 << 7, AddressSpaceView>; |
60 | template <typename TypeParam> |
61 | using TestMap = TestMapASVT<TypeParam, LocalAddressSpaceView>; |
62 | |
63 | template <typename TypeParam> |
64 | struct TestMapParam { |
65 | TestMap<TypeParam> *m; |
66 | size_t shard; |
67 | size_t num_shards; |
68 | }; |
69 | |
70 | template <typename TypeParam> |
71 | static void *TwoLevelMapUserThread(void *param) { |
72 | TestMapParam<TypeParam> *p = (TestMapParam<TypeParam> *)param; |
73 | for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) { |
74 | TypeParam val = (i % 100) + 1; |
75 | (*p->m)[i] = val; |
76 | EXPECT_EQ((*p->m)[i], val); |
77 | } |
78 | return 0; |
79 | } |
80 | |
81 | TYPED_TEST(FlatMapTest, ThreadedTwoLevelByteMap) { |
82 | TestMap<TypeParam> m; |
83 | m.Init(); |
84 | static const int kNumThreads = 4; |
85 | pthread_t t[kNumThreads]; |
86 | TestMapParam<TypeParam> p[kNumThreads]; |
87 | for (int i = 0; i < kNumThreads; i++) { |
88 | p[i].m = &m; |
89 | p[i].shard = i; |
90 | p[i].num_shards = kNumThreads; |
91 | PTHREAD_CREATE(&t[i], 0, TwoLevelMapUserThread<TypeParam>, &p[i]); |
92 | } |
93 | for (int i = 0; i < kNumThreads; i++) PTHREAD_JOIN(t[i], 0); |
94 | m.TestOnlyUnmap(); |
95 | } |
96 | |
97 | } // namespace |
98 | |