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