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