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();		}
getNumRecords(void) const150 	std::size_t				getNumRecords				(void) const { return m_records.size();		}
151 
152 private:
153 	typedef de::AppendList<AllocationCallbackRecord> Records;
154 
155 	Records					m_records;
156 };
157 
158 //! Allocator that starts returning null after N allocs
159 class DeterministicFailAllocator : public ChainedAllocator
160 {
161 public:
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 
178 private:
179 	Mode					m_mode;
180 	deUint32				m_numPassingAllocs;
181 	volatile deUint32		m_allocationNdx;
182 };
183 
184 struct 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 
AllocationCallbackViolationvk::AllocationCallbackViolation204 	AllocationCallbackViolation (void)
205 		: reason(REASON_LAST)
206 	{}
207 
AllocationCallbackViolationvk::AllocationCallbackViolation208 	AllocationCallbackViolation (const AllocationCallbackRecord& record_, Reason reason_)
209 		: record(record_)
210 		, reason(reason_)
211 	{}
212 };
213 
214 struct 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 
225 void							validateAllocationCallbacks		(const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results);
226 bool							checkAndLog						(tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits);
227 bool							validateAndLog					(tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits);
228 
229 size_t							getLiveSystemAllocationTotal	(const AllocationCallbackValidationResults& validationResults);
230 
231 std::ostream&					operator<<						(std::ostream& str, const AllocationCallbackRecord& record);
232 std::ostream&					operator<<						(std::ostream& str, const AllocationCallbackViolation& violation);
233 
234 const VkAllocationCallbacks*	getSystemAllocator				(void);
235 
236 } // vk
237 
238 #endif // _VKALLOCATIONCALLBACKUTIL_HPP
239