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