Publishing R3
[platform/upstream/dldt.git] / inference-engine / thirdparty / mkl-dnn / tests / benchdnn / common.cpp
1 /*******************************************************************************
2 * Copyright 2017-2018 Intel Corporation
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 <stdint.h>
18 #include <limits.h>
19 #include <assert.h>
20
21 #include "common.hpp"
22
23 const char *bench_mode2str(bench_mode_t mode) {
24     const char *modes[] = {
25         "MODE_UNDEF", "CORR", "PERF", "CORR+PERF"
26     };
27     assert((int)mode < 4);
28     return modes[(int)mode];
29 }
30
31 bench_mode_t str2bench_mode(const char *str) {
32     bench_mode_t mode = MODE_UNDEF;
33     if (strchr(str, 'c') || strchr(str, 'C'))
34         mode = (bench_mode_t)((int)mode | (int)CORR);
35     if (strchr(str, 'p') || strchr(str, 'P'))
36         mode = (bench_mode_t)((int)mode | (int)PERF);
37     if (mode == MODE_UNDEF)
38         []() { SAFE(FAIL, CRIT); return 0; }();
39     return mode;
40 }
41
42 /* perf */
43 #include <chrono>
44
45 static inline double ms_now() {
46     auto timePointTmp
47         = std::chrono::high_resolution_clock::now().time_since_epoch();
48     return std::chrono::duration<double, std::milli>(timePointTmp).count();
49 }
50
51 #if !defined(BENCHDNN_USE_RDPMC) || defined(_WIN32)
52 unsigned long long ticks_now() {
53     return (unsigned long long)0;
54 }
55 #else
56 unsigned long long ticks_now() {
57     unsigned eax, edx, ecx;
58
59     ecx = (1 << 30) + 1;
60     __asm__ volatile("rdpmc" : "=a" (eax), "=d" (edx) : "c" (ecx));
61
62     return (unsigned long long)eax | (unsigned long long)edx << 32;
63 }
64 #endif
65
66 void benchdnn_timer_t::reset() {
67     times_ = 0;
68     for (int i = 0; i < n_modes; ++i) ticks_[i] = 0;
69     ticks_start_ = 0;
70     for (int i = 0; i < n_modes; ++i) ms_[i] = 0;
71     ms_start_ = 0;
72
73     start();
74 }
75
76 void benchdnn_timer_t::start() {
77     ticks_start_ = ticks_now();
78     ms_start_ = ms_now();
79 }
80
81 void benchdnn_timer_t::stop() {
82     long long d_ticks = ticks_now() - ticks_start_; /* FIXME: overflow? */
83     double d_ms = ms_now() - ms_start_;
84
85     ticks_start_ += d_ticks;
86     ms_start_ += d_ms;
87
88     ms_[benchdnn_timer_t::min] = times_
89         ? MIN2(ms_[benchdnn_timer_t::min], d_ms) : d_ms;
90     ms_[benchdnn_timer_t::avg] += d_ms;
91     ms_[benchdnn_timer_t::max] = times_
92         ? MAX2(ms_[benchdnn_timer_t::max], d_ms) : d_ms;
93
94     ticks_[benchdnn_timer_t::min] = times_
95         ? MIN2(ticks_[benchdnn_timer_t::min], d_ticks) : d_ticks;
96     ticks_[benchdnn_timer_t::avg] += d_ticks;
97     ticks_[benchdnn_timer_t::max] = times_
98         ? MAX2(ticks_[benchdnn_timer_t::max], d_ticks) : d_ticks;
99
100     times_++;
101 }
102
103 benchdnn_timer_t &benchdnn_timer_t::operator=(const benchdnn_timer_t &rhs) {
104     if (this == &rhs) return *this;
105     times_ = rhs.times_;
106     for (int i = 0; i < n_modes; ++i) ticks_[i] = rhs.ticks_[i];
107     ticks_start_ = rhs.ticks_start_;
108     for (int i = 0; i < n_modes; ++i) ms_[i] = rhs.ms_[i];
109     ms_start_ = rhs.ms_start_;
110     return *this;
111 }
112
113 /* result structure */
114 const char *state2str(res_state_t state) {
115 #define CASE(x) if (state == x) return STRINGIFY(x)
116     CASE(UNTESTED);
117     CASE(PASSED);
118     CASE(SKIPPED);
119     CASE(MISTRUSTED);
120     CASE(UNIMPLEMENTED);
121     CASE(FAILED);
122 #undef CASE
123     assert(!"unknown res state");
124     return "STATE_UNDEF";
125 }
126
127 void parse_result(res_t &res, bool &want_perf_report, bool allow_unimpl,
128         int status, char *pstr) {
129     auto &bs = benchdnn_stat;
130     const char *state = state2str(res.state);
131
132     switch (res.state) {
133     case UNTESTED:
134         if (!(bench_mode & CORR)) {
135             want_perf_report = true;
136             break;
137         }
138     case FAILED:
139         assert(status == FAIL);
140         bs.failed++;
141         print(0, "%d:%s (errors:%lu total:%lu) __REPRO: %s\n", bs.tests, state,
142                 (unsigned long)res.errors,
143                 (unsigned long)res.total, pstr);
144         break;
145     case SKIPPED:
146         assert(status == OK);
147         print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
148         bs.skipped++;
149         break;
150     case UNIMPLEMENTED:
151         assert(status == OK);
152         print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
153         bs.unimplemented++;
154         bs.failed += !allow_unimpl;
155         break;
156     case MISTRUSTED:
157         assert(status == OK);
158         bs.mistrusted++;
159         print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
160         // bs.failed++; /* temporal workaround for some tests */
161         break;
162     case PASSED:
163         assert(status == OK);
164         print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
165         want_perf_report = true;
166         bs.passed++;
167         break;
168     default:
169         assert(!"unknown state");
170         { []() { SAFE(FAIL, CRIT); return 0; }(); }
171     }
172
173     if (bench_mode & PERF) {
174         using bt = benchdnn_timer_t;
175         for (int mode = 0; mode < (int)bt::n_modes; ++mode)
176             bs.ms[mode] += res.timer.ms((bt::mode_t)mode);
177     }
178 }
179
180 /* misc */
181 void *zmalloc(size_t size, size_t align) {
182     void *ptr;
183 #ifdef _WIN32
184     ptr = _aligned_malloc(size, align);
185     int rc = ((ptr) ? 0 : errno);
186 #else
187     // TODO. Heuristics: Increasing the size to alignment increases
188     // the stability of performance results.
189     if (size < align)
190         size = align;
191     int rc = ::posix_memalign(&ptr, align, size);
192 #endif /* _WIN32 */
193     return rc == 0 ? ptr : 0;
194 }
195
196 void zfree(void *ptr) {
197 #ifdef _WIN32
198     _aligned_free(ptr);
199 #else
200     return ::free(ptr);
201 #endif /* _WIN32 */
202 }
203
204 bool str2bool(const char *str) {
205     return !strcasecmp("true", str) || !strcasecmp("1", str);
206 }
207
208 const char *bool2str(bool value) {
209     return value ? "true" : "false";
210 }
211
212 #ifdef _WIN32
213 /* NOTE: this should be supported on linux as well, but currently
214  * having issues for ICC170 and Clang*/
215 #include <regex>
216
217 bool match_regex(const char *str, const char *pattern) {
218     std::regex re(pattern);
219     return std::regex_search(str, re);
220 }
221 #else
222 #include <sys/types.h>
223 #include <regex.h>
224
225 bool match_regex(const char *str, const char *pattern) {
226     static regex_t regex;
227     static const char *prev_pattern = NULL;
228     if (pattern != prev_pattern) {
229         if (prev_pattern)
230             regfree(&regex);
231
232         if (regcomp(&regex, pattern, 0)) {
233             fprintf(stderr, "could not create regex\n");
234             return true;
235         }
236
237         prev_pattern = pattern;
238     }
239
240     return !regexec(&regex, str, 0, NULL, 0);
241 }
242 #endif /* _WIN32 */
243
244 bool maybe_skip(const char *skip_impl, const char *impl_str) {
245     if (skip_impl == NULL || *skip_impl == '\0')
246         return false;
247
248     const size_t max_len = 128;
249     char what[max_len] = {0};
250
251     const char *s_start = skip_impl;
252     while (1) {
253         if (*s_start == '"' || *s_start == '\'')
254             ++s_start;
255
256         const char *s_end = strchr(s_start, ':');
257         size_t len = s_end ? s_end - s_start : strlen(s_start);
258
259         if (s_start[len - 1] == '"' || s_start[len - 1] == '\'')
260             --len;
261
262         SAFE(len < max_len ? OK : FAIL, CRIT);
263         len = MIN2(len, max_len - 1);
264         strncpy(what, s_start, len);
265         what[len] = '\0';
266
267         if (strstr(impl_str, what))
268             return true;
269
270         if (s_end == NULL)
271             break;
272
273         s_start = s_end + 1;
274         if (*s_start == '\0')
275             break;
276     }
277
278     return false;
279 }
280
281 #if defined(_WIN32) && !defined(__GNUC__)
282 #include <windows.h>
283 #define PATH_MAX MAX_PATH
284 static char *dirname(char *path) {
285     char drive[_MAX_DRIVE];
286     char dir[_MAX_DIR];
287     _splitpath(path, drive, dir, NULL, NULL);
288     path[0] = '\0';
289     if (drive != NULL) strncat(path, drive, _MAX_DRIVE);
290     if (dir != NULL) strncat(path, dir, MAX_PATH);
291     if (path[0] == '\0') strcat(path, ".");
292     return path;
293 }
294 #else
295 #include <libgen.h>
296 #endif /* _WIN32 */
297
298 FILE *open_batch_file(const char *fname) {
299     const int max_paths = 4;
300
301     static int n_paths = 0;
302     static char search_paths[max_paths][PATH_MAX] = {{0}};
303
304     char *fdir = NULL;
305     {
306         char fname_copy[PATH_MAX];
307         strncpy(fname_copy, fname, PATH_MAX);
308         fdir = dirname(fname_copy);
309     }
310
311     bool dir_found = false;
312     for (int n = 0; n_paths < max_paths && n < n_paths; ++n)
313         if (!strcmp(fdir, search_paths[n])) {
314             dir_found = true;
315             break;
316         }
317     if (!dir_found)
318         strcpy(search_paths[n_paths++], fdir);
319
320     FILE *fp = fopen(fname, "r");
321     if (fp) return fp;
322
323     for (int n = 0; n < n_paths; ++n) {
324         char fullname[PATH_MAX];
325         snprintf(fullname, PATH_MAX, "%s/%s", search_paths[n], fname);
326         fp = fopen(fullname, "r");
327         print(50, "batch file used: %s\n", fullname);
328         if (fp) break;
329     }
330
331     return fp;
332 }
333
334 int batch(const char *fname, bench_f bench) {
335     FILE *fp = open_batch_file(fname);
336     SAFE(fp ? OK : FAIL, CRIT);
337
338     const size_t maxlen = 1024;
339     char *opts[8*1024] = {0}, buf[maxlen + 1];
340     char line[1024];
341     int n_opts = 0;
342     while (fgets(line, sizeof(line), fp)) {
343         int offset = 0;
344         const char *l = line;
345         while (sscanf(l, "%s%n", buf, &offset) == 1) {
346             if (buf[0] == '#')
347                 break; /* stop reading till eol */
348
349             const size_t len = strnlen(buf, maxlen) + 1;
350             opts[n_opts] = (char *)malloc(len);
351             SAFE(opts[n_opts] ? OK : FAIL, CRIT);
352             strncpy(opts[n_opts], buf, len);
353             ++n_opts;
354
355             l += offset;
356         }
357     }
358     bench(n_opts, opts, false);
359
360     for (int n = 0; n < n_opts; ++n)
361         free(opts[n]);
362
363     fclose(fp);
364
365     return OK;
366 }
367
368 int flip_coin(ptrdiff_t seed, float probability) {
369     const ptrdiff_t big_prime = 1000003;
370     const ptrdiff_t prime = 753737;
371     seed *= prime;
372     return (seed % big_prime) < (probability * big_prime);
373 }
374
375 int div_up(const int a, const int b){
376     SAFE_V(b != 0 ? OK : FAIL);
377     return (a + b - 1) / b;
378 }
379
380 void array_set(char *arr, size_t size) {
381     for (size_t i = 0; i < size; ++i)
382         arr[i] = 0;
383 }