xref: /aosp_15_r20/external/deqp/external/vulkancts/framework/vulkan/vkBinaryRegistry.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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     uint32_t word;  //!< 4 bytes of search string.
98     uint32_t 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
109     {
110         return m_elements.size();
111     }
112 
113 private:
114     enum
115     {
116         ELEMENTS_PER_PAGE_LOG2 = 10
117     };
118 
getPageForElement(size_t elemNdx) const119     inline size_t getPageForElement(size_t elemNdx) const
120     {
121         return elemNdx >> ELEMENTS_PER_PAGE_LOG2;
122     }
isPageResident(size_t pageNdx) const123     inline bool isPageResident(size_t pageNdx) const
124     {
125         return m_isPageResident[pageNdx];
126     }
127 
128     void makePageResident(size_t pageNdx);
129 
130     de::UniquePtr<tcu::Resource> m_resource;
131 
132     std::vector<Element> m_elements;
133     std::vector<bool> m_isPageResident;
134 };
135 
136 template <typename Element>
LazyResource(de::MovePtr<tcu::Resource> resource)137 LazyResource<Element>::LazyResource(de::MovePtr<tcu::Resource> resource) : m_resource(resource)
138 {
139     const size_t resSize     = m_resource->getSize();
140     const size_t numElements = resSize / sizeof(Element);
141     const size_t numPages =
142         (numElements >> ELEMENTS_PER_PAGE_LOG2) + ((numElements & ((1u << ELEMENTS_PER_PAGE_LOG2) - 1u)) == 0 ? 0 : 1);
143 
144     TCU_CHECK_INTERNAL(numElements * sizeof(Element) == resSize);
145 
146     m_elements.resize(numElements);
147     m_isPageResident.resize(numPages, false);
148 }
149 
150 template <typename Element>
operator [](size_t ndx)151 const Element &LazyResource<Element>::operator[](size_t ndx)
152 {
153     const size_t pageNdx = getPageForElement(ndx);
154 
155     if (ndx >= m_elements.size())
156         throw std::out_of_range("");
157 
158     if (!isPageResident(pageNdx))
159         makePageResident(pageNdx);
160 
161     return m_elements[ndx];
162 }
163 
164 template <typename Element>
makePageResident(size_t pageNdx)165 void LazyResource<Element>::makePageResident(size_t pageNdx)
166 {
167     const size_t pageSize       = (size_t)(1 << ELEMENTS_PER_PAGE_LOG2) * sizeof(Element);
168     const size_t pageOffset     = pageNdx * pageSize;
169     const size_t numBytesToRead = de::min(m_elements.size() * sizeof(Element) - pageOffset, pageSize);
170 
171     DE_ASSERT(!isPageResident(pageNdx));
172 
173     if ((size_t)m_resource->getPosition() != pageOffset)
174         m_resource->setPosition((int)pageOffset);
175 
176     m_resource->read((uint8_t *)&m_elements[pageNdx << ELEMENTS_PER_PAGE_LOG2], (int)numBytesToRead);
177     m_isPageResident[pageNdx] = true;
178 }
179 
180 typedef LazyResource<BinaryIndexNode> BinaryIndexAccess;
181 
182 class BinaryRegistryReader
183 {
184 public:
185     BinaryRegistryReader(const tcu::Archive &archive, const std::string &srcPath);
186     ~BinaryRegistryReader(void);
187 
188     ProgramBinary *loadProgram(const ProgramIdentifier &id) const;
189 
190 private:
191     typedef de::MovePtr<BinaryIndexAccess> BinaryIndexPtr;
192 
193     const tcu::Archive &m_archive;
194     const std::string m_srcPath;
195 
196     mutable BinaryIndexPtr m_binaryIndex;
197 };
198 
199 struct ProgramIdentifierIndex
200 {
201     ProgramIdentifier id;
202     uint32_t index;
203 
ProgramIdentifierIndexvk::BinaryRegistryDetail::ProgramIdentifierIndex204     ProgramIdentifierIndex(const ProgramIdentifier &id_, uint32_t index_) : id(id_), index(index_)
205     {
206     }
207 };
208 
209 DE_DECLARE_POOL_HASH(BinaryIndexHashImpl, const ProgramBinary *, uint32_t);
210 
211 class BinaryIndexHash
212 {
213 public:
214     BinaryIndexHash(void);
215     ~BinaryIndexHash(void);
216 
217     uint32_t *find(const ProgramBinary *binary) const;
218     void insert(const ProgramBinary *binary, uint32_t index);
219 
220 private:
221     BinaryIndexHash(const BinaryIndexHash &);
222     BinaryIndexHash &operator=(const BinaryIndexHash &);
223 
224     de::MemPool m_memPool;
225     BinaryIndexHashImpl *const m_hash;
226 };
227 
228 class BinaryRegistryWriter
229 {
230 public:
231     BinaryRegistryWriter(const std::string &dstPath);
232     ~BinaryRegistryWriter(void);
233 
234     void addProgram(const ProgramIdentifier &id, const ProgramBinary &binary);
235     void write(void) const;
236 
237 private:
238     void initFromPath(const std::string &srcPath);
239     void writeToPath(const std::string &dstPath) const;
240 
241     uint32_t *findBinary(const ProgramBinary &binary) const;
242     uint32_t getNextSlot(void) const;
243     void addBinary(uint32_t index, const ProgramBinary &binary);
244 
245     struct BinarySlot
246     {
247         ProgramBinary *binary;
248         size_t referenceCount;
249 
BinarySlotvk::BinaryRegistryDetail::BinaryRegistryWriter::BinarySlot250         BinarySlot(ProgramBinary *binary_, size_t referenceCount_) : binary(binary_), referenceCount(referenceCount_)
251         {
252         }
253 
BinarySlotvk::BinaryRegistryDetail::BinaryRegistryWriter::BinarySlot254         BinarySlot(void) : binary(DE_NULL), referenceCount(0)
255         {
256         }
257     };
258 
259     typedef std::vector<BinarySlot> BinaryVector;
260     typedef std::vector<ProgramIdentifierIndex> ProgIdIndexVector;
261 
262     const std::string &m_dstPath;
263 
264     ProgIdIndexVector m_binaryIndices; //!< ProgramIdentifier -> slot in m_binaries
265     BinaryIndexHash m_binaryHash;      //!< ProgramBinary -> slot in m_binaries
266     BinaryVector m_binaries;
267 };
268 
269 } // namespace BinaryRegistryDetail
270 
271 using BinaryRegistryDetail::BinaryRegistryReader;
272 using BinaryRegistryDetail::BinaryRegistryWriter;
273 using BinaryRegistryDetail::ProgramIdentifier;
274 using BinaryRegistryDetail::ProgramNotFoundException;
275 
276 } // namespace vk
277 
278 #endif // _VKBINARYREGISTRY_HPP
279