• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "VkReconstruction.h"
15 
16 #include "base/EntityManager.h"
17 
18 #include "VkDecoder.h"
19 #include "IOStream.h"
20 
21 #include <unordered_map>
22 
23 #include <string.h>
24 
25 #define DEBUG_RECONSTRUCTION 0
26 
27 #if DEBUG_RECONSTRUCTION
28 
29 #define DEBUG_RECON(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
30 
31 #else
32 
33 #define DEBUG_RECON(fmt,...)
34 
35 #endif
36 
37 VkReconstruction::VkReconstruction() = default;
38 
typeTagSortedHandles(const std::vector<uint64_t> & handles)39 std::vector<uint64_t> typeTagSortedHandles(const std::vector<uint64_t>& handles) {
40     using EntityManagerTypeForHandles =
41         android::base::EntityManager<32, 16, 16, int>;
42 
43     std::vector<uint64_t> res = handles;
44 
45     std::sort(res.begin(), res.end(), [](uint64_t lhs, uint64_t rhs) {
46         return EntityManagerTypeForHandles::getHandleType(lhs) <
47                EntityManagerTypeForHandles::getHandleType(rhs); });
48 
49     return res;
50 }
51 
save(android::base::Stream * stream)52 void VkReconstruction::save(android::base::Stream* stream) {
53     DEBUG_RECON("start")
54 
55 #if DEBUG_RECON
56     dump();
57 #endif
58 
59     std::unordered_map<uint64_t, uint64_t> backDeps;
60 
61     mHandleReconstructions.forEachLiveComponent_const(
62         [&backDeps](bool live, uint64_t componentHandle, uint64_t entityHandle, const HandleReconstruction& item) {
63         for (auto handle : item.childHandles) {
64             backDeps[handle] = entityHandle;
65         }
66     });
67 
68     std::vector<uint64_t> topoOrder;
69 
70     mHandleReconstructions.forEachLiveComponent_const(
71         [&topoOrder, &backDeps](bool live, uint64_t componentHandle, uint64_t entityHandle, const HandleReconstruction& item) {
72         // Start with populating the roots
73         if (backDeps.find(entityHandle) == backDeps.end()) {
74             DEBUG_RECON("found root: 0x%llx",
75                         (unsigned long long)entityHandle);
76             topoOrder.push_back(entityHandle);
77         }
78     });
79 
80     std::vector<uint64_t> next;
81 
82     std::unordered_map<uint64_t, uint64_t> uniqApiRefsToTopoOrder;
83     std::unordered_map<uint64_t, std::vector<uint64_t>> uniqApiRefsByTopoOrder;
84     std::unordered_map<uint64_t, std::vector<uint64_t>> uniqApiRefsByTopoAndDependencyOrder;
85 
86     size_t topoLevel = 0;
87 
88     topoOrder = typeTagSortedHandles(topoOrder);
89 
90     while (!topoOrder.empty()) {
91 
92         next.clear();
93 
94         for (auto handle : topoOrder) {
95             auto item = mHandleReconstructions.get(handle);
96 
97             for (auto apiHandle : item->apiRefs) {
98 
99                 if (uniqApiRefsToTopoOrder.find(apiHandle) == uniqApiRefsToTopoOrder.end()) {
100                     DEBUG_RECON("level %zu: 0x%llx api ref: 0x%llx",
101                                 topoLevel,
102                                 (unsigned long long)handle,
103                                 (unsigned long long)apiHandle);
104                     auto& refs = uniqApiRefsByTopoOrder[topoLevel];
105                     refs.push_back(apiHandle);
106                 }
107 
108                 uniqApiRefsToTopoOrder[apiHandle] = topoLevel;
109             }
110 
111             for (auto childHandle : item->childHandles) {
112                 next.push_back(childHandle);
113             }
114         }
115 
116         next = typeTagSortedHandles(next);
117 
118         topoOrder = next;
119         ++topoLevel;
120     }
121 
122     uniqApiRefsByTopoOrder[topoLevel] = getOrderedUniqueModifyApis();
123     ++topoLevel;
124 
125     size_t totalApiTraceSize = 0; // 4 bytes to store size of created handles
126 
127     for (size_t i = 0; i < topoLevel; ++i) {
128         for (auto apiHandle : uniqApiRefsByTopoOrder[i]) {
129             auto item = mApiTrace.get(apiHandle);
130             totalApiTraceSize += 4; // opcode
131             totalApiTraceSize += 4; // buffer size of trace
132             totalApiTraceSize += item->traceBytes; // the actual trace
133         }
134     }
135 
136     DEBUG_RECON(
137         "total api trace size: %zu",
138         totalApiTraceSize);
139 
140     std::vector<uint64_t> createdHandleBuffer;
141 
142     for (size_t i = 0; i < topoLevel; ++i) {
143         for (auto apiHandle : uniqApiRefsByTopoOrder[i]) {
144             auto item = mApiTrace.get(apiHandle);
145             for (auto createdHandle : item->createdHandles) {
146                 DEBUG_RECON("save handle: 0x%llx\n", createdHandle);
147                 createdHandleBuffer.push_back(createdHandle);
148             }
149         }
150     }
151 
152     std::vector<uint8_t> apiTraceBuffer;
153     apiTraceBuffer.resize(totalApiTraceSize);
154 
155     uint8_t* apiTracePtr = apiTraceBuffer.data();
156 
157     for (size_t i = 0; i < topoLevel; ++i) {
158         for (auto apiHandle : uniqApiRefsByTopoOrder[i]) {
159             auto item = mApiTrace.get(apiHandle);
160             // 4 bytes for opcode, and 4 bytes for saveBufferRaw's size field
161             memcpy(apiTracePtr, &item->opCode, sizeof(uint32_t));
162             apiTracePtr += 4;
163             uint32_t traceBytesForSnapshot = item->traceBytes + 8;
164             memcpy(apiTracePtr, &traceBytesForSnapshot, sizeof(uint32_t)); // and 8 bytes for 'self' struct of { opcode, packetlen } as that is what decoder expects
165             apiTracePtr += 4;
166             memcpy(apiTracePtr, item->trace.data(), item->traceBytes);
167             apiTracePtr += item->traceBytes;
168         }
169     }
170 
171     DEBUG_RECON(
172         "created handle buffer size: %zu trace: %zu",
173         createdHandleBuffer.size(), apiTraceBuffer.size());
174 
175     android::base::saveBufferRaw(stream, (char*)(createdHandleBuffer.data()), createdHandleBuffer.size() * sizeof(uint64_t));
176     android::base::saveBufferRaw(stream, (char*)(apiTraceBuffer.data()), apiTraceBuffer.size());
177 }
178 
179 class TrivialStream : public IOStream {
180 public:
TrivialStream()181     TrivialStream() : IOStream(4) { }
182     virtual ~TrivialStream() = default;
183 
allocBuffer(size_t minSize)184     void* allocBuffer(size_t minSize) {
185         size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
186         if (!m_buf) {
187             m_buf = (unsigned char *)malloc(allocSize);
188         }
189         else if (m_bufsize < allocSize) {
190             unsigned char *p = (unsigned char *)realloc(m_buf, allocSize);
191             if (p != NULL) {
192                 m_buf = p;
193                 m_bufsize = allocSize;
194             } else {
195                 ERR("realloc (%zu) failed\n", allocSize);
196                 free(m_buf);
197                 m_buf = NULL;
198                 m_bufsize = 0;
199             }
200         }
201 
202         return m_buf;
203     }
204 
commitBuffer(size_t size)205     int commitBuffer(size_t size) {
206         if (size == 0) return 0;
207         return writeFully(m_buf, size);
208     }
209 
writeFully(const void * buf,size_t len)210     int writeFully(const void *buf, size_t len) {
211         return 0;
212     }
213 
readFully(void * buf,size_t len)214     const unsigned char* readFully(void *buf, size_t len) {
215         return NULL;
216     }
217 
getDmaForReading(uint64_t guest_paddr)218     virtual void* getDmaForReading(uint64_t guest_paddr) { return nullptr; }
unlockDma(uint64_t guest_paddr)219     virtual void unlockDma(uint64_t guest_paddr) { }
220 
221 protected:
readRaw(void * buf,size_t * inout_len)222     virtual const unsigned char *readRaw(void *buf, size_t *inout_len) {
223         return nullptr;
224     }
onSave(android::base::Stream * stream)225     virtual void onSave(android::base::Stream* stream) { }
onLoad(android::base::Stream * stream)226     virtual unsigned char* onLoad(android::base::Stream* stream) { return nullptr; }
227 };
228 
load(android::base::Stream * stream)229 void VkReconstruction::load(android::base::Stream* stream) {
230     DEBUG_RECON("start. assuming VkDecoderGlobalState has been cleared for loading already");
231     mApiTrace.clear();
232     mHandleReconstructions.clear();
233 
234     std::vector<uint8_t> createdHandleBuffer;
235     std::vector<uint8_t> apiTraceBuffer;
236 
237     android::base::loadBuffer(stream, &createdHandleBuffer);
238     android::base::loadBuffer(stream, &apiTraceBuffer);
239 
240     DEBUG_RECON(
241         "created handle buffer size: %zu trace: %zu",
242         createdHandleBuffer.size(), apiTraceBuffer.size());
243 
244     uint32_t createdHandleBufferSize = createdHandleBuffer.size();
245 
246     mLoadedTrace.resize(4 + createdHandleBufferSize + apiTraceBuffer.size());
247 
248     unsigned char* finalTraceData =
249         (unsigned char*)(mLoadedTrace.data());
250 
251     memcpy(finalTraceData, &createdHandleBufferSize, sizeof(uint32_t));
252     memcpy(finalTraceData + 4, createdHandleBuffer.data(), createdHandleBufferSize);
253     memcpy(finalTraceData + 4 + createdHandleBufferSize, apiTraceBuffer.data(), apiTraceBuffer.size());
254 
255     VkDecoder decoderForLoading;
256     // A decoder that is set for snapshot load will load up the created handles first,
257     // if any, allowing us to 'catch' the results as they are decoded.
258     decoderForLoading.setForSnapshotLoad(true);
259     TrivialStream trivialStream;
260 
261     DEBUG_RECON("start decoding trace");
262 
263     // TODO: This needs to be the puid seqno ptr
264     uint32_t seqno;
265     decoderForLoading.decode(mLoadedTrace.data(), mLoadedTrace.size(), &trivialStream, &seqno);
266 
267     DEBUG_RECON("finished decoding trace");
268 }
269 
createApiInfo()270 VkReconstruction::ApiHandle VkReconstruction::createApiInfo() {
271     auto handle = mApiTrace.add(ApiInfo(), 1);
272     return handle;
273 }
274 
destroyApiInfo(VkReconstruction::ApiHandle h)275 void VkReconstruction::destroyApiInfo(VkReconstruction::ApiHandle h) {
276     auto item = mApiTrace.get(h);
277 
278     if (!item) return;
279 
280     item->traceBytes = 0;
281     item->createdHandles.clear();
282 
283     mApiTrace.remove(h);
284 }
285 
getApiInfo(VkReconstruction::ApiHandle h)286 VkReconstruction::ApiInfo* VkReconstruction::getApiInfo(VkReconstruction::ApiHandle h) {
287     return mApiTrace.get(h);
288 }
289 
setApiTrace(VkReconstruction::ApiInfo * apiInfo,uint32_t opCode,const uint8_t * traceBegin,size_t traceBytes)290 void VkReconstruction::setApiTrace(VkReconstruction::ApiInfo* apiInfo, uint32_t opCode, const uint8_t* traceBegin, size_t traceBytes) {
291     if (apiInfo->trace.size() < traceBytes) apiInfo->trace.resize(traceBytes);
292     apiInfo->opCode = opCode;
293     memcpy(apiInfo->trace.data(), traceBegin, traceBytes);
294     apiInfo->traceBytes = traceBytes;
295 }
296 
dump()297 void VkReconstruction::dump() {
298     fprintf(stderr, "%s: api trace dump\n", __func__);
299 
300     size_t traceBytesTotal = 0;
301 
302     mApiTrace.forEachLiveEntry_const([&traceBytesTotal](bool live, uint64_t handle, const ApiInfo& info) {
303          fprintf(stderr, "VkReconstruction::%s: api handle 0x%llx: %s\n", __func__, (unsigned long long)handle, goldfish_vk::api_opcode_to_string(info.opCode));
304          traceBytesTotal += info.traceBytes;
305     });
306 
307     mHandleReconstructions.forEachLiveComponent_const([this](bool live, uint64_t componentHandle, uint64_t entityHandle, const HandleReconstruction& reconstruction) {
308         fprintf(stderr, "VkReconstruction::%s: %p handle 0x%llx api refs:\n", __func__, this, (unsigned long long)entityHandle);
309         for (auto apiHandle : reconstruction.apiRefs) {
310             auto apiInfo = mApiTrace.get(apiHandle);
311             const char* apiName = apiInfo ? goldfish_vk::api_opcode_to_string(apiInfo->opCode) : "unalloced";
312             fprintf(stderr, "VkReconstruction::%s:     0x%llx: %s\n", __func__, (unsigned long long)apiHandle, apiName);
313             for (auto createdHandle : apiInfo->createdHandles) {
314                 fprintf(stderr, "VkReconstruction::%s:         created 0x%llx\n", __func__, (unsigned long long)createdHandle);
315             }
316         }
317     });
318 
319     mHandleModifications.forEachLiveComponent_const([this](bool live, uint64_t componentHandle, uint64_t entityHandle, const HandleModification& modification) {
320         fprintf(stderr, "VkReconstruction::%s: mod: %p handle 0x%llx api refs:\n", __func__, this, (unsigned long long)entityHandle);
321         for (auto apiHandle : modification.apiRefs) {
322             auto apiInfo = mApiTrace.get(apiHandle);
323             const char* apiName = apiInfo ? goldfish_vk::api_opcode_to_string(apiInfo->opCode) : "unalloced";
324             fprintf(stderr, "VkReconstruction::%s: mod:     0x%llx: %s\n", __func__, (unsigned long long)apiHandle, apiName);
325         }
326     });
327 
328     fprintf(stderr, "%s: total trace bytes: %zu\n", __func__, traceBytesTotal);
329 }
330 
addHandles(const uint64_t * toAdd,uint32_t count)331 void VkReconstruction::addHandles(const uint64_t* toAdd, uint32_t count) {
332     if (!toAdd) return;
333 
334     for (uint32_t i = 0; i < count; ++i) {
335         DEBUG_RECON("add 0x%llx", (unsigned long long)toAdd[i]);
336         mHandleReconstructions.add(toAdd[i], HandleReconstruction());
337     }
338 }
339 
removeHandles(const uint64_t * toRemove,uint32_t count)340 void VkReconstruction::removeHandles(const uint64_t* toRemove, uint32_t count) {
341     if (!toRemove) return;
342 
343     forEachHandleDeleteApi(toRemove, count);
344 
345     for (uint32_t i = 0; i < count; ++i) {
346         DEBUG_RECON("remove 0x%llx", (unsigned long long)toRemove[i]);
347         auto item = mHandleReconstructions.get(toRemove[i]);
348 
349         if (!item) continue;
350 
351         mHandleReconstructions.remove(toRemove[i]);
352 
353         removeHandles(item->childHandles.data(), item->childHandles.size());
354 
355         item->childHandles.clear();
356     }
357 }
358 
forEachHandleAddApi(const uint64_t * toProcess,uint32_t count,uint64_t apiHandle)359 void VkReconstruction::forEachHandleAddApi(const uint64_t* toProcess, uint32_t count, uint64_t apiHandle) {
360     if (!toProcess) return;
361 
362     for (uint32_t i = 0; i < count; ++i) {
363         auto item = mHandleReconstructions.get(toProcess[i]);
364 
365         if (!item) continue;
366 
367         item->apiRefs.push_back(apiHandle);
368     }
369 }
370 
forEachHandleDeleteApi(const uint64_t * toProcess,uint32_t count)371 void VkReconstruction::forEachHandleDeleteApi(const uint64_t* toProcess, uint32_t count) {
372     if (!toProcess) return;
373 
374     for (uint32_t i = 0; i < count; ++i) {
375 
376         auto item = mHandleReconstructions.get(toProcess[i]);
377 
378         if (!item) continue;
379 
380         for (auto handle : item->apiRefs) {
381             destroyApiInfo(handle);
382         }
383 
384         item->apiRefs.clear();
385 
386         auto modifyItem = mHandleModifications.get(toProcess[i]);
387 
388         if (!modifyItem) continue;
389 
390         modifyItem->apiRefs.clear();
391     }
392 }
393 
addHandleDependency(const uint64_t * handles,uint32_t count,uint64_t parentHandle)394 void VkReconstruction::addHandleDependency(const uint64_t* handles, uint32_t count, uint64_t parentHandle) {
395     if (!handles) return;
396 
397     auto item = mHandleReconstructions.get(parentHandle);
398 
399     if (!item) return;
400 
401     for (uint32_t i = 0; i < count; ++i) {
402         item->childHandles.push_back(handles[i]);
403     }
404 }
405 
setCreatedHandlesForApi(uint64_t apiHandle,const uint64_t * created,uint32_t count)406 void VkReconstruction::setCreatedHandlesForApi(uint64_t apiHandle, const uint64_t* created, uint32_t count) {
407     if (!created) return;
408 
409     auto item = mApiTrace.get(apiHandle);
410 
411     if (!item) return;
412 
413     for (uint32_t i = 0; i < count; ++i) {
414         item->createdHandles.push_back(created[i]);
415     }
416 }
417 
forEachHandleAddModifyApi(const uint64_t * toProcess,uint32_t count,uint64_t apiHandle)418 void VkReconstruction::forEachHandleAddModifyApi(const uint64_t* toProcess, uint32_t count, uint64_t apiHandle) {
419     if (!toProcess) return;
420 
421     for (uint32_t i = 0; i < count; ++i) {
422         mHandleModifications.add(toProcess[i], HandleModification());
423 
424         auto item = mHandleModifications.get(toProcess[i]);
425 
426         if (!item) continue;
427 
428         item->apiRefs.push_back(apiHandle);
429     }
430 }
431 
getOrderedUniqueModifyApis() const432 std::vector<uint64_t> VkReconstruction::getOrderedUniqueModifyApis() const {
433     std::vector<HandleModification> orderedModifies;
434 
435     // Now add all handle modifications to the trace, ordered by the .order field.
436     mHandleModifications.forEachLiveComponent_const(
437         [&orderedModifies](bool live, uint64_t componentHandle, uint64_t entityHandle, const HandleModification& mod) {
438         orderedModifies.push_back(mod);
439     });
440 
441     // Sort by the |order| field for each modify API
442     // since it may be important to apply modifies in a particular
443     // order (e.g., when dealing with descriptor set updates
444     // or commands in a command buffer).
445     std::sort(orderedModifies.begin(), orderedModifies.end(),
446         [](const HandleModification& lhs, const HandleModification& rhs) {
447         return lhs.order < rhs.order;
448     });
449 
450     std::unordered_set<uint64_t> usedModifyApis;
451     std::vector<uint64_t> orderedUniqueModifyApis;
452 
453     for (const auto& mod : orderedModifies) {
454         for (auto apiRef : mod.apiRefs) {
455             if (usedModifyApis.find(apiRef) == usedModifyApis.end()) {
456                 orderedUniqueModifyApis.push_back(apiRef);
457                 usedModifyApis.insert(apiRef);
458             }
459         }
460     }
461 
462     return orderedUniqueModifyApis;
463 }
464