/* * Copyright (C) 2023 Intel Corporation * * SPDX-License-Identifier: MIT * */ #pragma once #include "shared/source/helpers/constants.h" #include "shared/source/helpers/non_copyable_or_moveable.h" #include "shared/source/utilities/stackvec.h" #include #include #include #include #include namespace NEO { class GraphicsAllocation; class HeapAllocator; class MemoryManager; template struct SmallBuffersParams { protected: static constexpr auto aggregatedSmallBuffersPoolSize = 64 * KB; static constexpr auto smallBufferThreshold = 4 * KB; static constexpr auto chunkAlignment = 512u; static constexpr auto startingOffset = chunkAlignment; }; template struct AbstractBuffersPool : public SmallBuffersParams, public NonCopyableClass { // The prototype of a function allocating the `mainStorage` is not specified. // That would be an unnecessary limitation here - it is completely up to derived class implementation. // Perhaps the allocating function needs to leverage `HeapAllocator::allocate()` and also // a BufferType-dependent function reserving chunks within `mainStorage`. // Example: see `NEO::Context::BufferPool::allocate()` using Params = SmallBuffersParams; using Params::aggregatedSmallBuffersPoolSize; using Params::chunkAlignment; using Params::smallBufferThreshold; using Params::startingOffset; using AllocsVecCRef = const StackVec &; using OnChunkFreeCallback = void (PoolT::*)(uint64_t offset, size_t size); AbstractBuffersPool(MemoryManager *memoryManager, OnChunkFreeCallback onChunkFreeCallback); AbstractBuffersPool(AbstractBuffersPool &&bufferPool); AbstractBuffersPool &operator=(AbstractBuffersPool &&) = delete; void tryFreeFromPoolBuffer(BufferParentType *possiblePoolBuffer, size_t offset, size_t size); bool isPoolBuffer(const BufferParentType *buffer) const; void drain(); // Derived class needs to provide its own implementation of getAllocationsVector(). // This is a CRTP-replacement for virtual functions. AllocsVecCRef getAllocationsVector() { return static_cast(this)->getAllocationsVector(); } MemoryManager *memoryManager{nullptr}; std::unique_ptr mainStorage; std::unique_ptr chunkAllocator; std::vector> chunksToFree; OnChunkFreeCallback onChunkFreeCallback = nullptr; }; template class AbstractBuffersAllocator : public SmallBuffersParams { // The prototype of a function allocating buffers from the pool is not specified (see similar comment in `AbstractBufersPool`). // By common sense, in order to allocate buffers from the pool the function should leverage a call provided by `BuffersPoolType`. // Example: see `NEO::Context::BufferPoolAllocator::allocateBufferFromPool()`. public: using Params = SmallBuffersParams; using Params::aggregatedSmallBuffersPoolSize; using Params::chunkAlignment; using Params::smallBufferThreshold; using Params::startingOffset; static_assert(aggregatedSmallBuffersPoolSize > smallBufferThreshold, "Largest allowed buffer needs to fit in pool"); void releaseSmallBufferPool() { this->bufferPools.clear(); } bool isPoolBuffer(const BufferParentType *buffer) const; void tryFreeFromPoolBuffer(BufferParentType *possiblePoolBuffer, size_t offset, size_t size); protected: inline bool isSizeWithinThreshold(size_t size) const { return smallBufferThreshold >= size; } void tryFreeFromPoolBuffer(BufferParentType *possiblePoolBuffer, size_t offset, size_t size, std::vector &bufferPoolsVec); void drain(); void drain(std::vector &bufferPoolsVec); void addNewBufferPool(BuffersPoolType &&bufferPool); void addNewBufferPool(BuffersPoolType &&bufferPool, std::vector &bufferPoolsVec); std::mutex mutex; std::vector bufferPools; }; } // namespace NEO