mirror of
https://github.com/intel/compute-runtime.git
synced 2025-12-24 04:12:57 +08:00
Refactor buffer pool allocator to support configurable SmallBuffersParams based on product helper capabilities. This patch enables setting custom pool parameters instead of using fixed static values. For devices with 2MB local memory alignment enabled (is2MBLocalMemAlignmentEnabled), use larger pool configuration: - Pool size: 16MB (up from 2MB) - Threshold: 2MB (up from 1MB) - Alignment: 64KB (unchanged) - Starting offset: 64KB (unchanged) This improves memory utilization for devices supporting larger memory alignments while maintaining original parameters for other devices. Key changes: - Moved params from static template to instance member - Added SmallBuffersParams struct with default/large configs - Added constructor and setter methods for params configuration Related-To: NEO-12287 Signed-off-by: Fabian Zwoliński <fabian.zwolinski@intel.com>
121 lines
4.9 KiB
C++
121 lines
4.9 KiB
C++
/*
|
|
* Copyright (C) 2023-2025 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 <functional>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
namespace NEO {
|
|
|
|
class GraphicsAllocation;
|
|
class HeapAllocator;
|
|
class MemoryManager;
|
|
class ProductHelper;
|
|
|
|
struct SmallBuffersParams {
|
|
size_t aggregatedSmallBuffersPoolSize{0};
|
|
size_t smallBufferThreshold{0};
|
|
size_t chunkAlignment{0};
|
|
size_t startingOffset{0};
|
|
|
|
static SmallBuffersParams getDefaultParams() {
|
|
return {
|
|
2 * MemoryConstants::megaByte, // aggregatedSmallBuffersPoolSize
|
|
1 * MemoryConstants::megaByte, // smallBufferThreshold
|
|
MemoryConstants::pageSize64k, // chunkAlignment
|
|
MemoryConstants::pageSize64k // startingOffset
|
|
};
|
|
}
|
|
|
|
static SmallBuffersParams getLargePagesParams() {
|
|
return {
|
|
16 * MemoryConstants::megaByte, // aggregatedSmallBuffersPoolSize
|
|
2 * MemoryConstants::megaByte, // smallBufferThreshold
|
|
MemoryConstants::pageSize64k, // chunkAlignment
|
|
MemoryConstants::pageSize64k // startingOffset
|
|
};
|
|
}
|
|
|
|
static inline SmallBuffersParams getPreferredBufferPoolParams(const ProductHelper &productHelper);
|
|
};
|
|
|
|
template <typename PoolT, typename BufferType, typename BufferParentType = BufferType>
|
|
struct AbstractBuffersPool : 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 AllocsVecCRef = const StackVec<NEO::GraphicsAllocation *, 1> &;
|
|
using OnChunkFreeCallback = void (PoolT::*)(uint64_t offset, size_t size);
|
|
|
|
AbstractBuffersPool(MemoryManager *memoryManager, OnChunkFreeCallback onChunkFreeCallback);
|
|
AbstractBuffersPool(MemoryManager *memoryManager, OnChunkFreeCallback onChunkFreeCallback, const SmallBuffersParams ¶ms);
|
|
AbstractBuffersPool(AbstractBuffersPool<PoolT, BufferType, BufferParentType> &&bufferPool);
|
|
AbstractBuffersPool &operator=(AbstractBuffersPool &&) = delete;
|
|
virtual ~AbstractBuffersPool() = default;
|
|
|
|
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<PoolT *>(this)->getAllocationsVector();
|
|
}
|
|
|
|
MemoryManager *memoryManager{nullptr};
|
|
std::unique_ptr<BufferType> mainStorage;
|
|
std::unique_ptr<HeapAllocator> chunkAllocator;
|
|
std::vector<std::pair<uint64_t, size_t>> chunksToFree;
|
|
OnChunkFreeCallback onChunkFreeCallback = nullptr;
|
|
SmallBuffersParams params;
|
|
};
|
|
|
|
template <typename BuffersPoolType, typename BufferType, typename BufferParentType = BufferType>
|
|
class AbstractBuffersAllocator {
|
|
// 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:
|
|
AbstractBuffersAllocator(const SmallBuffersParams ¶ms);
|
|
AbstractBuffersAllocator();
|
|
|
|
void releasePools() { this->bufferPools.clear(); }
|
|
bool isPoolBuffer(const BufferParentType *buffer) const;
|
|
void tryFreeFromPoolBuffer(BufferParentType *possiblePoolBuffer, size_t offset, size_t size);
|
|
uint32_t getPoolsCount() { return static_cast<uint32_t>(this->bufferPools.size()); }
|
|
|
|
void setParams(const SmallBuffersParams &newParams) {
|
|
params = newParams;
|
|
}
|
|
SmallBuffersParams getParams() const {
|
|
return params;
|
|
};
|
|
|
|
protected:
|
|
inline bool isSizeWithinThreshold(size_t size) const { return params.smallBufferThreshold >= size; }
|
|
void tryFreeFromPoolBuffer(BufferParentType *possiblePoolBuffer, size_t offset, size_t size, std::vector<BuffersPoolType> &bufferPoolsVec);
|
|
void drain();
|
|
void drain(std::vector<BuffersPoolType> &bufferPoolsVec);
|
|
void addNewBufferPool(BuffersPoolType &&bufferPool);
|
|
void addNewBufferPool(BuffersPoolType &&bufferPool, std::vector<BuffersPoolType> &bufferPoolsVec);
|
|
|
|
std::mutex mutex;
|
|
std::vector<BuffersPoolType> bufferPools;
|
|
SmallBuffersParams params;
|
|
};
|
|
} // namespace NEO
|