• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _VKBINARYREGISTRY_HPP
2 #define _VKBINARYREGISTRY_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 Program binary registry.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vkDefs.hpp"
27 #include "vkPrograms.hpp"
28 #include "tcuResource.hpp"
29 #include "deMemPool.hpp"
30 #include "dePoolHash.h"
31 #include "deUniquePtr.hpp"
32 
33 #include <map>
34 #include <vector>
35 #include <stdexcept>
36 
37 namespace vk
38 {
39 namespace BinaryRegistryDetail
40 {
41 
42 struct ProgramIdentifier
43 {
44 	std::string		testCasePath;
45 	std::string		programName;
46 
ProgramIdentifiervk::BinaryRegistryDetail::ProgramIdentifier47 	ProgramIdentifier (const std::string& testCasePath_, const std::string& programName_)
48 		: testCasePath	(testCasePath_)
49 		, programName	(programName_)
50 	{
51 	}
52 };
53 
operator <(const ProgramIdentifier & a,const ProgramIdentifier & b)54 inline bool operator< (const ProgramIdentifier& a, const ProgramIdentifier& b)
55 {
56 	return (a.testCasePath < b.testCasePath) || ((a.testCasePath == b.testCasePath) && (a.programName < b.programName));
57 }
58 
59 class ProgramNotFoundException : public tcu::ResourceError
60 {
61 public:
ProgramNotFoundException(const ProgramIdentifier & id,const std::string & reason)62 	ProgramNotFoundException (const ProgramIdentifier& id, const std::string& reason)
63 		: tcu::ResourceError("Program " + id.testCasePath + " / '" + id.programName + "' not found: " + reason)
64 	{
65 	}
66 };
67 
68 // Program Binary Index
69 // --------------------
70 //
71 // When SPIR-V binaries are stored on disk, duplicate binaries are eliminated
72 // to save a significant amount of space. Many tests use identical binaries and
73 // just storing each compiled binary without de-duplication would be incredibly
74 // wasteful.
75 //
76 // To locate binary that corresponds given ProgramIdentifier, a program binary
77 // index is needed. Since that index is accessed every time a test requests shader
78 // binary, it must be fast to load (to reduce statup cost), and fast to access.
79 //
80 // Simple trie is used to store binary indices. It is laid out as an array of
81 // BinaryIndexNodes. Nodes store 4-byte pieces (words) of search string, rather
82 // than just a single character. This gives more regular memory layout in exchange
83 // of a little wasted storage.
84 //
85 // Search strings are created by splitting original string into 4-byte words and
86 // appending one or more terminating 0 bytes.
87 //
88 // For each node where word doesn't have trailing 0 bytes (not terminated), the
89 // index points into a offset of its child list. Children for each node are stored
90 // consecutively, and the list is terminated by child with word = 0.
91 //
92 // If word contains one or more trailing 0 bytes, index denotes the binary index
93 // instead of index of the child list.
94 
95 struct BinaryIndexNode
96 {
97 	deUint32	word;		//!< 4 bytes of search string.
98 	deUint32	index;		//!< Binary index if word ends with 0 bytes, or index of first child node otherwise.
99 };
100 
101 template<typename Element>
102 class LazyResource
103 {
104 public:
105 									LazyResource		(de::MovePtr<tcu::Resource> resource);
106 
107 	const Element&					operator[]			(size_t ndx);
size(void) const108 	size_t							size				(void) const { return m_elements.size();	}
109 
110 private:
111 	enum
112 	{
113 		ELEMENTS_PER_PAGE_LOG2	= 10
114 	};
115 
getPageForElement(size_t elemNdx) const116 	inline size_t					getPageForElement	(size_t elemNdx) const { return elemNdx >> ELEMENTS_PER_PAGE_LOG2;	}
isPageResident(size_t pageNdx) const117 	inline bool						isPageResident		(size_t pageNdx) const { return m_isPageResident[pageNdx];			}
118 
119 	void							makePageResident	(size_t pageNdx);
120 
121 	de::UniquePtr<tcu::Resource>	m_resource;
122 
123 	std::vector<Element>			m_elements;
124 	std::vector<bool>				m_isPageResident;
125 };
126 
127 template<typename Element>
LazyResource(de::MovePtr<tcu::Resource> resource)128 LazyResource<Element>::LazyResource (de::MovePtr<tcu::Resource> resource)
129 	: m_resource(resource)
130 {
131 	const size_t	resSize		= m_resource->getSize();
132 	const size_t	numElements	= resSize/sizeof(Element);
133 	const size_t	numPages	= (numElements >> ELEMENTS_PER_PAGE_LOG2) + ((numElements & ((1u<<ELEMENTS_PER_PAGE_LOG2)-1u)) == 0 ? 0 : 1);
134 
135 	TCU_CHECK_INTERNAL(numElements*sizeof(Element) == resSize);
136 
137 	m_elements.resize(numElements);
138 	m_isPageResident.resize(numPages, false);
139 }
140 
141 template<typename Element>
operator [](size_t ndx)142 const Element& LazyResource<Element>::operator[] (size_t ndx)
143 {
144 	const size_t pageNdx = getPageForElement(ndx);
145 
146 	if (ndx >= m_elements.size())
147 		throw std::out_of_range("");
148 
149 	if (!isPageResident(pageNdx))
150 		makePageResident(pageNdx);
151 
152 	return m_elements[ndx];
153 }
154 
155 template<typename Element>
makePageResident(size_t pageNdx)156 void LazyResource<Element>::makePageResident (size_t pageNdx)
157 {
158 	const size_t	pageSize		= (size_t)(1<<ELEMENTS_PER_PAGE_LOG2)*sizeof(Element);
159 	const size_t	pageOffset		= pageNdx*pageSize;
160 	const size_t	numBytesToRead	= de::min(m_elements.size()*sizeof(Element) - pageOffset, pageSize);
161 
162 	DE_ASSERT(!isPageResident(pageNdx));
163 
164 	if ((size_t)m_resource->getPosition() != pageOffset)
165 		m_resource->setPosition((int)pageOffset);
166 
167 	m_resource->read((deUint8*)&m_elements[pageNdx << ELEMENTS_PER_PAGE_LOG2], (int)numBytesToRead);
168 	m_isPageResident[pageNdx] = true;
169 }
170 
171 typedef LazyResource<BinaryIndexNode> BinaryIndexAccess;
172 
173 class BinaryRegistryReader
174 {
175 public:
176 							BinaryRegistryReader	(const tcu::Archive& archive, const std::string& srcPath);
177 							~BinaryRegistryReader	(void);
178 
179 	ProgramBinary*			loadProgram				(const ProgramIdentifier& id) const;
180 
181 private:
182 	typedef de::MovePtr<BinaryIndexAccess> BinaryIndexPtr;
183 
184 	const tcu::Archive&		m_archive;
185 	const std::string		m_srcPath;
186 
187 	mutable BinaryIndexPtr	m_binaryIndex;
188 };
189 
190 struct ProgramIdentifierIndex
191 {
192 	ProgramIdentifier	id;
193 	deUint32			index;
194 
ProgramIdentifierIndexvk::BinaryRegistryDetail::ProgramIdentifierIndex195 	ProgramIdentifierIndex (const ProgramIdentifier&	id_,
196 							deUint32					index_)
197 		: id	(id_)
198 		, index	(index_)
199 	{}
200 };
201 
202 DE_DECLARE_POOL_HASH(BinaryIndexHashImpl, const ProgramBinary*, deUint32);
203 
204 class BinaryIndexHash
205 {
206 public:
207 								BinaryIndexHash		(void);
208 								~BinaryIndexHash	(void);
209 
210 	deUint32*					find				(const ProgramBinary* binary) const;
211 	void						insert				(const ProgramBinary* binary, deUint32 index);
212 
213 private:
214 								BinaryIndexHash		(const BinaryIndexHash&);
215 	BinaryIndexHash&			operator=			(const BinaryIndexHash&);
216 
217 	de::MemPool					m_memPool;
218 	BinaryIndexHashImpl* const	m_hash;
219 };
220 
221 class BinaryRegistryWriter
222 {
223 public:
224 						BinaryRegistryWriter	(const std::string& dstPath);
225 						~BinaryRegistryWriter	(void);
226 
227 	void				addProgram				(const ProgramIdentifier& id, const ProgramBinary& binary);
228 	void				write					(void) const;
229 
230 private:
231 	void				initFromPath			(const std::string& srcPath);
232 	void				writeToPath				(const std::string& dstPath) const;
233 
234 	deUint32*			findBinary				(const ProgramBinary& binary) const;
235 	deUint32			getNextSlot				(void) const;
236 	void				addBinary				(deUint32 index, const ProgramBinary& binary);
237 
238 	struct BinarySlot
239 	{
240 		ProgramBinary*	binary;
241 		size_t			referenceCount;
242 
BinarySlotvk::BinaryRegistryDetail::BinaryRegistryWriter::BinarySlot243 		BinarySlot (ProgramBinary* binary_, size_t referenceCount_)
244 			: binary		(binary_)
245 			, referenceCount(referenceCount_)
246 		{}
247 
BinarySlotvk::BinaryRegistryDetail::BinaryRegistryWriter::BinarySlot248 		BinarySlot (void)
249 			: binary		(DE_NULL)
250 			, referenceCount(0)
251 		{}
252 	};
253 
254 	typedef std::vector<BinarySlot>				BinaryVector;
255 	typedef std::vector<ProgramIdentifierIndex>	ProgIdIndexVector;
256 
257 	const std::string&	m_dstPath;
258 
259 	ProgIdIndexVector	m_binaryIndices;		//!< ProgramIdentifier -> slot in m_binaries
260 	BinaryIndexHash		m_binaryHash;			//!< ProgramBinary -> slot in m_binaries
261 	BinaryVector		m_binaries;
262 };
263 
264 } // BinaryRegistryDetail
265 
266 using BinaryRegistryDetail::BinaryRegistryReader;
267 using BinaryRegistryDetail::BinaryRegistryWriter;
268 using BinaryRegistryDetail::ProgramIdentifier;
269 using BinaryRegistryDetail::ProgramNotFoundException;
270 
271 } // vk
272 
273 #endif // _VKBINARYREGISTRY_HPP
274