Files
compute-runtime/shared/source/utilities/buffer_pool_allocator.h
Fabian Zwoliński 1eb8e0efd9 fix: configure small buffers params based on productHelper
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>
2025-02-07 12:01:23 +01:00

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 &params);
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 &params);
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