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 32namespace tcu 33{ 34class TestLog; 35} 36 37namespace vk 38{ 39 40class AllocationCallbacks 41{ 42public: 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 53 const VkAllocationCallbacks* getCallbacks (void) const { return &m_callbacks; } 54 55private: 56 const VkAllocationCallbacks m_callbacks; 57}; 58 59struct 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 107 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 116class ChainedAllocator : public AllocationCallbacks 117{ 118public: 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 129private: 130 const VkAllocationCallbacks* m_nextAllocator; 131}; 132 133class AllocationCallbackRecorder : public ChainedAllocator 134{ 135public: 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 148 RecordIterator getRecordsBegin (void) const { return m_records.begin(); } 149 RecordIterator getRecordsEnd (void) const { return m_records.end(); } 150 std::size_t getNumRecords (void) const { return m_records.size(); } 151 152private: 153 typedef de::AppendList<AllocationCallbackRecord> Records; 154 155 Records m_records; 156}; 157 158//! Allocator that starts returning null after N allocs 159class DeterministicFailAllocator : public ChainedAllocator 160{ 161public: 162 enum Mode 163 { 164 MODE_DO_NOT_COUNT = 0, //!< Do not count allocations, all allocs will succeed 165 MODE_COUNT_AND_FAIL, //!< Count allocations, fail when reaching alloc N 166 167 MODE_LAST 168 }; 169 170 DeterministicFailAllocator (const VkAllocationCallbacks* allocator, Mode mode, deUint32 numPassingAllocs); 171 ~DeterministicFailAllocator (void); 172 173 void reset (Mode mode, deUint32 numPassingAllocs); 174 175 void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 176 void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); 177 178private: 179 Mode m_mode; 180 deUint32 m_numPassingAllocs; 181 volatile deUint32 m_allocationNdx; 182}; 183 184struct AllocationCallbackViolation 185{ 186 enum Reason 187 { 188 REASON_DOUBLE_FREE = 0, 189 REASON_FREE_NOT_ALLOCATED_PTR, 190 REASON_REALLOC_NOT_ALLOCATED_PTR, 191 REASON_REALLOC_FREED_PTR, 192 REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL, 193 REASON_INVALID_ALLOCATION_SCOPE, 194 REASON_INVALID_INTERNAL_ALLOCATION_TYPE, 195 REASON_INVALID_ALIGNMENT, 196 REASON_REALLOC_DIFFERENT_ALIGNMENT, 197 198 REASON_LAST 199 }; 200 201 AllocationCallbackRecord record; 202 Reason reason; 203 204 AllocationCallbackViolation (void) 205 : reason(REASON_LAST) 206 {} 207 208 AllocationCallbackViolation (const AllocationCallbackRecord& record_, Reason reason_) 209 : record(record_) 210 , reason(reason_) 211 {} 212}; 213 214struct AllocationCallbackValidationResults 215{ 216 std::vector<AllocationCallbackRecord> liveAllocations; 217 size_t internalAllocationTotal[VK_INTERNAL_ALLOCATION_TYPE_LAST][VK_SYSTEM_ALLOCATION_SCOPE_LAST]; 218 std::vector<AllocationCallbackViolation> violations; 219 220 AllocationCallbackValidationResults (void); 221 222 void clear (void); 223}; 224 225void validateAllocationCallbacks (const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results); 226bool checkAndLog (tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits); 227bool validateAndLog (tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits); 228 229size_t getLiveSystemAllocationTotal (const AllocationCallbackValidationResults& validationResults); 230 231std::ostream& operator<< (std::ostream& str, const AllocationCallbackRecord& record); 232std::ostream& operator<< (std::ostream& str, const AllocationCallbackViolation& violation); 233 234const VkAllocationCallbacks* getSystemAllocator (void); 235 236} // vk 237 238#endif // _VKALLOCATIONCALLBACKUTIL_HPP 239