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/Session.hpp"
|
|
|
|
#include "core/TensorUtils.hpp"
|
|
|
|
#include "Utils.hpp"
|
2020-01-15 13:33:47 +08:00
|
|
|
#include <MNN/AutoTime.hpp>
|
2020-02-26 23:08:52 +08:00
|
|
|
#include "core/WrapExecution.hpp"
|
2020-11-05 16:41:56 +08:00
|
|
|
#include "geometry/GeometryComputerUtils.hpp"
|
|
|
|
#include <MNN/expr/ExecutorScope.hpp>
|
2020-02-26 09:57:17 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
#define MNN_EXPRESS_ERROR_REPORT
|
|
|
|
#endif
|
2020-05-07 18:19:02 +08:00
|
|
|
#define MNN_EXPRESS_OPEN_MEMORY_REUSE
|
2019-12-27 22:16:57 +08:00
|
|
|
namespace MNN {
|
|
|
|
namespace Express {
|
2020-11-05 16:41:56 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
2020-01-15 13:33:47 +08:00
|
|
|
class Executor::Profiler {
|
|
|
|
public:
|
|
|
|
void reset();
|
|
|
|
void dump() const;
|
2020-11-05 16:41:56 +08:00
|
|
|
void add(const std::string& opType, float timeInMs);
|
|
|
|
void addFlops(const std::string& opType, float flops);
|
2020-01-15 13:33:47 +08:00
|
|
|
private:
|
2020-11-05 16:41:56 +08:00
|
|
|
std::map<std::string, float> mTimes;
|
|
|
|
std::map<std::string, float> mFlops;
|
2020-01-15 13:33:47 +08:00
|
|
|
};
|
|
|
|
void Executor::Profiler::reset() {
|
|
|
|
mTimes.clear();
|
|
|
|
}
|
|
|
|
void Executor::Profiler::dump() const {
|
2020-11-05 16:41:56 +08:00
|
|
|
float sumValue = 0.0f;
|
2020-01-15 13:33:47 +08:00
|
|
|
for (auto iter : mTimes) {
|
2020-11-05 16:41:56 +08:00
|
|
|
MNN_PRINT("%s: %f ms\n", iter.first.c_str(), iter.second);
|
|
|
|
sumValue += iter.second;
|
|
|
|
}
|
|
|
|
MNN_PRINT("Total: %f ms\n", sumValue);
|
|
|
|
sumValue = 0.0f;
|
|
|
|
for (auto iter : mFlops) {
|
|
|
|
MNN_PRINT("%s: %f \n", iter.first.c_str(), iter.second);
|
|
|
|
sumValue += iter.second;
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
MNN_PRINT("Total flops: %f ms\n", sumValue);
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
void Executor::Profiler::add(const std::string& opType, float timeInMs) {
|
2020-01-15 13:33:47 +08:00
|
|
|
auto iter = mTimes.find(opType);
|
|
|
|
if (iter == mTimes.end()) {
|
|
|
|
mTimes[opType] = timeInMs;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
iter->second += timeInMs;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
void Executor::Profiler::addFlops(const std::string& opType, float flops) {
|
|
|
|
auto iter = mFlops.find(opType);
|
|
|
|
if (iter == mFlops.end()) {
|
|
|
|
mFlops[opType] = flops;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
iter->second += flops;
|
|
|
|
}
|
|
|
|
#endif
|
2019-12-27 22:16:57 +08:00
|
|
|
void Executor::setGlobalExecutorConfig(MNNForwardType type, const BackendConfig& config, int numberThread) {
|
|
|
|
std::lock_guard<std::mutex> _l(mMutex);
|
2020-11-05 16:41:56 +08:00
|
|
|
auto creator = MNNGetExtraRuntimeCreator(type);
|
2019-12-27 22:16:57 +08:00
|
|
|
if (nullptr == creator) {
|
2020-11-05 16:41:56 +08:00
|
|
|
MNN_ERROR("Error to find creator of %d, set CPU default\n", type);
|
|
|
|
type = MNN_FORWARD_CPU;
|
|
|
|
creator = MNNGetExtraRuntimeCreator(type);
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
MNN_ASSERT(nullptr != creator);
|
2019-12-27 22:16:57 +08:00
|
|
|
Backend::Info info;
|
|
|
|
info.type = type;
|
2020-11-05 16:41:56 +08:00
|
|
|
info.mode = Backend::Info::DIRECT;
|
2019-12-27 22:16:57 +08:00
|
|
|
info.numThread = numberThread;
|
2020-11-05 16:41:56 +08:00
|
|
|
info.user = (BackendConfig*)&config;
|
|
|
|
std::shared_ptr<Runtime> bn(creator->onCreate(info));
|
|
|
|
mRuntime.first = bn;
|
|
|
|
mRuntime.second = type;
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
|
2019-12-27 22:16:57 +08:00
|
|
|
void Executor::gc(GCFlag flag) {
|
2020-01-15 13:33:47 +08:00
|
|
|
if (FULL == flag) {
|
2020-11-05 16:41:56 +08:00
|
|
|
mBackupRuntime.first->onGabageCollect(100);
|
|
|
|
mRuntime.first->onGabageCollect(100);
|
2020-01-15 13:33:47 +08:00
|
|
|
} else {
|
2020-11-05 16:41:56 +08:00
|
|
|
mBackupRuntime.first->onGabageCollect(0);
|
|
|
|
mRuntime.first->onGabageCollect(0);
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
|
|
|
Executor::Executor(std::shared_ptr<Runtime> backend, MNNForwardType type) {
|
|
|
|
mRuntime.first = backend;
|
|
|
|
mRuntime.second = type;
|
|
|
|
Backend::Info info;
|
|
|
|
info.type = MNN_FORWARD_CPU;
|
|
|
|
auto cre = MNNGetExtraRuntimeCreator(MNN_FORWARD_CPU);
|
|
|
|
info.mode = Backend::Info::DIRECT;
|
|
|
|
info.numThread = 1;
|
|
|
|
mBackupRuntime.first.reset(cre->onCreate(info));
|
|
|
|
mBackupRuntime.second = MNN_FORWARD_CPU;
|
|
|
|
|
2020-01-15 13:33:47 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
mProfiler.reset(new Profiler);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
Executor::~Executor(){
|
2020-11-05 16:41:56 +08:00
|
|
|
mRuntime.first = nullptr;
|
|
|
|
mBackupRuntime.first = nullptr;
|
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) {
|
|
|
|
req.contentNeedContent[i] = SizeComputer::opNeedContent(op->type(), i);
|
2020-11-05 16:41:56 +08:00
|
|
|
req.shapeNeedContent[i] = false;
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
auto needIndexId = SizeComputer::needInputContent(op);
|
|
|
|
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;
|
2019-12-27 22:16:57 +08:00
|
|
|
std::shared_ptr<Executor> Executor::getGlobalExecutor() {
|
|
|
|
static std::shared_ptr<Executor> gExecutor;
|
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));
|
|
|
|
gExecutor.reset(new Executor(bn, MNN_FORWARD_CPU));
|
2019-12-27 22:16:57 +08:00
|
|
|
});
|
|
|
|
return gExecutor;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
Backend::Info info;
|
|
|
|
info.type = type;
|
|
|
|
info.numThread = numberThread;
|
|
|
|
std::shared_ptr<Runtime> bn(creator->onCreate(info));
|
|
|
|
return std::shared_ptr<Executor>(new Executor(bn, type));
|
|
|
|
}
|
|
|
|
|
|
|
|
RuntimeInfo Executor::getRuntime() {
|
|
|
|
RuntimeInfo info;
|
|
|
|
auto glo = ExecutorScope::Current();
|
|
|
|
info.second = glo->mBackupRuntime.first;
|
|
|
|
info.first.insert(std::make_pair(glo->mRuntime.second, glo->mRuntime.first));
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
class Executor::ComputeCache {
|
2020-02-26 23:08:52 +08:00
|
|
|
public:
|
2020-11-05 16:41:56 +08:00
|
|
|
void setShapeDirty();
|
|
|
|
void setContentDirty();
|
|
|
|
void* mapOutput(int offset, Tensor* dest);
|
2020-02-26 23:08:52 +08:00
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
~ ComputeCache();
|
|
|
|
ComputeCache(std::shared_ptr<Backend> backend, std::shared_ptr<Backend> backupBackend);
|
2020-07-04 01:21:30 +08:00
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
ErrorCode compute();
|
|
|
|
ErrorCode resize();
|
2020-02-26 23:08:52 +08:00
|
|
|
private:
|
|
|
|
std::set<std::shared_ptr<ComputeCache>> mInputs;
|
|
|
|
std::vector<Tensor*> mOutputs;
|
|
|
|
std::vector<std::shared_ptr<Unit>> mUnits;
|
|
|
|
std::shared_ptr<Backend> mBackend;
|
|
|
|
std::shared_ptr<Backend> mBackupBackend;
|
2020-11-05 16:41:56 +08:00
|
|
|
std::set<std::shared_ptr<Expr::Inside>> mInputInside;
|
2020-02-26 23:08:52 +08:00
|
|
|
friend class Executor;
|
2020-11-05 16:41:56 +08:00
|
|
|
bool mContentDirty = true;
|
|
|
|
bool mShapeDirty = true;
|
|
|
|
GeometryComputer::Context mContext;
|
|
|
|
CommandBuffer mCmdBuffer;
|
|
|
|
std::vector<std::shared_ptr<Execution>> mExecutions;
|
|
|
|
std::map<const Op*, std::shared_ptr<Execution>> mCacheExes;
|
2020-02-26 23:08:52 +08:00
|
|
|
};
|
2020-11-05 16:41:56 +08:00
|
|
|
void Executor::setShapeDirty(ComputeCache* cache) {
|
|
|
|
cache->setShapeDirty();
|
|
|
|
}
|
|
|
|
void Executor::setContentDirty(ComputeCache* cache) {
|
|
|
|
cache->setContentDirty();
|
|
|
|
}
|
|
|
|
void* Executor::mapOutput(ComputeCache* cache, int offset, Tensor* dest) {
|
|
|
|
return cache->mapOutput(offset, dest);
|
|
|
|
}
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
struct Executor::Unit {
|
2020-02-26 23:08:52 +08:00
|
|
|
std::vector<Tensor*> inputs;
|
|
|
|
std::vector<Tensor*> outputs;
|
|
|
|
const Op* op;
|
2020-02-29 10:34:24 +08:00
|
|
|
std::weak_ptr<Expr::Inside> inside;
|
2020-02-26 23:08:52 +08:00
|
|
|
std::shared_ptr<char> extraBuffer;
|
2020-11-05 16:41:56 +08:00
|
|
|
std::vector<std::shared_ptr<Tensor>> outputContents;
|
2020-02-26 23:08:52 +08:00
|
|
|
};
|
2020-11-05 16:41:56 +08:00
|
|
|
void* Executor::ComputeCache::mapOutput(int offset, Tensor* dest) {
|
|
|
|
auto tensor = mOutputs[offset];
|
|
|
|
if (0 == tensor->deviceId()) {
|
|
|
|
auto ptr = tensor->host<void>();
|
|
|
|
Utils::releaseMemoryForHostTensor(dest);
|
|
|
|
TensorUtils::getDescribe(dest)->memoryType = Tensor::InsideDescribe::MEMORY_BACKEND;
|
|
|
|
dest->buffer().host = (uint8_t*)ptr;
|
|
|
|
//MNN_ASSERT(nullptr != ptr);
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
Utils::allocMemoryForHostTensor(dest);
|
|
|
|
tensor->copyToHostTensor(dest);
|
|
|
|
MNN_ASSERT(nullptr != dest->host<void>());
|
|
|
|
return dest->host<void>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Executor::ComputeCache::setShapeDirty() {
|
|
|
|
mShapeDirty = true;
|
2020-02-26 23:08:52 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
void Executor::ComputeCache::setContentDirty() {
|
|
|
|
mContentDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Executor::ComputeCache::ComputeCache(std::shared_ptr<Backend> backend, std::shared_ptr<Backend> backupBackend) : mContext(backupBackend) {
|
|
|
|
mBackend = backend;
|
|
|
|
mBackupBackend = backupBackend;
|
|
|
|
}
|
|
|
|
Executor::ComputeCache::~ComputeCache() {
|
2020-02-26 23:08:52 +08:00
|
|
|
mUnits.clear();
|
2020-11-05 16:41:56 +08:00
|
|
|
mCacheExes.clear();
|
2020-02-26 23:08:52 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
ErrorCode Executor::ComputeCache::compute() {
|
2020-01-15 13:33:47 +08:00
|
|
|
if (mShapeDirty) {
|
|
|
|
auto code = resize();
|
|
|
|
if (NO_ERROR != code) {
|
|
|
|
return code;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
if (!mContentDirty) {
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
for (auto& c : mInputInside) {
|
|
|
|
if (c->mContentDirty) {
|
|
|
|
return CALL_BACK_STOP;
|
|
|
|
}
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
for (auto c : mInputs) {
|
|
|
|
auto code = c->compute();
|
|
|
|
if (NO_ERROR != code) {
|
|
|
|
return code;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
mBackend->onExecuteBegin();
|
2020-11-05 16:41:56 +08:00
|
|
|
mBackupBackend->onExecuteBegin();
|
|
|
|
MNN_ASSERT(mExecutions.size() == mCmdBuffer.command.size());
|
|
|
|
for (int i=0; i<mCmdBuffer.command.size(); ++i) {
|
2020-01-15 13:33:47 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
Timer autoTime;
|
|
|
|
#endif
|
2020-11-05 16:41:56 +08:00
|
|
|
auto& iter = mCmdBuffer.command[i];
|
|
|
|
auto code = mExecutions[i]->onExecute(iter.inputs, iter.outputs);
|
|
|
|
if (NO_ERROR != code) {
|
2020-02-26 09:57:17 +08:00
|
|
|
#ifdef MNN_EXPRESS_ERROR_REPORT
|
2020-11-05 16:41:56 +08:00
|
|
|
auto op = iter.buffer.empty() ? iter.op : flatbuffers::GetRoot<Op>(iter.buffer.data());
|
|
|
|
MNN_ERROR("Error to compute for %s, \n", EnumNameOpType(op->type()));
|
2020-02-26 09:57:17 +08:00
|
|
|
#endif
|
2020-11-05 16:41:56 +08:00
|
|
|
mBackend->onExecuteEnd();
|
|
|
|
return code;
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-07-04 01:21:30 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
float costTime = (float)autoTime.durationInUs() / (float)1000;
|
2020-11-05 16:41:56 +08:00
|
|
|
auto op = iter.op;
|
|
|
|
if (!iter.buffer.empty()) {
|
|
|
|
op = flatbuffers::GetMutableRoot<Op>(iter.buffer.data());
|
|
|
|
}
|
|
|
|
ExecutorScope::Current()->addOpCostTime((int)op->type(), costTime);
|
2020-07-04 01:21:30 +08:00
|
|
|
#endif
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
|
|
|
mBackend->onExecuteEnd();
|
2020-11-05 16:41:56 +08:00
|
|
|
mBackupBackend->onExecuteEnd();
|
2020-01-15 13:33:47 +08:00
|
|
|
mContentDirty = false;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
ErrorCode Executor::ComputeCache::resize() {
|
2020-01-15 13:33:47 +08:00
|
|
|
if (!mShapeDirty) {
|
2019-12-27 22:16:57 +08:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
for (auto& c : mInputInside) {
|
|
|
|
if (c->mInfoDirty) {
|
|
|
|
return CALL_BACK_STOP;
|
|
|
|
}
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
for (auto c : mInputs) {
|
|
|
|
auto code = c->resize();
|
|
|
|
if (NO_ERROR != code) {
|
|
|
|
return code;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
}
|
2020-02-28 17:26:43 +08:00
|
|
|
mShapeDirty = false;
|
2020-11-05 16:41:56 +08:00
|
|
|
/** Encoder Begin */
|
|
|
|
{
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
{
|
|
|
|
Timer autoTime;
|
|
|
|
#endif
|
|
|
|
mCmdBuffer.command.clear();
|
|
|
|
mCmdBuffer.extras.clear();
|
|
|
|
mBackend->onClearBuffer();
|
|
|
|
mBackupBackend->onClearBuffer();
|
|
|
|
mExecutions.clear();
|
|
|
|
mContext.clear();
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
float costTime = (float)autoTime.durationInUs() / (float)1000;
|
|
|
|
ExecutorScope::Current()->addOpCostTime((int)OpType_While, costTime);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
CommandBuffer buffer;
|
|
|
|
for (int unitIndex = 0; unitIndex < mUnits.size(); ++unitIndex) {
|
|
|
|
auto& iter = *mUnits[unitIndex];
|
|
|
|
auto inside = iter.inside.lock();
|
|
|
|
if (nullptr == inside || inside->mInfoDirty) {
|
|
|
|
mShapeDirty = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Check zero shape
|
|
|
|
bool zeroShape = false;
|
|
|
|
for (int i=0; i<iter.outputs.size(); ++i) {
|
|
|
|
TensorUtils::copyShape(inside->mOutputTensors[i], iter.outputs[i], true);
|
|
|
|
auto t = iter.outputs[i];
|
|
|
|
// FIXME: Find better way to may compability for old model
|
|
|
|
/**
|
|
|
|
For Convolution of 2D / 3D Tensor(Dense / 1D Convolution)
|
|
|
|
Because of old code, we will acces dim[2] / dim[3] to get width and height
|
|
|
|
Set the lenght to 1 for compability
|
|
|
|
*/
|
|
|
|
for (int v=t->dimensions(); v<4; ++v) {
|
|
|
|
t->setLength(v, 1);
|
|
|
|
}
|
|
|
|
iter.outputs[i]->buffer().type = inside->mOutputTensors[i]->buffer().type;
|
|
|
|
auto des = TensorUtils::getDescribe(iter.outputs[i]);
|
|
|
|
if (des->memoryType == Tensor::InsideDescribe::MEMORY_BACKEND) {
|
|
|
|
des->backend = nullptr;
|
|
|
|
}
|
|
|
|
des->regions.clear();
|
|
|
|
for (int v=0; v<t->dimensions(); ++v) {
|
|
|
|
if (t->length(v) == 0) {
|
|
|
|
zeroShape = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (t->length(v) < 0) {
|
|
|
|
return INPUT_DATA_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (zeroShape) {
|
|
|
|
// FIXME: for multi output and one tensor zero shape should support
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
{
|
|
|
|
Timer autoTime;
|
|
|
|
#endif
|
|
|
|
auto geo = GeometryComputer::search(iter.op->type());
|
|
|
|
geo->compute(iter.op, iter.inputs, iter.outputs, mContext, buffer);
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
float costTime = (float)autoTime.durationInUs() / (float)1000;
|
|
|
|
ExecutorScope::Current()->addOpCostTime((int)iter.op->type(), costTime);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
{
|
|
|
|
Timer autoTime;
|
|
|
|
#endif
|
|
|
|
GeometryComputerUtils::makeRaster(buffer, mCmdBuffer, mContext);
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
float costTime = (float)autoTime.durationInUs() / (float)1000;
|
|
|
|
ExecutorScope::Current()->addOpCostTime((int)OpType_If, costTime);
|
2020-02-28 17:26:43 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
for (int k=0; k<mCmdBuffer.command.size(); ++k) {
|
|
|
|
auto& cmd = mCmdBuffer.command[k];
|
|
|
|
auto op = cmd.op;
|
|
|
|
if (!cmd.buffer.empty()) {
|
|
|
|
op = flatbuffers::GetMutableRoot<Op>(cmd.buffer.data());
|
2020-02-27 10:00:19 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
for (auto v = 0; v<cmd.inputs.size(); ++v) {
|
|
|
|
if (!SizeComputer::opNeedContent(op->type(), v)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto des = TensorUtils::getDescribe(cmd.inputs[v]);
|
|
|
|
if (des->memoryType == Tensor::InsideDescribe::MEMORY_BACKEND && des->usage == Tensor::InsideDescribe::NORMAL) {
|
|
|
|
des->useCount+=1;
|
|
|
|
continue;;
|
|
|
|
}
|
|
|
|
for (auto& s : des->regions) {
|
|
|
|
auto subDes = TensorUtils::getDescribe(s.origin);
|
|
|
|
if (subDes->memoryType == Tensor::InsideDescribe::MEMORY_BACKEND && subDes->usage == Tensor::InsideDescribe::NORMAL) {
|
|
|
|
subDes->useCount+=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** Encoder End */
|
|
|
|
|
|
|
|
/** Prepare Begin */
|
|
|
|
mExecutions.resize(mCmdBuffer.command.size());
|
|
|
|
for (int k=0; k<mCmdBuffer.command.size(); ++k) {
|
|
|
|
auto& cmd = mCmdBuffer.command[k];
|
|
|
|
auto op = cmd.op;
|
|
|
|
bool origin = true;
|
|
|
|
if (!cmd.buffer.empty()) {
|
|
|
|
origin = false;
|
|
|
|
op = flatbuffers::GetMutableRoot<Op>(cmd.buffer.data());
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
2020-11-05 16:41:56 +08:00
|
|
|
Timer autoTime;
|
2020-01-15 13:33:47 +08:00
|
|
|
#endif
|
2020-11-05 16:41:56 +08:00
|
|
|
mExecutions[k] = nullptr;
|
|
|
|
bool cacheed = false;
|
|
|
|
if (!mCacheExes.empty() && origin) {
|
|
|
|
auto iter = mCacheExes.find(op);
|
|
|
|
if (iter != mCacheExes.end()) {
|
|
|
|
mExecutions[k] = iter->second;
|
|
|
|
cacheed = true;
|
2020-02-26 23:08:52 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
|
|
|
if (nullptr == mExecutions[k]) {
|
|
|
|
mExecutions[k].reset(mBackend->onCreate(cmd.inputs, cmd.outputs, op));
|
|
|
|
if (nullptr == mExecutions[k]) {
|
|
|
|
mExecutions[k].reset(mBackupBackend->onCreate(cmd.inputs, cmd.outputs, op));
|
|
|
|
}
|
|
|
|
if (nullptr == mExecutions[k]) {
|
2020-07-23 16:54:55 +08:00
|
|
|
return NOT_SUPPORT;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
}
|
|
|
|
// Check if need wrap
|
|
|
|
bool needWrap = false;
|
|
|
|
auto bn = mExecutions[k]->backend();
|
|
|
|
auto iterType = bn->type();
|
|
|
|
for (int i=0; i<cmd.inputs.size(); ++i) {
|
|
|
|
if (!SizeComputer::opNeedContent(op->type(), i)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto inpDes = TensorUtils::getDescribe(cmd.inputs[i]);
|
|
|
|
if (inpDes->memoryType == Tensor::InsideDescribe::MEMORY_VIRTUAL) {
|
|
|
|
for (auto& reg : inpDes->regions) {
|
|
|
|
auto orgDes = TensorUtils::getDescribe(reg.origin);
|
|
|
|
auto tensorBn = orgDes->backend;
|
|
|
|
auto type = MNN_FORWARD_CPU;
|
|
|
|
if (nullptr != tensorBn) {
|
|
|
|
type = tensorBn->type();
|
|
|
|
}
|
|
|
|
if (iterType != type) {
|
|
|
|
needWrap = true;
|
|
|
|
break;
|
|
|
|
}
|
2020-02-26 23:08:52 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
} else {
|
|
|
|
auto tensorBn = inpDes->backend;
|
2020-02-26 23:08:52 +08:00
|
|
|
auto type = MNN_FORWARD_CPU;
|
|
|
|
if (nullptr != tensorBn) {
|
|
|
|
type = tensorBn->type();
|
|
|
|
}
|
|
|
|
if (iterType != type) {
|
|
|
|
needWrap = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (needWrap) {
|
2020-11-05 16:41:56 +08:00
|
|
|
break;
|
2020-02-26 23:08:52 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
if (needWrap && (!cacheed)) {
|
|
|
|
mExecutions[k].reset(new WrapExecution(mBackupBackend.get(), mExecutions[k], false));
|
|
|
|
}
|
|
|
|
if ((op->type() == OpType_Convolution && cmd.inputs.size() == 1)) {
|
|
|
|
// TODO: Support Other op's cache
|
|
|
|
mCacheExes.insert(std::make_pair(op, mExecutions[k]));
|
|
|
|
}
|
|
|
|
for (auto t : cmd.outputs) {
|
|
|
|
auto des = TensorUtils::getDescribe(t);
|
|
|
|
if (nullptr == des->backend) {
|
|
|
|
TensorUtils::setLinearLayout(t);
|
|
|
|
auto res = bn->onAcquireBuffer(t, Backend::DYNAMIC);
|
|
|
|
des->backend = bn;
|
|
|
|
if (!res) {
|
|
|
|
return OUT_OF_MEMORY;
|
|
|
|
}
|
2020-02-26 23:08:52 +08:00
|
|
|
}
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
auto code= mExecutions[k]->onResize(cmd.inputs, cmd.outputs);
|
|
|
|
if (NO_ERROR != code) {
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
for (auto v = 0; v<cmd.inputs.size(); ++v) {
|
|
|
|
if (!SizeComputer::opNeedContent(op->type(), v)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto t = cmd.inputs[v];
|
|
|
|
auto des = TensorUtils::getDescribe(t);
|
|
|
|
if (des->memoryType == Tensor::InsideDescribe::MEMORY_BACKEND) {
|
|
|
|
if (des->usage == Tensor::InsideDescribe::NORMAL) {
|
|
|
|
des->useCount-=1;
|
|
|
|
if (0 == des->useCount && nullptr != des->backend) {
|
|
|
|
des->backend->onReleaseBuffer(t, Backend::DYNAMIC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto& s : des->regions) {
|
|
|
|
auto subDes = TensorUtils::getDescribe(s.origin);
|
|
|
|
MNN_ASSERT(subDes->regions.empty());
|
|
|
|
if (subDes->memoryType == Tensor::InsideDescribe::MEMORY_BACKEND && subDes->usage == Tensor::InsideDescribe::NORMAL) {
|
|
|
|
subDes->useCount-=1;
|
|
|
|
if (0 == subDes->useCount && nullptr != subDes->backend) {
|
|
|
|
subDes->backend->onReleaseBuffer(s.origin, Backend::DYNAMIC);
|
|
|
|
}
|
|
|
|
}
|
2020-07-04 01:21:30 +08:00
|
|
|
}
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
float costTime = (float)autoTime.durationInUs() / (float)1000;
|
2020-11-05 16:41:56 +08:00
|
|
|
ExecutorScope::Current()->addOpCostTime((int)op->type(), costTime);
|
2020-01-15 13:33:47 +08:00
|
|
|
#endif
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
/** Prepare End */
|
|
|
|
|
2020-02-26 23:08:52 +08:00
|
|
|
mContentDirty = true;
|
2020-01-15 13:33:47 +08:00
|
|
|
return NO_ERROR;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
static void _collectExecuteUnit(std::vector<std::shared_ptr<Executor::Unit>>& dest, EXPRP expr) {
|
2020-01-15 13:33:47 +08:00
|
|
|
auto& inputs = expr->inputs();
|
|
|
|
auto& req = expr->inside()->mReq.contentNeedContent;
|
|
|
|
MNN_ASSERT(inputs.size() == req.size());
|
|
|
|
|
|
|
|
for (int i=0; i<inputs.size(); ++i) {
|
|
|
|
if (!req[i]) {
|
|
|
|
continue;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
auto inputExpr = inputs[i]->expr();
|
2020-02-26 23:08:52 +08:00
|
|
|
auto unit = inputExpr.first->inside()->mUnit;
|
|
|
|
if (nullptr == unit) {
|
2020-01-15 13:33:47 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto inputCache = inputExpr.first->inside()->mCache;
|
|
|
|
if (nullptr != inputCache) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-02-26 23:08:52 +08:00
|
|
|
_collectExecuteUnit(dest, inputExpr.first);
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-02-26 23:08:52 +08:00
|
|
|
auto unit = expr->inside()->mUnit;
|
|
|
|
if (nullptr == unit) {
|
2020-01-15 13:33:47 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-02-26 23:08:52 +08:00
|
|
|
dest.emplace_back(std::move(unit));
|
|
|
|
expr->inside()->mUnit = nullptr;
|
|
|
|
}
|
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
void Executor::_create(const std::vector<EXPRP>& outputs, std::set<std::shared_ptr<Executor::ComputeCache>>&& inputCaches, std::set<std::shared_ptr<Expr::Inside>>&& inputNode, bool forceCPU) {
|
2020-01-15 13:33:47 +08:00
|
|
|
std::vector<EXPRP> packed;
|
|
|
|
for (auto expr : outputs) {
|
|
|
|
auto cache = expr->inside()->mCache;
|
|
|
|
if (nullptr != cache) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (nullptr != expr->get()) {
|
|
|
|
packed.emplace_back(expr);
|
|
|
|
continue;
|
|
|
|
}
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
if (packed.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
//MNN_PRINT("Create %p begin\n", packed[0].get());
|
|
|
|
std::shared_ptr<Backend> cacheBn;
|
|
|
|
std::shared_ptr<Backend> cacheBackupBn;
|
2020-02-27 10:00:19 +08:00
|
|
|
if (forceCPU) {
|
2020-11-05 16:41:56 +08:00
|
|
|
cacheBn.reset(mBackupRuntime.first->onCreate());
|
|
|
|
cacheBackupBn = cacheBn;
|
2020-02-27 10:00:19 +08:00
|
|
|
} else {
|
2020-11-05 16:41:56 +08:00
|
|
|
cacheBn.reset(mRuntime.first->onCreate());
|
|
|
|
cacheBackupBn.reset(mBackupRuntime.first->onCreate());
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
std::shared_ptr<ComputeCache> packedCache(new ComputeCache(cacheBn, cacheBackupBn));
|
2020-02-27 10:00:19 +08:00
|
|
|
packedCache->mInputs = std::move(inputCaches);
|
2020-11-05 16:41:56 +08:00
|
|
|
packedCache->mInputInside = std::move(inputNode);
|
2020-01-15 13:33:47 +08:00
|
|
|
for (auto expr : packed) {
|
2020-02-26 23:08:52 +08:00
|
|
|
expr->inside()->mCacheOffset = (int)packedCache->mOutputs.size();
|
|
|
|
MNN_ASSERT(expr->inside()->mUnit != nullptr);
|
|
|
|
auto& originOutputs = expr->inside()->mUnit->outputs;
|
|
|
|
for (auto t : originOutputs) {
|
|
|
|
packedCache->mOutputs.emplace_back(t);
|
2020-11-05 16:41:56 +08:00
|
|
|
TensorUtils::getDescribe(t)->usage = Tensor::InsideDescribe::OUTPUT;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
for (auto expr : packed) {
|
2020-02-26 23:08:52 +08:00
|
|
|
_collectExecuteUnit(packedCache->mUnits, expr);
|
2020-01-15 13:33:47 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
for (auto expr : packed) {
|
|
|
|
expr->inside()->mCache = packedCache;
|
|
|
|
}
|
|
|
|
//MNN_PRINT("Create %p End\n", packed[0].get());
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
|
2020-11-05 16:41:56 +08:00
|
|
|
void Executor::_visit(EXPRP expr, std::set<std::shared_ptr<Executor::ComputeCache>>& inputCaches, std::set<std::shared_ptr<Expr::Inside>>& inputNode) {
|
2020-01-15 13:33:47 +08:00
|
|
|
auto& inputs = expr->inputs();
|
|
|
|
auto& req = expr->inside()->mReq.contentNeedContent;
|
|
|
|
MNN_ASSERT(inputs.size() == req.size());
|
|
|
|
|
|
|
|
// Create Input's Unit / Cache
|
|
|
|
for (int i=0; i<inputs.size(); ++i) {
|
|
|
|
if (!req[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
//MNN_PRINT("Use %d\n", i);
|
2020-01-15 13:33:47 +08:00
|
|
|
auto inputExpr = inputs[i]->expr();
|
2020-02-26 23:08:52 +08:00
|
|
|
if (nullptr != inputExpr.first->inside()->mUnit) {
|
2020-01-15 13:33:47 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto inputCache = inputExpr.first->inside()->mCache;
|
|
|
|
if (nullptr != inputCache) {
|
|
|
|
inputCaches.insert(inputCache);
|
|
|
|
continue;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
_visit(inputExpr.first, inputCaches, inputNode);
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-02-27 10:00:19 +08:00
|
|
|
|
2020-01-15 13:33:47 +08:00
|
|
|
auto op = expr->get();
|
|
|
|
if (nullptr == op) {
|
|
|
|
return;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
if (nullptr != expr->inside()->mUnit) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::shared_ptr<Unit> unitP(new Unit);
|
|
|
|
Unit& unit = *unitP;
|
2020-02-26 23:08:52 +08:00
|
|
|
unit.op = expr->get();
|
|
|
|
unit.extraBuffer = expr->extra().first;
|
2020-02-29 10:34:24 +08:00
|
|
|
unit.inside = std::weak_ptr<Expr::Inside>(expr->inside());
|
2020-01-15 13:33:47 +08:00
|
|
|
unit.inputs.resize(inputs.size());
|
2020-11-05 16:41:56 +08:00
|
|
|
unit.outputs.resize(expr->inside()->mOutputTensors.size());
|
|
|
|
unit.outputContents.resize(unit.outputs.size());
|
|
|
|
for (int i=0; i<unit.outputs.size(); ++i) {
|
|
|
|
unit.outputContents[i].reset(new Tensor);
|
|
|
|
unit.outputs[i] = unit.outputContents[i].get();
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
for (int i=0; i<inputs.size(); ++i) {
|
|
|
|
auto inputExpr = inputs[i]->expr();
|
2020-11-05 16:41:56 +08:00
|
|
|
unit.inputs[i] = inputExpr.first->inside()->mOutputTensors[inputExpr.second];
|
2020-01-15 13:33:47 +08:00
|
|
|
if (!req[i]) {
|
2020-11-05 16:41:56 +08:00
|
|
|
// The compute don't need it
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (inputExpr.first->get() == nullptr) {
|
|
|
|
if (inputExpr.first->inputType() == VARP::INPUT) {
|
|
|
|
inputNode.insert(inputExpr.first->inside());
|
|
|
|
}
|
2020-01-15 13:33:47 +08:00
|
|
|
continue;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-02-26 23:08:52 +08:00
|
|
|
auto inputUnit = inputExpr.first->inside()->mUnit;
|
|
|
|
if (nullptr != inputUnit) {
|
|
|
|
unit.inputs[i] = inputUnit->outputs[inputExpr.second];
|
2020-01-15 13:33:47 +08:00
|
|
|
continue;
|
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
MNN_ASSERT(nullptr != inputExpr.first->inside()->mCache);
|
|
|
|
inputCaches.insert(inputExpr.first->inside()->mCache);
|
|
|
|
auto offset = inputExpr.second + inputExpr.first->inside()->mCacheOffset;
|
|
|
|
unit.inputs[i] = inputExpr.first->inside()->mCache->mOutputs[offset];
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
MNN_ASSERT(expr->inside()->mUnit == nullptr);
|
|
|
|
//MNN_PRINT("Create %p, %s\n", expr.get(), EnumNameOpType(expr->get()->type()));
|
2020-02-26 23:08:52 +08:00
|
|
|
expr->inside()->mUnit = unitP;
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +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;
|
|
|
|
for (auto e : expr) {
|
|
|
|
_visit(e, inputCaches, inputNode);
|
|
|
|
}
|
|
|
|
_create(expr, std::move(inputCaches), std::move(inputNode), forceCPU);
|
|
|
|
}
|
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) {
|
2019-12-27 22:16:57 +08:00
|
|
|
std::lock_guard<std::mutex> _l(mMutex);
|
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::addOpCostTime(int op, float costTime) {
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
2020-11-05 16:41:56 +08:00
|
|
|
auto opType = MNN::EnumNameOpType((OpType)op);
|
|
|
|
if (nullptr == opType) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mProfiler->add(opType, costTime);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void Executor::addOpCostTime(const std::string& type, float costTime) {
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
mProfiler->add(type, costTime);
|
2020-01-15 13:33:47 +08:00
|
|
|
#endif
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
2020-11-05 16:41:56 +08:00
|
|
|
void Executor::addOpFlops(const std::string& type, float flops) {
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
mProfiler->addFlops(type, flops);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:33:47 +08:00
|
|
|
|
|
|
|
ErrorCode Executor::runCache(std::shared_ptr<ComputeCache> cache) {
|
2019-12-27 22:16:57 +08:00
|
|
|
std::lock_guard<std::mutex> _l(mMutex);
|
2020-01-15 13:33:47 +08:00
|
|
|
return cache->compute();
|
|
|
|
}
|
|
|
|
void Executor::resetProfile() {
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
mProfiler->reset();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void Executor::dumpProfile() {
|
|
|
|
#ifdef MNN_EXPR_ENABLE_PROFILER
|
|
|
|
mProfiler->dump();
|
|
|
|
#endif
|
2019-12-27 22:16:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Express
|
|
|
|
} // namespace MNN
|