File: buffer_pool_allocator.h

package info (click to toggle)
intel-compute-runtime 25.35.35096.9-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 79,324 kB
  • sloc: cpp: 926,243; lisp: 3,433; sh: 715; makefile: 162; python: 21
file content (118 lines) | stat: -rw-r--r-- 5,006 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
 * 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 {
            .aggregatedSmallBuffersPoolSize = 2 * MemoryConstants::megaByte,
            .smallBufferThreshold = 1 * MemoryConstants::megaByte,
            .chunkAlignment = MemoryConstants::pageSize64k,
            .startingOffset = MemoryConstants::pageSize64k};
    }

    static SmallBuffersParams getLargePagesParams() {
        return {
            .aggregatedSmallBuffersPoolSize = 16 * MemoryConstants::megaByte,
            .smallBufferThreshold = 2 * MemoryConstants::megaByte,
            .chunkAlignment = MemoryConstants::pageSize64k,
            .startingOffset = MemoryConstants::pageSize64k};
    }

    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) noexcept;
    AbstractBuffersPool &operator=(AbstractBuffersPool &&other) noexcept = 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