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, VkSystemAllocationScope allocationScope) = 0; 48 virtual void free (void* mem) = 0; 49 50 virtual void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0; 51 virtual void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0; 52 getCallbacks(void) const53 const VkAllocationCallbacks* getCallbacks (void) const { return &m_callbacks; } 54 55 private: 56 const VkAllocationCallbacks m_callbacks; 57 }; 58 59 struct AllocationCallbackRecord 60 { 61 enum Type 62 { 63 TYPE_ALLOCATION = 0, //! Call to pfnAllocation 64 TYPE_REALLOCATION, //! Call to pfnReallocation 65 TYPE_FREE, //! Call to pfnFree 66 TYPE_INTERNAL_ALLOCATION, //! Call to pfnInternalAllocation 67 TYPE_INTERNAL_FREE, //! Call to pfnInternalFree 68 69 TYPE_LAST 70 }; 71 72 Type type; 73 74 union 75 { 76 struct 77 { 78 size_t size; 79 size_t alignment; 80 VkSystemAllocationScope scope; 81 void* returnedPtr; 82 } allocation; 83 84 struct 85 { 86 void* original; 87 size_t size; 88 size_t alignment; 89 VkSystemAllocationScope scope; 90 void* returnedPtr; 91 } reallocation; 92 93 struct 94 { 95 void* mem; 96 } free; 97 98 // \note Used for both INTERNAL_ALLOCATION and INTERNAL_FREE 99 struct 100 { 101 size_t size; 102 VkInternalAllocationType type; 103 VkSystemAllocationScope scope; 104 } internalAllocation; 105 } data; 106 AllocationCallbackRecordvk::AllocationCallbackRecord107 AllocationCallbackRecord (void) : type(TYPE_LAST) {} 108 109 static AllocationCallbackRecord allocation (size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr); 110 static AllocationCallbackRecord reallocation (void* original, size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr); 111 static AllocationCallbackRecord free (void* mem); 112 static AllocationCallbackRecord internalAllocation (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope); 113 static AllocationCallbackRecord internalFree (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope); 114 }; 115 116 class ChainedAllocator : public AllocationCallbacks 117 { 118 public: 119 ChainedAllocator (const VkAllocationCallbacks* nextAllocator); 120 ~ChainedAllocator (void); 121 122 void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 123 void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 124 void free (void* mem); 125 126 void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); 127 void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); 128 129 private: 130 const VkAllocationCallbacks* m_nextAllocator; 131 }; 132 133 class AllocationCallbackRecorder : public ChainedAllocator 134 { 135 public: 136 AllocationCallbackRecorder (const VkAllocationCallbacks* allocator, deUint32 callCountHint = 1024); 137 ~AllocationCallbackRecorder (void); 138 139 void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 140 void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 141 void free (void* mem); 142 143 void notifyInternalAllocation (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); 144 void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); 145 146 typedef de::AppendList<AllocationCallbackRecord>::const_iterator RecordIterator; 147 getRecordsBegin(void) const148 RecordIterator getRecordsBegin (void) const { return m_records.begin(); } getRecordsEnd(void) const149 RecordIterator getRecordsEnd (void) const { return m_records.end(); } 150 151 private: 152 typedef de::AppendList<AllocationCallbackRecord> Records; 153 154 Records m_records; 155 }; 156 157 //! Allocator that starts returning null after N allocs 158 class DeterministicFailAllocator : public ChainedAllocator 159 { 160 public: 161 DeterministicFailAllocator (const VkAllocationCallbacks* allocator, deUint32 numPassingAllocs); 162 ~DeterministicFailAllocator (void); 163 164 void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 165 void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 166 167 private: 168 const deUint32 m_numPassingAllocs; 169 volatile deUint32 m_allocationNdx; 170 }; 171 172 struct AllocationCallbackViolation 173 { 174 enum Reason 175 { 176 REASON_DOUBLE_FREE = 0, 177 REASON_FREE_NOT_ALLOCATED_PTR, 178 REASON_REALLOC_NOT_ALLOCATED_PTR, 179 REASON_REALLOC_FREED_PTR, 180 REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL, 181 REASON_INVALID_ALLOCATION_SCOPE, 182 REASON_INVALID_INTERNAL_ALLOCATION_TYPE, 183 REASON_INVALID_ALIGNMENT, 184 REASON_REALLOC_DIFFERENT_ALIGNMENT, 185 186 REASON_LAST 187 }; 188 189 AllocationCallbackRecord record; 190 Reason reason; 191 AllocationCallbackViolationvk::AllocationCallbackViolation192 AllocationCallbackViolation (void) 193 : reason(REASON_LAST) 194 {} 195 AllocationCallbackViolationvk::AllocationCallbackViolation196 AllocationCallbackViolation (const AllocationCallbackRecord& record_, Reason reason_) 197 : record(record_) 198 , reason(reason_) 199 {} 200 }; 201 202 struct AllocationCallbackValidationResults 203 { 204 std::vector<AllocationCallbackRecord> liveAllocations; 205 size_t internalAllocationTotal[VK_INTERNAL_ALLOCATION_TYPE_LAST][VK_SYSTEM_ALLOCATION_SCOPE_LAST]; 206 std::vector<AllocationCallbackViolation> violations; 207 208 AllocationCallbackValidationResults (void); 209 210 void clear (void); 211 }; 212 213 void validateAllocationCallbacks (const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results); 214 bool checkAndLog (tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits); 215 bool validateAndLog (tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits); 216 217 size_t getLiveSystemAllocationTotal (const AllocationCallbackValidationResults& validationResults); 218 219 std::ostream& operator<< (std::ostream& str, const AllocationCallbackRecord& record); 220 std::ostream& operator<< (std::ostream& str, const AllocationCallbackViolation& violation); 221 222 const VkAllocationCallbacks* getSystemAllocator (void); 223 224 } // vk 225 226 #endif // _VKALLOCATIONCALLBACKUTIL_HPP 227