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