From 3cc573b5b8fdb7b8f8de7b5e6c0bd22f088540c2 Mon Sep 17 00:00:00 2001 From: zhupuxu Date: Wed, 10 Mar 2021 16:22:47 +0800 Subject: [PATCH] zero copy Signed-off-by: zhupuxu --- .../ccsrc/cxx_api/graph/acl/model_process.cc | 28 +-- .../ccsrc/cxx_api/graph/acl/model_process.h | 1 + tests/st/cpp/data/dataset/aipp_resnet50.cfg | 27 +++ tests/st/cpp/model/test_zero_copy.cc | 159 ++++++++++++++++++ 4 files changed, 205 insertions(+), 10 deletions(-) create mode 100644 tests/st/cpp/data/dataset/aipp_resnet50.cfg create mode 100644 tests/st/cpp/model/test_zero_copy.cc diff --git a/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc b/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc index f70346577e..9800934571 100644 --- a/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc +++ b/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc @@ -102,7 +102,7 @@ Status ModelProcess::ConstructTensors(const std::vector &acl_tens for (size_t i = 0; i < acl_tensor_list.size(); ++i) { tensor_list->emplace_back(names[i], data_types[i], shapes[i], nullptr, mem_sizes[i]); auto ret = aclrtMemcpy((*tensor_list)[i].MutableData(), (*tensor_list)[i].DataSize(), - acl_tensor_list[i].device_data, acl_tensor_list[i].buffer_size, kind); + acl_tensor_list[i].cur_device_data, acl_tensor_list[i].buffer_size, kind); if (ret != ACL_ERROR_NONE) { MS_LOG(ERROR) << "Memcpy input " << i << " from " << (is_run_on_device_ ? "host" : "device") << " to host failed, memory size " << acl_tensor_list[i].buffer_size; @@ -164,7 +164,8 @@ Status ModelProcess::InitInputsBuffer() { MS_LOG(WARNING) << "Get name of input " << i << " failed."; } MS_LOG(INFO) << "Name of input " << i << " is " << input_name; - input_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, data_type, shape, input_name}); + input_infos_.emplace_back( + AclTensorInfo{data_mem_buffer, data_mem_buffer, buffer_size, data_type, shape, input_name}); } MS_LOG(INFO) << "Create model inputs success"; return kSuccess; @@ -246,7 +247,8 @@ Status ModelProcess::InitOutputsBuffer() { MS_LOG(WARNING) << "Get name of output " << i << " failed."; } MS_LOG(INFO) << "Name of input " << i << " is " << output_name; - output_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, data_type, shape, output_name}); + output_infos_.emplace_back( + AclTensorInfo{data_mem_buffer, data_mem_buffer, buffer_size, data_type, shape, output_name}); } MS_LOG(INFO) << "Create model output success"; return kSuccess; @@ -381,17 +383,23 @@ Status ModelProcess::CheckAndInitInput(const std::vector &inputs) { } // copy inputs for (size_t i = 0; i < input_infos_.size(); ++i) { - const auto &info = input_infos_[i]; + auto &info = input_infos_[i]; auto input = inputs[i]; - const void *data = input.MutableData(); + void *data = input.MutableData(); void *input_buffer = nullptr; if (!is_run_on_device_) { - ret = aclrtMemcpy(info.device_data, info.buffer_size, data, input.DataSize(), ACL_MEMCPY_HOST_TO_DEVICE); - if (ret != ACL_ERROR_NONE) { - MS_LOG(ERROR) << "Acl memcpy input " << i << " data to device failed, buffer size " << input.DataSize(); - return kMCDeviceError; + if (input.IsDevice()) { + info.cur_device_data = data; + input_buffer = info.cur_device_data; + } else { + info.cur_device_data = info.device_data; + ret = aclrtMemcpy(info.cur_device_data, info.buffer_size, data, input.DataSize(), ACL_MEMCPY_HOST_TO_DEVICE); + if (ret != ACL_ERROR_NONE) { + MS_LOG(ERROR) << "Acl memcpy input " << i << " data to device failed, buffer size " << input.DataSize(); + return kMCDeviceError; + } + input_buffer = info.cur_device_data; } - input_buffer = info.device_data; } else { input_buffer = const_cast(data); } diff --git a/mindspore/ccsrc/cxx_api/graph/acl/model_process.h b/mindspore/ccsrc/cxx_api/graph/acl/model_process.h index 6ebddd97a8..342170ecbd 100644 --- a/mindspore/ccsrc/cxx_api/graph/acl/model_process.h +++ b/mindspore/ccsrc/cxx_api/graph/acl/model_process.h @@ -27,6 +27,7 @@ namespace mindspore { struct AclTensorInfo { + void *cur_device_data; void *device_data; size_t buffer_size; aclDataType data_type; diff --git a/tests/st/cpp/data/dataset/aipp_resnet50.cfg b/tests/st/cpp/data/dataset/aipp_resnet50.cfg new file mode 100644 index 0000000000..875fce7086 --- /dev/null +++ b/tests/st/cpp/data/dataset/aipp_resnet50.cfg @@ -0,0 +1,27 @@ +aipp_op { + aipp_mode: static + input_format : YUV420SP_U8 + csc_switch : true + rbuv_swap_switch : false + matrix_r0c0 : 256 + matrix_r0c1 : 0 + matrix_r0c2 : 359 + matrix_r1c0 : 256 + matrix_r1c1 : -88 + matrix_r1c2 : -183 + matrix_r2c0 : 256 + matrix_r2c1 : 454 + matrix_r2c2 : 0 + input_bias_0 : 0 + input_bias_1 : 128 + input_bias_2 : 128 + mean_chn_0 : 124 + mean_chn_1 : 116 + mean_chn_2 : 102 + min_chn_0 : 0.0 + min_chn_1 : 0.0 + min_chn_2 : 0.0 + var_reci_chn_0 : 0.017125 + var_reci_chn_1 : 0.017507 + var_reci_chn_2 : 0.017429 +} diff --git a/tests/st/cpp/model/test_zero_copy.cc b/tests/st/cpp/model/test_zero_copy.cc new file mode 100644 index 0000000000..5b13bd7d63 --- /dev/null +++ b/tests/st/cpp/model/test_zero_copy.cc @@ -0,0 +1,159 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include "common/common_test.h" +#include "include/api/types.h" +#include "minddata/dataset/include/execute.h" +#include "minddata/dataset/include/transforms.h" +#include "minddata/dataset/include/vision.h" +#ifdef ENABLE_ACL +#include "minddata/dataset/include/vision_ascend.h" +#endif +#include "minddata/dataset/kernels/tensor_op.h" +#include "include/api/model.h" +#include "include/api/serialization.h" +#include "include/api/context.h" + +using namespace mindspore; +using namespace mindspore::dataset; +using namespace mindspore::dataset::vision; + +class TestZeroCopy : public ST::Common { + public: + TestZeroCopy() {} +}; + +constexpr auto resnet_file = "/home/workspace/mindspore_dataset/mindir/resnet50/resnet50_imagenet.mindir"; +constexpr auto image_path = "/home/workspace/mindspore_dataset/imagenet/imagenet_original/val/n01440764/"; +constexpr auto aipp_path = "./data/dataset/aipp_resnet50.cfg"; + +size_t GetMax(mindspore::MSTensor data); +std::string RealPath(std::string_view path); +DIR *OpenDir(std::string_view dir_name); +std::vector GetAllFiles(std::string_view dir_name); + +TEST_F(TestZeroCopy, TestMindIR) { +#ifdef ENABLE_ACL + // Set context + mindspore::GlobalContext::SetGlobalDeviceTarget(mindspore::kDeviceTypeAscend310); + mindspore::GlobalContext::SetGlobalDeviceID(0); + auto model_context = std::make_shared(); + ModelContext::SetInsertOpConfigPath(model_context,aipp_path); + // Define model + auto graph = mindspore::Serialization::LoadModel(resnet_file, mindspore::ModelType::kMindIR); + mindspore::Model resnet50(mindspore::GraphCell(graph),model_context); + // Build model + ASSERT_TRUE(resnet50.Build() == kSuccess); + // Get model info + std::vector model_inputs =resnet50.GetInputs(); + ASSERT_EQ(model_inputs.size(), 1); + // Define transform operations + std::shared_ptr decode(new vision::Decode()); + std::shared_ptr resize(new vision::Resize({256})); + std::shared_ptr center_crop(new vision::CenterCrop({224,224})); + mindspore::dataset::Execute Transform({decode,resize,center_crop},MapTargetDevice::kAscend310); + size_t count=0; + // Read images + std::vector images =GetAllFiles(image_path); + for(const auto &image_file:images){ + // prepare input + std::vector inputs; + std::vector outputs; + std::shared_ptr de_tensor; + mindspore::dataset::Tensor::CreateFromFile(image_file, &de_tensor); + auto image = mindspore::MSTensor(std::make_shared(de_tensor)); + // Apply transform on images + Status rc = Transform(image, &image); + ASSERT_TRUE(rc == kSuccess); + inputs.push_back(image); + // infer + ASSERT_TRUE(resnet50.Predict(inputs, &outputs)==kSuccess); + if(GetMax(outputs[0])==0){ + ++count; + } + Transform.DeviceMemoryRelease(); + } + ASSERT_GE(static_cast(count)/images.size()*100.0, 20.0); +#endif +} + +size_t GetMax(mindspore::MSTensor data) { + float max_value = -1; + size_t max_idx = 0; + const float *p = reinterpret_cast(data.MutableData()); + for (size_t i = 0; i < data.DataSize() / sizeof(float); ++i) { + if (p[i] > max_value) { + max_value = p[i]; + max_idx = i; + } + } + return max_idx; +} + +std::string RealPath(std::string_view path) { + char real_path_mem[PATH_MAX] = {0}; + char *real_path_ret = realpath(path.data(), real_path_mem); + if (real_path_ret == nullptr) { + return ""; + } + return std::string(real_path_mem); +} + +DIR *OpenDir(std::string_view dir_name) { + // check the parameter ! + if (dir_name.empty()) { + return nullptr; + } + std::string real_path = RealPath(dir_name); + + // check if dir_name is a valid dir + struct stat s; + lstat(real_path.c_str(), &s); + if (!S_ISDIR(s.st_mode)) { + return nullptr; + } + + DIR *dir; + dir = opendir(real_path.c_str()); + if (dir == nullptr) { + return nullptr; + } + return dir; +} + +std::vector GetAllFiles(std::string_view dir_name) { + struct dirent *filename; + DIR *dir = OpenDir(dir_name); + if (dir == nullptr) { + return {}; + } + /* read all the files in the dir ~ */ + std::vector res; + while ((filename = readdir(dir)) != nullptr) { + std::string d_name = std::string(filename->d_name); + // get rid of "." and ".." + if (d_name == "." || d_name == ".." || filename->d_type != DT_REG) + continue; + res.emplace_back(std::string(dir_name) + "/" + filename->d_name); + } + + std::sort(res.begin(), res.end()); + return res; +}