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