LLVM 24.0.0git
PerThreadBumpPtrAllocator.h
Go to the documentation of this file.
1//===- PerThreadBumpPtrAllocator.h ------------------------------*- C++ -*-===//
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#ifndef LLVM_SUPPORT_PERTHREADBUMPPTRALLOCATOR_H
10#define LLVM_SUPPORT_PERTHREADBUMPPTRALLOCATOR_H
11
15#include <memory>
16#include <mutex>
17#include <vector>
18
19namespace llvm {
20namespace parallel {
21
22namespace detail {
23/// Return a new process-unique PerThreadAllocator instance id. Ids are never
24/// reused.
26} // namespace detail
27
28/// PerThreadAllocator wraps a thread-unsafe allocator (e.g. BumpPtrAllocator)
29/// for lock-free concurrent allocation: each thread receives its own
30/// sub-allocator on first allocation, and the PerThreadAllocator owns all
31/// sub-allocators. Recommended to used with the thread pool in Parallel.h even
32/// if there is no dependency on it.
33template <typename AllocatorTy>
35 : public AllocatorBase<PerThreadAllocator<AllocatorTy>> {
36 // Heap-allocated so that the class stays movable while holding a mutex.
37 struct State {
38 std::mutex Mutex;
39 std::vector<std::unique_ptr<AllocatorTy>> Allocators;
40 };
41
42public:
44 : S(std::make_unique<State>()), Id(detail::claimPerThreadAllocatorId()) {}
45
46 /// \defgroup Methods which could be called asynchronously:
47 ///
48 /// @{
49
51
53
54 /// Allocate \a Size bytes of \a Alignment aligned memory.
55 void *Allocate(size_t Size, size_t Alignment) {
56 return getThreadLocalAllocator().Allocate(Size, Alignment);
57 }
58
59 /// Deallocate \a Ptr to \a Size bytes of memory allocated by this
60 /// allocator.
61 void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
62 return getThreadLocalAllocator().Deallocate(Ptr, Size, Alignment);
63 }
64
65 /// Return the calling thread's sub-allocator, creating it on first use.
66 AllocatorTy &getThreadLocalAllocator() {
67 // The calling thread's sub-allocator of each instance, indexed by a
68 // process-unique instance id.
69 //
70 // mlir::ThreadLocalCache keys an analogous per-thread map on the instance
71 // pointer and reclaims a thread's slot once the instance dies, but pays a
72 // map lookup and shared_ptr bookkeeping per allocation. Instances here are
73 // few and short-lived, so we prefer the O(1) vector index and accept that a
74 // thread's Cache only grows with the number of instances created.
75 static thread_local std::vector<AllocatorTy *> Cache;
76 if (LLVM_UNLIKELY(Cache.size() <= Id))
77 Cache.resize(Id + 1);
78 AllocatorTy *&A = Cache[Id];
79 if (LLVM_UNLIKELY(!A)) {
80 // Heap-allocate sub-allocators so that their addresses are stable and
81 // different threads' bump pointers do not share a cache line.
82 auto New = std::make_unique<AllocatorTy>();
83 A = New.get();
84 std::lock_guard<std::mutex> Lock(S->Mutex);
85 S->Allocators.push_back(std::move(New));
86 }
87 return *A;
88 }
89
90 /// Return the number of sub-allocators, i.e. threads that have allocated.
91 size_t getNumberOfAllocators() const {
92 std::lock_guard<std::mutex> Lock(S->Mutex);
93 return S->Allocators.size();
94 }
95 /// @}
96
97 /// \defgroup Methods which could not be called asynchronously:
98 ///
99 /// @{
100
101 /// Reset state of allocators.
102 void Reset() {
103 for (const auto &A : S->Allocators)
104 A->Reset();
105 }
106
107 /// Return total memory size used by all allocators.
108 size_t getTotalMemory() const {
109 size_t TotalMemory = 0;
110 for (const auto &A : S->Allocators)
111 TotalMemory += A->getTotalMemory();
112 return TotalMemory;
113 }
114
115 /// Set red zone for all allocators.
116 void setRedZoneSize(size_t NewSize) {
117 for (const auto &A : S->Allocators)
118 A->setRedZoneSize(NewSize);
119 }
120
121 /// Print statistic for each allocator.
122 void PrintStats() const {
123 size_t Idx = 0;
124 for (const auto &A : S->Allocators) {
125 errs() << "\n Allocator " << Idx++ << "\n";
126 A->PrintStats();
127 }
128 }
129 /// @}
130
131protected:
132 std::unique_ptr<State> S;
133 unsigned Id;
134};
135
137
138} // end namespace parallel
139} // end namespace llvm
140
141#endif // LLVM_SUPPORT_PERTHREADBUMPPTRALLOCATOR_H
This file defines the BumpPtrAllocator interface.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:338
#define LLVM_ABI
Definition Compiler.h:215
CRTP base class providing obvious overloads for the core Allocate() methods of LLVM-style allocators.
PerThreadAllocator wraps a thread-unsafe allocator (e.g.
size_t getNumberOfAllocators() const
Return the number of sub-allocators, i.e. threads that have allocated.
size_t getTotalMemory() const
Return total memory size used by all allocators.
void Deallocate(const void *Ptr, size_t Size, size_t Alignment)
Deallocate Ptr to Size bytes of memory allocated by this allocator.
void Reset()
Reset state of allocators.
void * Allocate(size_t Size, size_t Alignment)
Allocate Size bytes of Alignment aligned memory.
void PrintStats() const
Print statistic for each allocator.
AllocatorTy & getThreadLocalAllocator()
Return the calling thread's sub-allocator, creating it on first use.
void setRedZoneSize(size_t NewSize)
Set red zone for all allocators.
LLVM_ABI unsigned claimPerThreadAllocatorId()
Return a new process-unique PerThreadAllocator instance id.
Definition Allocator.cpp:40
PerThreadAllocator< BumpPtrAllocator > PerThreadBumpPtrAllocator
SmartMutex< false > Mutex
Mutex - A standard, always enforced mutex.
Definition Mutex.h:66
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878