text: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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.
   */
  
  /*
   * Copyright (c) 2017, Open AI Lab
   * Author: haitao@openailab.com
   */
  #include <unistd.h>
  
  #include <iostream>
  #include <functional>
  #include <algorithm>
  #include <fstream>
  #include <iomanip>
  
  #include "tengine_c_api.h"
  #include "common_util.hpp"
  #include "opencv2/imgproc/imgproc.hpp"
  #include "opencv2/highgui/highgui.hpp"
  
  const char* text_file = "./models/mobilenet_deploy.prototxt";
  const char* model_file = "./models/mobilenet.caffemodel";
  const char* image_file = "./tests/images/cat.jpg";
  const char* label_file = "./models/synset_words.txt";
  
  const float channel_mean[3] = {104.007, 116.669, 122.679};
  
  using namespace TEngine;
  
  int repeat_count = 100;
  
  void LoadLabelFile(std::vector<std::string>& result, const char* fname)
  {
      std::ifstream labels(fname);
  
      std::string line;
      while(std::getline(labels, line))
          result.push_back(line);
  }
  
  void get_input_data(const char* image_file, float* input_data, int img_h, int img_w, const float* mean, float scale)
  {
      cv::Mat img = cv::imread(image_file, -1);
  
      if(img.empty())
      {
          std::cerr << "failed to read image file " << image_file << "\n";
          return;
      }
      cv::resize(img, img, cv::Size(img_h, img_w));
      img.convertTo(img, CV_32FC3);
      float* img_data = ( float* )img.data;
      int hw = img_h * img_w;
      for(int h = 0; h < img_h; h++)
          for(int w = 0; w < img_w; w++)
              for(int c = 0; c < 3; c++)
              {
                  input_data[c * hw + h * img_w + w] = (*img_data - mean[c]) * scale;
                  img_data++;
              }
  }
  
  int main(int argc, char* argv[])
  {
      std::string device = "";
      std::string file_path = "";
      char* cpu_list_str = nullptr;
      ;
  
      int res;
  
      while((res = getopt(argc, argv, "p:d:f:r:")) != -1)
      {
          switch(res)
          {
              case 'p':
                  cpu_list_str = optarg;
                  break;
  
              case 'd':
                  device = optarg;
                  break;
  
              case 'f':
                  file_path = optarg;
                  break;
  
              case 'r':
                  repeat_count = strtoul(optarg, NULL, 10);
                  break;
  
              default:
                  break;
          }
      }
  
      int img_h = 224;
      int img_w = 224;
  
      std::string sub_dir = "/repo.log";
  
      std::string filename = "";
      if("" != file_path)
      {
          filename = file_path + sub_dir;
      }
  
      /* prepare input data */
      float* input_data = ( float* )malloc(sizeof(float) * img_h * img_w * 3);
  
      get_input_data(image_file, input_data, img_h, img_w, channel_mean, 0.017);
  
      if(cpu_list_str)
      set_cpu_list(cpu_list_str);
  
      init_tengine();
  
      std::cout << "run-time library version: " << get_tengine_version() << "\n";
  
      if(request_tengine_version("0.9") < 0)
          return -1;
  
      graph_t graph = create_graph(nullptr, "caffe", text_file, model_file);
  
      if(graph == nullptr)
      {
          std::cout << "Create graph0 failed\n";
          std::cout << "errno: " << get_tengine_errno() << "\n";
          return -1;
      }
  
      /* get input tensor */
      int node_idx = 0;
      int tensor_idx = 0;
  
      tensor_t input_tensor = get_graph_input_tensor(graph, node_idx, tensor_idx);
  
      if(input_tensor == nullptr)
      {
          std::printf("Cannot find input tensor,node_idx: %d,tensor_idx: %d\n", node_idx, tensor_idx);
          return -1;
      }
  
      int dims[] = {1, 3, img_h, img_w};
  
      set_tensor_shape(input_tensor, dims, 4);
  
      /* setup input buffer */
  
      if(set_tensor_buffer(input_tensor, input_data, 3 * img_h * img_w * 4) < 0)
      {
          std::printf("Set buffer for tensor failed\n");
          return -1;
      }
  
      if(!device.empty())
          set_graph_device(graph, device.c_str());
  
      /* run the graph */
      int ret_prerun = prerun_graph(graph);
      if(ret_prerun < 0)
      {
          std::printf("prerun failed\n");
          return -1;
      }
  
      run_graph(graph, 1);
  
      // benchmark start here
      printf("REPEAT COUNT= %d\n", repeat_count);
  
      unsigned long start_time = get_cur_time();
  
      for(int i = 0; i < repeat_count; i++)
          run_graph(graph, 1);
  
      unsigned long end_time = get_cur_time();
  
      unsigned long off_time = end_time - start_time;
      std::printf("Repeat [%d] time %.2f us per RUN. used %lu us\n", repeat_count, 1.0f * off_time / repeat_count,
                  off_time);
  
      if(filename != "")
      {
          FILE* fp = fopen(filename.c_str(), "a");
  
          fprintf(fp, "device:%20s,  repeat_count:%5d,  per use_time:%10.2f,", device.c_str(), repeat_count,
                  1.0f * off_time / repeat_count);
          fprintf(fp, "\n");
  
          fclose(fp);
      }
  
      /* get output tensor */
      tensor_t output_tensor = get_graph_output_tensor(graph, node_idx, tensor_idx);
  
      if(output_tensor == nullptr)
      {
          std::printf("Cannot find output tensor , node_idx: %d,tensor_idx: %d\n", node_idx, tensor_idx);
          return -1;
      }
  
      int count = get_tensor_buffer_size(output_tensor) / 4;
  
      float* data = ( float* )(get_tensor_buffer(output_tensor));
      float* end = data + count;
  
      std::vector<float> result(data, end);
  
      std::vector<int> top_N = Argmax(result, 5);
  
      std::vector<std::string> labels;
  
      LoadLabelFile(labels, label_file);
  
      for(unsigned int i = 0; i < top_N.size(); i++)
      {
          int idx = top_N[i];
  
          std::cout << std::fixed << std::setprecision(4) << result[idx] << " - \"";
          std::cout << labels[idx] << "\"\n";
      }
  
      release_graph_tensor(output_tensor);
      release_graph_tensor(input_tensor);
      postrun_graph(graph);
      destroy_graph(graph);
  
      free(input_data);
  
      std::cout << "ALL TEST DONE\n";
  
      release_tengine();
      return 0;
  }
  