MNN 执行推理(九)

系列文章目录

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

Pipeline

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

OpCacheInfoBackendCacheCommandCommandBuffer

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 ,此处 mBackendVulkanBackend,其具体实现代码如下:

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();
}

   

相关推荐
名字还没想好☜5 小时前
Python f-string 进阶:数字格式化、对齐填充、调试 = 号与嵌套表达式
开发语言·数据库·python·字符串格式化·f-string
ltl6 小时前
Serverless 数据库弹性理论:Neon 与 Aurora Serverless v2
数据库
·薯条大王6 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
ZJH__GO9 小时前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
小小、码农9 小时前
Linux进程控制:从fork到exec,手写一个简易Shell
linux·运维·服务器
不会就选b9 小时前
Linux之进程间通信(二)---模拟进程池
linux·运维·服务器
marvelyu10 小时前
每天10分钟学会OceanBase系列(Day 20):跨机房容灾实战——构建多数据中心高可用架构
java·大数据·数据库
NeilYuen10 小时前
用UDP实现向DNS服务器请求IP地址
服务器·tcp/ip·udp
ZCBUS实时计算11 小时前
金融证券实时数仓建设实践:轻量化实时计算平台落地,实现交易数据端到端秒级处理
大数据·数据库·数据仓库·金融·flink·dba·etl
zd20057211 小时前
海洋微生物数据库
数据库·宏基因组