• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "tools/benchmark/benchmark_base.h"
18 #include <algorithm>
19 #include <utility>
20 #include <regex>
21 #include <functional>
22 #include "include/context.h"
23 #include "include/ms_tensor.h"
24 #include "include/version.h"
25 #include "schema/model_generated.h"
26 #include "src/common/common.h"
27 #include "src/tensor.h"
28 #ifdef ENABLE_ARM64
29 #include <linux/perf_event.h>
30 #include <sys/ioctl.h>
31 #include <asm/unistd.h>
32 #include <unistd.h>
33 #endif
34 
35 namespace mindspore {
36 namespace lite {
37 constexpr int kThreadNumMin = 1;
38 constexpr int kParallelThreadNumMin = 1;
39 constexpr int kColumnLen = 4;
40 constexpr int kPrintColNum = 5;
41 constexpr int kPrintRowLenMax = 100;
42 
43 constexpr float kInputDataFloatMin = 0.1f;
44 constexpr float kInputDataFloatMax = 1.0f;
45 constexpr double kInputDataDoubleMin = 0.1;
46 constexpr double kInputDataDoubleMax = 1.0;
47 constexpr int64_t kInputDataInt64Min = 0;
48 constexpr int64_t kInputDataInt64Max = 1;
49 constexpr int32_t kInputDataInt32Min = 0;
50 constexpr int32_t kInputDataInt32Max = 1;
51 constexpr int16_t kInputDataInt16Min = 0;
52 constexpr int16_t kInputDataInt16Max = 1;
53 constexpr int16_t kInputDataInt8Min = -127;
54 constexpr int16_t kInputDataInt8Max = 127;
55 constexpr int16_t kInputDataUint8Min = 0;
56 constexpr int16_t kInputDataUint8Max = 254;
57 
58 const std::unordered_map<int, std::string> kTypeIdMap{
59   {kNumberTypeFloat16, "Float16"}, {kNumberTypeFloat, "Float32"},    {kNumberTypeFloat32, "Float32"},
60   {kNumberTypeInt8, "Int8"},       {kNumberTypeInt16, "Int16"},      {kNumberTypeInt, "Int32"},
61   {kNumberTypeInt32, "Int32"},     {kNumberTypeUInt8, "UInt8"},      {kNumberTypeUInt16, "UInt16"},
62   {kNumberTypeUInt, "UInt32"},     {kNumberTypeUInt32, "UInt32"},    {kObjectTypeString, "String"},
63   {kNumberTypeBool, "Bool"},       {kObjectTypeTensorType, "Tensor"}};
64 
65 const std::unordered_map<mindspore::Format, std::string> kTensorFormatMap{
66   {mindspore::NCHW, "NCHW"}, {mindspore::NHWC, "NHWC"},     {mindspore::NHWC4, "NHWC4"}, {mindspore::HWKC, "HWKC"},
67   {mindspore::HWCK, "HWCK"}, {mindspore::KCHW, "KCHW"},     {mindspore::CKHW, "CKHW"},   {mindspore::KHWC, "KHWC"},
68   {mindspore::CHWK, "CHWK"}, {mindspore::HW, "HW"},         {mindspore::HW4, "HW4"},     {mindspore::NC, "NC"},
69   {mindspore::NC4, "NC4"},   {mindspore::NC4HW4, "NC4HW4"}, {mindspore::NCDHW, "NCDHW"}};
70 
GenerateRandomData(size_t size,void * data,int data_type)71 int BenchmarkBase::GenerateRandomData(size_t size, void *data, int data_type) {
72   MS_ASSERT(data != nullptr);
73   switch (data_type) {
74     case kNumberTypeFloat32:
75     case kNumberTypeFloat:
76       FillInputData<float>(size, data, std::uniform_real_distribution<float>(kInputDataFloatMin, kInputDataFloatMax));
77       break;
78     case kNumberTypeFloat64:
79       FillInputData<double>(size, data,
80                             std::uniform_real_distribution<double>(kInputDataDoubleMin, kInputDataDoubleMax));
81       break;
82     case kNumberTypeInt64:
83       FillInputData<int64_t>(size, data,
84                              std::uniform_int_distribution<int64_t>(kInputDataInt64Min, kInputDataInt64Max));
85       break;
86     case kNumberTypeInt:
87     case kNumberTypeInt32:
88       FillInputData<int32_t>(size, data,
89                              std::uniform_int_distribution<int32_t>(kInputDataInt32Min, kInputDataInt32Max));
90       break;
91     case kNumberTypeInt16:
92       FillInputData<int16_t>(size, data,
93                              std::uniform_int_distribution<int16_t>(kInputDataInt16Min, kInputDataInt16Max));
94       break;
95     case kNumberTypeInt8:
96       FillInputData<int8_t>(size, data, std::uniform_int_distribution<int16_t>(kInputDataInt8Min, kInputDataInt8Max));
97       break;
98     case kNumberTypeUInt8:
99       FillInputData<uint8_t>(size, data,
100                              std::uniform_int_distribution<uint16_t>(kInputDataUint8Min, kInputDataUint8Max));
101       break;
102     default:
103       char *casted_data = static_cast<char *>(data);
104       for (size_t i = 0; i < size; i++) {
105         casted_data[i] = static_cast<char>(i);
106       }
107   }
108   return RET_OK;
109 }
110 
LoadInput()111 int BenchmarkBase::LoadInput() {
112   if (flags_->in_data_file_.empty()) {
113     auto status = GenerateInputData();
114     if (status != 0) {
115       std::cerr << "Generate input data error " << status << std::endl;
116       MS_LOG(ERROR) << "Generate input data error " << status;
117       return status;
118     }
119   } else {
120     auto status = ReadInputFile();
121     if (status != 0) {
122       std::cerr << "ReadInputFile error, " << status << std::endl;
123       MS_LOG(ERROR) << "ReadInputFile error, " << status;
124       return status;
125     }
126   }
127   return RET_OK;
128 }
129 
130 // calibData is FP32
ReadCalibData()131 int BenchmarkBase::ReadCalibData() {
132   const char *calib_data_path = flags_->benchmark_data_file_.c_str();
133   // read calib data
134   std::ifstream in_file(calib_data_path);
135   if (!in_file.good()) {
136     std::cerr << "file: " << calib_data_path << " is not exist" << std::endl;
137     MS_LOG(ERROR) << "file: " << calib_data_path << " is not exist";
138     return RET_ERROR;
139   }
140 
141   if (!in_file.is_open()) {
142     std::cerr << "file: " << calib_data_path << " open failed" << std::endl;
143     MS_LOG(ERROR) << "file: " << calib_data_path << " open failed";
144     in_file.close();
145     return RET_ERROR;
146   }
147   MS_LOG(INFO) << "Start reading calibData file";
148   std::string line;
149   std::string tensor_name;
150 
151   while (!in_file.eof()) {
152     getline(in_file, line);
153     std::stringstream string_line1(line);
154     size_t dim = 0;
155     string_line1 >> tensor_name >> dim;
156     std::vector<size_t> dims;
157     for (size_t i = 0; i < dim; i++) {
158       size_t tmp_dim;
159       string_line1 >> tmp_dim;
160       dims.push_back(tmp_dim);
161     }
162     auto ret = ReadTensorData(in_file, tensor_name, dims);
163     if (ret != RET_OK) {
164       MS_LOG(ERROR) << "Read tensor data failed, tensor name: " << tensor_name;
165       return RET_ERROR;
166     }
167   }
168   in_file.close();
169   MS_LOG(INFO) << "Finish reading calibData file";
170   return RET_OK;
171 }
172 
ReadTensorData(std::ifstream & in_file_stream,const std::string & tensor_name,const std::vector<size_t> & dims)173 int BenchmarkBase::ReadTensorData(std::ifstream &in_file_stream, const std::string &tensor_name,
174                                   const std::vector<size_t> &dims) {
175   std::string line;
176   getline(in_file_stream, line);
177   std::stringstream line_stream(line);
178   if (this->benchmark_data_.find(tensor_name) != this->benchmark_data_.end()) {
179     return RET_OK;
180   }
181   std::vector<float> data;
182   std::vector<std::string> strings_data;
183   size_t shape_size = std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<size_t>());
184   if (GetDataTypeByTensorName(tensor_name) == static_cast<int>(kObjectTypeString)) {
185     strings_data.push_back(line);
186     for (size_t i = 1; i < shape_size; i++) {
187       getline(in_file_stream, line);
188       strings_data.push_back(line);
189     }
190   } else {
191     for (size_t i = 0; i < shape_size; i++) {
192       float tmp_data;
193       line_stream >> tmp_data;
194       data.push_back(tmp_data);
195     }
196   }
197   auto *check_tensor = new (std::nothrow) CheckTensor(dims, data, strings_data);
198   if (check_tensor == nullptr) {
199     MS_LOG(ERROR) << "New CheckTensor failed, tensor name: " << tensor_name;
200     return RET_ERROR;
201   }
202   this->benchmark_tensor_names_.push_back(tensor_name);
203   this->benchmark_data_.insert(std::make_pair(tensor_name, check_tensor));
204   return RET_OK;
205 }
206 
CompareStringData(const std::string & name,const std::vector<std::string> & calib_strings,const std::vector<std::string> & output_strings)207 int BenchmarkBase::CompareStringData(const std::string &name, const std::vector<std::string> &calib_strings,
208                                      const std::vector<std::string> &output_strings) {
209   size_t compare_num = std::min(calib_strings.size(), output_strings.size());
210   size_t print_num = std::min(compare_num, static_cast<size_t>(kNumPrintMin));
211 
212   std::cout << "Data of node " << name << " : " << std::endl;
213   for (size_t i = 0; i < compare_num; i++) {
214     if (i < print_num) {
215       std::cout << "  " << output_strings[i] << std::endl;
216     }
217     if (calib_strings[i] != output_strings[i]) {
218       MS_LOG(ERROR) << "Compare failed, index: " << i;
219       std::cerr << "Compare failed, index: " << i << std::endl;
220       return RET_ERROR;
221     }
222   }
223   return RET_OK;
224 }
225 
InitInputDataList()226 void BenchmarkFlags::InitInputDataList() {
227   if (in_data_file_.empty()) {
228     input_data_list_ = {};
229     return;
230   }
231   std::regex re{"[\\s,]+"};
232   input_data_list_ = std::vector<std::string>{
233     std::sregex_token_iterator(in_data_file_.begin(), in_data_file_.end(), re, -1), std::sregex_token_iterator()};
234 }
235 
InitResizeDimsList()236 void BenchmarkFlags::InitResizeDimsList() {
237   std::string content = this->resize_dims_in_;
238   if (content.empty()) {
239     return;
240   }
241   std::vector<int> shape;
242   auto shape_strs = StrSplit(content, std::string(DELIM_COLON));
243   for (const auto &shape_str : shape_strs) {
244     shape.clear();
245     auto dim_strs = StrSplit(shape_str, std::string(DELIM_COMMA));
246     std::cout << "Resize Dims: ";
247     for (const auto &dim_str : dim_strs) {
248       std::cout << dim_str << " ";
249       shape.emplace_back(static_cast<int>(std::stoi(dim_str)));
250     }
251     std::cout << std::endl;
252     this->resize_dims_.emplace_back(shape);
253   }
254 }
255 
CheckThreadNumValid()256 int BenchmarkBase::CheckThreadNumValid() {
257   if (this->flags_->num_threads_ < kThreadNumMin) {
258     MS_LOG(ERROR) << "numThreads:" << this->flags_->num_threads_ << " must be greater than 0";
259     std::cerr << "numThreads:" << this->flags_->num_threads_ << " must be greater than 0" << std::endl;
260     return RET_ERROR;
261   }
262 
263   if (flags_->enable_parallel_) {
264     if (flags_->num_threads_ < kParallelThreadNumMin) {
265       MS_LOG(ERROR) << "enable parallel need more than 1 thread.";
266       std::cerr << "enable parallel need more than 1 thread." << std::endl;
267       return RET_ERROR;
268     }
269   }
270   return RET_OK;
271 }
272 
CheckDeviceTypeValid()273 int BenchmarkBase::CheckDeviceTypeValid() {
274   if (flags_->device_ != "CPU" && flags_->device_ != "GPU" && flags_->device_ != "NPU" &&
275       flags_->device_ != "Ascend310" && flags_->device_ != "NNRT") {
276     MS_LOG(ERROR) << "Device type:" << flags_->device_ << " is not supported.";
277     std::cerr << "Device type:" << flags_->device_ << " is not supported." << std::endl;
278     return RET_ERROR;
279   }
280   return RET_OK;
281 }
282 
InitDumpConfigFromJson(char * path)283 int BenchmarkBase::InitDumpConfigFromJson(char *path) {
284 #ifndef BENCHMARK_CLIP_JSON
285   auto real_path = RealPath(path);
286   std::ifstream ifs(real_path);
287   if (!ifs.good()) {
288     MS_LOG(ERROR) << "file: " << real_path << " is not exist";
289     return RET_ERROR;
290   }
291   if (!ifs.is_open()) {
292     MS_LOG(ERROR) << "file: " << real_path << " open failed";
293     return RET_ERROR;
294   }
295 
296   try {
297     dump_cfg_json_ = nlohmann::json::parse(ifs);
298   } catch (const nlohmann::json::parse_error &error) {
299     MS_LOG(ERROR) << "parse json file failed, please check your file.";
300     return RET_ERROR;
301   }
302   if (dump_cfg_json_[dump::kSettings] == nullptr) {
303     MS_LOG(ERROR) << "\"common_dump_settings\" is required.";
304     return RET_ERROR;
305   }
306   if (dump_cfg_json_[dump::kSettings][dump::kMode] == nullptr) {
307     MS_LOG(ERROR) << "\"dump_mode\" is required.";
308     return RET_ERROR;
309   }
310   if (dump_cfg_json_[dump::kSettings][dump::kPath] == nullptr) {
311     MS_LOG(ERROR) << "\"path\" is required.";
312     return RET_ERROR;
313   }
314   if (dump_cfg_json_[dump::kSettings][dump::kNetName] == nullptr) {
315     dump_cfg_json_[dump::kSettings][dump::kNetName] = "default";
316   }
317   if (dump_cfg_json_[dump::kSettings][dump::kInputOutput] == nullptr) {
318     dump_cfg_json_[dump::kSettings][dump::kInputOutput] = 0;
319   }
320   if (dump_cfg_json_[dump::kSettings][dump::kKernels] != nullptr &&
321       !dump_cfg_json_[dump::kSettings][dump::kKernels].empty()) {
322     if (dump_cfg_json_[dump::kSettings][dump::kMode] == 0) {
323       MS_LOG(ERROR) << R"("dump_mode" should be 1 when "kernels" isn't empty.)";
324       return RET_ERROR;
325     }
326   }
327 
328   auto abs_path = dump_cfg_json_[dump::kSettings][dump::kPath].get<std::string>();
329   auto net_name = dump_cfg_json_[dump::kSettings][dump::kNetName].get<std::string>();
330   if (abs_path.back() == '\\' || abs_path.back() == '/') {
331     dump_file_output_dir_ = abs_path + net_name;
332   } else {
333 #ifdef _WIN32
334     dump_file_output_dir_ = abs_path + "\\" + net_name;
335 #else
336     dump_file_output_dir_ = abs_path + "/" + net_name;
337 #endif
338   }
339 
340   auto status = CreateOutputDir(&dump_file_output_dir_);
341   if (status != RET_OK) {
342     MS_LOG(ERROR) << "create data output directory failed.";
343     return RET_ERROR;
344   }
345 #endif
346   return RET_OK;
347 }
348 
InitCallbackParameter()349 int BenchmarkBase::InitCallbackParameter() {
350   int ret = RET_OK;
351   if (flags_->time_profiling_) {
352     ret = InitTimeProfilingCallbackParameter();
353   } else if (flags_->perf_profiling_) {
354     ret = InitPerfProfilingCallbackParameter();
355   } else if (flags_->print_tensor_data_) {
356     ret = InitPrintTensorDataCallbackParameter();
357   } else if (flags_->dump_tensor_data_) {
358     ret = InitDumpTensorDataCallbackParameter();
359   }
360   return ret;
361 }
362 
Init()363 int BenchmarkBase::Init() {
364   if (this->flags_ == nullptr) {
365     return 1;
366   }
367   MS_LOG(INFO) << "ModelPath = " << this->flags_->model_file_;
368   MS_LOG(INFO) << "InDataPath = " << this->flags_->in_data_file_;
369   MS_LOG(INFO) << "ConfigFilePath = " << this->flags_->config_file_;
370   MS_LOG(INFO) << "InDataType = " << this->flags_->in_data_type_in_;
371   MS_LOG(INFO) << "LoopCount = " << this->flags_->loop_count_;
372   MS_LOG(INFO) << "DeviceType = " << this->flags_->device_;
373   MS_LOG(INFO) << "AccuracyThreshold = " << this->flags_->accuracy_threshold_;
374   MS_LOG(INFO) << "WarmUpLoopCount = " << this->flags_->warm_up_loop_count_;
375   MS_LOG(INFO) << "NumThreads = " << this->flags_->num_threads_;
376   MS_LOG(INFO) << "Fp16Priority = " << this->flags_->enable_fp16_;
377   MS_LOG(INFO) << "EnableParallel = " << this->flags_->enable_parallel_;
378   MS_LOG(INFO) << "calibDataPath = " << this->flags_->benchmark_data_file_;
379   std::cout << "ModelPath = " << this->flags_->model_file_ << std::endl;
380   std::cout << "InDataPath = " << this->flags_->in_data_file_ << std::endl;
381   std::cout << "ConfigFilePath = " << this->flags_->config_file_ << std::endl;
382   std::cout << "InDataType = " << this->flags_->in_data_type_in_ << std::endl;
383   std::cout << "LoopCount = " << this->flags_->loop_count_ << std::endl;
384   std::cout << "DeviceType = " << this->flags_->device_ << std::endl;
385   std::cout << "AccuracyThreshold = " << this->flags_->accuracy_threshold_ << std::endl;
386   std::cout << "WarmUpLoopCount = " << this->flags_->warm_up_loop_count_ << std::endl;
387   std::cout << "NumThreads = " << this->flags_->num_threads_ << std::endl;
388   std::cout << "Fp16Priority = " << this->flags_->enable_fp16_ << std::endl;
389   std::cout << "EnableParallel = " << this->flags_->enable_parallel_ << std::endl;
390   std::cout << "calibDataPath = " << this->flags_->benchmark_data_file_ << std::endl;
391   if (this->flags_->loop_count_ < 1) {
392     MS_LOG(ERROR) << "LoopCount:" << this->flags_->loop_count_ << " must be greater than 0";
393     std::cerr << "LoopCount:" << this->flags_->loop_count_ << " must be greater than 0" << std::endl;
394     return RET_ERROR;
395   }
396 
397   auto thread_ret = CheckThreadNumValid();
398   if (thread_ret != RET_OK) {
399     MS_LOG(ERROR) << "Invalid numThreads.";
400     std::cerr << "Invalid numThreads." << std::endl;
401     return RET_ERROR;
402   }
403   static std::vector<std::string> CPU_BIND_MODE_MAP = {"NO_BIND", "HIGHER_CPU", "MID_CPU"};
404   if (this->flags_->cpu_bind_mode_ >= 1) {
405     MS_LOG(INFO) << "cpuBindMode = " << CPU_BIND_MODE_MAP[this->flags_->cpu_bind_mode_];
406     std::cout << "cpuBindMode = " << CPU_BIND_MODE_MAP[this->flags_->cpu_bind_mode_] << std::endl;
407   } else {
408     MS_LOG(INFO) << "cpuBindMode = NO_BIND";
409     std::cout << "cpuBindMode = NO_BIND" << std::endl;
410   }
411 
412   this->flags_->in_data_type_ = this->flags_->in_data_type_in_ == "img" ? kImage : kBinary;
413 
414   if (!flags_->benchmark_data_type_.empty()) {
415     if (data_type_map_.find(flags_->benchmark_data_type_) == data_type_map_.end()) {
416       MS_LOG(ERROR) << "CalibDataType not supported: " << flags_->benchmark_data_type_.c_str();
417       return RET_ERROR;
418     }
419     msCalibDataType = data_type_map_.at(flags_->benchmark_data_type_);
420     MS_LOG(INFO) << "CalibDataType = " << flags_->benchmark_data_type_.c_str();
421     std::cout << "CalibDataType = " << flags_->benchmark_data_type_.c_str() << std::endl;
422   }
423 
424   if (flags_->model_file_.empty()) {
425     MS_LOG(ERROR) << "modelPath is required";
426     std::cerr << "modelPath is required" << std::endl;
427     return 1;
428   }
429   flags_->InitInputDataList();
430   flags_->InitResizeDimsList();
431   if (!flags_->resize_dims_.empty() && !flags_->input_data_list_.empty() &&
432       flags_->resize_dims_.size() != flags_->input_data_list_.size()) {
433     MS_LOG(ERROR) << "Size of input resizeDims should be equal to size of input inDataPath";
434     std::cerr << "Size of input resizeDims should be equal to size of input inDataPath" << std::endl;
435     return RET_ERROR;
436   }
437 
438   if (CheckDeviceTypeValid() != RET_OK) {
439     MS_LOG(ERROR) << "Device type is invalid.";
440     return RET_ERROR;
441   }
442 
443   if (flags_->time_profiling_ && flags_->perf_profiling_) {
444     MS_LOG(INFO) << "time_profiling is enabled, will not run perf_profiling.";
445   }
446 
447   // get dump data output path
448   auto dump_cfg_path = std::getenv(dump::kConfigPath);
449   if (dump_cfg_path != nullptr) {
450     flags_->dump_tensor_data_ = true;
451     if (InitDumpConfigFromJson(dump_cfg_path) != RET_OK) {
452       MS_LOG(ERROR) << "parse dump config file failed.";
453       return RET_ERROR;
454     }
455   } else {
456     MS_LOG(INFO) << "No MINDSPORE_DUMP_CONFIG in env, don't need to dump data";
457   }
458 
459   auto status = InitCallbackParameter();
460   if (status != RET_OK) {
461     MS_LOG(ERROR) << "Init callback Parameter failed.";
462     std::cerr << "Init callback Parameter failed." << std::endl;
463     return RET_ERROR;
464   }
465 
466   return RET_OK;
467 }
468 
PrintResult(const std::vector<std::string> & title,const std::map<std::string,std::pair<int,float>> & result)469 int BenchmarkBase::PrintResult(const std::vector<std::string> &title,
470                                const std::map<std::string, std::pair<int, float>> &result) {
471   std::vector<size_t> columnLenMax(kPrintColNum);
472   std::vector<std::vector<std::string>> rows;
473 
474   for (auto &iter : result) {
475     char stringBuf[kPrintColNum][kPrintRowLenMax] = {};
476     std::vector<std::string> columns;
477     size_t len = 0;
478     int index = 0;
479     len = iter.first.size();
480     if (len > columnLenMax.at(index)) {
481       columnLenMax.at(index) = len + kColumnLen;
482     }
483     columns.push_back(iter.first);
484 
485     index++;
486     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%f",
487                    iter.second.second / static_cast<float>(flags_->loop_count_));
488     if (len > columnLenMax.at(index)) {
489       columnLenMax.at(index) = len + kColumnLen;
490     }
491     columns.emplace_back(stringBuf[index]);
492 
493     index++;
494     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%f", iter.second.second / op_cost_total_);
495     if (len > columnLenMax.at(index)) {
496       columnLenMax.at(index) = len + kColumnLen;
497     }
498     columns.emplace_back(stringBuf[index]);
499 
500     index++;
501     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%d", iter.second.first);
502     if (len > columnLenMax.at(index)) {
503       columnLenMax.at(index) = len + kColumnLen;
504     }
505     columns.emplace_back(stringBuf[index]);
506 
507     index++;
508     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%f", iter.second.second);
509     if (len > columnLenMax.at(index)) {
510       columnLenMax.at(index) = len + kColumnLen;
511     }
512     columns.emplace_back(stringBuf[index]);
513 
514     rows.push_back(columns);
515   }
516 
517   printf("-------------------------------------------------------------------------\n");
518   for (int i = 0; i < kPrintColNum; i++) {
519     auto printBuf = title[i];
520     if (printBuf.size() > columnLenMax.at(i)) {
521       columnLenMax.at(i) = printBuf.size();
522     }
523     printBuf.resize(columnLenMax.at(i), ' ');
524     printf("%s\t", printBuf.c_str());
525   }
526   printf("\n");
527   for (auto &row : rows) {
528     for (int j = 0; j < kPrintColNum; j++) {
529       auto printBuf = row[j];
530       printBuf.resize(columnLenMax.at(j), ' ');
531       printf("%s\t", printBuf.c_str());
532     }
533     printf("\n");
534   }
535   return RET_OK;
536 }
537 
538 #ifdef ENABLE_ARM64
PrintPerfResult(const std::vector<std::string> & title,const std::map<std::string,std::pair<int,struct PerfCount>> & result)539 int BenchmarkBase::PrintPerfResult(const std::vector<std::string> &title,
540                                    const std::map<std::string, std::pair<int, struct PerfCount>> &result) {
541   std::vector<size_t> columnLenMax(kPrintColNum);
542   std::vector<std::vector<std::string>> rows;
543 
544   for (auto &iter : result) {
545     char stringBuf[kPrintColNum][kPrintRowLenMax] = {};
546     std::vector<std::string> columns;
547     size_t len = 0;
548     int index = 0;
549     len = iter.first.size();
550     if (len > columnLenMax.at(index)) {
551       columnLenMax.at(index) = len + kColumnLen;
552     }
553     columns.push_back(iter.first);
554     index++;
555     float tmp = float_t(flags_->num_threads_) * iter.second.second.value[0] / float_t(flags_->loop_count_) / kFloatMSEC;
556     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%.2f", tmp);
557     if (len > columnLenMax.at(index)) {
558       columnLenMax.at(index) = len + kColumnLen;
559     }
560     columns.emplace_back(stringBuf[index]);
561     index++;
562     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%f", iter.second.second.value[0] / op_cost_total_);
563     if (len > columnLenMax.at(index)) {
564       columnLenMax.at(index) = len + kColumnLen;
565     }
566     columns.emplace_back(stringBuf[index]);
567 
568     index++;
569     tmp = float_t(flags_->num_threads_) * iter.second.second.value[1] / float_t(flags_->loop_count_) / kFloatMSEC;
570     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%.2f", tmp);
571     if (len > columnLenMax.at(index)) {
572       columnLenMax.at(index) = len + kColumnLen;
573     }
574     columns.emplace_back(stringBuf[index]);
575 
576     index++;
577     len = snprintf(stringBuf[index], sizeof(stringBuf[index]), "%f", iter.second.second.value[1] / op_cost2_total_);
578     if (len > columnLenMax.at(index)) {
579       columnLenMax.at(index) = len + kColumnLen;
580     }
581     columns.emplace_back(stringBuf[index]);
582 
583     rows.push_back(columns);
584   }
585 
586   printf("-------------------------------------------------------------------------\n");
587   for (int i = 0; i < kPrintColNum; i++) {
588     auto printBuf = title[i];
589     if (printBuf.size() > columnLenMax.at(i)) {
590       columnLenMax.at(i) = printBuf.size();
591     }
592     printBuf.resize(columnLenMax.at(i), ' ');
593     printf("%s\t", printBuf.c_str());
594   }
595   printf("\n");
596   for (auto &row : rows) {
597     for (int j = 0; j < kPrintColNum; j++) {
598       auto printBuf = row[j];
599       printBuf.resize(columnLenMax.at(j), ' ');
600       printf("%s\t", printBuf.c_str());
601     }
602     printf("\n");
603   }
604   return RET_OK;
605 }
606 #endif
607 
~BenchmarkBase()608 BenchmarkBase::~BenchmarkBase() {
609   for (auto &iter : this->benchmark_data_) {
610     iter.second->shape.clear();
611     iter.second->data.clear();
612     delete iter.second;
613     iter.second = nullptr;
614   }
615   this->benchmark_data_.clear();
616 }
617 }  // namespace lite
618 }  // namespace mindspore
619