2023-05-12 16:51:52 +00:00
|
|
|
/*
|
2025-02-06 23:56:09 +00:00
|
|
|
* Copyright (C) 2023-2025 Intel Corporation
|
2023-05-12 16:51:52 +00:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
#include "shared/source/helpers/constants.h"
|
feature: add optional onChunkFree callback to AbstractBuffersPool
Instances returned by `getAllocationsVector()` in some cases cannot be
freed (in the `malloc/new` sense) until the `drain()` function invokes
`allocInUse()` on them. Plus, the `chunksToFree` container operates on
pairs `{offset, size}`, not pointers, so such pair cannot be used to
release allocations either.
Provide an optional callback, which can be implemented by the custom
pool derived from `AbstractBuffersPool`. This callback can be used, for
example, to perform actual release of an allocation related to the
currently processed chunk.
Additionally, provide the `drain()` and `tryFreeFromPoolBuffer()`
functions with pool-independent versions and keep the previous versions
as defaults (for allocators with a single pool). The new versions allow
reusing the code for cases when allocator has multiple pools.
In both cases, there was no such needs so far but it arose when working
on `IsaBuffersAllocator`. The latter is coming with future commits, but
the shared code modifications are extracted as an independent step.
Related-To: NEO-7788
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
2023-06-29 15:15:50 +00:00
|
|
|
#include "shared/source/helpers/non_copyable_or_moveable.h"
|
2023-05-12 16:51:52 +00:00
|
|
|
#include "shared/source/utilities/stackvec.h"
|
|
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
namespace NEO {
|
|
|
|
|
|
|
|
|
|
class GraphicsAllocation;
|
|
|
|
|
class HeapAllocator;
|
|
|
|
|
class MemoryManager;
|
2025-02-06 23:56:09 +00:00
|
|
|
class ProductHelper;
|
2023-05-12 16:51:52 +00:00
|
|
|
|
|
|
|
|
struct SmallBuffersParams {
|
2025-02-06 23:56:09 +00:00
|
|
|
size_t aggregatedSmallBuffersPoolSize{0};
|
|
|
|
|
size_t smallBufferThreshold{0};
|
|
|
|
|
size_t chunkAlignment{0};
|
|
|
|
|
size_t startingOffset{0};
|
|
|
|
|
|
|
|
|
|
static SmallBuffersParams getDefaultParams() {
|
|
|
|
|
return {
|
2025-02-11 16:36:49 +00:00
|
|
|
.aggregatedSmallBuffersPoolSize = 2 * MemoryConstants::megaByte,
|
|
|
|
|
.smallBufferThreshold = 1 * MemoryConstants::megaByte,
|
|
|
|
|
.chunkAlignment = MemoryConstants::pageSize64k,
|
|
|
|
|
.startingOffset = MemoryConstants::pageSize64k};
|
2025-02-06 23:56:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static SmallBuffersParams getLargePagesParams() {
|
|
|
|
|
return {
|
2025-02-11 16:36:49 +00:00
|
|
|
.aggregatedSmallBuffersPoolSize = 16 * MemoryConstants::megaByte,
|
|
|
|
|
.smallBufferThreshold = 2 * MemoryConstants::megaByte,
|
|
|
|
|
.chunkAlignment = MemoryConstants::pageSize64k,
|
|
|
|
|
.startingOffset = MemoryConstants::pageSize64k};
|
2025-02-06 23:56:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline SmallBuffersParams getPreferredBufferPoolParams(const ProductHelper &productHelper);
|
2023-05-12 16:51:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename PoolT, typename BufferType, typename BufferParentType = BufferType>
|
2025-02-06 23:56:09 +00:00
|
|
|
struct AbstractBuffersPool : public NonCopyableClass {
|
2023-05-12 16:51:52 +00:00
|
|
|
// 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> &;
|
feature: add optional onChunkFree callback to AbstractBuffersPool
Instances returned by `getAllocationsVector()` in some cases cannot be
freed (in the `malloc/new` sense) until the `drain()` function invokes
`allocInUse()` on them. Plus, the `chunksToFree` container operates on
pairs `{offset, size}`, not pointers, so such pair cannot be used to
release allocations either.
Provide an optional callback, which can be implemented by the custom
pool derived from `AbstractBuffersPool`. This callback can be used, for
example, to perform actual release of an allocation related to the
currently processed chunk.
Additionally, provide the `drain()` and `tryFreeFromPoolBuffer()`
functions with pool-independent versions and keep the previous versions
as defaults (for allocators with a single pool). The new versions allow
reusing the code for cases when allocator has multiple pools.
In both cases, there was no such needs so far but it arose when working
on `IsaBuffersAllocator`. The latter is coming with future commits, but
the shared code modifications are extracted as an independent step.
Related-To: NEO-7788
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
2023-06-29 15:15:50 +00:00
|
|
|
using OnChunkFreeCallback = void (PoolT::*)(uint64_t offset, size_t size);
|
2023-05-12 16:51:52 +00:00
|
|
|
|
feature: add optional onChunkFree callback to AbstractBuffersPool
Instances returned by `getAllocationsVector()` in some cases cannot be
freed (in the `malloc/new` sense) until the `drain()` function invokes
`allocInUse()` on them. Plus, the `chunksToFree` container operates on
pairs `{offset, size}`, not pointers, so such pair cannot be used to
release allocations either.
Provide an optional callback, which can be implemented by the custom
pool derived from `AbstractBuffersPool`. This callback can be used, for
example, to perform actual release of an allocation related to the
currently processed chunk.
Additionally, provide the `drain()` and `tryFreeFromPoolBuffer()`
functions with pool-independent versions and keep the previous versions
as defaults (for allocators with a single pool). The new versions allow
reusing the code for cases when allocator has multiple pools.
In both cases, there was no such needs so far but it arose when working
on `IsaBuffersAllocator`. The latter is coming with future commits, but
the shared code modifications are extracted as an independent step.
Related-To: NEO-7788
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
2023-06-29 15:15:50 +00:00
|
|
|
AbstractBuffersPool(MemoryManager *memoryManager, OnChunkFreeCallback onChunkFreeCallback);
|
2025-02-06 23:56:09 +00:00
|
|
|
AbstractBuffersPool(MemoryManager *memoryManager, OnChunkFreeCallback onChunkFreeCallback, const SmallBuffersParams ¶ms);
|
2025-06-05 13:28:04 +00:00
|
|
|
AbstractBuffersPool(AbstractBuffersPool<PoolT, BufferType, BufferParentType> &&bufferPool) noexcept;
|
2025-02-18 17:32:35 +00:00
|
|
|
AbstractBuffersPool &operator=(AbstractBuffersPool &&other) noexcept = delete;
|
2024-04-29 17:12:50 +00:00
|
|
|
virtual ~AbstractBuffersPool() = default;
|
|
|
|
|
|
2023-05-12 16:51:52 +00:00
|
|
|
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;
|
feature: add optional onChunkFree callback to AbstractBuffersPool
Instances returned by `getAllocationsVector()` in some cases cannot be
freed (in the `malloc/new` sense) until the `drain()` function invokes
`allocInUse()` on them. Plus, the `chunksToFree` container operates on
pairs `{offset, size}`, not pointers, so such pair cannot be used to
release allocations either.
Provide an optional callback, which can be implemented by the custom
pool derived from `AbstractBuffersPool`. This callback can be used, for
example, to perform actual release of an allocation related to the
currently processed chunk.
Additionally, provide the `drain()` and `tryFreeFromPoolBuffer()`
functions with pool-independent versions and keep the previous versions
as defaults (for allocators with a single pool). The new versions allow
reusing the code for cases when allocator has multiple pools.
In both cases, there was no such needs so far but it arose when working
on `IsaBuffersAllocator`. The latter is coming with future commits, but
the shared code modifications are extracted as an independent step.
Related-To: NEO-7788
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
2023-06-29 15:15:50 +00:00
|
|
|
OnChunkFreeCallback onChunkFreeCallback = nullptr;
|
2025-02-06 23:56:09 +00:00
|
|
|
SmallBuffersParams params;
|
2023-05-12 16:51:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename BuffersPoolType, typename BufferType, typename BufferParentType = BufferType>
|
2025-02-06 23:56:09 +00:00
|
|
|
class AbstractBuffersAllocator {
|
2023-05-12 16:51:52 +00:00
|
|
|
// 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:
|
2025-02-06 23:56:09 +00:00
|
|
|
AbstractBuffersAllocator(const SmallBuffersParams ¶ms);
|
|
|
|
|
AbstractBuffersAllocator();
|
2023-05-12 16:51:52 +00:00
|
|
|
|
2024-04-29 17:12:50 +00:00
|
|
|
void releasePools() { this->bufferPools.clear(); }
|
2023-05-12 16:51:52 +00:00
|
|
|
bool isPoolBuffer(const BufferParentType *buffer) const;
|
|
|
|
|
void tryFreeFromPoolBuffer(BufferParentType *possiblePoolBuffer, size_t offset, size_t size);
|
2024-12-16 10:19:12 +00:00
|
|
|
uint32_t getPoolsCount() { return static_cast<uint32_t>(this->bufferPools.size()); }
|
2023-05-12 16:51:52 +00:00
|
|
|
|
2025-02-06 23:56:09 +00:00
|
|
|
void setParams(const SmallBuffersParams &newParams) {
|
|
|
|
|
params = newParams;
|
|
|
|
|
}
|
|
|
|
|
SmallBuffersParams getParams() const {
|
|
|
|
|
return params;
|
|
|
|
|
};
|
|
|
|
|
|
2023-05-12 16:51:52 +00:00
|
|
|
protected:
|
2025-02-06 23:56:09 +00:00
|
|
|
inline bool isSizeWithinThreshold(size_t size) const { return params.smallBufferThreshold >= size; }
|
feature: add optional onChunkFree callback to AbstractBuffersPool
Instances returned by `getAllocationsVector()` in some cases cannot be
freed (in the `malloc/new` sense) until the `drain()` function invokes
`allocInUse()` on them. Plus, the `chunksToFree` container operates on
pairs `{offset, size}`, not pointers, so such pair cannot be used to
release allocations either.
Provide an optional callback, which can be implemented by the custom
pool derived from `AbstractBuffersPool`. This callback can be used, for
example, to perform actual release of an allocation related to the
currently processed chunk.
Additionally, provide the `drain()` and `tryFreeFromPoolBuffer()`
functions with pool-independent versions and keep the previous versions
as defaults (for allocators with a single pool). The new versions allow
reusing the code for cases when allocator has multiple pools.
In both cases, there was no such needs so far but it arose when working
on `IsaBuffersAllocator`. The latter is coming with future commits, but
the shared code modifications are extracted as an independent step.
Related-To: NEO-7788
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
2023-06-29 15:15:50 +00:00
|
|
|
void tryFreeFromPoolBuffer(BufferParentType *possiblePoolBuffer, size_t offset, size_t size, std::vector<BuffersPoolType> &bufferPoolsVec);
|
2023-05-12 16:51:52 +00:00
|
|
|
void drain();
|
feature: add optional onChunkFree callback to AbstractBuffersPool
Instances returned by `getAllocationsVector()` in some cases cannot be
freed (in the `malloc/new` sense) until the `drain()` function invokes
`allocInUse()` on them. Plus, the `chunksToFree` container operates on
pairs `{offset, size}`, not pointers, so such pair cannot be used to
release allocations either.
Provide an optional callback, which can be implemented by the custom
pool derived from `AbstractBuffersPool`. This callback can be used, for
example, to perform actual release of an allocation related to the
currently processed chunk.
Additionally, provide the `drain()` and `tryFreeFromPoolBuffer()`
functions with pool-independent versions and keep the previous versions
as defaults (for allocators with a single pool). The new versions allow
reusing the code for cases when allocator has multiple pools.
In both cases, there was no such needs so far but it arose when working
on `IsaBuffersAllocator`. The latter is coming with future commits, but
the shared code modifications are extracted as an independent step.
Related-To: NEO-7788
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
2023-06-29 15:15:50 +00:00
|
|
|
void drain(std::vector<BuffersPoolType> &bufferPoolsVec);
|
2023-05-12 16:51:52 +00:00
|
|
|
void addNewBufferPool(BuffersPoolType &&bufferPool);
|
feature: add optional onChunkFree callback to AbstractBuffersPool
Instances returned by `getAllocationsVector()` in some cases cannot be
freed (in the `malloc/new` sense) until the `drain()` function invokes
`allocInUse()` on them. Plus, the `chunksToFree` container operates on
pairs `{offset, size}`, not pointers, so such pair cannot be used to
release allocations either.
Provide an optional callback, which can be implemented by the custom
pool derived from `AbstractBuffersPool`. This callback can be used, for
example, to perform actual release of an allocation related to the
currently processed chunk.
Additionally, provide the `drain()` and `tryFreeFromPoolBuffer()`
functions with pool-independent versions and keep the previous versions
as defaults (for allocators with a single pool). The new versions allow
reusing the code for cases when allocator has multiple pools.
In both cases, there was no such needs so far but it arose when working
on `IsaBuffersAllocator`. The latter is coming with future commits, but
the shared code modifications are extracted as an independent step.
Related-To: NEO-7788
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
2023-06-29 15:15:50 +00:00
|
|
|
void addNewBufferPool(BuffersPoolType &&bufferPool, std::vector<BuffersPoolType> &bufferPoolsVec);
|
2023-05-12 16:51:52 +00:00
|
|
|
|
|
|
|
|
std::mutex mutex;
|
|
|
|
|
std::vector<BuffersPoolType> bufferPools;
|
2025-02-06 23:56:09 +00:00
|
|
|
SmallBuffersParams params;
|
2023-05-12 16:51:52 +00:00
|
|
|
};
|
|
|
|
|
} // namespace NEO
|