1 /*******************************************************************************
2 * Copyright 2017-2018 Intel Corporation
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *******************************************************************************/
23 const char *bench_mode2str(bench_mode_t mode) {
24 const char *modes[] = {
25 "MODE_UNDEF", "CORR", "PERF", "CORR+PERF"
27 assert((int)mode < 4);
28 return modes[(int)mode];
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; }();
45 static inline double ms_now() {
47 = std::chrono::high_resolution_clock::now().time_since_epoch();
48 return std::chrono::duration<double, std::milli>(timePointTmp).count();
51 #if !defined(BENCHDNN_USE_RDPMC) || defined(_WIN32)
52 unsigned long long ticks_now() {
53 return (unsigned long long)0;
56 unsigned long long ticks_now() {
57 unsigned eax, edx, ecx;
60 __asm__ volatile("rdpmc" : "=a" (eax), "=d" (edx) : "c" (ecx));
62 return (unsigned long long)eax | (unsigned long long)edx << 32;
66 void benchdnn_timer_t::reset() {
68 for (int i = 0; i < n_modes; ++i) ticks_[i] = 0;
70 for (int i = 0; i < n_modes; ++i) ms_[i] = 0;
76 void benchdnn_timer_t::start() {
77 ticks_start_ = ticks_now();
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_;
85 ticks_start_ += d_ticks;
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;
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;
103 benchdnn_timer_t &benchdnn_timer_t::operator=(const benchdnn_timer_t &rhs) {
104 if (this == &rhs) return *this;
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_;
113 /* result structure */
114 const char *state2str(res_state_t state) {
115 #define CASE(x) if (state == x) return STRINGIFY(x)
123 assert(!"unknown res state");
124 return "STATE_UNDEF";
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);
134 if (!(bench_mode & CORR)) {
135 want_perf_report = true;
139 assert(status == FAIL);
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);
146 assert(status == OK);
147 print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
151 assert(status == OK);
152 print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
154 bs.failed += !allow_unimpl;
157 assert(status == OK);
159 print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
160 // bs.failed++; /* temporal workaround for some tests */
163 assert(status == OK);
164 print(0, "%d:%s __REPRO: %s\n", bs.tests, state, pstr);
165 want_perf_report = true;
169 assert(!"unknown state");
170 { []() { SAFE(FAIL, CRIT); return 0; }(); }
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);
181 void *zmalloc(size_t size, size_t align) {
184 ptr = _aligned_malloc(size, align);
185 int rc = ((ptr) ? 0 : errno);
187 // TODO. Heuristics: Increasing the size to alignment increases
188 // the stability of performance results.
191 int rc = ::posix_memalign(&ptr, align, size);
193 return rc == 0 ? ptr : 0;
196 void zfree(void *ptr) {
204 bool str2bool(const char *str) {
205 return !strcasecmp("true", str) || !strcasecmp("1", str);
208 const char *bool2str(bool value) {
209 return value ? "true" : "false";
213 /* NOTE: this should be supported on linux as well, but currently
214 * having issues for ICC170 and Clang*/
217 bool match_regex(const char *str, const char *pattern) {
218 std::regex re(pattern);
219 return std::regex_search(str, re);
222 #include <sys/types.h>
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) {
232 if (regcomp(®ex, pattern, 0)) {
233 fprintf(stderr, "could not create regex\n");
237 prev_pattern = pattern;
240 return !regexec(®ex, str, 0, NULL, 0);
244 bool maybe_skip(const char *skip_impl, const char *impl_str) {
245 if (skip_impl == NULL || *skip_impl == '\0')
248 const size_t max_len = 128;
249 char what[max_len] = {0};
251 const char *s_start = skip_impl;
253 if (*s_start == '"' || *s_start == '\'')
256 const char *s_end = strchr(s_start, ':');
257 size_t len = s_end ? s_end - s_start : strlen(s_start);
259 if (s_start[len - 1] == '"' || s_start[len - 1] == '\'')
262 SAFE(len < max_len ? OK : FAIL, CRIT);
263 len = MIN2(len, max_len - 1);
264 strncpy(what, s_start, len);
267 if (strstr(impl_str, what))
274 if (*s_start == '\0')
281 #if defined(_WIN32) && !defined(__GNUC__)
283 #define PATH_MAX MAX_PATH
284 static char *dirname(char *path) {
285 char drive[_MAX_DRIVE];
287 _splitpath(path, drive, dir, NULL, NULL);
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, ".");
298 FILE *open_batch_file(const char *fname) {
299 const int max_paths = 4;
301 static int n_paths = 0;
302 static char search_paths[max_paths][PATH_MAX] = {{0}};
306 char fname_copy[PATH_MAX];
307 strncpy(fname_copy, fname, PATH_MAX);
308 fdir = dirname(fname_copy);
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])) {
318 strcpy(search_paths[n_paths++], fdir);
320 FILE *fp = fopen(fname, "r");
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);
334 int batch(const char *fname, bench_f bench) {
335 FILE *fp = open_batch_file(fname);
336 SAFE(fp ? OK : FAIL, CRIT);
338 const size_t maxlen = 1024;
339 char *opts[8*1024] = {0}, buf[maxlen + 1];
342 while (fgets(line, sizeof(line), fp)) {
344 const char *l = line;
345 while (sscanf(l, "%s%n", buf, &offset) == 1) {
347 break; /* stop reading till eol */
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);
358 bench(n_opts, opts, false);
360 for (int n = 0; n < n_opts; ++n)
368 int flip_coin(ptrdiff_t seed, float probability) {
369 const ptrdiff_t big_prime = 1000003;
370 const ptrdiff_t prime = 753737;
372 return (seed % big_prime) < (probability * big_prime);
375 int div_up(const int a, const int b){
376 SAFE_V(b != 0 ? OK : FAIL);
377 return (a + b - 1) / b;
380 void array_set(char *arr, size_t size) {
381 for (size_t i = 0; i < size; ++i)