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