xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===- PerThreadBumpPtrAllocator.h ------------------------------*- C++ -*-===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric 
9*06c3fb27SDimitry Andric #ifndef LLVM_SUPPORT_PERTHREADBUMPPTRALLOCATOR_H
10*06c3fb27SDimitry Andric #define LLVM_SUPPORT_PERTHREADBUMPPTRALLOCATOR_H
11*06c3fb27SDimitry Andric 
12*06c3fb27SDimitry Andric #include "llvm/Support/Allocator.h"
13*06c3fb27SDimitry Andric #include "llvm/Support/Parallel.h"
14*06c3fb27SDimitry Andric 
15*06c3fb27SDimitry Andric namespace llvm {
16*06c3fb27SDimitry Andric namespace parallel {
17*06c3fb27SDimitry Andric 
18*06c3fb27SDimitry Andric /// PerThreadAllocator is used in conjunction with ThreadPoolExecutor to allow
19*06c3fb27SDimitry Andric /// per-thread allocations. It wraps a possibly thread-unsafe allocator,
20*06c3fb27SDimitry Andric /// e.g. BumpPtrAllocator. PerThreadAllocator must be used with only main thread
21*06c3fb27SDimitry Andric /// or threads created by ThreadPoolExecutor, as it utilizes getThreadIndex,
22*06c3fb27SDimitry Andric /// which is set by ThreadPoolExecutor. To work properly, ThreadPoolExecutor
23*06c3fb27SDimitry Andric /// should be initialized before PerThreadAllocator is created.
24*06c3fb27SDimitry Andric /// TODO: The same approach might be implemented for ThreadPool.
25*06c3fb27SDimitry Andric 
26*06c3fb27SDimitry Andric template <typename AllocatorTy>
27*06c3fb27SDimitry Andric class PerThreadAllocator
28*06c3fb27SDimitry Andric     : public AllocatorBase<PerThreadAllocator<AllocatorTy>> {
29*06c3fb27SDimitry Andric public:
PerThreadAllocator()30*06c3fb27SDimitry Andric   PerThreadAllocator()
31*06c3fb27SDimitry Andric       : NumOfAllocators(parallel::getThreadCount()),
32*06c3fb27SDimitry Andric         Allocators(std::make_unique<AllocatorTy[]>(NumOfAllocators)) {}
33*06c3fb27SDimitry Andric 
34*06c3fb27SDimitry Andric   /// \defgroup Methods which could be called asynchronously:
35*06c3fb27SDimitry Andric   ///
36*06c3fb27SDimitry Andric   /// @{
37*06c3fb27SDimitry Andric 
38*06c3fb27SDimitry Andric   using AllocatorBase<PerThreadAllocator<AllocatorTy>>::Allocate;
39*06c3fb27SDimitry Andric 
40*06c3fb27SDimitry Andric   using AllocatorBase<PerThreadAllocator<AllocatorTy>>::Deallocate;
41*06c3fb27SDimitry Andric 
42*06c3fb27SDimitry Andric   /// Allocate \a Size bytes of \a Alignment aligned memory.
Allocate(size_t Size,size_t Alignment)43*06c3fb27SDimitry Andric   void *Allocate(size_t Size, size_t Alignment) {
44*06c3fb27SDimitry Andric     assert(getThreadIndex() < NumOfAllocators);
45*06c3fb27SDimitry Andric     return Allocators[getThreadIndex()].Allocate(Size, Alignment);
46*06c3fb27SDimitry Andric   }
47*06c3fb27SDimitry Andric 
48*06c3fb27SDimitry Andric   /// Deallocate \a Ptr to \a Size bytes of memory allocated by this
49*06c3fb27SDimitry Andric   /// allocator.
Deallocate(const void * Ptr,size_t Size,size_t Alignment)50*06c3fb27SDimitry Andric   void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
51*06c3fb27SDimitry Andric     assert(getThreadIndex() < NumOfAllocators);
52*06c3fb27SDimitry Andric     return Allocators[getThreadIndex()].Deallocate(Ptr, Size, Alignment);
53*06c3fb27SDimitry Andric   }
54*06c3fb27SDimitry Andric 
55*06c3fb27SDimitry Andric   /// Return allocator corresponding to the current thread.
getThreadLocalAllocator()56*06c3fb27SDimitry Andric   AllocatorTy &getThreadLocalAllocator() {
57*06c3fb27SDimitry Andric     assert(getThreadIndex() < NumOfAllocators);
58*06c3fb27SDimitry Andric     return Allocators[getThreadIndex()];
59*06c3fb27SDimitry Andric   }
60*06c3fb27SDimitry Andric 
61*06c3fb27SDimitry Andric   // Return number of used allocators.
getNumberOfAllocators()62*06c3fb27SDimitry Andric   size_t getNumberOfAllocators() const { return NumOfAllocators; }
63*06c3fb27SDimitry Andric   /// @}
64*06c3fb27SDimitry Andric 
65*06c3fb27SDimitry Andric   /// \defgroup Methods which could not be called asynchronously:
66*06c3fb27SDimitry Andric   ///
67*06c3fb27SDimitry Andric   /// @{
68*06c3fb27SDimitry Andric 
69*06c3fb27SDimitry Andric   /// Reset state of allocators.
Reset()70*06c3fb27SDimitry Andric   void Reset() {
71*06c3fb27SDimitry Andric     for (size_t Idx = 0; Idx < getNumberOfAllocators(); Idx++)
72*06c3fb27SDimitry Andric       Allocators[Idx].Reset();
73*06c3fb27SDimitry Andric   }
74*06c3fb27SDimitry Andric 
75*06c3fb27SDimitry Andric   /// Return total memory size used by all allocators.
getTotalMemory()76*06c3fb27SDimitry Andric   size_t getTotalMemory() const {
77*06c3fb27SDimitry Andric     size_t TotalMemory = 0;
78*06c3fb27SDimitry Andric 
79*06c3fb27SDimitry Andric     for (size_t Idx = 0; Idx < getNumberOfAllocators(); Idx++)
80*06c3fb27SDimitry Andric       TotalMemory += Allocators[Idx].getTotalMemory();
81*06c3fb27SDimitry Andric 
82*06c3fb27SDimitry Andric     return TotalMemory;
83*06c3fb27SDimitry Andric   }
84*06c3fb27SDimitry Andric 
85*06c3fb27SDimitry Andric   /// Return allocated size by all allocators.
getBytesAllocated()86*06c3fb27SDimitry Andric   size_t getBytesAllocated() const {
87*06c3fb27SDimitry Andric     size_t BytesAllocated = 0;
88*06c3fb27SDimitry Andric 
89*06c3fb27SDimitry Andric     for (size_t Idx = 0; Idx < getNumberOfAllocators(); Idx++)
90*06c3fb27SDimitry Andric       BytesAllocated += Allocators[Idx].getBytesAllocated();
91*06c3fb27SDimitry Andric 
92*06c3fb27SDimitry Andric     return BytesAllocated;
93*06c3fb27SDimitry Andric   }
94*06c3fb27SDimitry Andric 
95*06c3fb27SDimitry Andric   /// Set red zone for all allocators.
setRedZoneSize(size_t NewSize)96*06c3fb27SDimitry Andric   void setRedZoneSize(size_t NewSize) {
97*06c3fb27SDimitry Andric     for (size_t Idx = 0; Idx < getNumberOfAllocators(); Idx++)
98*06c3fb27SDimitry Andric       Allocators[Idx].setRedZoneSize(NewSize);
99*06c3fb27SDimitry Andric   }
100*06c3fb27SDimitry Andric 
101*06c3fb27SDimitry Andric   /// Print statistic for each allocator.
PrintStats()102*06c3fb27SDimitry Andric   void PrintStats() const {
103*06c3fb27SDimitry Andric     for (size_t Idx = 0; Idx < getNumberOfAllocators(); Idx++) {
104*06c3fb27SDimitry Andric       errs() << "\n Allocator " << Idx << "\n";
105*06c3fb27SDimitry Andric       Allocators[Idx].PrintStats();
106*06c3fb27SDimitry Andric     }
107*06c3fb27SDimitry Andric   }
108*06c3fb27SDimitry Andric   /// @}
109*06c3fb27SDimitry Andric 
110*06c3fb27SDimitry Andric protected:
111*06c3fb27SDimitry Andric   size_t NumOfAllocators;
112*06c3fb27SDimitry Andric   std::unique_ptr<AllocatorTy[]> Allocators;
113*06c3fb27SDimitry Andric };
114*06c3fb27SDimitry Andric 
115*06c3fb27SDimitry Andric using PerThreadBumpPtrAllocator = PerThreadAllocator<BumpPtrAllocator>;
116*06c3fb27SDimitry Andric 
117*06c3fb27SDimitry Andric } // end namespace parallel
118*06c3fb27SDimitry Andric } // end namespace llvm
119*06c3fb27SDimitry Andric 
120*06c3fb27SDimitry Andric #endif // LLVM_SUPPORT_PERTHREADBUMPPTRALLOCATOR_H
121