1、Interpreter::runSession
// source/core/Interpreter.cpp ErrorCode Interpreter::runSession(Session* session) const { std::unique_lock<std::mutex> _l(mNet->lock); #ifdef MNN_INTERNAL_ENABLED Timer timer; #endif ErrorCode errorcode = session->run(); #ifdef MNN_INTERNAL_ENABLED if (shouldLog(FREQ_LOW)) { waitSessionFinish(session); float costTime = (float)timer.durationInUs() / (float)1000; logForRunSession(session, costTime, "Interpreter::runSession"); } #endif // MNN_INTERNAL_ENABLED return errorcode; }
1.1 Session::run
// source/core/Session.cpp ErrorCode Session::run() const { if (mNeedResize) { MNN_ERROR("Can't run session because not resized\n"); return COMPUTE_SIZE_ERROR; } // mPipelines 类型为 std::vector<std::shared_ptr<Pipeline>> for (auto& iter : mPipelines) { auto error = iter->execute(); if (NO_ERROR != error) { return error; } } return NO_ERROR; }
1.1.1 Pipeline::execute
OpCacheInfo 、BackendCache、Command、CommandBuffer
// source/core/Pipeline.cpp // typedef std::pair<BackendCache, std::vector<OpCacheInfo>> PipelineInfo ErrorCode Pipeline::execute() { _copyInputs(); auto& mBackend = mInfo.first.cache.first; auto& mBackupBackend = mInfo.first.cache.second; mBackend->onExecuteBegin(); // mInfo 类型为 std::pair<BackendCache, std::vector<OpCacheInfo>> for (auto& info : mInfo.second) { auto& buffer = info.executeBuffer; //#define LOG_VERPOSE #ifdef LOG_VERPOSE FUNC_PRINT_ALL(info.op->name()->c_str(), s); #endif for (auto& cmdP : buffer.command) { auto& cmd = *cmdP; auto code = cmd.execution->onExecute(cmd.workInputs, cmd.workOutputs); // #define LOG_VERPOSE #ifdef LOG_VERPOSE auto dumpT = [](Tensor* t) { auto size = TensorUtils::getRawSize(t); size = size > 10 ? 10 : size; if (t->getType() == halide_type_of<float>()) { for (int i=0; i<size; ++i) { MNN_PRINT("%f, ", t->host<float>()[i]); } } else { for (int i=0; i<size; ++i) { MNN_PRINT("%d, ", t->host<int>()[i]); } } MNN_PRINT("\n"); }; if (/* cmd.op->name() && cmd.op->name()->str() == "/embed/embed_/Gather_output_0"*/ cmd.op->type() == OpType_Convolution) { MNN_PRINT("%s Input begin:\n", EnumNameOpType(cmd.op->type())); for (auto t : cmd.workInputs) { dumpT(t); } MNN_PRINT("%s Output begin:\n", EnumNameOpType(cmd.op->type())); for (auto t : cmd.workOutputs) { dumpT(t); } } #endif if (NO_ERROR != code) { mBackend->onExecuteEnd(); return code; } } } mBackend->onExecuteEnd(); return NO_ERROR; }
1.1.1.1 VulkanBackend::onExecuteBegin
在函数 Pipeline::execute 中调用 Backend::onExecuteBegin 函数的代码如下:
mBackend->onExecuteBegin();
onExecuteBegin 函数是个虚函数, mBackend->onExecuteBegin 调用是个多态,其基类为 Backend,此处 mBackend 为 VulkanBackend,其具体实现代码如下:
// source/backend/vulkan/image/backend/VulkanBackend.cpp void VulkanBackend::onExecuteBegin() const { // 非直接运行情况,此处不执行 if (!mDirect) { mCmdBuffers.push_back(mCmdBuffer->get()); } // FUNC_PRINT_ALL(mDynamicMemoryPool->computeSize(), f); }
1.1.1.2 Execution::onExecute
在函数 Pipeline::execute 中调用 Execution::onExecute 函数的代码如下:
auto code = cmd.execution->onExecute(cmd.workInputs, cmd.workOutputs);
Execution::onExecute 函数是个虚函数,对于 Vulkan 来说,主要有 VulkanBasicExecutionDirect 和 VulkanBasicExecutionInDirect,我们以
VulkanBasicExecutionDirect 进行分析:
// source/backend/vulkan/image/execution/VulkanBasicExecution.cpp ErrorCode VulkanBasicExecutionDirect::onExecute(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) { auto extra = static_cast<VulkanBackend *>(backend()); // 把算子中录制的指令加入到 VulkanBackend 的 mCmdBuffers 中 extra->pushCommand(mCmdBuffer->get()); return NO_ERROR; }
1.1.1.2.1 VulkanBackend::pushCommand
// source/backend/vulkan/image/backend/VulkanBackend.cpp void VulkanBackend::pushCommand(VkCommandBuffer buffer) const { mCmdBuffers.emplace_back(buffer); // _finish(); }
1.1.1.3 Backend::onExecuteEnd
在函数 Pipeline::execute 中调用 Backend::onExecuteEnd 函数的代码如下:
mBackend->onExecuteEnd();
Backend::onExecuteEnd 函数是个虚函数,对于 Vulkan 来说为 VulkanBackend ,以下为其代码:
// source/backend/vulkan/image/backend/VulkanBackend.cpp void VulkanBackend::onExecuteEnd() const { _finish(); }
1.1.1.3.1 _finish
// source/backend/vulkan/image/backend/VulkanBackend.cpp void VulkanBackend::_finish() const { if (mCmdBuffers.empty()) { return; } VkSubmitInfo submit_info = {/* .sType = */ VK_STRUCTURE_TYPE_SUBMIT_INFO, /* .pNext = */ nullptr, /* .waitSemaphoreCount = */ 0, /* .pWaitSemaphores = */ nullptr, /* .pWaitDstStageMask = */ nullptr, /* .commandBufferCount = */ (uint32_t)mCmdBuffers.size(), /* .pCommandBuffers = */ mCmdBuffers.data(), /* .signalSemaphoreCount = */ 0, /* .pSignalSemaphores = */ nullptr}; auto fenceReal = mFence->get(); mFence->reset(); CALL_VK(vkQueueSubmit(device().acquireDefaultDevQueue(), 1, &submit_info, fenceReal)); auto res = mFence->wait(); MNN_VK_CHECK(res); mCmdBuffers.clear(); }
提交各个算子中的指令缓存,开始推理。
☆