From: @zhoufeng54 Reviewed-by: @xu-yfei,@chujinjin Signed-off-by: @chujinjintags/v1.1.0
| @@ -37,6 +37,7 @@ set(INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Installation directory f | |||
| set(INSTALL_PY_DIR ".") | |||
| set(INSTALL_BASE_DIR ".") | |||
| set(INSTALL_BIN_DIR "bin") | |||
| set(INSTALL_CFG_DIR "config") | |||
| if (CMAKE_SYSTEM_NAME MATCHES "Windows") | |||
| set(INSTALL_LIB_DIR ".") | |||
| @@ -308,6 +309,13 @@ install( | |||
| COMPONENT mindspore | |||
| ) | |||
| ## config files | |||
| install( | |||
| FILES ${CMAKE_SOURCE_DIR}/config/op_info.config | |||
| DESTINATION ${INSTALL_CFG_DIR} | |||
| COMPONENT mindspore | |||
| ) | |||
| if (ENABLE_SERVING) | |||
| install( | |||
| TARGETS ms_serving | |||
| @@ -106,17 +106,15 @@ extern MS_API const char *kDeviceTypeAscend310; | |||
| extern MS_API const char *kDeviceTypeAscend910; | |||
| constexpr auto kModelOptionDumpCfgPath = "mindspore.option.dump_config_file_path"; | |||
| constexpr auto kModelOptionDvppCfgPath = "mindspore.option.dvpp_config_file_path"; | |||
| constexpr auto kModelOptionInsertOpCfgPath = "mindspore.option.insert_op_config_file_path"; // aipp config file | |||
| constexpr auto kModelOptionInputFormat = "mindspore.option.input_format"; // nchw or nhwc | |||
| // Mandatory while dynamic batch: e.g. "input_op_name1: n1,c2,h3,w4;input_op_name2: n4,c3,h2,w1" | |||
| constexpr auto kModelOptionInputShape = "mindspore.option.input_shape"; | |||
| constexpr auto kModelOptionDynamicBatchSize = "mindspore.option.dynamic_batch_size"; | |||
| constexpr auto kModelOptionDynamicImageSize = "mindspore.option.dynamic_image_size"; | |||
| constexpr auto kModelOptionDynamicDims = "mindspore.option.dynamic_dims"; | |||
| constexpr auto kModelOptionSerialInput = "mindspore.option.serial_inputs_name"; // separated by ';' | |||
| constexpr auto kModelOptionOutputNode = "mindspore.option.output_node"; // e.g. "node_name1:0;node_name2:1" | |||
| constexpr auto kModelOptionOutputType = "mindspore.option.output_type"; // "FP32", "UINT8" or "FP16", default as "FP32" | |||
| constexpr auto kModelOptionPrecisionMode = "mindspore.option.precision_mode"; | |||
| // "force_fp16", "allow_fp32_to_fp16", "must_keep_origin_dtype" or "allow_mix_precision", default as "force_fp16" | |||
| constexpr auto kModelOptionOpSelectImplMode = "mindspore.option.op_select_impl_mode"; | |||
| // "high_precision" or "high_performance", default as "high_performance" | |||
| } // namespace api | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_INCLUDE_API_TYPES_H | |||
| @@ -10,6 +10,7 @@ if (ENABLE_ACL) | |||
| include_directories(${CMAKE_SOURCE_DIR}/graphengine/src/ge) | |||
| include_directories(${CMAKE_BINARY_DIR}/proto/ge) | |||
| file(GLOB_RECURSE API_ACL_SRC ${CMAKE_CURRENT_SOURCE_DIR} | |||
| "python_utils.cc" | |||
| "model/acl/*.cc" | |||
| "model/model_converter_utils/*.cc" | |||
| "graph/acl/*.cc" | |||
| @@ -17,14 +18,13 @@ if (ENABLE_ACL) | |||
| endif () | |||
| if (ENABLE_D) | |||
| file(GLOB_RECURSE API_MS_INFER_SRC ${CMAKE_CURRENT_SOURCE_DIR} "model/ms/*.cc" "graph/ms/*.cc") | |||
| file(GLOB_RECURSE API_MS_INFER_SRC ${CMAKE_CURRENT_SOURCE_DIR} "python_utils.cc" "model/ms/*.cc" "graph/ms/*.cc") | |||
| endif () | |||
| set(MSLIB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/types.cc | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/context.cc | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/cell.cc | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/serialization.cc | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/python_utils.cc | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/graph/graph.cc | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/graph/graph_data.cc | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/model/model.cc | |||
| @@ -219,7 +219,6 @@ Status AclGraphImpl::Load() { | |||
| Status AclGraphImpl::ConvertToOM() { | |||
| MS_LOG(INFO) << "Start convert to om model."; | |||
| RegAllOpFromPython(); | |||
| if (graph_ == nullptr) { | |||
| MS_LOG(ERROR) << "Invalid graph_ is null."; | |||
| return FAILED; | |||
| @@ -15,6 +15,7 @@ | |||
| */ | |||
| #include "cxx_api/graph/acl/model_process.h" | |||
| #include <sys/time.h> | |||
| #include <algorithm> | |||
| #include <map> | |||
| #include "utils/utils.h" | |||
| @@ -345,7 +346,18 @@ Status ModelProcess::PredictFromHost(const std::vector<Buffer> &inputs, std::vec | |||
| DestroyInputsDataset(); | |||
| return ret; // forward status error | |||
| } | |||
| struct timeval start_time; | |||
| struct timeval end_time; | |||
| (void)gettimeofday(&start_time, nullptr); | |||
| acl_ret = aclmdlExecute(model_id_, inputs_, outputs_); | |||
| (void)gettimeofday(&end_time, nullptr); | |||
| constexpr uint64_t kUSecondInSecond = 1000000; | |||
| uint64_t cost = | |||
| (kUSecondInSecond * static_cast<uint64_t>(end_time.tv_sec) + static_cast<uint64_t>(end_time.tv_usec)) - | |||
| (kUSecondInSecond * static_cast<uint64_t>(start_time.tv_sec) + static_cast<uint64_t>(start_time.tv_usec)); | |||
| MS_LOG(INFO) << "Model execute in " << cost << " us"; | |||
| DestroyInputsDataset(); | |||
| if (acl_ret != ACL_ERROR_NONE) { | |||
| MS_LOG(ERROR) << "Execute Model Failed"; | |||
| @@ -72,12 +72,16 @@ MsGraphImpl::MsGraphImpl() | |||
| outputs_(), | |||
| input_names_(), | |||
| output_names_(), | |||
| init_flag_(false), | |||
| load_flag_(false) {} | |||
| MsGraphImpl::~MsGraphImpl() { (void)FinalizeEnv(); } | |||
| Status MsGraphImpl::InitEnv() { | |||
| RegAllOpFromPython(); | |||
| if (init_flag_) { | |||
| return SUCCESS; | |||
| } | |||
| RegAllOp(); | |||
| auto ms_context = MsContext::GetInstance(); | |||
| if (ms_context == nullptr) { | |||
| MS_LOG(ERROR) << "Get Context failed!"; | |||
| @@ -100,12 +104,16 @@ Status MsGraphImpl::InitEnv() { | |||
| } | |||
| session_impl_->Init(device_id_); | |||
| init_flag_ = true; | |||
| return SUCCESS; | |||
| } | |||
| Status MsGraphImpl::FinalizeEnv() { | |||
| if (!init_flag_) { | |||
| return SUCCESS; | |||
| } | |||
| MS_LOG_INFO << "Start finalize env"; | |||
| pybind11::gil_scoped_acquire acquire; | |||
| session::ExecutorManager::Instance().Clear(); | |||
| device::KernelRuntimeManager::Instance().ClearRuntimeResource(); | |||
| auto ms_context = MsContext::GetInstance(); | |||
| @@ -117,6 +125,8 @@ Status MsGraphImpl::FinalizeEnv() { | |||
| MS_LOG(ERROR) << "CloseTsd failed!"; | |||
| return FAILED; | |||
| } | |||
| init_flag_ = false; | |||
| MS_LOG(INFO) << "End finalize env"; | |||
| return SUCCESS; | |||
| } | |||
| @@ -125,7 +135,6 @@ Status MsGraphImpl::CompileGraph(const std::shared_ptr<FuncGraph> &funcGraphPtr) | |||
| MS_ASSERT(session_impl_ != nullptr); | |||
| try { | |||
| graph_id_ = session_impl_->CompileGraph(NOT_NULL(funcGraphPtr)); | |||
| pybind11::gil_scoped_release gil_release; | |||
| return SUCCESS; | |||
| } catch (std::exception &e) { | |||
| MS_LOG(ERROR) << "CompileGraph failed: " << e.what(); | |||
| @@ -59,6 +59,7 @@ class MsGraphImpl : public GraphCell::GraphImpl { | |||
| std::vector<tensor::TensorPtr> outputs_; | |||
| std::vector<std::string> input_names_; | |||
| std::vector<std::string> output_names_; | |||
| bool init_flag_; | |||
| bool load_flag_; | |||
| }; | |||
| } // namespace mindspore::api | |||
| @@ -25,7 +25,6 @@ API_FACTORY_REG(ModelImpl, Ascend310, AclModel); | |||
| Status AclModel::Build(const std::map<std::string, std::string> &options_map) { | |||
| MS_LOG(INFO) << "Start build model."; | |||
| MS_EXCEPTION_IF_NULL(graph_); | |||
| RegAllOpFromPython(); | |||
| std::unique_ptr<AclModelOptions> options = std::make_unique<AclModelOptions>(options_map); | |||
| std::string options_str = GenerateOptionsStr(options_map); | |||
| MS_EXCEPTION_IF_NULL(options); | |||
| @@ -15,6 +15,7 @@ | |||
| */ | |||
| #include "cxx_api/model/acl/acl_model_options.h" | |||
| #include <memory> | |||
| #include "utils/log_adapter.h" | |||
| #include "external/ge/ge_api_types.h" | |||
| namespace mindspore::api { | |||
| @@ -27,40 +28,45 @@ static std::string ParseOption(const std::map<std::string, std::string> &options | |||
| } | |||
| AclModelOptions::AclModelOptions(const std::map<std::string, std::string> &options) { | |||
| dump_cfg_path = ParseOption(options, kModelOptionDumpCfgPath); | |||
| dvpp_cfg_path = ParseOption(options, kModelOptionDvppCfgPath); | |||
| output_node = ParseOption(options, kModelOptionOutputNode); | |||
| // to acl | |||
| insert_op_cfg_path = ParseOption(options, kModelOptionInsertOpCfgPath); | |||
| input_format = ParseOption(options, kModelOptionInputFormat); | |||
| input_shape = ParseOption(options, kModelOptionInputShape); | |||
| dynamic_batch_size = ParseOption(options, kModelOptionInputShape); | |||
| dynamic_image_size = ParseOption(options, kModelOptionInputShape); | |||
| dynamic_dims = ParseOption(options, kModelOptionInputShape); | |||
| serial_nodes_name = ParseOption(options, kModelOptionSerialInput); | |||
| output_type = ParseOption(options, kModelOptionOutputType); | |||
| precision_mode = ParseOption(options, kModelOptionPrecisionMode); | |||
| op_select_impl_mode = ParseOption(options, kModelOptionOpSelectImplMode); | |||
| } | |||
| std::map<std::string, std::string> AclModelOptions::GenAclOptions() const { | |||
| const std::map<std::string const *, std::string> acl_options_map = { | |||
| {&insert_op_cfg_path, ge::ir_option::INSERT_OP_FILE}, | |||
| {&input_format, ge::ir_option::INPUT_FORMAT}, | |||
| {&input_shape, ge::ir_option::INPUT_SHAPE}, | |||
| {&dynamic_batch_size, ge::ir_option::DYNAMIC_BATCH_SIZE}, | |||
| {&dynamic_image_size, ge::ir_option::DYNAMIC_IMAGE_SIZE}, | |||
| {&dynamic_dims, ge::ir_option::DYNAMIC_DIMS}, | |||
| {&serial_nodes_name, ge::ir_option::INPUT_FP16_NODES}, | |||
| {&output_type, ge::ir_option::OUTPUT_TYPE}, | |||
| std::tuple<std::map<std::string, std::string>, std::map<std::string, std::string>> AclModelOptions::GenAclOptions() | |||
| const { | |||
| const std::map<std::string const *, std::string> init_options_map = { | |||
| {&op_select_impl_mode, ge::ir_option::OP_SELECT_IMPL_MODE}, | |||
| {&soc_version, ge::ir_option::SOC_VERSION}, | |||
| }; | |||
| std::map<std::string, std::string> acl_options; | |||
| for (auto [ms_option, acl_option_key] : acl_options_map) { | |||
| const std::map<std::string const *, std::string> build_options_map = { | |||
| {&insert_op_cfg_path, ge::ir_option::INSERT_OP_FILE}, {&input_format, ge::ir_option::INPUT_FORMAT}, | |||
| {&input_shape, ge::ir_option::INPUT_SHAPE}, {&output_type, ge::ir_option::OUTPUT_TYPE}, | |||
| {&precision_mode, ge::ir_option::PRECISION_MODE}, | |||
| }; | |||
| std::map<std::string, std::string> init_options; | |||
| std::map<std::string, std::string> build_options; | |||
| for (auto [ms_option, acl_option_key] : init_options_map) { | |||
| if (ms_option == nullptr || ms_option->empty()) { | |||
| continue; | |||
| } | |||
| acl_options.emplace(acl_option_key, *ms_option); | |||
| MS_LOG(INFO) << "Option " << acl_option_key << " : " << *ms_option; | |||
| init_options.emplace(acl_option_key, *ms_option); | |||
| } | |||
| return acl_options; | |||
| } | |||
| for (auto [ms_option, acl_option_key] : build_options_map) { | |||
| if (ms_option == nullptr || ms_option->empty()) { | |||
| continue; | |||
| } | |||
| MS_LOG(INFO) << "Option " << acl_option_key << " : " << *ms_option; | |||
| build_options.emplace(acl_option_key, *ms_option); | |||
| } | |||
| return {init_options, build_options}; | |||
| } | |||
| } // namespace mindspore::api | |||
| @@ -19,28 +19,27 @@ | |||
| #include <vector> | |||
| #include <string> | |||
| #include <map> | |||
| #include <tuple> | |||
| #include "include/api/types.h" | |||
| #include "include/api/status.h" | |||
| namespace mindspore::api { | |||
| struct AclModelOptions { | |||
| std::string dump_cfg_path; | |||
| std::string dvpp_cfg_path; | |||
| std::string output_node; // todo: at convert.cc::BuildGraph(), no atc options | |||
| // build options | |||
| std::string insert_op_cfg_path; | |||
| std::string input_format; | |||
| std::string input_shape; | |||
| std::string dynamic_batch_size; | |||
| std::string dynamic_image_size; | |||
| std::string dynamic_dims; | |||
| std::string serial_nodes_name; | |||
| std::string output_type; | |||
| std::string precision_mode; | |||
| std::string op_select_impl_mode; | |||
| std::string soc_version = "Ascend310"; | |||
| explicit AclModelOptions(const std::map<std::string, std::string> &options); | |||
| ~AclModelOptions() = default; | |||
| std::map<std::string, std::string> GenAclOptions() const; | |||
| // return tuple<init_options, build_options> | |||
| std::tuple<std::map<std::string, std::string>, std::map<std::string, std::string>> GenAclOptions() const; | |||
| }; | |||
| } // namespace mindspore::api | |||
| @@ -131,17 +131,16 @@ transform::DfGraphPtr ModelConverter::ConvertFuncGraphToAIR(const FuncGraphPtr & | |||
| } | |||
| Buffer ModelConverter::BuildAirModel(const transform::DfGraphPtr &graph, | |||
| const std::map<std::string, std::string> &acl_options) { | |||
| const std::map<std::string, std::string> &init_options, | |||
| const std::map<std::string, std::string> &build_options) { | |||
| ge::ModelBufferData model; | |||
| auto ge_options = acl_options; | |||
| ge_options.emplace(ge::ir_option::SOC_VERSION, "Ascend310"); | |||
| auto ret = ge::aclgrphBuildInitialize(ge_options); | |||
| auto ret = ge::aclgrphBuildInitialize(init_options); | |||
| if (ret != ge::SUCCESS) { | |||
| MS_LOG(ERROR) << "Call aclgrphBuildInitialize fail."; | |||
| return Buffer(); | |||
| } | |||
| ret = ge::aclgrphBuildModel(*graph, acl_options, model); | |||
| ret = ge::aclgrphBuildModel(*graph, build_options, model); | |||
| if (ret != ge::SUCCESS) { | |||
| MS_LOG(ERROR) << "Call aclgrphBuildModel fail."; | |||
| return Buffer(); | |||
| @@ -290,7 +289,6 @@ Buffer ModelConverter::LoadAscendIR(const Buffer &model_data) { | |||
| } | |||
| Buffer ModelConverter::LoadMindIRInner(const FuncGraphPtr &func_graph) { | |||
| RegAllOpFromPython(); | |||
| if (func_graph == nullptr) { | |||
| MS_LOG(ERROR) << "Convert MindIR to FuncGraph failed."; | |||
| return Buffer(); | |||
| @@ -302,17 +300,17 @@ Buffer ModelConverter::LoadMindIRInner(const FuncGraphPtr &func_graph) { | |||
| return Buffer(); | |||
| } | |||
| std::map<std::string, std::string> acl_options; | |||
| std::map<std::string, std::string> init_options; | |||
| std::map<std::string, std::string> build_options; | |||
| if (options_ != nullptr) { | |||
| acl_options = options_->GenAclOptions(); | |||
| std::tie(init_options, build_options) = options_->GenAclOptions(); | |||
| } | |||
| auto om_data = BuildAirModel(df_graph, acl_options); | |||
| auto om_data = BuildAirModel(df_graph, init_options, build_options); | |||
| return om_data; | |||
| } | |||
| Buffer ModelConverter::LoadAscendIRInner(const Buffer &model_data) { | |||
| RegAllOpFromPython(); | |||
| ge::Model load_model = ge::Model("loadmodel", "version2"); | |||
| ge::Status ret = | |||
| ge::Model::Load(reinterpret_cast<const uint8_t *>(model_data.Data()), model_data.DataSize(), load_model); | |||
| @@ -327,12 +325,13 @@ Buffer ModelConverter::LoadAscendIRInner(const Buffer &model_data) { | |||
| return Buffer(); | |||
| } | |||
| std::map<std::string, std::string> acl_options; | |||
| std::map<std::string, std::string> init_options; | |||
| std::map<std::string, std::string> build_options; | |||
| if (options_ != nullptr) { | |||
| acl_options = options_->GenAclOptions(); | |||
| std::tie(init_options, build_options) = options_->GenAclOptions(); | |||
| } | |||
| auto om_data = BuildAirModel(df_graph, acl_options); | |||
| auto om_data = BuildAirModel(df_graph, init_options, build_options); | |||
| return om_data; | |||
| } | |||
| } // namespace mindspore::api | |||
| @@ -39,7 +39,8 @@ class ModelConverter { | |||
| private: | |||
| transform::DfGraphPtr ConvertFuncGraphToAIR(const FuncGraphPtr &anf_graph); | |||
| Buffer BuildAirModel(const transform::DfGraphPtr &graph, const std::map<std::string, std::string> &acl_options); | |||
| Buffer BuildAirModel(const transform::DfGraphPtr &graph, const std::map<std::string, std::string> &init_options, | |||
| const std::map<std::string, std::string> &build_options); | |||
| AclModelOptions *options_; | |||
| Buffer LoadMindIRInner(const FuncGraphPtr &func_graph); | |||
| @@ -14,25 +14,23 @@ | |||
| * limitations under the License. | |||
| */ | |||
| #include "cxx_api/python_utils.h" | |||
| #include <dlfcn.h> | |||
| #include <mutex> | |||
| #include <vector> | |||
| #include <memory> | |||
| #include <string> | |||
| #include <fstream> | |||
| #include "mindspore/core/utils/ms_context.h" | |||
| #include "pybind11/pybind11.h" | |||
| #include "backend/kernel_compiler/oplib/oplib.h" | |||
| namespace py = pybind11; | |||
| namespace mindspore::api { | |||
| void RegAllOpFromPython() { | |||
| static std::mutex init_mutex; | |||
| static bool Initialized = false; | |||
| static std::mutex init_mutex; | |||
| static bool Initialized = false; | |||
| std::lock_guard<std::mutex> lock(init_mutex); | |||
| if (Initialized) { | |||
| return; | |||
| } | |||
| Initialized = true; | |||
| namespace mindspore::api { | |||
| static void RegAllOpFromPython() { | |||
| MsContext::GetInstance()->set_param<int>(MS_CTX_EXECUTION_MODE, kGraphMode); | |||
| Py_Initialize(); | |||
| auto c_expression = PyImport_ImportModule("mindspore._c_expression"); | |||
| @@ -61,5 +59,64 @@ void RegAllOpFromPython() { | |||
| Py_DECREF(c_expression); | |||
| } | |||
| static bool RegAllOpFromFile() { | |||
| Dl_info info; | |||
| int dl_ret = dladdr(reinterpret_cast<void *>(RegAllOpFromFile), &info); | |||
| if (dl_ret == 0) { | |||
| MS_LOG(INFO) << "Get dladdr failed, skip."; | |||
| return false; | |||
| } | |||
| std::string dir(info.dli_fname); | |||
| MS_LOG(INFO) << "Get library path is " << dir; | |||
| auto split_pos = dir.find_last_of('/'); | |||
| if (dir.empty() || split_pos == std::string::npos) { | |||
| MS_LOG(INFO) << "Missing op config file, skip."; | |||
| return false; | |||
| } | |||
| dir = dir.substr(0, split_pos) + "/../config/op_info.config"; | |||
| if (dir.size() >= PATH_MAX) { | |||
| MS_LOG(ERROR) << "Op info path is invalid: " << dir; | |||
| return false; | |||
| } | |||
| char real_path_mem[PATH_MAX] = {0}; | |||
| if (realpath(common::SafeCStr(dir), real_path_mem) == nullptr) { | |||
| MS_LOG(ERROR) << "Op info path is invalid: " << dir; | |||
| return false; | |||
| } | |||
| std::string real_path(real_path_mem); | |||
| MS_LOG(INFO) << "Start to read op info from local file " << real_path; | |||
| std::ifstream file(real_path); | |||
| if (!file.is_open()) { | |||
| MS_LOG(ERROR) << "Find op info file failed."; | |||
| return false; | |||
| } | |||
| std::string line; | |||
| while (getline(file, line)) { | |||
| if (!line.empty()) { | |||
| (void)kernel::OpLib::RegOp(line, ""); | |||
| } | |||
| } | |||
| MS_LOG(INFO) << "End"; | |||
| return true; | |||
| } | |||
| void RegAllOp() { | |||
| std::lock_guard<std::mutex> lock(init_mutex); | |||
| if (Initialized) { | |||
| return; | |||
| } | |||
| bool ret = RegAllOpFromFile(); | |||
| if (!ret) { | |||
| MS_LOG(INFO) << "Reg all op from file failed, start to reg from python."; | |||
| RegAllOpFromPython(); | |||
| } | |||
| Initialized = true; | |||
| } | |||
| bool PythonIsInited() { return Py_IsInitialized() != 0; } | |||
| } // namespace mindspore::api | |||
| @@ -17,10 +17,8 @@ | |||
| #ifndef MINDSPORE_CCSRC_CXXAPI_PYTHON_UTILS_H | |||
| #define MINDSPORE_CCSRC_CXXAPI_PYTHON_UTILS_H | |||
| #include "pybind11/pybind11.h" | |||
| namespace mindspore::api { | |||
| void RegAllOpFromPython(); | |||
| void RegAllOp(); | |||
| bool PythonIsInited(); | |||
| } // namespace mindspore::api | |||
| @@ -133,6 +133,7 @@ package_data = { | |||
| 'lib/*.a', | |||
| '.commit_id', | |||
| 'ms_serving', | |||
| 'config/*' | |||
| 'include/*', | |||
| 'include/*/*', | |||
| 'include/*/*/*', | |||
| @@ -8,4 +8,4 @@ include_directories(${CUDA_INCLUDE_DIRS}) | |||
| file(GLOB_RECURSE CXX_ST_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cc) | |||
| add_executable(st_tests ${CXX_ST_SRC}) | |||
| target_link_libraries(st_tests PRIVATE mindspore_shared_lib mindspore::gtest) | |||
| target_link_libraries(st_tests PRIVATE mindspore_shared_lib mindspore::gtest) | |||