系列文章目录
MNN createFromBuffer(一)
MNN createRuntime(二)
MNN createSession 之 Schedule(三)
MNN createSession 之创建流水线后端(四)
MNN Session 之维度计算(五)
MNN Session 之几何计算(六)
MNN Session 之 CPU 算子(七)
MNN Session 之 Vulkan 算子(八)
MNN 执行推理(九)
文章目录
- 系列文章目录
- 1、Interpreter::runSession
-
- [1.1 Session::run](#1.1 Session::run)
- [1.1.1 Pipeline::execute](#1.1.1 Pipeline::execute)
- [1.1.1.1 VulkanBackend::onExecuteBegin](#1.1.1.1 VulkanBackend::onExecuteBegin)
- [1.1.1.2 Execution::onExecute](#1.1.1.2 Execution::onExecute)
- [1.1.1.3 Backend::onExecuteEnd](#1.1.1.3 Backend::onExecuteEnd)
- [1.1.1.3.1 _finish](#1.1.1.3.1 _finish)
1、Interpreter::runSession
cpp
// 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
cpp
// 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
cpp
// 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 函数的代码如下:
cpp
mBackend->onExecuteBegin();
onExecuteBegin 函数是个虚函数, mBackend->onExecuteBegin 调用是个多态,其基类为 Backend ,此处 mBackend 为 VulkanBackend,其具体实现代码如下:
cpp
// source/backend/vulkan/image/backend/VulkanBackend.cpp
void VulkanBackend::onExecuteBegin() const {
if (!mDirect) {
mCmdBuffers.push_back(mCmdBuffer->get());
}
// FUNC_PRINT_ALL(mDynamicMemoryPool->computeSize(), f);
}
VulkanBasicExecutionDirect::onExecute
1.1.1.2 Execution::onExecute
在函数 Pipeline::execute 中调用 Execution::onExecute 函数的代码如下:
cpp
auto code = cmd.execution->onExecute(cmd.workInputs, cmd.workOutputs);
Execution::onExecute 函数是个虚函数,对于 Vulkan 来说,主要有 VulkanBasicExecutionDirect 和 VulkanBasicExecutionInDirect,我们以 VulkanBasicExecutionDirect 进行分析:
cpp
// 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());
extra->pushCommand(mCmdBuffer->get());
return NO_ERROR;
}
1.1.1.3 Backend::onExecuteEnd
在函数 Pipeline::execute 中调用 Backend::onExecuteEnd 函数的代码如下:
cpp
mBackend->onExecuteEnd();
Backend::onExecuteEnd 函数是个虚函数,对于 Vulkan 来说为 VulkanBackend ,以下为其代码:
cpp
// source/backend/vulkan/image/backend/VulkanBackend.cpp
void VulkanBackend::onExecuteEnd() const {
_finish();
}
1.1.1.3.1 _finish
cpp
// 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();
}
☆