• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // MemoryTracking.h:
7 //    Defines the classes used for memory tracking in ANGLE.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
11 #define LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
12 
13 #include <array>
14 #include <atomic>
15 
16 #include "common/SimpleMutex.h"
17 #include "common/angleutils.h"
18 #include "common/backtrace_utils.h"
19 #include "common/hash_containers.h"
20 #include "common/vulkan/vk_headers.h"
21 
22 namespace rx
23 {
24 namespace vk
25 {
26 class Renderer;
27 
28 // Used to designate memory allocation type for tracking purposes.
29 enum class MemoryAllocationType
30 {
31     Unspecified                              = 0,
32     ImageExternal                            = 1,
33     OffscreenSurfaceAttachmentImage          = 2,
34     SwapchainMSAAImage                       = 3,
35     SwapchainDepthStencilImage               = 4,
36     StagingImage                             = 5,
37     ImplicitMultisampledRenderToTextureImage = 6,
38     TextureImage                             = 7,
39     FontImage                                = 8,
40     RenderBufferStorageImage                 = 9,
41     Buffer                                   = 10,
42     BufferExternal                           = 11,
43 
44     InvalidEnum = 12,
45     EnumCount   = InvalidEnum,
46 };
47 
48 constexpr const char *kMemoryAllocationTypeMessage[] = {
49     "Unspecified",
50     "ImageExternal",
51     "OffscreenSurfaceAttachmentImage",
52     "SwapchainMSAAImage",
53     "SwapchainDepthStencilImage",
54     "StagingImage",
55     "ImplicitMultisampledRenderToTextureImage",
56     "TextureImage",
57     "FontImage",
58     "RenderBufferStorageImage",
59     "Buffer",
60     "BufferExternal",
61     "Invalid",
62 };
63 constexpr const uint32_t kMemoryAllocationTypeCount =
64     static_cast<uint32_t>(MemoryAllocationType::EnumCount);
65 
66 // Used to select the severity for memory allocation logs.
67 enum class MemoryLogSeverity
68 {
69     INFO,
70     WARN,
71 };
72 
73 // Used to store memory allocation information for tracking purposes.
74 struct MemoryAllocationInfo
75 {
76     MemoryAllocationInfo() = default;
77     uint64_t id;
78     MemoryAllocationType allocType;
79     uint32_t memoryHeapIndex;
80     void *handle;
81     VkDeviceSize size;
82 };
83 
84 class MemoryAllocInfoMapKey
85 {
86   public:
MemoryAllocInfoMapKey()87     MemoryAllocInfoMapKey() : handle(nullptr) {}
MemoryAllocInfoMapKey(void * handle)88     MemoryAllocInfoMapKey(void *handle) : handle(handle) {}
89 
90     bool operator==(const MemoryAllocInfoMapKey &rhs) const
91     {
92         return reinterpret_cast<uint64_t>(handle) == reinterpret_cast<uint64_t>(rhs.handle);
93     }
94 
95     size_t hash() const;
96 
97   private:
98     void *handle;
99 };
100 
101 // Process GPU memory reports
102 class MemoryReport final : angle::NonCopyable
103 {
104   public:
105     MemoryReport();
106     void processCallback(const VkDeviceMemoryReportCallbackDataEXT &callbackData, bool logCallback);
107     void logMemoryReportStats() const;
108 
109   private:
110     struct MemorySizes
111     {
112         VkDeviceSize allocatedMemory;
113         VkDeviceSize allocatedMemoryMax;
114         VkDeviceSize importedMemory;
115         VkDeviceSize importedMemoryMax;
116     };
117     mutable angle::SimpleMutex mMemoryReportMutex;
118     VkDeviceSize mCurrentTotalAllocatedMemory;
119     VkDeviceSize mMaxTotalAllocatedMemory;
120     angle::HashMap<VkObjectType, MemorySizes> mSizesPerType;
121     VkDeviceSize mCurrentTotalImportedMemory;
122     VkDeviceSize mMaxTotalImportedMemory;
123     angle::HashMap<uint64_t, int> mUniqueIDCounts;
124 };
125 }  // namespace vk
126 }  // namespace rx
127 
128 // Introduce std::hash for MemoryAllocInfoMapKey.
129 namespace std
130 {
131 template <>
132 struct hash<rx::vk::MemoryAllocInfoMapKey>
133 {
134     size_t operator()(const rx::vk::MemoryAllocInfoMapKey &key) const { return key.hash(); }
135 };
136 }  // namespace std
137 
138 namespace rx
139 {
140 
141 // Memory tracker for allocations and deallocations, which is used in vk::Renderer.
142 class MemoryAllocationTracker : angle::NonCopyable
143 {
144   public:
145     MemoryAllocationTracker(vk::Renderer *renderer);
146     void initMemoryTrackers();
147     void onDeviceInit();
148     void onDestroy();
149 
150     // Memory statistics are logged when handling a context error.
151     void logMemoryStatsOnError();
152 
153     // Collect information regarding memory allocations and deallocations.
154     void onMemoryAllocImpl(vk::MemoryAllocationType allocType,
155                            VkDeviceSize size,
156                            uint32_t memoryTypeIndex,
157                            void *handle);
158     void onMemoryDeallocImpl(vk::MemoryAllocationType allocType,
159                              VkDeviceSize size,
160                              uint32_t memoryTypeIndex,
161                              void *handle);
162 
163     // Memory allocation statistics functions.
164     VkDeviceSize getActiveMemoryAllocationsSize(uint32_t allocTypeIndex) const;
165     VkDeviceSize getActiveHeapMemoryAllocationsSize(uint32_t allocTypeIndex,
166                                                     uint32_t heapIndex) const;
167 
168     uint64_t getActiveMemoryAllocationsCount(uint32_t allocTypeIndex) const;
169     uint64_t getActiveHeapMemoryAllocationsCount(uint32_t allocTypeIndex, uint32_t heapIndex) const;
170 
171     // Compare the expected flags with the flags of the allocated memory.
172     void compareExpectedFlagsWithAllocatedFlags(VkMemoryPropertyFlags requiredFlags,
173                                                 VkMemoryPropertyFlags preferredFlags,
174                                                 VkMemoryPropertyFlags allocatedFlags,
175                                                 void *handle);
176 
177     // Issue warning in case of exceeding maximum allowed allocation size.
178     void onExceedingMaxMemoryAllocationSize(VkDeviceSize size);
179 
180     // Pending memory allocation information is used for logging in case of an unsuccessful
181     // allocation. It is cleared in onMemoryAlloc().
182     VkDeviceSize getPendingMemoryAllocationSize() const;
183     vk::MemoryAllocationType getPendingMemoryAllocationType() const;
184     uint32_t getPendingMemoryTypeIndex() const;
185 
186     void resetPendingMemoryAlloc();
187     void setPendingMemoryAlloc(vk::MemoryAllocationType allocType,
188                                VkDeviceSize size,
189                                uint32_t memoryTypeIndex);
190 
191   private:
192     // Pointer to parent renderer object.
193     vk::Renderer *const mRenderer;
194 
195     // For tracking the overall memory allocation sizes and counts per memory allocation type.
196     std::array<std::atomic<VkDeviceSize>, vk::kMemoryAllocationTypeCount>
197         mActiveMemoryAllocationsSize;
198     std::array<std::atomic<uint64_t>, vk::kMemoryAllocationTypeCount> mActiveMemoryAllocationsCount;
199 
200     // Memory allocation data per memory heap.
201     using PerHeapMemoryAllocationSizeArray =
202         std::array<std::atomic<VkDeviceSize>, VK_MAX_MEMORY_HEAPS>;
203     using PerHeapMemoryAllocationCountArray =
204         std::array<std::atomic<uint64_t>, VK_MAX_MEMORY_HEAPS>;
205 
206     std::array<PerHeapMemoryAllocationSizeArray, vk::kMemoryAllocationTypeCount>
207         mActivePerHeapMemoryAllocationsSize;
208     std::array<PerHeapMemoryAllocationCountArray, vk::kMemoryAllocationTypeCount>
209         mActivePerHeapMemoryAllocationsCount;
210 
211     // Pending memory allocation information is used for logging in case of an allocation error.
212     // It includes the size and type of the last attempted allocation, which are cleared after
213     // the allocation is successful.
214     std::atomic<VkDeviceSize> mPendingMemoryAllocationSize;
215     std::atomic<vk::MemoryAllocationType> mPendingMemoryAllocationType;
216     std::atomic<uint32_t> mPendingMemoryTypeIndex;
217 
218     // Mutex is used to update the data when debug layers are enabled.
219     angle::SimpleMutex mMemoryAllocationMutex;
220 
221     // Additional information regarding memory allocation with debug layers enabled, including
222     // allocation ID and a record of all active allocations.
223     uint64_t mMemoryAllocationID;
224     using MemoryAllocInfoMap = angle::HashMap<vk::MemoryAllocInfoMapKey, vk::MemoryAllocationInfo>;
225     std::unordered_map<angle::BacktraceInfo, MemoryAllocInfoMap> mMemoryAllocationRecord;
226 };
227 }  // namespace rx
228 
229 #endif  // LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
230