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