1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ohos_common.h"
17 #include <numeric>
18 #include <inttypes.h>
19 #include <sys/time.h>
20 #include <unistd.h>
21 #include <cfloat>
22 #include <climits>
23 #include <cstdint>
24 #include <cstdlib>
25 #include <cstring>
26 #include <string>
27 #include <iostream>
28 #include <functional>
29 #include <ctime>
30 #include <cstdio>
31 #include <fstream>
32 #include <vector>
33 #include <map>
34 #include <cmath>
35 #include <regex>
36 #include <sstream>
37 #include <malloc.h>
38 #include <numeric>
39 /*
40  * getDimInfo: get dim info from data file(int64_t)
41  * param:
42  * fp: the testing datafile object
43  *
44  * return :
45  * dim_info: array to store the info of the dim in datafile, like
46  * [4,3,3,6,3,162(3*3*6*3)],4 is dim size,3,3,6,3 is the dim shape data_size:
47  * the size of the testing data including the data file
48  * */
getDimInfo(FILE *fp, std::vector<int64_t>* dim_info)49 void getDimInfo(FILE *fp, std::vector<int64_t>* dim_info) {
50   const int MAX_HEAD_SIZE = 50;
51   uint32_t *dim_buffer = reinterpret_cast<uint32_t *>(malloc(MAX_HEAD_SIZE * sizeof(uint32_t)));
52   size_t ret = fread(dim_buffer, sizeof(uint32_t), MAX_HEAD_SIZE, fp);
53   if (ret == 0) {
54     free(dim_buffer);
55     return;
56   }
57   dim_info->push_back(*dim_buffer);  // get dim size
58 
59   // get data shape to compute the datasize
60   uint64_t data_size = 1;
61   uint32_t i = 1;
62   for (; i <= dim_info->at(0); i++) {
63     dim_info->push_back(*(dim_buffer + i));
64     data_size *= *(dim_buffer + i);
65   }
66   dim_info->push_back(data_size);
67 
68   free(dim_buffer);
69 }
70 
71 /*
72  * readTestDataFile: read test date from hisi .t datafile(int64_t)
73  * param:
74  * infile: the path of hisi .t datafile
75  * return:
76  * dim_info: array to store the info of the dim in datafile, like [4,3,3,6,3],4
77  * is dim size,3,3,6,3 is the dim shape
78  * */
readTestDataFile(std::string infile, std::vector<int64_t>* dim_info1)79 void *readTestDataFile(std::string infile, std::vector<int64_t>* dim_info1) {
80   printf("\n [common.cpp] Loading data from: %s\n", infile.c_str());
81 
82   FILE *fp;
83   fp = fopen(infile.c_str(), "r");
84   if (fp == nullptr) {
85     printf("ERROR: cant't open file %s\n", infile.c_str());
86     return nullptr;
87   } else {
88     std::vector<int64_t> dim_info;
89     std::vector<int64_t>* ptr_dim_info = &dim_info;
90     getDimInfo(fp, ptr_dim_info);
91     uint64_t data_size = ptr_dim_info->at(ptr_dim_info->size() - 1);
92     fclose(fp);
93 
94     fp = fopen(infile.c_str(), "r");
95     if (fp == nullptr) {
96       printf("ERROR: cant't open file %s\n", infile.c_str());
97       return nullptr;
98     }
99     uint32_t *memory = reinterpret_cast<uint32_t *>(malloc((dim_info[0] + 1) * sizeof(uint32_t)));
100 
101     size_t ret = fread(memory, sizeof(uint32_t), (dim_info[0] + 1), fp);
102     if (ret == 0) {
103       free(memory);
104       fclose(fp);
105       return nullptr;
106     }
107     uint32_t *data = reinterpret_cast<uint32_t *>(malloc((data_size) * sizeof(uint32_t)));
108     size_t ret2 = fread(data, sizeof(uint32_t), data_size, fp);
109     if (ret2 == 0) {
110       free(data);
111       fclose(fp);
112       return nullptr;
113     }
114     free(memory);
115     fclose(fp);
116 
117     for (int i = 0; i < dim_info[0]; i++) {
118       dim_info1->push_back(dim_info[i + 1]);
119     }
120 
121     printf("\n [common.cpp] Read test data file Over, get dimInfo as: (");
122     int count = dim_info1->size();
123     for (int i = 0; i < count; i++) {
124       printf("%" PRId64, dim_info1->at(i));
125     }
126     printf(")\n");
127     return data;
128   }
129 }
130 
131 /*
132  * allclose
133  * param:
134  *  a:compared file a
135  *  b:compared file b
136  *  count: the count size which will compare
137  *  rtol:
138  *  atol:
139  * return:
140  *  true or false
141  * */
allclose(float *a, float *b, uint64_t count, float rtol = 1e-05, float atol = 1e-08, bool isquant = false)142 bool allclose(float *a, float *b, uint64_t count, float rtol = 1e-05,
143               float atol = 1e-08, bool isquant = false) {
144   uint32_t i = 0;
145 
146   // add fail loop print
147   uint32_t fail_count = 0;
148   float tol = 0;
149   float tol1 = 0;
150   float tol2 = 0;
151   bool nan_occur_in_accuray = false;
152 
153   float sum = 0.0f;
154   static float sum_all;
155   static float maximum = 0;
156   static float minimum = 0;
157   static uint64_t c = 0;
158 
159   if (a == nullptr || b == nullptr) {
160     return false;
161   }
162 
163   for (; i < count; ++i) {
164     sum = sum + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i]));
165     sum_all = sum_all + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i]));
166     maximum = max(maximum, fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i])));
167     minimum = min(minimum, fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i])));
168     if (isnan(a[i]) || isinf(a[i])) {
169       fail_count = fail_count + 1;
170       nan_occur_in_accuray = true;
171       if (fail_count < 100) {
172         printf("     i = %2u:   %+f  |  %+f\n", i, a[i], b[i]);
173       }
174     } else if (fabs(a[i] - b[i]) > (atol + rtol * fabs(b[i]))) {
175       tol = tol + fabs(a[i] - b[i]) / (fabs(b[i]) + 1);
176       tol1 = tol1 + fabs(a[i] - b[i]);
177       tol2 = tol2 + fabs(a[i] - b[i]) / fabs(b[i]);
178       fail_count = fail_count + 1;
179       if (fail_count < 100) {
180         printf("     i = %2u:   %+f  |  %+f\n", i, a[i], b[i]);
181       }
182     }
183 
184     if (i == count - 1) {
185       printf("     ......\n");
186       printf("\n *** Total fail_count: %u\n", fail_count);
187       if (fail_count != 0) {
188         printf("\n     fabs(a[i] - b[i])/(fabs(b[i])+1) : %f\n",
189               tol / fail_count);
190         printf("\n     fabs(a[i] - b[i]) : %f\n", tol1 / fail_count);
191         printf("\n     fabs(a[i] - b[i])/fabs(b[i]) : %f\n", tol2 / fail_count);
192       }
193       c = c + count;
194       printf("\n     avg : %f\n", sum / count);
195       printf("\n     min : %f\n", minimum);
196       printf("\n     max :  %f\n", maximum);
197       printf("\n     avg_all :  %f\n", sum_all / c);
198       printf("\n");
199       fstream file;
200       file.open("cout.csv", ios::app);
201 
202       file << ","
203            << "1,"
204            << "0," << maximum;
205       if (fail_count == 0) {
206         file << "," << sum_all / c;
207       } else {
208         file << "," << tol / fail_count;
209       }
210       file.close();
211     }
212   }
213   if (nan_occur_in_accuray) {
214     printf("\n[common.cpp] eval output include some NAN/INF\n");
215     return false;
216   }
217 
218   if (fail_count > 0) {
219     printf("\n *** These data compare failed: atol = %f, rtol = %f\n", atol,
220            rtol);
221     printf("\n");
222     if (isquant) {
223       if (tol / fail_count < 0.04) {
224         return true;
225       }
226     }
227     return false;
228   }
229   return true;
230 }
231 
allclose_int8(uint8_t *a, uint8_t *b, uint64_t count, float rtol = 1e-05, float atol = 1e-08, bool isquant = false)232 bool allclose_int8(uint8_t *a, uint8_t *b, uint64_t count, float rtol = 1e-05,
233                    float atol = 1e-08, bool isquant = false) {
234   uint32_t i = 0;
235   // add fail loop print
236   uint32_t fail_count = 0;
237   float tol = 0;
238   float tol1 = 0;
239   float tol2 = 0;
240   bool nan_occur_in_accuray = false;
241 
242   float sum = 0.0f;
243   static float sum_all;
244   static float maximum = 0;
245   static float minimum = 0;
246   static uint64_t c = 0;
247   // add fail loop print
248 
249   if (a == nullptr || b == nullptr) {
250     return false;
251   }
252 
253   for (; i < count; ++i) {
254     sum = sum + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i]));
255     sum_all = sum_all + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i]));
256     maximum = max(static_cast<double>(maximum),
257                   static_cast<double>(fabs(a[i] - b[i])) / (atol + rtol * fabs(b[i])));
258     minimum = min(static_cast<double>(minimum),
259                   static_cast<double>(fabs(a[i] - b[i])) / (atol + rtol * fabs(b[i])));
260     if (isnan(a[i]) || isinf(a[i])) {
261       fail_count = fail_count + 1;
262       nan_occur_in_accuray = true;
263       if (fail_count < 100) {
264         printf("     i = %2u:   %+f  |  %+f\n", i, static_cast<float>(a[i]), static_cast<float>(b[i]));
265       }
266     } else if (fabs(a[i] - b[i]) > 0) {
267       tol = tol + fabs(a[i] - b[i]) / (fabs(b[i]) + 1);
268       tol1 = tol1 + fabs(a[i] - b[i]);
269       tol2 = tol2 + fabs(a[i] - b[i]) / fabs(b[i]);
270       fail_count = fail_count + 1;
271       printf("%2d", static_cast<int>(fabs(a[i] - b[i])));
272       printf("     i = %2u:   %2d  |  %2d\n", i, a[i], b[i]);
273     }
274     if (i == count - 1) {
275       printf("     ……\n");
276       printf("\n *** Total fail_count: %u\n", fail_count);
277       if (fail_count != 0) {
278         printf("\n     fabs(a[i] - b[i])/(fabs(b[i])+1) : %f\n",
279               tol / fail_count);
280         printf("\n     fabs(a[i] - b[i]) : %f\n", tol1 / fail_count);
281         printf("\n     fabs(a[i] - b[i])/fabs(b[i]) : %f\n", tol2 / fail_count);
282       }
283 
284       c = c + count;
285       printf("\n     avg : %f\n", sum / count);
286       printf("\n     min : %f\n", minimum);
287 
288       printf("\n     max :  %f\n", maximum);
289       printf("\n     avg_all :  %f\n", sum_all / c);
290       printf("\n");
291       fstream file;
292       file.open("cout.csv", ios::app);
293 
294       file << ","
295            << "1,"
296            << "0," << maximum;
297       if (fail_count == 0) {
298         file << "," << sum_all / c;
299       } else {
300         file << "," << tol / fail_count;
301       }
302       file.close();
303     }
304   }
305   if (nan_occur_in_accuray) {
306     printf("\n[common.cpp] eval output include some NAN/INF\n");
307     return false;
308   }
309   if (fail_count > 0) {
310     printf("\n *** These data compare failed: atol = %f, rtol = %f\n", atol,
311            rtol);
312     printf("\n");
313     if (isquant) {
314       if (tol / fail_count < 0.04) {
315         return true;
316       }
317     }
318     return false;
319   }
320   return true;
321 }
322 
323 /*
324  * compFp32WithTData: compare the data with the data in hisi .t file
325  * param:
326  *  actualOutputData: the result of ge
327  *  expectedDataFile: the path of hisi .t result file
328  *  rtol:
329  *  atol:
330  * return:
331  *  true of false
332  * */
compFp32WithTData(float *actualOutputData, const std::string& expectedDataFile, float rtol = 1e-05, float atol = 1e-08, bool isquant = false)333 bool compFp32WithTData(float *actualOutputData, const std::string& expectedDataFile,
334                        float rtol = 1e-05, float atol = 1e-08,
335                        bool isquant = false) {
336   std::vector<int64_t> dim_info;
337   std::vector<int64_t>* ptr_dim_info = &dim_info;
338   float *expectedOutputData =
339       reinterpret_cast<float *>(readTestDataFile(expectedDataFile, ptr_dim_info));
340   uint32_t i = 0;
341   uint64_t data_size = 1;
342   data_size = accumulate(dim_info.begin(), dim_info.end(), 1, std::multiplies<uint64_t>());
343 
344   // print caffe/tf output:
345   printf("[common.cpp] expected output data:");
346   for (; i < data_size && i < 10; i++) {
347     printf("%4f ", expectedOutputData[i]);
348   }
349   printf("\n");
350   if (isquant) {
351     bool ret = allclose(actualOutputData, expectedOutputData, data_size, rtol, atol,
352                     true);
353     free(expectedOutputData);
354     return ret;
355   }
356   bool ret =  allclose(actualOutputData, expectedOutputData, data_size, rtol, atol);
357   free(expectedOutputData);
358   return ret;
359 }
360 
compUint8WithTData(uint8_t *actualOutputData, const std::string& expectedDataFile, float rtol = 1e-05, float atol = 1e-08, bool isquant = false)361 bool compUint8WithTData(uint8_t *actualOutputData, const std::string& expectedDataFile,
362                         float rtol = 1e-05, float atol = 1e-08,
363                         bool isquant = false) {
364   std::vector<int64_t> dim_info;
365   std::vector<int64_t>* ptr_dim_info = &dim_info;
366   auto dataFile = readTestDataFile(expectedDataFile, ptr_dim_info);
367   if(dataFile == nullptr){
368     return false;
369   }
370   uint8_t *expectedOutputData =
371       reinterpret_cast<uint8_t *>(dataFile);
372   uint32_t i = 0;
373   uint64_t data_size = 1;
374   data_size = accumulate(dim_info.begin(), dim_info.end(), 1, std::multiplies<uint64_t>());
375 
376   // print caffe/tf output:
377   printf("\n [common.cpp] expected output data:\n");
378   for (; i < data_size && i < 10; i++) {
379     printf("%4hhu ", static_cast<unsigned char>(expectedOutputData[i]));
380   }
381   printf("\n");
382   if (isquant) {
383     bool ret =  allclose_int8(actualOutputData, expectedOutputData, data_size, rtol,
384                          atol, true);
385     free(expectedOutputData);
386     return ret;
387   }
388   bool ret =  allclose_int8(actualOutputData, expectedOutputData, data_size, rtol,
389                        atol);
390   free(expectedOutputData);
391   return ret;
392 }
393 
394 /*
395  * ReadFile: read file of model
396  * param:
397  *  file: file location
398  *  size: file size
399  * return:
400  *  buf of file
401  * */
ReadFile(const char *file, size_t* size)402 char *ReadFile(const char *file, size_t* size) {
403   printf("[common.cpp] Loading data from: %s\n", file);
404 
405   std::ifstream ifs(file);
406   if (!ifs.good()) {
407     return nullptr;
408   }
409 
410   if (!ifs.is_open()) {
411     ifs.close();
412     return nullptr;
413   }
414 
415   ifs.seekg(0, std::ios::end);
416   *size = ifs.tellg();
417 
418   char *buf = new char[*size];
419   if (buf == nullptr) {
420     ifs.close();
421     return nullptr;
422   }
423 
424   ifs.seekg(0, std::ios::beg);
425   ifs.read(buf, *size);
426   ifs.close();
427   printf("[common.cpp]Read Binary Data Over, get tensorSize as: %" PRId64 ".\n", static_cast<int64_t>(*size));
428 
429   return buf;
430 }
431 
PackNCHWToNHWCFp32(const char *src, char *dst, int batch, int plane, int channel)432 void PackNCHWToNHWCFp32(const char *src, char *dst, int batch, int plane, int channel) {
433     for (int n = 0; n < batch; n++) {
434         for (int c = 0; c < channel; c++) {
435             for (int hw = 0; hw < plane; hw++) {
436                 int nhwc_index = n * channel * plane + hw * channel + c;
437                 int nchw_index = n * channel * plane + c * plane + hw;
438                 dst[nhwc_index * 4] = src[nchw_index * 4];
439                 dst[nhwc_index * 4 + 1] = src[nchw_index * 4 + 1];
440                 dst[nhwc_index * 4 + 2] = src[nchw_index * 4 + 2];
441                 dst[nhwc_index * 4 + 3] = src[nchw_index * 4 + 3];
442             }
443         }
444     }
445     return;
446 }
447 
448 
getTimeInUs()449 uint64_t getTimeInUs() {
450     const uint64_t MICROSECONDS_PER_SECOND = 1000000;
451     uint64_t time;
452     struct timeval tv;
453     gettimeofday(&tv, nullptr);
454     time = static_cast<uint64_t>(tv.tv_sec) * MICROSECONDS_PER_SECOND + tv.tv_usec;
455     return time;
456 }
457 
CalculateIntVector(std::vector<float> vec)458 std::map<std::string, float> CalculateIntVector(std::vector<float> vec) {
459     float max = 0, min = FLT_MAX, sum = 0, avg;
460     for (auto v : vec) {
461         max = fmax(max, v);
462         min = fmin(min, v);
463         sum += v;
464     }
465     avg = vec.size() > 0 ? sum / vec.size() : 0;
466     std::map<std::string, float> result = {
467             {"MIN", min},
468             {"MAX", max},
469             {"AVG", avg},
470             {"SUM", sum}};
471     return result;
472 }
473 
474