text: /**
   * Copyright 2019 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 "transform/graph_ir/graph_runner.h"
  #include <algorithm>
  #include <string>
  #include <memory>
  #include "utils/log_adapter.h"
  #include "utils/config_manager.h"
  #include "sys/time.h"
  #include "utils/callbacks.h"
  #include "utils/utils.h"
  #include "./common.h"
  #ifdef ENABLE_GE
  #include "utils/callbacks_ge.h"
  #endif
  
  #ifdef NO_GE_CLIENT
  namespace ge {
  Session::Session(const std::map<std::string, std::string> &options) {
    if (options.empty()) {
      MS_LOG(ERROR) << "session input options is empty";
    }
    sessionId_ = 0;
  }
  Session::~Session() {}
  }  // namespace ge
  #endif
  
  namespace mindspore {
  namespace transform {
  std::shared_ptr<ge::Session> GraphRunner::NewSession(const SessionOptions &sess_options) {
    std::shared_ptr<ge::Session> ret = std::make_shared<ge::Session>(sess_options);
    if (ret == nullptr) {
      MS_LOG(ERROR) << "Create GE session failed";
      return nullptr;
    }
    MS_LOG(INFO) << "Create new GE session success";
    return ret;
  }
  
  GraphRunner::GraphRunner(const GraphRunnerOptions &options)
      : options_(options), graph_manager_(DfGraphManager::GetInstance()) {
    if (ConfigManager::GetInstance().parallel_strategy() == ParallelStrategy::ONE_DEVICE) {
      MS_LOG(INFO) << "ME run in ONE_DEVICE strategy mode";
    }
  
    if (options.sess_ptr != nullptr) {
      sess_ = options.sess_ptr;
    } else {
      sess_ = NewSession(options.options);
      if (sess_ == nullptr) {
        MS_LOG(EXCEPTION) << "GraphRunner initialize failed!!";
        return;
      }
    }
  
  #if (defined ENABLE_GE)
    // register the callback function
    if (sess_->RegisterCallBackFunc(callbacks::kCheckPoint, callbacks::CheckpointSaveCallback) != ge::GRAPH_SUCCESS) {
      MS_LOG(EXCEPTION) << "register callback failed!";
      return;
    }
  
    if (sess_->RegisterCallBackFunc(callbacks::kSummary, callbacks::SummarySaveCallback) != ge::GRAPH_SUCCESS) {
      MS_LOG(EXCEPTION) << "register summary callback failed!";
      return;
    }
  #endif
  
    std::vector<DfGraphWrapperPtr> wrappers = graph_manager_.GetAllGraphs();
    if (wrappers.empty()) {
      MS_LOG(INFO) << "The GraphManager is empty!!";
      return;
    }
  
  #ifdef ENABLE_GE
    for (auto &it : wrappers) {
      std::set<string> saved_graph = graph_manager_.GetSavedGraphs();
      auto iter_find = saved_graph.find(std::to_string(it->id_));
      if (iter_find != saved_graph.end()) {
        continue;
      }
      MS_LOG(INFO) << "Add the graph " << (*it).name_ << " to GE, it's id is: " << (*it).id_;
      graph_manager_.AddSavedGraphs(std::to_string(it->id_));
      (void)sess_->AddGraph(it->id_, *(it->graph_ptr_), it->options_);
    }
  #endif
  }
  
  Status GraphRunner::RunGraph(const RunOptions &options, const std::vector<GeTensorPtr> &inputs,
                               std::vector<GeTensorPtr> *outputs) {
    std::string name = options.name;
    if (name.empty()) {
      MS_LOG(ERROR) << "The graph name is null";
      return Status::INVALID_ARGUMENT;
    }
  
    DfGraphWrapperPtr wrap_ptr = graph_manager_.GetGraphByName(name);
    if (wrap_ptr == nullptr) {
      MS_LOG(ERROR) << "Get graph form DfGraphManager failed!";
      return Status::NOT_FOUND;
    }
  
    if (wrap_ptr->graph_ptr_ == nullptr) {
      MS_LOG(WARNING) << "The graph is null";
      return Status::NOT_FOUND;
    }
  
    // call ge::RunGraph() to exec a graph;
    std::vector<GeTensor> ge_inputs;
    std::vector<GeTensor> ge_outputs;
  
    (void)std::transform(inputs.begin(), inputs.end(), std::back_inserter(ge_inputs),
                         [](const GeTensorPtr &i) { return *i; });
  
    MS_LOG(INFO) << "Run the graph in GE with " << ge_inputs.size() << " inputs";
  
    struct timeval start_time, end_time;
    (void)gettimeofday(&start_time, nullptr);
  
  #ifdef ENABLE_GE
    if (sess_ == nullptr) {
      MS_LOG(ERROR) << "The GE session is null, can't run the graph!";
      return Status::FAILED;
    }
  
    // The information of some nodes could be changed after fusion in some cases
    // Therefore a graph needs to be rebuilt in above situation
    if (sess_->IsGraphNeedRebuild(wrap_ptr->id_)) {
      sess_->RemoveGraph(wrap_ptr->id_);
      sess_->AddGraph(wrap_ptr->id_, *(wrap_ptr->graph_ptr_), wrap_ptr->options_);
    }
  
    ge::Status ret = sess_->RunGraph(wrap_ptr->id_, ge_inputs, ge_outputs);
    if (ret != ge::GRAPH_SUCCESS) {
      MS_LOG(ERROR) << "Call GE RunGraph Failed, ret is: " << ret;
      return Status::FAILED;
    }
  #else
    ge_outputs.swap(ge_inputs);
  #endif
  
    (void)gettimeofday(&end_time, nullptr);
    const uint64_t kUSecondInSecond = 1000000;
    uint64_t cost = kUSecondInSecond * static_cast<uint64_t>(end_time.tv_sec - start_time.tv_sec);
    cost += static_cast<uint64_t>(end_time.tv_usec - start_time.tv_usec);
    MS_LOG(INFO) << "Call GE RunGraph Success in " << cost << " us, the GE outputs num is: " << ge_outputs.size();
  
    (void)std::transform(ge_outputs.begin(), ge_outputs.end(), std::back_inserter(*outputs),
                         [](const GeTensor &ge_tensor) { return std::make_shared<GeTensor>(ge_tensor); });
  
    return Status::SUCCESS;
  }
  
  Status GraphRunner::RunGraph(const RunOptions &options, const std::vector<MeTensorPtr> &inputs,
                               std::vector<MeTensorPtr> *const outputs) {
    std::vector<GeTensorPtr> ge_inputs;
    for (auto it : inputs) {
      MS_LOG(INFO) << "inputs tensor's data size is: " << (*it).DataSize();
      auto shape = (*it).shape();
      std::string shape_str;
      for (const auto &elem : shape) {
        shape_str += std::to_string(elem);
        shape_str += " ";
      }
      MS_LOG(INFO) << "inputs tensor's shape is: { " << shape_str << "}";
  
      auto ge_tensor_ptr = TransformUtil::ConvertTensor(it, kOpFormat_NCHW);
      if (ge_tensor_ptr != nullptr) {
        ge_inputs.emplace_back(ge_tensor_ptr);
      } else {
        MS_LOG(INFO) << "Convert input Me tensor to Ge tensor failed. Abort this graph";
        return Status::FAILED;
      }
    }
  
    std::vector<GeTensorPtr> ge_outputs;
    Status ret;
    {
      // Release GIL before calling into (potentially long-running) C++ code
      py::gil_scoped_release release;
      ret = RunGraph(options, ge_inputs, &ge_outputs);
    }
    if (ret != Status::SUCCESS) {
      return ret;
    } else {
      // conver GeTensor to MeTensor
      for (auto &it : ge_outputs) {
        auto tensor = TransformUtil::ConvertGeTensor(it);
        if (tensor != nullptr) {
          outputs->emplace_back(tensor);
        }
      }
      MS_LOG(INFO) << "Return Me tensor outputs num is: " << outputs->size();
      return Status::SUCCESS;
    }
  }
  }  // namespace transform
  }  // namespace mindspore
  