|
- /**
- * \file src/cambricon/impl/cambricon_runtime_opr.cpp
- * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
- *
- * Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- */
-
- #include "megbrain/cambricon/cambricon_runtime_opr.h"
- #include "megbrain/common.h"
-
- #if MGB_CAMBRICON
-
- using namespace mgb;
- using namespace opr;
-
- namespace {
- SmallVector<int> mgb_shape_to_cnrt_shape(TensorShape mgb_shp) {
- int ndim = mgb_shp.ndim;
- SmallVector<int> cnrt_shp(ndim);
- for (int i = 0; i < ndim; ++i) {
- cnrt_shp[i] = mgb_shp[i];
- }
- return cnrt_shp;
- }
- TensorShape cnrt_shape_to_mgb_shape(int* dim_values, int dim_num) {
- TensorShape ret;
- ret.ndim = dim_num;
- for (int i = 0; i < dim_num; ++i) {
- ret[i] = dim_values[i];
- }
- return ret;
- }
- DType cnrt_dtype_to_mgb_dtype(cnrtDataType_t data_type) {
- switch (data_type) {
- case CNRT_FLOAT16:
- #if !MEGDNN_DISABLE_FLOAT16
- return dtype::Float16();
- #else
- mgb_throw(MegBrainError,
- "Float16 support is disabled at compile time.");
- #endif
- case CNRT_FLOAT32:
- return dtype::Float32();
- case CNRT_INT8:
- return dtype::QuantizedS8(1.f);
- case CNRT_INT16:
- return dtype::Int16();
- case CNRT_INT32:
- return dtype::Int32();
- case CNRT_UINT8:
- return dtype::Uint8();
- //! TODO: check scale
- case CNRT_QUANT8:
- return dtype::QuantizedS8(1.f);
- default:
- mgb_throw(MegBrainError,
- "cnrtDataType %x is not supported by MegBrain.",
- data_type);
- }
- }
- cnrtDataType_t mgb_dtype_to_cnrt_dtype(DType data_type) {
- switch (data_type.enumv()) {
- #if !MEGDNN_DISABLE_FLOAT16
- case DTypeEnum::Float16:
- return CNRT_FLOAT16;
- #endif
- case DTypeEnum::Float32:
- return CNRT_FLOAT32;
- case DTypeEnum::QuantizedS8:
- return CNRT_QUANT8;
- case DTypeEnum::Quantized8Asymm:
- return CNRT_QUANT8;
- case DTypeEnum::Int8:
- return CNRT_INT8;
- case DTypeEnum::Int32:
- return CNRT_INT32;
- case DTypeEnum::Uint8:
- return CNRT_UINT8;
- default:
- mgb_throw(MegBrainError,
- "megbrain data type %s is not supported by cnrt.",
- data_type.name());
- }
- }
- }; // namespace
-
- /* ====================== CambriconRuntimeOpr ==================== */
- MGB_DYN_TYPE_OBJ_FINAL_IMPL(CambriconRuntimeOpr);
- CambriconRuntimeOpr::CambriconRuntimeOpr(SharedBuffer buf, std::string symbol,
- const VarNodeArray& inputs,
- bool tensor_dim_mutable,
- const OperatorNodeConfig& config)
- : Super(inputs[0]->owner_graph(), config, "cambricon_runtime", inputs),
- m_buffer{std::move(buf)},
- m_symbol{std::move(symbol)},
- m_model{nullptr},
- m_function{nullptr},
- m_context{nullptr},
- m_tensor_dim_mutable{tensor_dim_mutable} {
- mgb_assert(inputs[0]->comp_node().device_type() ==
- CompNode::DeviceType::CAMBRICON,
- "CambriconRuntimeOpr can only be used on cambricon comp node; "
- "got %s",
- inputs[0]->comp_node().to_string().c_str());
-
- for (auto i : inputs) {
- add_input({i});
- }
- if (m_model == nullptr) {
- m_model = {new cnrtModel_t(), cnrt_intl::ModelUnloader()};
- MGB_CNRT_CHECK(cnrtLoadModelFromMem(
- m_model.get(),
- reinterpret_cast<char*>(const_cast<void*>(m_buffer.data()))));
- }
- if (m_function == nullptr) {
- m_function = {new cnrtFunction_t(), cnrt_intl::FunctionDeleter()};
- MGB_CNRT_CHECK(cnrtCreateFunction(m_function.get()));
- MGB_CNRT_CHECK(cnrtExtractFunction(m_function.get(), *m_model,
- m_symbol.c_str()));
- }
- int nr_inputs = 0;
- int nr_outputs = 0;
- int64_t* inputs_size = nullptr;
- int64_t* outputs_size = nullptr;
- MGB_CNRT_CHECK(cnrtGetInputDataSize(&inputs_size, &nr_inputs, *m_function));
- mgb_assert(static_cast<size_t>(nr_inputs) == inputs.size(),
- "inputs size mismatch: expect=%d, got=%zu", nr_inputs,
- inputs.size());
- MGB_CNRT_CHECK(
- cnrtGetOutputDataSize(&outputs_size, &nr_outputs, *m_function));
- if (nr_outputs == 1) {
- add_output(None);
- } else {
- for (int i = 0; i < nr_outputs; ++i) {
- add_output(ssprintf("o%d", i));
- }
- }
- add_equivalence_component<mgb::ScalarHash<const void*>>(m_buffer.data());
- };
-
- void CambriconRuntimeOpr::scn_do_execute() {
- mgb_assert(m_function != nullptr);
- auto&& cnrt_env =
- CompNodeEnv::from_comp_node(input(0)->comp_node()).cnrt_env();
- cnrt_env.activate();
- if (m_context == nullptr) {
- m_context = {new cnrtRuntimeContext_t(),
- cnrt_intl::RuntimeContextDeleter()};
- MGB_CNRT_CHECK(cnrtCreateRuntimeContext(m_context.get(), *m_function,
- nullptr));
- int dev_id = cnrt_env.device;
- MGB_CNRT_CHECK(cnrtSetRuntimeContextDeviceId(*m_context, dev_id));
- MGB_CNRT_CHECK(cnrtInitRuntimeContext(*m_context, nullptr));
- }
- size_t nr_inputs = input().size(), nr_outputs = output().size();
- SmallVector<void*> params(nr_inputs + nr_outputs);
- SmallVector<cnrtParamDesc_t> param_descs(nr_inputs + nr_outputs);
- for (size_t i = 0; i < nr_inputs; ++i) {
- params[i] = input(i)->dev_tensor().raw_ptr();
- MGB_CNRT_CHECK(cnrtCreateParamDesc(¶m_descs[i]));
- MGB_CNRT_CHECK(cnrtSetDataTypeToParamDesc(
- param_descs[i], mgb_dtype_to_cnrt_dtype(input(i)->dtype())));
- auto dims = mgb_shape_to_cnrt_shape(input(i)->shape());
- MGB_CNRT_CHECK(cnrtSetShapeToParamDesc(param_descs[i], dims.data(),
- static_cast<int>(dims.size())));
- }
- for (size_t i = 0; i < nr_outputs; ++i) {
- params[nr_inputs + i] = output(i)->dev_tensor().raw_ptr();
- MGB_CNRT_CHECK(cnrtCreateParamDesc(¶m_descs[nr_inputs + i]));
- MGB_CNRT_CHECK(cnrtSetDataTypeToParamDesc(
- param_descs[nr_inputs + i],
- mgb_dtype_to_cnrt_dtype(output(i)->dtype())));
- auto dims = mgb_shape_to_cnrt_shape(output(i)->shape());
- MGB_CNRT_CHECK(cnrtSetShapeToParamDesc(param_descs[nr_inputs + i],
- dims.data(),
- static_cast<int>(dims.size())));
- }
- MGB_CNRT_CHECK(cnrtInvokeRuntimeContext_V2(*m_context, param_descs.data(),
- params.data(), cnrt_env.queue,
- nullptr));
- for (auto& param : param_descs) {
- MGB_CNRT_CHECK(cnrtDestroyParamDesc(param));
- }
- }
-
- void CambriconRuntimeOpr::get_output_var_shape(
- const TensorShapeArray& inp_shape, TensorShapeArray& out_shape) const {
- mgb_assert(m_function != nullptr);
- mgb_assert(input().size() == inp_shape.size());
- if (m_tensor_dim_mutable) {
- cnrtParamDescArray_t input_descs, output_descs;
- int inp_param_num = input().size();
- int out_param_num = output().size();
- MGB_CNRT_CHECK(cnrtCreateParamDescArray(&input_descs, inp_param_num));
- MGB_CNRT_CHECK(cnrtCreateParamDescArray(&output_descs, out_param_num));
- for (int i = 0; i < inp_param_num; ++i) {
- MGB_CNRT_CHECK(cnrtSetDataTypeToParamDesc(
- input_descs[i],
- mgb_dtype_to_cnrt_dtype(input(i)->dtype())));
- auto dims = mgb_shape_to_cnrt_shape(inp_shape[i]);
- MGB_CNRT_CHECK(
- cnrtSetShapeToParamDesc(input_descs[i], dims.data(),
- static_cast<int>(dims.size())));
- }
- MGB_CNRT_CHECK(cnrtInferFunctionOutputShape(*m_function, inp_param_num,
- input_descs, out_param_num,
- output_descs));
- for (int i = 0; i < out_param_num; ++i) {
- int* dims = nullptr;
- int dim_num = 0;
- MGB_CNRT_CHECK(cnrtGetShapeFromParamDesc(output_descs[i], &dims,
- &dim_num));
- out_shape[i] = cnrt_shape_to_mgb_shape(dims, dim_num);
- }
- MGB_CNRT_CHECK(cnrtDestroyParamDescArray(input_descs, inp_param_num));
- MGB_CNRT_CHECK(cnrtDestroyParamDescArray(output_descs, out_param_num));
- } else {
- //! check input shape match
- for (size_t i = 0; i < inp_shape.size(); ++i) {
- int* dim_values = nullptr;
- int dim_num = 0;
- MGB_CNRT_CHECK(cnrtGetInputDataShape(
- &dim_values, &dim_num, static_cast<int>(i), *m_function));
- auto shp_in_func = cnrt_shape_to_mgb_shape(dim_values, dim_num);
- auto inpshp = inp_shape[i];
- MGB_MARK_USED_VAR(shp_in_func);
- mgb_assert(
- inpshp.eq_shape(shp_in_func),
- "input shape(%s) mismatch with that(%s) in cnrtFunction_t.",
- inpshp.to_string().c_str(),
- shp_in_func.to_string().c_str());
- }
- //! remarks: cnrt does not provide interface to let user manage
- //! workspace
- MGB_MARK_USED_VAR(mgb_dtype_to_cnrt_dtype);
- for (size_t i = 0; i < out_shape.size(); ++i) {
- int* dim_values = nullptr;
- int dim_num = 0;
- MGB_CNRT_CHECK(cnrtGetOutputDataShape(
- &dim_values, &dim_num, static_cast<int>(i), *m_function));
- out_shape[i] = cnrt_shape_to_mgb_shape(dim_values, dim_num);
- }
- }
- }
-
- void CambriconRuntimeOpr::add_input_layout_constraint() {
- //! default contiguous
- for (auto i : input()) {
- i->add_layout_constraint_contiguous();
- }
- }
-
- void CambriconRuntimeOpr::init_output_dtype() {
- cnrtDataType_t* inp_dtype_array = nullptr;
- int inp_num;
- MGB_CNRT_CHECK(
- cnrtGetInputDataType(&inp_dtype_array, &inp_num, *m_function));
- for (size_t i = 0; i < input().size(); ++i) {
- auto dt_cnrt = cnrt_dtype_to_mgb_dtype(inp_dtype_array[i]);
- auto dt_inp = input(i)->dtype();
- MGB_MARK_USED_VAR(dt_cnrt);
- MGB_MARK_USED_VAR(dt_inp);
- mgb_assert(dt_cnrt.valid() && dt_inp.valid() &&
- dt_cnrt.enumv() == dt_inp.enumv(),
- "Input %zu's data type mismatch with that in "
- "cnrtFunction_t: expected %s, got %s",
- i, dt_cnrt.name(), dt_inp.name());
- }
- cnrtDataType_t* out_dtype_array = nullptr;
- int out_num;
- MGB_CNRT_CHECK(
- cnrtGetOutputDataType(&out_dtype_array, &out_num, *m_function));
- for (size_t i = 0; i < output().size(); ++i) {
- auto dt_cnrt = cnrt_dtype_to_mgb_dtype(out_dtype_array[i]);
- mgb_assert(dt_cnrt.valid(),
- "output dtype checking failed: invalid dtype returned.");
- if (dt_cnrt.enumv() == DTypeEnum::QuantizedS8) {
- mgb_assert(output(i)->dtype().valid(),
- "user should specify scale of output tensor of "
- "CambriconRuntimeOpr.");
- }
- if (!output(i)->dtype().valid())
- output(i)->dtype(dt_cnrt);
- }
- }
-
- SymbolVarArray CambriconRuntimeOpr::make(SharedBuffer buf, std::string symbol,
- const SymbolVarArray& src,
- bool tensor_dim_mutable,
- const OperatorNodeConfig& config) {
- VarNodeArray var_node_array = cg::to_var_node_array(src);
- auto cambricon_runtime_opr = std::make_unique<CambriconRuntimeOpr>(
- std::move(buf), std::move(symbol), var_node_array,
- tensor_dim_mutable, config);
- auto ret = cg::to_symbol_var_array(
- src[0].node()
- ->owner_graph()
- ->insert_opr(std::move(cambricon_runtime_opr))
- ->output());
- return ret;
- }
-
- SymbolVarArray CambriconRuntimeOpr::make(const void* buf, size_t size,
- std::string symbol,
- const SymbolVarArray& src,
- bool tensor_dim_mutable,
- const OperatorNodeConfig& config) {
- mgb_throw_if(!CompNode::get_device_count(CompNode::DeviceType::CAMBRICON),
- SystemError,
- "can not create CambriconRuntimeOpr when Cambricon is not "
- "available");
- std::shared_ptr<uint8_t> shptr{new uint8_t[size],
- [](uint8_t* p) { delete[] p; }};
- memcpy(shptr.get(), buf, size);
- SharedBuffer buffer{std::move(shptr), size};
- return make(std::move(buffer), std::move(symbol), src, tensor_dim_mutable,
- config);
- }
-
- #endif // MGB_CAMBRICON
-
- // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}
|