2019-12-27 22:16:57 +08:00
|
|
|
//
|
|
|
|
// Executor.cpp
|
|
|
|
// MNN
|
|
|
|
//
|
|
|
|
// Created by MNN on 2019/07/26.
|
|
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <MNN/expr/Executor.hpp>
|
|
|
|
#include "core/TensorUtils.hpp"
|
2021-09-18 15:52:30 +08:00
|
|
|
#include "core/FileLoader.hpp"
|
2019-12-27 22:16:57 +08:00
|
|
|
#include "Utils.hpp"
|
2020-01-15 13:33:47 +08:00
|
|
|
#include <MNN/AutoTime.hpp>
|
2021-04-08 15:34:23 +08:00
|
|
|
#include "core/OpCommonUtils.hpp"
|
2020-11-05 16:41:56 +08:00
|
|
|
#include "geometry/GeometryComputerUtils.hpp"
|
|
|
|
#include <MNN/expr/ExecutorScope.hpp>
|
2021-11-30 10:10:53 +08:00
|
|
|
#include "core/Backend.hpp"
|
2022-01-04 10:50:40 +08:00
|
|
|
#include "RuntimeAttr.hpp"
|
2022-05-06 19:51:20 +08:00
|
|
|
#include <stack>
|
2024-07-22 19:51:53 +08:00
|
|
|
#define DEFAULT_BACKUP_RUNTIME_KEY MNN_FORWARD_CPU
|
2020-02-26 09:57:17 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
#define MNN_EXPRESS_ERROR_REPORT
|
|
|
|
#endif
|
2023-09-04 10:42:11 +08:00
|
|
|
|
2019-12-27 22:16:57 +08:00
|
|
|
namespace MNN {
|
|
|
|
namespace Express {
|
2021-09-18 15:52:30 +08:00
|
|
|
|
2019-12-27 22:16:57 +08:00
|
|
|
void Executor::setGlobalExecutorConfig(MNNForwardType type, const BackendConfig& config, int numberThread) {
|
2023-06-16 09:42:45 +08:00
|
|
|
std::lock_guard<std::mutex> _l(mMutex);
|
2024-05-11 19:17:02 +08:00
|
|
|
|
2021-09-18 15:52:30 +08:00
|
|
|
if(type == MNN_FORWARD_AUTO) {
|
|
|
|
ScheduleConfig sConfig;
|
|
|
|
sConfig.type = type;
|
|
|
|
type = Schedule::getApprociateType(sConfig);
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2024-10-14 19:26:28 +08:00
|
|
|
auto rt = _getOrCreateRuntime(type, &config, numberThread);
|
|
|
|
if (rt == nullptr) {
|
|
|
|
type = MNN_FORWARD_CPU;
|
|
|
|
numberThread = 1;
|
|
|
|
rt = _getOrCreateRuntime(type, &config, numberThread);
|
|
|
|
}
|
|
|
|
MNN_ASSERT(nullptr != rt);
|
|
|
|
mAttr->firstType = type;
|
2024-11-18 14:37:45 +08:00
|
|
|
// Cache threadnumber and config
|
|
|
|
mAttr->numThread = numberThread;
|
|
|
|
mAttr->config = config;
|
|
|
|
// Remove sharedContext because it's not used for create backend
|
|
|
|
mAttr->config.sharedContext = nullptr;
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
|
2021-11-30 10:10:53 +08:00
|
|
|
int Executor::getCurrentRuntimeStatus(RuntimeStatus statusEnum) {
|
2024-10-14 19:26:28 +08:00
|
|
|
return mRuntimeInfo.first[mAttr->firstType]->onGetRuntimeStatus(statusEnum);
|
|
|
|
}
|
|
|
|
std::shared_ptr<Runtime> Executor::_getOrCreateRuntime(MNNForwardType type, const BackendConfig* config, int numberThread, bool reset) {
|
|
|
|
auto iter = mRuntimeInfo.first.find(type);
|
|
|
|
if (iter != mRuntimeInfo.first.end()) {
|
|
|
|
iter->second->onReset(numberThread, config, reset);
|
|
|
|
return iter->second;
|
|
|
|
}
|
|
|
|
// Create Backend
|
|
|
|
auto cre = MNNGetExtraRuntimeCreator(type);
|
|
|
|
if (nullptr == cre) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Backend::Info info;
|
|
|
|
info.type = type;
|
|
|
|
info.mode = Backend::Info::DIRECT;
|
|
|
|
info.numThread = numberThread;
|
|
|
|
info.user = (BackendConfig*)config;
|
|
|
|
std::shared_ptr<Runtime> rt(cre->onCreate(info));
|
|
|
|
if (nullptr != rt) {
|
|
|
|
mRuntimeInfo.first.insert(std::make_pair(type, rt));
|
|
|
|
}
|
|
|
|
return rt;
|
2021-11-30 10:10:53 +08:00
|
|
|
}
|
|
|
|
|
2019-12-27 22:16:57 +08:00
|
|
|
void Executor::gc(GCFlag flag) {
|
2021-11-30 10:10:53 +08:00
|
|
|
int level = flag == FULL ? 100 : 0;
|
2024-10-14 19:26:28 +08:00
|
|
|
for (auto& iter : mRuntimeInfo.first) {
|
2021-11-30 10:10:53 +08:00
|
|
|
iter.second->onGabageCollect(level);
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
2023-04-27 15:11:05 +08:00
|
|
|
|
2024-10-14 19:26:28 +08:00
|
|
|
Executor::Executor(std::shared_ptr<Runtime> runtime, MNNForwardType type, int numberThread) {
|
|
|
|
mRuntimeInfo.first.insert(std::make_pair(type, runtime));
|
2022-12-30 15:18:58 +08:00
|
|
|
mAttr.reset(new ExecutorAttr);
|
2024-07-22 19:51:53 +08:00
|
|
|
mAttr->firstType = type;
|
2024-10-14 19:26:28 +08:00
|
|
|
if (type == MNN_FORWARD_CPU) {
|
|
|
|
mRuntimeInfo.second = runtime;
|
|
|
|
} else {
|
|
|
|
mRuntimeInfo.second = _getOrCreateRuntime(MNN_FORWARD_CPU, nullptr, 1);
|
2021-11-30 10:10:53 +08:00
|
|
|
}
|
|
|
|
mDebug.reset(new DebugTools);
|
2022-12-30 15:18:58 +08:00
|
|
|
BackendConfig defaultConfig;
|
|
|
|
defaultConfig.flags = 4;
|
2024-10-14 19:26:28 +08:00
|
|
|
std::shared_ptr<Backend> defaultBackend(mRuntimeInfo.second->onCreate(&defaultConfig));
|
2022-12-30 15:18:58 +08:00
|
|
|
mAttr->constantBackend = defaultBackend;
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
Executor::~Executor(){
|
2021-11-30 10:10:53 +08:00
|
|
|
// Do nothing
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
|
2021-11-30 10:10:53 +08:00
|
|
|
void Executor::setCallBack(TensorCallBackWithInfo&& before, TensorCallBackWithInfo&& after) {
|
|
|
|
mDebug->before = std::move(before);
|
|
|
|
mDebug->after = std::move(after);
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:33:47 +08:00
|
|
|
Executor::Requirement Executor::getRequirement(Expr* expr) const {
|
|
|
|
Executor::Requirement req;
|
|
|
|
auto op = expr->get();
|
|
|
|
auto inputSize = expr->inputs().size();
|
|
|
|
req.contentNeedContent.resize(inputSize);
|
|
|
|
req.shapeNeedContent.resize(inputSize);
|
|
|
|
if (op->type() == OpType_Extra) {
|
|
|
|
for (int i = 0; i < inputSize; ++i) {
|
|
|
|
req.contentNeedContent[i] = true;
|
|
|
|
req.shapeNeedContent[i] = false;
|
|
|
|
}
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < inputSize; ++i) {
|
2023-12-27 17:26:44 +08:00
|
|
|
req.contentNeedContent[i] = OpCommonUtils::opNeedContent(op, i);
|
2020-11-05 16:41:56 +08:00
|
|
|
req.shapeNeedContent[i] = false;
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2021-04-08 15:34:23 +08:00
|
|
|
auto needIndexId = SizeComputer::needInputContent(op, inputSize);
|
2020-01-15 13:33:47 +08:00
|
|
|
for (auto index : needIndexId) {
|
|
|
|
if (index < req.shapeNeedContent.size()) {
|
|
|
|
req.shapeNeedContent[index] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return req;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
static std::once_flag gInitFlag;
|
2021-09-18 15:52:30 +08:00
|
|
|
static std::shared_ptr<Executor>* gExecutor = nullptr;
|
2019-12-27 22:16:57 +08:00
|
|
|
std::shared_ptr<Executor> Executor::getGlobalExecutor() {
|
2020-11-05 16:41:56 +08:00
|
|
|
std::call_once(gInitFlag, [&]() {
|
|
|
|
auto creator = MNNGetExtraRuntimeCreator(MNN_FORWARD_CPU);
|
2019-12-27 22:16:57 +08:00
|
|
|
Backend::Info info;
|
|
|
|
info.type = MNN_FORWARD_CPU;
|
|
|
|
info.numThread = 1;
|
2020-11-05 16:41:56 +08:00
|
|
|
std::shared_ptr<Runtime> bn(creator->onCreate(info));
|
2024-07-22 19:51:53 +08:00
|
|
|
RuntimeHint hint;
|
|
|
|
hint.memoryAllocatorType = 0;// Defer
|
|
|
|
bn->setRuntimeHint(hint);
|
2024-09-12 12:57:57 +08:00
|
|
|
gExecutor = new std::shared_ptr<Executor>;
|
|
|
|
gExecutor->reset(new Executor(bn, MNN_FORWARD_CPU, 1));
|
2019-12-27 22:16:57 +08:00
|
|
|
});
|
2021-09-18 15:52:30 +08:00
|
|
|
return *gExecutor;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
std::shared_ptr<Executor> Executor::newExecutor(MNNForwardType type,
|
|
|
|
const BackendConfig& config,
|
|
|
|
int numberThread) {
|
|
|
|
auto creator = MNNGetExtraRuntimeCreator(type);
|
2024-05-11 19:17:02 +08:00
|
|
|
if(nullptr == creator) {
|
|
|
|
MNN_ERROR("Don't support %d\n", type);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
Backend::Info info;
|
|
|
|
info.type = type;
|
|
|
|
info.numThread = numberThread;
|
2021-06-11 17:17:13 +08:00
|
|
|
info.user = const_cast<BackendConfig*>(&config);
|
2022-09-30 10:02:52 +08:00
|
|
|
std::shared_ptr<Runtime> runtime(creator->onCreate(info));
|
|
|
|
auto executor = new Executor(runtime, type, numberThread);
|
|
|
|
return std::shared_ptr<Executor>(executor);
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
RuntimeInfo Executor::getRuntime() {
|
|
|
|
auto glo = ExecutorScope::Current();
|
2023-05-18 19:11:50 +08:00
|
|
|
return glo->mRuntimeInfo;
|
|
|
|
}
|
|
|
|
bool Executor::getComputeInfo(EXPRP expr, Interpreter::SessionInfoCode code, void* ptr) {
|
|
|
|
if (nullptr == expr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (nullptr == expr->inside()->mCache.get()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto session = expr->inside()->mCache->getSession();
|
|
|
|
if (nullptr == session) {
|
|
|
|
return false;
|
2022-12-30 15:18:58 +08:00
|
|
|
}
|
2023-05-18 19:11:50 +08:00
|
|
|
return session->getInfo(code, ptr);
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2021-09-18 15:52:30 +08:00
|
|
|
static bool loadCache(std::shared_ptr<Runtime> &rt, const void* buffer, size_t size) {
|
|
|
|
auto res = rt->onSetCache(buffer, size);
|
|
|
|
if (res) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
static std::pair<const void*, size_t> getCache(std::shared_ptr<Runtime> &rt) {
|
|
|
|
auto res = rt->onGetCache();
|
|
|
|
if (res.first != nullptr) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
return std::make_pair(nullptr, 0);
|
|
|
|
}
|
|
|
|
|
2022-06-24 18:30:05 +08:00
|
|
|
static void writeCacheFile(std::shared_ptr<Cache> cache, std::pair<const void*, size_t> buffer) {
|
2021-09-18 15:52:30 +08:00
|
|
|
auto verifyInfo = std::make_pair((const void*)cache->modelBuffer.get(), cache->cacheOffset);
|
2022-01-04 10:50:40 +08:00
|
|
|
bool res = FileLoader::write(cache->cacheFile.c_str(), buffer);
|
2021-09-18 15:52:30 +08:00
|
|
|
if (!res) {
|
|
|
|
MNN_ERROR("Write Cache File error!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-11-30 10:10:53 +08:00
|
|
|
Executor::RuntimeManager* Executor::RuntimeManager::createRuntimeManager(std::vector<ScheduleConfig>& configs) {
|
|
|
|
if (configs.empty()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return createRuntimeManager(configs[0]);
|
2021-09-18 15:52:30 +08:00
|
|
|
}
|
2022-08-12 10:30:48 +08:00
|
|
|
void Executor::RuntimeManager::destroy(RuntimeManager* rtmgr) {
|
|
|
|
if (nullptr != rtmgr) {
|
|
|
|
delete rtmgr;
|
|
|
|
}
|
|
|
|
}
|
2021-09-18 15:52:30 +08:00
|
|
|
|
2022-01-04 10:50:40 +08:00
|
|
|
void Executor::RuntimeManager::setMode(Interpreter::SessionMode mode) {
|
2024-06-15 15:39:59 +08:00
|
|
|
mInside->modes.setMode(mode);
|
2022-01-04 10:50:40 +08:00
|
|
|
}
|
|
|
|
void Executor::RuntimeManager::setHint(Interpreter::HintMode mode, int value) {
|
2024-06-15 15:39:59 +08:00
|
|
|
mInside->modes.setHint(mode, value);
|
2024-11-18 14:37:45 +08:00
|
|
|
auto current = ExecutorScope::Current();
|
|
|
|
auto rt = current->getRuntime();
|
|
|
|
for (auto& iter : rt.first) {
|
|
|
|
iter.second->setRuntimeHint(mInside->modes.runtimeHint);
|
|
|
|
}
|
2022-01-04 10:50:40 +08:00
|
|
|
}
|
2024-08-24 15:46:21 +08:00
|
|
|
void Executor::RuntimeManager::setExternalPath(std::string path, int type) {
|
|
|
|
mInside->modes.setExternalPath(path, type);
|
|
|
|
}
|
|
|
|
|
2022-01-04 10:50:40 +08:00
|
|
|
bool Executor::RuntimeManager::getInfo(Interpreter::SessionInfoCode code, void* ptr) {
|
|
|
|
// Only support get memory
|
|
|
|
switch (code) {
|
|
|
|
case Interpreter::MEMORY: {
|
|
|
|
auto dst = (float*)ptr;
|
2022-06-24 18:30:05 +08:00
|
|
|
float summer = mInside->mRuntime.second->onGetMemoryInMB();
|
|
|
|
for (auto& r : mInside->mRuntime.first) {
|
|
|
|
if (r.second.get() != mInside->mRuntime.second.get()) {
|
2022-01-04 10:50:40 +08:00
|
|
|
summer += r.second->onGetMemoryInMB();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*dst = summer;
|
|
|
|
return true;
|
|
|
|
} break;
|
2022-08-12 10:30:48 +08:00
|
|
|
case Interpreter::BACKENDS: {
|
|
|
|
auto dst = (int*)ptr;
|
|
|
|
if (!mInside->mRuntime.first.empty()) {
|
|
|
|
*dst = mInside->mRuntime.first.begin()->first;
|
|
|
|
}
|
|
|
|
} break;
|
2022-01-04 10:50:40 +08:00
|
|
|
default: {
|
|
|
|
// Do nothing
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Executor::RuntimeManager::RuntimeManager() {
|
|
|
|
mInside = new RuntimeAttr;
|
|
|
|
// Default set release for better performance
|
|
|
|
mInside->modes.callBackMode = Interpreter::Session_Release;
|
|
|
|
mInside->modes.inputMode = Interpreter::Session_Input_User;
|
|
|
|
mInside->modes.outputMode = Interpreter::Session_Output_User;
|
|
|
|
}
|
|
|
|
Executor::RuntimeManager::~RuntimeManager() {
|
2024-04-19 11:58:21 +08:00
|
|
|
updateCache();
|
2022-01-04 10:50:40 +08:00
|
|
|
delete mInside;
|
|
|
|
}
|
2021-11-30 10:10:53 +08:00
|
|
|
Executor::RuntimeManager* Executor::RuntimeManager::createRuntimeManager(const ScheduleConfig &config) {
|
|
|
|
auto res = new RuntimeManager;
|
|
|
|
auto glo = ExecutorScope::Current();
|
2023-06-16 09:42:45 +08:00
|
|
|
std::lock_guard<std::mutex> _l(glo->mMutex);
|
2024-10-14 19:26:28 +08:00
|
|
|
auto& originRt = glo->mRuntimeInfo;
|
|
|
|
auto type = Schedule::getApprociateType(config);
|
|
|
|
int numThread = config.numThread;
|
2021-11-30 10:10:53 +08:00
|
|
|
if(config.type == MNN_FORWARD_AUTO) {
|
2024-10-14 19:26:28 +08:00
|
|
|
if(type == MNN_FORWARD_OPENCL || type == MNN_FORWARD_METAL) {
|
2021-11-30 10:10:53 +08:00
|
|
|
// AUTO set default gpu-mode MNN_GPU_TUNING_FAST
|
2024-10-14 19:26:28 +08:00
|
|
|
numThread = 16;
|
2021-11-30 10:10:53 +08:00
|
|
|
}
|
|
|
|
}
|
2024-10-14 19:26:28 +08:00
|
|
|
auto rt = glo->_getOrCreateRuntime(type, config.backendConfig, numThread, false);
|
|
|
|
res->mInside->mRuntime.second = originRt.second;
|
|
|
|
res->mInside->mRuntime.first.insert(std::make_pair(type, rt));
|
|
|
|
res->mInside->mInfo = rt;
|
|
|
|
res->mInside->mNumberThread = numThread;
|
2022-06-24 18:30:05 +08:00
|
|
|
if (nullptr != config.backendConfig) {
|
|
|
|
res->mInside->mConfig = *config.backendConfig;
|
|
|
|
res->mInside->mUserConfig = true;
|
|
|
|
} else {
|
|
|
|
res->mInside->mUserConfig = false;
|
|
|
|
}
|
2021-11-30 10:10:53 +08:00
|
|
|
return res;
|
2021-09-18 15:52:30 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
ExecutorAttr* Executor::getAttr() const {
|
|
|
|
return mAttr.get();
|
|
|
|
}
|
|
|
|
|
2022-06-24 18:30:05 +08:00
|
|
|
BackendConfig* Executor::RuntimeManager::getBnConfig() {
|
|
|
|
if (mInside->mUserConfig) {
|
|
|
|
return &mInside->mConfig;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-09-18 15:52:30 +08:00
|
|
|
|
|
|
|
|
|
|
|
void Executor::RuntimeManager::setCache(std::string cacheName) {
|
2023-02-15 10:30:27 +08:00
|
|
|
std::lock_guard<std::mutex> _l(mLock);
|
|
|
|
|
2022-06-24 18:30:05 +08:00
|
|
|
mInside->mCache.reset(new Cache);
|
|
|
|
mInside->mCache->cacheFile = cacheName;
|
|
|
|
if (nullptr == mInside->mCache->cacheFile.c_str()) {
|
2021-09-18 15:52:30 +08:00
|
|
|
MNN_ERROR("Empty cacheFile\n");
|
|
|
|
return;
|
|
|
|
}
|
2024-04-19 11:58:21 +08:00
|
|
|
std::unique_ptr<FileLoader> loader(new FileLoader(mInside->mCache->cacheFile.c_str(), true));
|
2021-09-18 15:52:30 +08:00
|
|
|
if (!loader->valid()) {
|
|
|
|
MNN_ERROR("Load Cache file error.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bool result = loader->read();
|
|
|
|
if (!result) {
|
|
|
|
MNN_ERROR("Load Cache file error.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (loader->size() == 0) {
|
|
|
|
MNN_ERROR("Load Cache file error.\n");
|
|
|
|
return;
|
|
|
|
}
|
2022-06-24 18:30:05 +08:00
|
|
|
bool success = loader->merge(mInside->mCache->cacheBuffer);
|
2021-09-18 15:52:30 +08:00
|
|
|
if (!success) {
|
|
|
|
MNN_ERROR("Alloc memory for Cache error.\n");
|
|
|
|
return;
|
|
|
|
}
|
2021-11-30 10:10:53 +08:00
|
|
|
|
2021-09-18 15:52:30 +08:00
|
|
|
// load cache
|
2022-06-24 18:30:05 +08:00
|
|
|
bool valid = loadCache(mInside->mInfo, mInside->mCache->cacheBuffer.get() + mInside->mCache->cacheOffset,
|
|
|
|
mInside->mCache->cacheBuffer.size() - mInside->mCache->cacheOffset);
|
2021-09-18 15:52:30 +08:00
|
|
|
if(!valid) {
|
|
|
|
// Reset cache
|
2022-06-24 18:30:05 +08:00
|
|
|
loadCache(mInside->mInfo, nullptr, 0);
|
2021-09-18 15:52:30 +08:00
|
|
|
MNN_PRINT("Cache invalid, will be reset\n");
|
2024-04-19 11:58:21 +08:00
|
|
|
} else {
|
|
|
|
mInside->mCache->lastCacheSize = mInside->mCache->cacheBuffer.size() - mInside->mCache->cacheOffset;
|
2021-09-18 15:52:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-30 15:18:58 +08:00
|
|
|
void Executor::RuntimeManager::setExternalFile(std::string fileName) {
|
|
|
|
mInside->mExternalFile = fileName;
|
|
|
|
}
|
|
|
|
|
2021-09-18 15:52:30 +08:00
|
|
|
void Executor::RuntimeManager::updateCache() {
|
2024-04-19 11:58:21 +08:00
|
|
|
if (nullptr == mInside->mCache) {
|
|
|
|
return;
|
|
|
|
}
|
2023-02-15 10:30:27 +08:00
|
|
|
std::lock_guard<std::mutex> _l(mLock);
|
|
|
|
|
2023-01-11 15:08:58 +08:00
|
|
|
// Backend_Auto and no Async work, then don't need updateCache
|
|
|
|
if(mInside->modes.backendMode == Interpreter::Session_Backend_Auto && !(mInside->mInfo->hasAsyncWork())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set mCancelled for quickly ending
|
|
|
|
mInside->mInfo->mCancelled = true;
|
2022-06-24 18:30:05 +08:00
|
|
|
mInside->mInfo->waitAsyncWork();
|
|
|
|
auto buffer = getCache(mInside->mInfo);
|
2021-11-30 10:10:53 +08:00
|
|
|
|
2021-09-18 15:52:30 +08:00
|
|
|
//When current cacheSize bigger than previous, update
|
2022-06-24 18:30:05 +08:00
|
|
|
if (buffer.first != nullptr && buffer.second > mInside->mCache->lastCacheSize) {
|
|
|
|
MNN_PRINT("Update cache to %s, size = %zu\n", mInside->mCache->cacheFile.c_str(), buffer.second);
|
|
|
|
writeCacheFile(mInside->mCache, buffer);
|
|
|
|
mInside->mCache->lastCacheSize = buffer.second;
|
2021-09-18 15:52:30 +08:00
|
|
|
}
|
|
|
|
// Reset cache
|
2022-06-24 18:30:05 +08:00
|
|
|
loadCache(mInside->mInfo, nullptr, 0);
|
2021-09-18 15:52:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<bool> Executor::RuntimeManager::isBackendSupport(const std::vector<MNNForwardType> types) {
|
|
|
|
std::vector<bool> res;
|
|
|
|
for (auto bn : types) {
|
|
|
|
auto rt = MNNGetExtraRuntimeCreator(bn);
|
|
|
|
if (rt != nullptr) {
|
|
|
|
res.push_back(true);
|
|
|
|
} else {
|
|
|
|
res.push_back(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:33:47 +08:00
|
|
|
ErrorCode Executor::computeInfo(Expr* expr) {
|
|
|
|
MNN_ASSERT(nullptr != expr);
|
|
|
|
MNN_ASSERT(nullptr != expr->get());
|
|
|
|
if (expr->get()->type() == OpType_Extra) {
|
|
|
|
return NOT_SUPPORT;
|
|
|
|
}
|
|
|
|
auto op = expr->get();
|
2020-11-05 16:41:56 +08:00
|
|
|
std::vector<Tensor*> inputTensors(expr->inputs().size());
|
|
|
|
for (int i=0; i<inputTensors.size(); ++i) {
|
2020-01-15 13:33:47 +08:00
|
|
|
auto inputExpr = expr->inputs()[i]->expr();
|
2020-11-05 16:41:56 +08:00
|
|
|
inputTensors[i] = inputExpr.first->inside()->mOutputTensors[inputExpr.second];
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
bool res = SizeComputer::computeOutputSize(op, inputTensors, expr->inside()->mOutputTensors);
|
2020-01-15 13:33:47 +08:00
|
|
|
if (!res) {
|
|
|
|
// Compute Error
|
|
|
|
#ifdef MNN_EXPRESS_ERROR_REPORT
|
2020-02-26 09:57:17 +08:00
|
|
|
if (expr->name().empty()) {
|
|
|
|
MNN_ERROR("Error to compute shape for %s\n", EnumNameOpType(op->type()));
|
|
|
|
} else {
|
|
|
|
MNN_ERROR("Error to compute shape for %s, %s\n", EnumNameOpType(op->type()), expr->name().c_str());
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
#endif
|
|
|
|
return COMPUTE_SIZE_ERROR;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
for (int i = 0; i < expr->outputSize(); ++i) {
|
|
|
|
auto tensor = expr->inside()->mOutputTensors[i];
|
|
|
|
TensorUtils::setLinearLayout(tensor);
|
|
|
|
auto shape = expr->outputInfo(i);
|
2020-01-15 13:33:47 +08:00
|
|
|
Utils::copyTensorToInfo(shape, tensor);
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2021-11-30 10:10:53 +08:00
|
|
|
|
2022-12-30 15:18:58 +08:00
|
|
|
void Executor::_makeCache(const std::vector<EXPRP>& expr, bool forceCPU) {
|
|
|
|
std::set<std::shared_ptr<Executor::ComputeCache>> inputCaches;
|
|
|
|
std::set<std::shared_ptr<Expr::Inside>> inputNode;
|
|
|
|
std::stack<EXPRP> dfsStack;
|
|
|
|
// first: target expr, second: tensor offset
|
|
|
|
std::map<EXPRP, int> dstExpr;
|
|
|
|
std::map<EXPRP, int> visited;
|
|
|
|
std::set<std::shared_ptr<Expr::Inside>> extraInputs;
|
|
|
|
for (auto e : expr) {
|
|
|
|
if (e->get() != nullptr) {
|
|
|
|
dfsStack.push(e);
|
|
|
|
dstExpr.insert(std::make_pair(e, -1));
|
|
|
|
}
|
2021-11-30 10:10:53 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
if (dfsStack.empty()) {
|
|
|
|
return;
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
2024-04-19 11:58:21 +08:00
|
|
|
auto current = ExecutorScope::Current();
|
|
|
|
auto rt = current->getRuntime();
|
2022-12-30 15:18:58 +08:00
|
|
|
Schedule::ScheduleInfo scheduleInfo;
|
2024-04-19 11:58:21 +08:00
|
|
|
scheduleInfo.externalWeightPath = current->getAttr()->externalFile;
|
2022-12-30 15:18:58 +08:00
|
|
|
scheduleInfo.pipelineInfo.resize(1);
|
|
|
|
auto& pipeline = scheduleInfo.pipelineInfo[0].second;
|
|
|
|
std::vector<std::shared_ptr<BufferStorage>> opBuffers;
|
2022-04-19 10:34:00 +08:00
|
|
|
while (!dfsStack.empty()) {
|
2022-12-30 15:18:58 +08:00
|
|
|
auto expr = dfsStack.top();
|
|
|
|
auto& inputs = expr->inputs();
|
|
|
|
auto& req = expr->inside()->mReq.contentNeedContent;
|
|
|
|
MNN_ASSERT(inputs.size() == req.size());
|
|
|
|
bool ready = true;
|
|
|
|
for (int i = 0; i < inputs.size(); ++i) {
|
|
|
|
if (!req[i]) {
|
2020-11-05 16:41:56 +08:00
|
|
|
continue;
|
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
auto inputExpr = inputs[i]->expr();
|
|
|
|
if (nullptr == inputExpr.first->get()) {
|
|
|
|
if (VARP::INPUT == inputExpr.first->inputType()) {
|
|
|
|
extraInputs.insert(inputExpr.first->inside());
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
auto inputCache = inputExpr.first->inside()->mCache;
|
|
|
|
if (nullptr != inputCache) {
|
|
|
|
inputCaches.insert(inputCache);
|
2021-11-30 10:10:53 +08:00
|
|
|
continue;
|
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
if (visited.find(inputExpr.first) != visited.end()) {
|
|
|
|
continue;
|
2020-07-04 01:21:30 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
ready = false;
|
|
|
|
dfsStack.push(inputExpr.first);
|
|
|
|
break;
|
2020-07-04 01:21:30 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
if (!ready) {
|
2020-01-15 13:33:47 +08:00
|
|
|
continue;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
dfsStack.pop();
|
|
|
|
int currentIndex = (int)pipeline.size();
|
|
|
|
visited.insert(std::make_pair(expr, currentIndex));
|
|
|
|
Schedule::OpCacheInfo opInfo;
|
|
|
|
opInfo.op = expr->get();
|
|
|
|
opBuffers.emplace_back(expr->extra());
|
|
|
|
opInfo.inputs.resize(inputs.size());
|
|
|
|
opInfo.outputs.resize(expr->outputSize());
|
|
|
|
int offset = scheduleInfo.allTensors.size();
|
|
|
|
for (int i=0; i<opInfo.outputs.size(); ++i) {
|
|
|
|
std::shared_ptr<Tensor> tensor(new Tensor);
|
|
|
|
opInfo.outputs[i] = tensor.get();
|
|
|
|
auto srcTensor = expr->inside()->mOutputTensors[i];
|
|
|
|
TensorUtils::copyShape(srcTensor, tensor.get(), true, true);
|
2023-04-27 15:11:05 +08:00
|
|
|
if (TensorUtils::getDescribe(srcTensor)->quantAttr.get()) {
|
|
|
|
TensorUtils::getDescribe(tensor.get())->quantAttr.reset(new QuantAttr);
|
|
|
|
auto quant = TensorUtils::getDescribe(tensor.get())->quantAttr.get();
|
|
|
|
quant->scale = TensorUtils::getDescribe(srcTensor)->quantAttr.get()->scale;
|
2023-10-18 10:31:02 +08:00
|
|
|
quant->zero = TensorUtils::getDescribe(srcTensor)->quantAttr.get()->zero;
|
2023-04-27 15:11:05 +08:00
|
|
|
}
|
2024-02-29 16:21:40 +08:00
|
|
|
|
2022-12-30 15:18:58 +08:00
|
|
|
TensorUtils::getDescribe(tensor.get())->index = (int)scheduleInfo.allTensors.size();
|
|
|
|
scheduleInfo.allTensors.emplace_back(tensor);
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
auto dstIter = dstExpr.find(expr);
|
|
|
|
if (dstIter != dstExpr.end()) {
|
|
|
|
dstIter->second = offset;
|
|
|
|
for (int i=0; i<opInfo.outputs.size(); ++i) {
|
|
|
|
TensorUtils::getDescribe(opInfo.outputs[i])->usage = Tensor::InsideDescribe::OUTPUT;
|
2022-04-19 10:34:00 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
for (int i = 0; i < inputs.size(); ++i) {
|
|
|
|
auto inputExpr = inputs[i]->expr();
|
|
|
|
if (!req[i]) {
|
|
|
|
opInfo.inputs[i] = Utils::getTensor(inputs[i]);
|
|
|
|
continue;
|
2022-04-19 10:34:00 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
if (nullptr == inputExpr.first->get()) {
|
|
|
|
opInfo.inputs[i] = Utils::getTensor(inputs[i]);
|
|
|
|
continue;
|
2022-04-19 10:34:00 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
auto inputCache = inputExpr.first->inside()->mCache;
|
|
|
|
if (nullptr != inputCache) {
|
|
|
|
opInfo.inputs[i] = opInfo.inputs[i] = Utils::getTensor(inputs[i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto iter = visited.find(inputExpr.first);
|
|
|
|
MNN_ASSERT(iter != visited.end());
|
|
|
|
opInfo.inputs[i] = pipeline[iter->second].outputs[inputExpr.second];
|
2022-04-19 10:34:00 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
pipeline.emplace_back(std::move(opInfo));
|
|
|
|
}
|
|
|
|
Session::ModeGroup group;
|
|
|
|
group.inputMode = Interpreter::Session_Input_User;
|
|
|
|
group.outputMode = Interpreter::Session_Output_User;
|
2024-06-03 20:09:34 +08:00
|
|
|
auto globalExecutor = ExecutorScope::Current();
|
|
|
|
auto debug = globalExecutor->getDebugTools();
|
|
|
|
if (debug->after != nullptr && debug->before != nullptr) {
|
|
|
|
group.callBackMode = Interpreter::Session_Debug;
|
|
|
|
} else {
|
|
|
|
group.callBackMode = Interpreter::Session_Release;
|
|
|
|
}
|
2023-04-27 15:11:05 +08:00
|
|
|
group.memoryUsageMode = Interpreter::Session_Memory_Cache;
|
2022-12-30 15:18:58 +08:00
|
|
|
std::shared_ptr<ComputeCache> cahce(new ComputeCache);
|
|
|
|
for (auto& iter : dstExpr) {
|
|
|
|
auto expr = iter.first;
|
|
|
|
expr->inside()->mCacheOffset = iter.second;
|
|
|
|
expr->inside()->mCache = cahce;
|
|
|
|
}
|
|
|
|
cahce->mCacheBuffers = std::move(opBuffers);
|
2023-08-21 14:51:54 +08:00
|
|
|
// Don't report error when use expr dynamic compute, which will be called in model convert
|
|
|
|
scheduleInfo.pipelineInfo[0].first.reportError = false;
|
2020-02-27 10:00:19 +08:00
|
|
|
if (forceCPU) {
|
2022-12-30 15:18:58 +08:00
|
|
|
scheduleInfo.pipelineInfo[0].first.info.type = MNN_FORWARD_CPU;
|
2020-02-27 10:00:19 +08:00
|
|
|
} else {
|
2024-07-22 19:51:53 +08:00
|
|
|
scheduleInfo.pipelineInfo[0].first.info.type = current->getAttr()->firstType;
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
2022-12-30 15:18:58 +08:00
|
|
|
scheduleInfo.pipelineInfo[0].first.needComputeShape = false;
|
|
|
|
scheduleInfo.pipelineInfo[0].first.needComputeGeometry = mLazyMode != LAZY_CONTENT;
|
|
|
|
cahce->mSession.reset(new Session(std::move(scheduleInfo), group, std::move(rt)));
|
|
|
|
cahce->mInputs = inputCaches;
|
|
|
|
cahce->mInputInside = std::move(extraInputs);
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
|
2020-02-27 10:00:19 +08:00
|
|
|
void Executor::makeCache(const std::vector<EXPRP>& expr, bool forceCPU) {
|
2020-01-15 13:33:47 +08:00
|
|
|
//FUNC_PRINT(mCaches.size());
|
2020-11-05 16:41:56 +08:00
|
|
|
_makeCache(expr, forceCPU);
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Executor::resetProfile() {
|
2023-09-04 10:42:11 +08:00
|
|
|
// Depercated
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
void Executor::dumpProfile() {
|
2023-09-04 10:42:11 +08:00
|
|
|
// Depercated
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
|
2022-12-30 15:18:58 +08:00
|
|
|
bool Executor::registerSubGraph(const std::string& submoduleName, VARPS outputs, VARPS inputs) {
|
|
|
|
if (mSubGraph.find(submoduleName) != mSubGraph.end()) {
|
|
|
|
MNN_PRINT("Executor Error: Subgraph has exists: %s\n", submoduleName.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::shared_ptr<SubGraph> graph(new SubGraph);
|
|
|
|
std::vector<std::string> subInputs(inputs.size());
|
|
|
|
std::vector<std::string> subOutputs(outputs.size());
|
|
|
|
for (int i=0; i<inputs.size(); ++i) {
|
|
|
|
if (inputs[i]->name().empty()) {
|
|
|
|
MNN_PRINT("Executor Error: input %d name empty\n", i);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
subInputs[i] = inputs[i]->name();
|
|
|
|
}
|
|
|
|
for (int i=0; i<outputs.size(); ++i) {
|
|
|
|
if (outputs[i]->name().empty()) {
|
|
|
|
MNN_PRINT("Executor Error: output %d name empty\n", i);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
subOutputs[i] = outputs[i]->name();
|
|
|
|
}
|
|
|
|
std::unique_ptr<MNN::SubGraphProtoT> subInfo(new MNN::SubGraphProtoT);
|
|
|
|
subInfo->name = submoduleName;
|
|
|
|
std::unique_ptr<MNN::NetT> subNet(new MNN::NetT);
|
|
|
|
std::vector<MNN::Express::VARP> combine = inputs;
|
|
|
|
combine.insert(combine.end(), outputs.begin(), outputs.end());
|
|
|
|
Variable::save(combine, subNet.get());
|
|
|
|
std::map<std::string, int> subTensorMap;
|
|
|
|
for (int i=0; i<subNet->tensorName.size(); ++i) {
|
|
|
|
subTensorMap.insert(std::make_pair(subNet->tensorName[i], i));
|
|
|
|
}
|
|
|
|
subInfo->tensors = std::move(subNet->tensorName);
|
|
|
|
subInfo->inputs.resize(inputs.size());
|
|
|
|
for (int i=0; i<inputs.size(); ++i) {
|
|
|
|
subInfo->inputs[i] = subTensorMap[subInputs[i]];
|
|
|
|
}
|
|
|
|
subInfo->outputs.resize(outputs.size());
|
|
|
|
for (int i=0; i<outputs.size(); ++i) {
|
|
|
|
subInfo->outputs[i] = subTensorMap[subOutputs[i]];
|
|
|
|
}
|
|
|
|
subInfo->nodes = std::move(subNet->oplists);
|
|
|
|
for (int i=0; i<subNet->subgraphs.size(); ++i) {
|
|
|
|
graph->depends.emplace_back(subNet->subgraphs[i]->name);
|
|
|
|
}
|
|
|
|
graph->info = std::move(subInfo);
|
|
|
|
mSubGraph.insert(std::make_pair(submoduleName, graph));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<Executor::SubGraph> Executor::findSubGraph(const std::string& submoduleName) {
|
|
|
|
auto iter = mSubGraph.find(submoduleName);
|
|
|
|
if (iter == mSubGraph.end()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return iter->second;
|
|
|
|
}
|
2023-12-04 11:12:20 +08:00
|
|
|
void Executor::setLazyComputeMode(uint32_t mode) {
|
2022-12-30 15:18:58 +08:00
|
|
|
mLazyMode = mode;
|
|
|
|
}
|
|
|
|
|
2019-12-27 22:16:57 +08:00
|
|
|
} // namespace Express
|
|
|
|
} // namespace MNN
|