1 #ifndef _VKALLOCATIONCALLBACKUTIL_HPP 2 #define _VKALLOCATIONCALLBACKUTIL_HPP 3 /*------------------------------------------------------------------------- 4 * Vulkan CTS Framework 5 * -------------------- 6 * 7 * Copyright (c) 2015 Google Inc. 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Memory allocation callback utilities. 24 *//*--------------------------------------------------------------------*/ 25 26 #include "vkDefs.hpp" 27 #include "deAppendList.hpp" 28 29 #include <vector> 30 #include <ostream> 31 32 namespace tcu 33 { 34 class TestLog; 35 } 36 37 namespace vk 38 { 39 40 class AllocationCallbacks 41 { 42 public: 43 AllocationCallbacks(void); 44 virtual ~AllocationCallbacks(void); 45 46 virtual void *allocate(size_t size, size_t alignment, VkSystemAllocationScope allocationScope) = 0; 47 virtual void *reallocate(void *original, size_t size, size_t alignment, 48 VkSystemAllocationScope allocationScope) = 0; 49 virtual void free(void *mem) = 0; 50 51 virtual void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, 52 VkSystemAllocationScope allocationScope) = 0; 53 virtual void notifyInternalFree(size_t size, VkInternalAllocationType allocationType, 54 VkSystemAllocationScope allocationScope) = 0; 55 getCallbacks(void) const56 const VkAllocationCallbacks *getCallbacks(void) const 57 { 58 return &m_callbacks; 59 } 60 61 private: 62 const VkAllocationCallbacks m_callbacks; 63 }; 64 65 struct AllocationCallbackRecord 66 { 67 enum Type 68 { 69 TYPE_ALLOCATION = 0, //! Call to pfnAllocation 70 TYPE_REALLOCATION, //! Call to pfnReallocation 71 TYPE_FREE, //! Call to pfnFree 72 TYPE_INTERNAL_ALLOCATION, //! Call to pfnInternalAllocation 73 TYPE_INTERNAL_FREE, //! Call to pfnInternalFree 74 75 TYPE_LAST 76 }; 77 78 Type type; 79 80 union 81 { 82 struct 83 { 84 size_t size; 85 size_t alignment; 86 VkSystemAllocationScope scope; 87 void *returnedPtr; 88 } allocation; 89 90 struct 91 { 92 void *original; 93 size_t size; 94 size_t alignment; 95 VkSystemAllocationScope scope; 96 void *returnedPtr; 97 } reallocation; 98 99 struct 100 { 101 void *mem; 102 } free; 103 104 // \note Used for both INTERNAL_ALLOCATION and INTERNAL_FREE 105 struct 106 { 107 size_t size; 108 VkInternalAllocationType type; 109 VkSystemAllocationScope scope; 110 } internalAllocation; 111 } data; 112 AllocationCallbackRecordvk::AllocationCallbackRecord113 AllocationCallbackRecord(void) : type(TYPE_LAST) 114 { 115 } 116 117 static AllocationCallbackRecord allocation(size_t size, size_t alignment, VkSystemAllocationScope scope, 118 void *returnedPtr); 119 static AllocationCallbackRecord reallocation(void *original, size_t size, size_t alignment, 120 VkSystemAllocationScope scope, void *returnedPtr); 121 static AllocationCallbackRecord free(void *mem); 122 static AllocationCallbackRecord internalAllocation(size_t size, VkInternalAllocationType type, 123 VkSystemAllocationScope scope); 124 static AllocationCallbackRecord internalFree(size_t size, VkInternalAllocationType type, 125 VkSystemAllocationScope scope); 126 }; 127 128 class ChainedAllocator : public AllocationCallbacks 129 { 130 public: 131 ChainedAllocator(const VkAllocationCallbacks *nextAllocator); 132 ~ChainedAllocator(void); 133 134 void *allocate(size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 135 void *reallocate(void *original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 136 void free(void *mem); 137 138 void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, 139 VkSystemAllocationScope allocationScope); 140 void notifyInternalFree(size_t size, VkInternalAllocationType allocationType, 141 VkSystemAllocationScope allocationScope); 142 143 private: 144 const VkAllocationCallbacks *m_nextAllocator; 145 }; 146 147 class AllocationCallbackRecorder : public ChainedAllocator 148 { 149 public: 150 AllocationCallbackRecorder(const VkAllocationCallbacks *allocator, uint32_t callCountHint = 1024); 151 ~AllocationCallbackRecorder(void); 152 153 void *allocate(size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 154 void *reallocate(void *original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 155 void free(void *mem); 156 157 void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, 158 VkSystemAllocationScope allocationScope); 159 void notifyInternalFree(size_t size, VkInternalAllocationType allocationType, 160 VkSystemAllocationScope allocationScope); 161 162 typedef de::AppendList<AllocationCallbackRecord>::const_iterator RecordIterator; 163 getRecordsBegin(void) const164 RecordIterator getRecordsBegin(void) const 165 { 166 return m_records.begin(); 167 } getRecordsEnd(void) const168 RecordIterator getRecordsEnd(void) const 169 { 170 return m_records.end(); 171 } getNumRecords(void) const172 std::size_t getNumRecords(void) const 173 { 174 return m_records.size(); 175 } 176 177 private: 178 typedef de::AppendList<AllocationCallbackRecord> Records; 179 180 Records m_records; 181 }; 182 183 //! Allocator that starts returning null after N allocs 184 class DeterministicFailAllocator : public ChainedAllocator 185 { 186 public: 187 enum Mode 188 { 189 MODE_DO_NOT_COUNT = 0, //!< Do not count allocations, all allocs will succeed 190 MODE_COUNT_AND_FAIL, //!< Count allocations, fail when reaching alloc N 191 192 MODE_LAST 193 }; 194 195 DeterministicFailAllocator(const VkAllocationCallbacks *allocator, Mode mode, uint32_t numPassingAllocs); 196 ~DeterministicFailAllocator(void); 197 198 void reset(Mode mode, uint32_t numPassingAllocs); 199 200 void *allocate(size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 201 void *reallocate(void *original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 202 203 private: 204 Mode m_mode; 205 uint32_t m_numPassingAllocs; 206 volatile uint32_t m_allocationNdx; 207 }; 208 209 struct AllocationCallbackViolation 210 { 211 enum Reason 212 { 213 REASON_DOUBLE_FREE = 0, 214 REASON_FREE_NOT_ALLOCATED_PTR, 215 REASON_REALLOC_NOT_ALLOCATED_PTR, 216 REASON_REALLOC_FREED_PTR, 217 REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL, 218 REASON_INVALID_ALLOCATION_SCOPE, 219 REASON_INVALID_INTERNAL_ALLOCATION_TYPE, 220 REASON_INVALID_ALIGNMENT, 221 REASON_REALLOC_DIFFERENT_ALIGNMENT, 222 223 REASON_LAST 224 }; 225 226 AllocationCallbackRecord record; 227 Reason reason; 228 AllocationCallbackViolationvk::AllocationCallbackViolation229 AllocationCallbackViolation(void) : reason(REASON_LAST) 230 { 231 } 232 AllocationCallbackViolationvk::AllocationCallbackViolation233 AllocationCallbackViolation(const AllocationCallbackRecord &record_, Reason reason_) 234 : record(record_) 235 , reason(reason_) 236 { 237 } 238 }; 239 240 struct AllocationCallbackValidationResults 241 { 242 std::vector<AllocationCallbackRecord> liveAllocations; 243 size_t internalAllocationTotal[VK_INTERNAL_ALLOCATION_TYPE_LAST][VK_SYSTEM_ALLOCATION_SCOPE_LAST]; 244 std::vector<AllocationCallbackViolation> violations; 245 246 AllocationCallbackValidationResults(void); 247 248 void clear(void); 249 }; 250 251 void validateAllocationCallbacks(const AllocationCallbackRecorder &recorder, 252 AllocationCallbackValidationResults *results); 253 bool checkAndLog(tcu::TestLog &log, const AllocationCallbackValidationResults &results, 254 uint32_t allowedLiveAllocScopeBits); 255 bool validateAndLog(tcu::TestLog &log, const AllocationCallbackRecorder &recorder, uint32_t allowedLiveAllocScopeBits); 256 257 size_t getLiveSystemAllocationTotal(const AllocationCallbackValidationResults &validationResults); 258 259 std::ostream &operator<<(std::ostream &str, const AllocationCallbackRecord &record); 260 std::ostream &operator<<(std::ostream &str, const AllocationCallbackViolation &violation); 261 262 const VkAllocationCallbacks *getSystemAllocator(void); 263 264 } // namespace vk 265 266 #endif // _VKALLOCATIONCALLBACKUTIL_HPP 267