1d07c3cf6SSteven Wu //===- llvm/unittest/Support/ThreadSafeAllocatorTest.cpp ------------------===//
2d07c3cf6SSteven Wu //
3d07c3cf6SSteven Wu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d07c3cf6SSteven Wu // See https://llvm.org/LICENSE.txt for license information.
5d07c3cf6SSteven Wu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d07c3cf6SSteven Wu //
7d07c3cf6SSteven Wu //===----------------------------------------------------------------------===//
8d07c3cf6SSteven Wu
9d07c3cf6SSteven Wu #include "llvm/Support/ThreadSafeAllocator.h"
10d07c3cf6SSteven Wu #include "llvm/Config/llvm-config.h"
11d07c3cf6SSteven Wu #include "llvm/Support/ThreadPool.h"
12d07c3cf6SSteven Wu #include "gtest/gtest.h"
13d07c3cf6SSteven Wu #include <atomic>
14d07c3cf6SSteven Wu #include <thread>
15d07c3cf6SSteven Wu
16d07c3cf6SSteven Wu using namespace llvm;
17d07c3cf6SSteven Wu
18d07c3cf6SSteven Wu namespace {
19d07c3cf6SSteven Wu
20d07c3cf6SSteven Wu struct AllocCondition {
21d07c3cf6SSteven Wu std::mutex BusyLock, EndLock;
22d07c3cf6SSteven Wu std::condition_variable Busy, End;
23d07c3cf6SSteven Wu bool IsBusy = false, IsEnd = false;
24d07c3cf6SSteven Wu std::atomic<unsigned> BytesAllocated = 0;
25d07c3cf6SSteven Wu
startAllocation__anon300027430111::AllocCondition26d07c3cf6SSteven Wu void startAllocation() {
27d07c3cf6SSteven Wu {
28d07c3cf6SSteven Wu std::lock_guard<std::mutex> Lock(BusyLock);
29d07c3cf6SSteven Wu IsBusy = true;
30d07c3cf6SSteven Wu }
31d07c3cf6SSteven Wu Busy.notify_all();
32d07c3cf6SSteven Wu }
waitAllocationStarted__anon300027430111::AllocCondition33d07c3cf6SSteven Wu void waitAllocationStarted() {
34d07c3cf6SSteven Wu std::unique_lock<std::mutex> LBusy(BusyLock);
35d07c3cf6SSteven Wu Busy.wait(LBusy, [&]() { return IsBusy; });
36d07c3cf6SSteven Wu IsBusy = false;
37d07c3cf6SSteven Wu }
finishAllocation__anon300027430111::AllocCondition38d07c3cf6SSteven Wu void finishAllocation() {
39d07c3cf6SSteven Wu {
40d07c3cf6SSteven Wu std::lock_guard<std::mutex> Lock(EndLock);
41d07c3cf6SSteven Wu IsEnd = true;
42d07c3cf6SSteven Wu }
43d07c3cf6SSteven Wu End.notify_all();
44d07c3cf6SSteven Wu }
waitAllocationFinished__anon300027430111::AllocCondition45d07c3cf6SSteven Wu void waitAllocationFinished() {
46d07c3cf6SSteven Wu std::unique_lock<std::mutex> LEnd(EndLock);
47d07c3cf6SSteven Wu // Wait for end state.
48d07c3cf6SSteven Wu End.wait(LEnd, [&]() { return IsEnd; });
49d07c3cf6SSteven Wu IsEnd = false;
50d07c3cf6SSteven Wu }
51d07c3cf6SSteven Wu };
52d07c3cf6SSteven Wu
53d07c3cf6SSteven Wu class MockAllocator : public AllocatorBase<MockAllocator> {
54d07c3cf6SSteven Wu public:
55d07c3cf6SSteven Wu MockAllocator() = default;
56d07c3cf6SSteven Wu
Allocate(size_t Size,size_t Alignment)57d07c3cf6SSteven Wu void *Allocate(size_t Size, size_t Alignment) {
58d07c3cf6SSteven Wu C.startAllocation();
59d07c3cf6SSteven Wu C.waitAllocationFinished();
60d07c3cf6SSteven Wu C.BytesAllocated += Size;
61d07c3cf6SSteven Wu return Reserved;
62d07c3cf6SSteven Wu }
63d07c3cf6SSteven Wu
getAllocCondition()64d07c3cf6SSteven Wu AllocCondition &getAllocCondition() { return C; }
65d07c3cf6SSteven Wu
66d07c3cf6SSteven Wu private:
67d07c3cf6SSteven Wu char Reserved[16];
68d07c3cf6SSteven Wu AllocCondition C;
69d07c3cf6SSteven Wu };
70d07c3cf6SSteven Wu
71d07c3cf6SSteven Wu } // namespace
72d07c3cf6SSteven Wu
73d07c3cf6SSteven Wu #if (LLVM_ENABLE_THREADS)
TEST(ThreadSafeAllocatorTest,AllocWait)74d07c3cf6SSteven Wu TEST(ThreadSafeAllocatorTest, AllocWait) {
75d07c3cf6SSteven Wu ThreadSafeAllocator<MockAllocator> Alloc;
76d07c3cf6SSteven Wu AllocCondition *C;
77d07c3cf6SSteven Wu // Get the allocation from the allocator first since this requires a lock.
78d07c3cf6SSteven Wu Alloc.applyLocked(
79d07c3cf6SSteven Wu [&](MockAllocator &Alloc) { C = &Alloc.getAllocCondition(); });
80*716042a6SMehdi Amini DefaultThreadPool Threads;
81d07c3cf6SSteven Wu // First allocation of 1 byte.
82d07c3cf6SSteven Wu Threads.async([&Alloc]() {
83d07c3cf6SSteven Wu char *P = (char *)Alloc.Allocate(1, alignof(char));
84d07c3cf6SSteven Wu P[0] = 0;
85d07c3cf6SSteven Wu });
86d07c3cf6SSteven Wu // No allocation yet.
87d07c3cf6SSteven Wu EXPECT_EQ(C->BytesAllocated, 0u);
88d07c3cf6SSteven Wu C->waitAllocationStarted(); // wait till 1st alloocation starts.
89d07c3cf6SSteven Wu // Second allocation of 2 bytes.
90d07c3cf6SSteven Wu Threads.async([&Alloc]() {
91d07c3cf6SSteven Wu char *P = (char *)Alloc.Allocate(2, alignof(char));
92d07c3cf6SSteven Wu P[1] = 0;
93d07c3cf6SSteven Wu });
94d07c3cf6SSteven Wu C->finishAllocation(); // finish 1st allocation.
95d07c3cf6SSteven Wu
96d07c3cf6SSteven Wu C->waitAllocationStarted(); // wait till 2nd allocation starts.
97d07c3cf6SSteven Wu // still 1 byte allocated since 2nd allocation is not finished yet.
98d07c3cf6SSteven Wu EXPECT_EQ(C->BytesAllocated, 1u);
99d07c3cf6SSteven Wu C->finishAllocation(); // finish 2nd allocation.
100d07c3cf6SSteven Wu
101d07c3cf6SSteven Wu Threads.wait(); // all allocations done.
102d07c3cf6SSteven Wu EXPECT_EQ(C->BytesAllocated, 3u);
103d07c3cf6SSteven Wu }
104d07c3cf6SSteven Wu
TEST(ThreadSafeAllocatorTest,AllocWithAlign)105d07c3cf6SSteven Wu TEST(ThreadSafeAllocatorTest, AllocWithAlign) {
106d07c3cf6SSteven Wu ThreadSafeAllocator<BumpPtrAllocator> Alloc;
107*716042a6SMehdi Amini DefaultThreadPool Threads;
108d07c3cf6SSteven Wu
109d07c3cf6SSteven Wu for (unsigned Index = 1; Index < 100; ++Index)
110d07c3cf6SSteven Wu Threads.async(
111d07c3cf6SSteven Wu [&Alloc](unsigned I) {
112d07c3cf6SSteven Wu int *P = (int *)Alloc.Allocate(sizeof(int) * I, alignof(int));
113d07c3cf6SSteven Wu P[I - 1] = I;
114d07c3cf6SSteven Wu },
115d07c3cf6SSteven Wu Index);
116d07c3cf6SSteven Wu
117d07c3cf6SSteven Wu Threads.wait();
118d07c3cf6SSteven Wu
119d07c3cf6SSteven Wu Alloc.applyLocked([](BumpPtrAllocator &Alloc) {
120d07c3cf6SSteven Wu EXPECT_EQ(4950U * sizeof(int), Alloc.getBytesAllocated());
121d07c3cf6SSteven Wu });
122d07c3cf6SSteven Wu }
123d07c3cf6SSteven Wu
TEST(ThreadSafeAllocatorTest,SpecificBumpPtrAllocator)124d07c3cf6SSteven Wu TEST(ThreadSafeAllocatorTest, SpecificBumpPtrAllocator) {
125d07c3cf6SSteven Wu ThreadSafeAllocator<SpecificBumpPtrAllocator<int>> Alloc;
126*716042a6SMehdi Amini DefaultThreadPool Threads;
127d07c3cf6SSteven Wu
128d07c3cf6SSteven Wu for (unsigned Index = 1; Index < 100; ++Index)
129d07c3cf6SSteven Wu Threads.async(
130d07c3cf6SSteven Wu [&Alloc](unsigned I) {
131d07c3cf6SSteven Wu int *P = Alloc.Allocate(I);
132d07c3cf6SSteven Wu P[I - 1] = I;
133d07c3cf6SSteven Wu },
134d07c3cf6SSteven Wu Index);
135d07c3cf6SSteven Wu
136d07c3cf6SSteven Wu Threads.wait();
137d07c3cf6SSteven Wu }
138d07c3cf6SSteven Wu #endif
139