xref: /llvm-project/llvm/unittests/ADT/ConcurrentHashtableTest.cpp (revision 6ab43f9b87ce982fed7073d91da6c5f027321b53)
142058eeaSAlexey Lapshin //===- ConcurrentHashtableTest.cpp ----------------------------------------===//
242058eeaSAlexey Lapshin //
342058eeaSAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
442058eeaSAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information.
542058eeaSAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
642058eeaSAlexey Lapshin //
742058eeaSAlexey Lapshin //===----------------------------------------------------------------------===//
842058eeaSAlexey Lapshin 
942058eeaSAlexey Lapshin #include "llvm/ADT/ConcurrentHashtable.h"
1042058eeaSAlexey Lapshin #include "llvm/Support/Debug.h"
1142058eeaSAlexey Lapshin #include "llvm/Support/FormatVariadic.h"
1242058eeaSAlexey Lapshin #include "llvm/Support/Parallel.h"
13*6ab43f9bSAlexey Lapshin #include "llvm/Support/PerThreadBumpPtrAllocator.h"
1442058eeaSAlexey Lapshin #include "gtest/gtest.h"
1542058eeaSAlexey Lapshin #include <limits>
1642058eeaSAlexey Lapshin #include <random>
1742058eeaSAlexey Lapshin #include <vector>
1842058eeaSAlexey Lapshin using namespace llvm;
19*6ab43f9bSAlexey Lapshin using namespace parallel;
2042058eeaSAlexey Lapshin 
2142058eeaSAlexey Lapshin namespace {
2242058eeaSAlexey Lapshin class String {
2342058eeaSAlexey Lapshin public:
String()2442058eeaSAlexey Lapshin   String() {}
getKey() const2542058eeaSAlexey Lapshin   const std::string &getKey() const { return Data; }
2642058eeaSAlexey Lapshin 
2742058eeaSAlexey Lapshin   template <typename AllocatorTy>
create(const std::string & Num,AllocatorTy & Allocator)2842058eeaSAlexey Lapshin   static String *create(const std::string &Num, AllocatorTy &Allocator) {
2942058eeaSAlexey Lapshin     String *Result = Allocator.template Allocate<String>();
3042058eeaSAlexey Lapshin     new (Result) String(Num);
3142058eeaSAlexey Lapshin     return Result;
3242058eeaSAlexey Lapshin   }
3342058eeaSAlexey Lapshin 
3442058eeaSAlexey Lapshin protected:
String(const std::string & Num)3542058eeaSAlexey Lapshin   String(const std::string &Num) { Data += Num; }
3642058eeaSAlexey Lapshin 
3742058eeaSAlexey Lapshin   std::string Data;
3842058eeaSAlexey Lapshin   std::array<char, 0x20> ExtraData;
3942058eeaSAlexey Lapshin };
4042058eeaSAlexey Lapshin 
TEST(ConcurrentHashTableTest,AddStringEntries)4142058eeaSAlexey Lapshin TEST(ConcurrentHashTableTest, AddStringEntries) {
42*6ab43f9bSAlexey Lapshin   PerThreadBumpPtrAllocator Allocator;
43*6ab43f9bSAlexey Lapshin   ConcurrentHashTableByPtr<std::string, String, PerThreadBumpPtrAllocator,
44*6ab43f9bSAlexey Lapshin                            ConcurrentHashTableInfoByPtr<
45*6ab43f9bSAlexey Lapshin                                std::string, String, PerThreadBumpPtrAllocator>>
4642058eeaSAlexey Lapshin       HashTable(Allocator, 10);
4742058eeaSAlexey Lapshin 
48*6ab43f9bSAlexey Lapshin   // PerThreadBumpPtrAllocator should be accessed from threads created by
49*6ab43f9bSAlexey Lapshin   // ThreadPoolExecutor. Use TaskGroup to run on ThreadPoolExecutor threads.
50*6ab43f9bSAlexey Lapshin   parallel::TaskGroup tg;
51*6ab43f9bSAlexey Lapshin 
52*6ab43f9bSAlexey Lapshin   tg.spawn([&]() {
5342058eeaSAlexey Lapshin     size_t AllocatedBytesAtStart = Allocator.getBytesAllocated();
5442058eeaSAlexey Lapshin     std::pair<String *, bool> res1 = HashTable.insert("1");
5542058eeaSAlexey Lapshin     // Check entry is inserted.
5642058eeaSAlexey Lapshin     EXPECT_TRUE(res1.first->getKey() == "1");
5742058eeaSAlexey Lapshin     EXPECT_TRUE(res1.second);
5842058eeaSAlexey Lapshin 
5942058eeaSAlexey Lapshin     std::pair<String *, bool> res2 = HashTable.insert("2");
6042058eeaSAlexey Lapshin     // Check old entry is still valid.
6142058eeaSAlexey Lapshin     EXPECT_TRUE(res1.first->getKey() == "1");
6242058eeaSAlexey Lapshin     // Check new entry is inserted.
6342058eeaSAlexey Lapshin     EXPECT_TRUE(res2.first->getKey() == "2");
6442058eeaSAlexey Lapshin     EXPECT_TRUE(res2.second);
6542058eeaSAlexey Lapshin     // Check new and old entries use different memory.
6642058eeaSAlexey Lapshin     EXPECT_TRUE(res1.first != res2.first);
6742058eeaSAlexey Lapshin 
6842058eeaSAlexey Lapshin     std::pair<String *, bool> res3 = HashTable.insert("3");
6942058eeaSAlexey Lapshin     // Check one more entry is inserted.
7042058eeaSAlexey Lapshin     EXPECT_TRUE(res3.first->getKey() == "3");
7142058eeaSAlexey Lapshin     EXPECT_TRUE(res3.second);
7242058eeaSAlexey Lapshin 
7342058eeaSAlexey Lapshin     std::pair<String *, bool> res4 = HashTable.insert("1");
7442058eeaSAlexey Lapshin     // Check duplicated entry is inserted.
7542058eeaSAlexey Lapshin     EXPECT_TRUE(res4.first->getKey() == "1");
7642058eeaSAlexey Lapshin     EXPECT_FALSE(res4.second);
7742058eeaSAlexey Lapshin     // Check duplicated entry uses the same memory.
7842058eeaSAlexey Lapshin     EXPECT_TRUE(res1.first == res4.first);
7942058eeaSAlexey Lapshin 
8042058eeaSAlexey Lapshin     // Check first entry is still valid.
8142058eeaSAlexey Lapshin     EXPECT_TRUE(res1.first->getKey() == "1");
8242058eeaSAlexey Lapshin 
8342058eeaSAlexey Lapshin     // Check data was allocated by allocator.
8442058eeaSAlexey Lapshin     EXPECT_TRUE(Allocator.getBytesAllocated() > AllocatedBytesAtStart);
8542058eeaSAlexey Lapshin 
8642058eeaSAlexey Lapshin     // Check statistic.
8742058eeaSAlexey Lapshin     std::string StatisticString;
8842058eeaSAlexey Lapshin     raw_string_ostream StatisticStream(StatisticString);
8942058eeaSAlexey Lapshin     HashTable.printStatistic(StatisticStream);
9042058eeaSAlexey Lapshin 
9142058eeaSAlexey Lapshin     EXPECT_TRUE(StatisticString.find("Overall number of entries = 3\n") !=
9242058eeaSAlexey Lapshin                 std::string::npos);
93*6ab43f9bSAlexey Lapshin   });
9442058eeaSAlexey Lapshin }
9542058eeaSAlexey Lapshin 
TEST(ConcurrentHashTableTest,AddStringMultiplueEntries)9642058eeaSAlexey Lapshin TEST(ConcurrentHashTableTest, AddStringMultiplueEntries) {
97*6ab43f9bSAlexey Lapshin   PerThreadBumpPtrAllocator Allocator;
9842058eeaSAlexey Lapshin   const size_t NumElements = 10000;
99*6ab43f9bSAlexey Lapshin   ConcurrentHashTableByPtr<std::string, String, PerThreadBumpPtrAllocator,
100*6ab43f9bSAlexey Lapshin                            ConcurrentHashTableInfoByPtr<
101*6ab43f9bSAlexey Lapshin                                std::string, String, PerThreadBumpPtrAllocator>>
10242058eeaSAlexey Lapshin       HashTable(Allocator);
10342058eeaSAlexey Lapshin 
104*6ab43f9bSAlexey Lapshin   // PerThreadBumpPtrAllocator should be accessed from threads created by
105*6ab43f9bSAlexey Lapshin   // ThreadPoolExecutor. Use TaskGroup to run on ThreadPoolExecutor threads.
106*6ab43f9bSAlexey Lapshin   parallel::TaskGroup tg;
107*6ab43f9bSAlexey Lapshin 
108*6ab43f9bSAlexey Lapshin   tg.spawn([&]() {
10942058eeaSAlexey Lapshin     // Check insertion.
11042058eeaSAlexey Lapshin     for (size_t I = 0; I < NumElements; I++) {
111*6ab43f9bSAlexey Lapshin       BumpPtrAllocator &ThreadLocalAllocator =
112*6ab43f9bSAlexey Lapshin           Allocator.getThreadLocalAllocator();
113*6ab43f9bSAlexey Lapshin       size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
11442058eeaSAlexey Lapshin       std::string StringForElement = formatv("{0}", I);
11542058eeaSAlexey Lapshin       std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
11642058eeaSAlexey Lapshin       EXPECT_TRUE(Entry.second);
11742058eeaSAlexey Lapshin       EXPECT_TRUE(Entry.first->getKey() == StringForElement);
118*6ab43f9bSAlexey Lapshin       EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
119*6ab43f9bSAlexey Lapshin                   AllocatedBytesAtStart);
12042058eeaSAlexey Lapshin     }
12142058eeaSAlexey Lapshin 
12242058eeaSAlexey Lapshin     std::string StatisticString;
12342058eeaSAlexey Lapshin     raw_string_ostream StatisticStream(StatisticString);
12442058eeaSAlexey Lapshin     HashTable.printStatistic(StatisticStream);
12542058eeaSAlexey Lapshin 
12642058eeaSAlexey Lapshin     // Verifying that the table contains exactly the number of elements we
12742058eeaSAlexey Lapshin     // inserted.
12842058eeaSAlexey Lapshin     EXPECT_TRUE(StatisticString.find("Overall number of entries = 10000\n") !=
12942058eeaSAlexey Lapshin                 std::string::npos);
13042058eeaSAlexey Lapshin 
13142058eeaSAlexey Lapshin     // Check insertion of duplicates.
13242058eeaSAlexey Lapshin     for (size_t I = 0; I < NumElements; I++) {
133*6ab43f9bSAlexey Lapshin       BumpPtrAllocator &ThreadLocalAllocator =
134*6ab43f9bSAlexey Lapshin           Allocator.getThreadLocalAllocator();
135*6ab43f9bSAlexey Lapshin       size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
13642058eeaSAlexey Lapshin       std::string StringForElement = formatv("{0}", I);
13742058eeaSAlexey Lapshin       std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
13842058eeaSAlexey Lapshin       EXPECT_FALSE(Entry.second);
13942058eeaSAlexey Lapshin       EXPECT_TRUE(Entry.first->getKey() == StringForElement);
14042058eeaSAlexey Lapshin       // Check no additional bytes were allocated for duplicate.
141*6ab43f9bSAlexey Lapshin       EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
142*6ab43f9bSAlexey Lapshin                   AllocatedBytesAtStart);
14342058eeaSAlexey Lapshin     }
14442058eeaSAlexey Lapshin 
14542058eeaSAlexey Lapshin     // Check statistic.
14642058eeaSAlexey Lapshin     // Verifying that the table contains exactly the number of elements we
14742058eeaSAlexey Lapshin     // inserted.
14842058eeaSAlexey Lapshin     EXPECT_TRUE(StatisticString.find("Overall number of entries = 10000\n") !=
14942058eeaSAlexey Lapshin                 std::string::npos);
150*6ab43f9bSAlexey Lapshin   });
15142058eeaSAlexey Lapshin }
15242058eeaSAlexey Lapshin 
TEST(ConcurrentHashTableTest,AddStringMultiplueEntriesWithResize)15342058eeaSAlexey Lapshin TEST(ConcurrentHashTableTest, AddStringMultiplueEntriesWithResize) {
154*6ab43f9bSAlexey Lapshin   PerThreadBumpPtrAllocator Allocator;
15542058eeaSAlexey Lapshin   // Number of elements exceeds original size, thus hashtable should be resized.
15642058eeaSAlexey Lapshin   const size_t NumElements = 20000;
157*6ab43f9bSAlexey Lapshin   ConcurrentHashTableByPtr<std::string, String, PerThreadBumpPtrAllocator,
158*6ab43f9bSAlexey Lapshin                            ConcurrentHashTableInfoByPtr<
159*6ab43f9bSAlexey Lapshin                                std::string, String, PerThreadBumpPtrAllocator>>
16042058eeaSAlexey Lapshin       HashTable(Allocator, 100);
16142058eeaSAlexey Lapshin 
162*6ab43f9bSAlexey Lapshin   // PerThreadBumpPtrAllocator should be accessed from threads created by
163*6ab43f9bSAlexey Lapshin   // ThreadPoolExecutor. Use TaskGroup to run on ThreadPoolExecutor threads.
164*6ab43f9bSAlexey Lapshin   parallel::TaskGroup tg;
165*6ab43f9bSAlexey Lapshin 
166*6ab43f9bSAlexey Lapshin   tg.spawn([&]() {
16742058eeaSAlexey Lapshin     // Check insertion.
16842058eeaSAlexey Lapshin     for (size_t I = 0; I < NumElements; I++) {
169*6ab43f9bSAlexey Lapshin       BumpPtrAllocator &ThreadLocalAllocator =
170*6ab43f9bSAlexey Lapshin           Allocator.getThreadLocalAllocator();
171*6ab43f9bSAlexey Lapshin       size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
17242058eeaSAlexey Lapshin       std::string StringForElement = formatv("{0} {1}", I, I + 100);
17342058eeaSAlexey Lapshin       std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
17442058eeaSAlexey Lapshin       EXPECT_TRUE(Entry.second);
17542058eeaSAlexey Lapshin       EXPECT_TRUE(Entry.first->getKey() == StringForElement);
176*6ab43f9bSAlexey Lapshin       EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
177*6ab43f9bSAlexey Lapshin                   AllocatedBytesAtStart);
17842058eeaSAlexey Lapshin     }
17942058eeaSAlexey Lapshin 
18042058eeaSAlexey Lapshin     std::string StatisticString;
18142058eeaSAlexey Lapshin     raw_string_ostream StatisticStream(StatisticString);
18242058eeaSAlexey Lapshin     HashTable.printStatistic(StatisticStream);
18342058eeaSAlexey Lapshin 
18442058eeaSAlexey Lapshin     // Verifying that the table contains exactly the number of elements we
18542058eeaSAlexey Lapshin     // inserted.
18642058eeaSAlexey Lapshin     EXPECT_TRUE(StatisticString.find("Overall number of entries = 20000\n") !=
18742058eeaSAlexey Lapshin                 std::string::npos);
18842058eeaSAlexey Lapshin 
18942058eeaSAlexey Lapshin     // Check insertion of duplicates.
19042058eeaSAlexey Lapshin     for (size_t I = 0; I < NumElements; I++) {
191*6ab43f9bSAlexey Lapshin       BumpPtrAllocator &ThreadLocalAllocator =
192*6ab43f9bSAlexey Lapshin           Allocator.getThreadLocalAllocator();
193*6ab43f9bSAlexey Lapshin       size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
19442058eeaSAlexey Lapshin       std::string StringForElement = formatv("{0} {1}", I, I + 100);
19542058eeaSAlexey Lapshin       std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
19642058eeaSAlexey Lapshin       EXPECT_FALSE(Entry.second);
19742058eeaSAlexey Lapshin       EXPECT_TRUE(Entry.first->getKey() == StringForElement);
19842058eeaSAlexey Lapshin       // Check no additional bytes were allocated for duplicate.
199*6ab43f9bSAlexey Lapshin       EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
200*6ab43f9bSAlexey Lapshin                   AllocatedBytesAtStart);
20142058eeaSAlexey Lapshin     }
20242058eeaSAlexey Lapshin 
20342058eeaSAlexey Lapshin     // Check statistic.
20442058eeaSAlexey Lapshin     // Verifying that the table contains exactly the number of elements we
20542058eeaSAlexey Lapshin     // inserted.
20642058eeaSAlexey Lapshin     EXPECT_TRUE(StatisticString.find("Overall number of entries = 20000\n") !=
20742058eeaSAlexey Lapshin                 std::string::npos);
208*6ab43f9bSAlexey Lapshin   });
20942058eeaSAlexey Lapshin }
21042058eeaSAlexey Lapshin 
TEST(ConcurrentHashTableTest,AddStringEntriesParallel)21142058eeaSAlexey Lapshin TEST(ConcurrentHashTableTest, AddStringEntriesParallel) {
212*6ab43f9bSAlexey Lapshin   PerThreadBumpPtrAllocator Allocator;
21342058eeaSAlexey Lapshin   const size_t NumElements = 10000;
214*6ab43f9bSAlexey Lapshin   ConcurrentHashTableByPtr<std::string, String, PerThreadBumpPtrAllocator,
215*6ab43f9bSAlexey Lapshin                            ConcurrentHashTableInfoByPtr<
216*6ab43f9bSAlexey Lapshin                                std::string, String, PerThreadBumpPtrAllocator>>
21742058eeaSAlexey Lapshin       HashTable(Allocator);
21842058eeaSAlexey Lapshin 
21942058eeaSAlexey Lapshin   // Check parallel insertion.
22042058eeaSAlexey Lapshin   parallelFor(0, NumElements, [&](size_t I) {
221*6ab43f9bSAlexey Lapshin     BumpPtrAllocator &ThreadLocalAllocator =
222*6ab43f9bSAlexey Lapshin         Allocator.getThreadLocalAllocator();
223*6ab43f9bSAlexey Lapshin     size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
22442058eeaSAlexey Lapshin     std::string StringForElement = formatv("{0}", I);
22542058eeaSAlexey Lapshin     std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
22642058eeaSAlexey Lapshin     EXPECT_TRUE(Entry.second);
22742058eeaSAlexey Lapshin     EXPECT_TRUE(Entry.first->getKey() == StringForElement);
228*6ab43f9bSAlexey Lapshin     EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
229*6ab43f9bSAlexey Lapshin                 AllocatedBytesAtStart);
23042058eeaSAlexey Lapshin   });
23142058eeaSAlexey Lapshin 
23242058eeaSAlexey Lapshin   std::string StatisticString;
23342058eeaSAlexey Lapshin   raw_string_ostream StatisticStream(StatisticString);
23442058eeaSAlexey Lapshin   HashTable.printStatistic(StatisticStream);
23542058eeaSAlexey Lapshin 
23642058eeaSAlexey Lapshin   // Verifying that the table contains exactly the number of elements we
23742058eeaSAlexey Lapshin   // inserted.
23842058eeaSAlexey Lapshin   EXPECT_TRUE(StatisticString.find("Overall number of entries = 10000\n") !=
23942058eeaSAlexey Lapshin               std::string::npos);
24042058eeaSAlexey Lapshin 
24142058eeaSAlexey Lapshin   // Check parallel insertion of duplicates.
24242058eeaSAlexey Lapshin   parallelFor(0, NumElements, [&](size_t I) {
243*6ab43f9bSAlexey Lapshin     BumpPtrAllocator &ThreadLocalAllocator =
244*6ab43f9bSAlexey Lapshin         Allocator.getThreadLocalAllocator();
245*6ab43f9bSAlexey Lapshin     size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
24642058eeaSAlexey Lapshin     std::string StringForElement = formatv("{0}", I);
24742058eeaSAlexey Lapshin     std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
24842058eeaSAlexey Lapshin     EXPECT_FALSE(Entry.second);
24942058eeaSAlexey Lapshin     EXPECT_TRUE(Entry.first->getKey() == StringForElement);
25042058eeaSAlexey Lapshin     // Check no additional bytes were allocated for duplicate.
251*6ab43f9bSAlexey Lapshin     EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
252*6ab43f9bSAlexey Lapshin                 AllocatedBytesAtStart);
25342058eeaSAlexey Lapshin   });
25442058eeaSAlexey Lapshin 
25542058eeaSAlexey Lapshin   // Check statistic.
25642058eeaSAlexey Lapshin   // Verifying that the table contains exactly the number of elements we
25742058eeaSAlexey Lapshin   // inserted.
25842058eeaSAlexey Lapshin   EXPECT_TRUE(StatisticString.find("Overall number of entries = 10000\n") !=
25942058eeaSAlexey Lapshin               std::string::npos);
26042058eeaSAlexey Lapshin }
26142058eeaSAlexey Lapshin 
TEST(ConcurrentHashTableTest,AddStringEntriesParallelWithResize)26242058eeaSAlexey Lapshin TEST(ConcurrentHashTableTest, AddStringEntriesParallelWithResize) {
263*6ab43f9bSAlexey Lapshin   PerThreadBumpPtrAllocator Allocator;
26442058eeaSAlexey Lapshin   const size_t NumElements = 20000;
265*6ab43f9bSAlexey Lapshin   ConcurrentHashTableByPtr<std::string, String, PerThreadBumpPtrAllocator,
266*6ab43f9bSAlexey Lapshin                            ConcurrentHashTableInfoByPtr<
267*6ab43f9bSAlexey Lapshin                                std::string, String, PerThreadBumpPtrAllocator>>
26842058eeaSAlexey Lapshin       HashTable(Allocator, 100);
26942058eeaSAlexey Lapshin 
27042058eeaSAlexey Lapshin   // Check parallel insertion.
27142058eeaSAlexey Lapshin   parallelFor(0, NumElements, [&](size_t I) {
272*6ab43f9bSAlexey Lapshin     BumpPtrAllocator &ThreadLocalAllocator =
273*6ab43f9bSAlexey Lapshin         Allocator.getThreadLocalAllocator();
274*6ab43f9bSAlexey Lapshin     size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
27542058eeaSAlexey Lapshin     std::string StringForElement = formatv("{0}", I);
27642058eeaSAlexey Lapshin     std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
27742058eeaSAlexey Lapshin     EXPECT_TRUE(Entry.second);
27842058eeaSAlexey Lapshin     EXPECT_TRUE(Entry.first->getKey() == StringForElement);
279*6ab43f9bSAlexey Lapshin     EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
280*6ab43f9bSAlexey Lapshin                 AllocatedBytesAtStart);
28142058eeaSAlexey Lapshin   });
28242058eeaSAlexey Lapshin 
28342058eeaSAlexey Lapshin   std::string StatisticString;
28442058eeaSAlexey Lapshin   raw_string_ostream StatisticStream(StatisticString);
28542058eeaSAlexey Lapshin   HashTable.printStatistic(StatisticStream);
28642058eeaSAlexey Lapshin 
28742058eeaSAlexey Lapshin   // Verifying that the table contains exactly the number of elements we
28842058eeaSAlexey Lapshin   // inserted.
28942058eeaSAlexey Lapshin   EXPECT_TRUE(StatisticString.find("Overall number of entries = 20000\n") !=
29042058eeaSAlexey Lapshin               std::string::npos);
29142058eeaSAlexey Lapshin 
29242058eeaSAlexey Lapshin   // Check parallel insertion of duplicates.
29342058eeaSAlexey Lapshin   parallelFor(0, NumElements, [&](size_t I) {
294*6ab43f9bSAlexey Lapshin     BumpPtrAllocator &ThreadLocalAllocator =
295*6ab43f9bSAlexey Lapshin         Allocator.getThreadLocalAllocator();
296*6ab43f9bSAlexey Lapshin     size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
29742058eeaSAlexey Lapshin     std::string StringForElement = formatv("{0}", I);
29842058eeaSAlexey Lapshin     std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
29942058eeaSAlexey Lapshin     EXPECT_FALSE(Entry.second);
30042058eeaSAlexey Lapshin     EXPECT_TRUE(Entry.first->getKey() == StringForElement);
30142058eeaSAlexey Lapshin     // Check no additional bytes were allocated for duplicate.
302*6ab43f9bSAlexey Lapshin     EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
303*6ab43f9bSAlexey Lapshin                 AllocatedBytesAtStart);
30442058eeaSAlexey Lapshin   });
30542058eeaSAlexey Lapshin 
30642058eeaSAlexey Lapshin   // Check statistic.
30742058eeaSAlexey Lapshin   // Verifying that the table contains exactly the number of elements we
30842058eeaSAlexey Lapshin   // inserted.
30942058eeaSAlexey Lapshin   EXPECT_TRUE(StatisticString.find("Overall number of entries = 20000\n") !=
31042058eeaSAlexey Lapshin               std::string::npos);
31142058eeaSAlexey Lapshin }
31242058eeaSAlexey Lapshin 
31342058eeaSAlexey Lapshin } // namespace
314