FFmpeg
checkasm.c
Go to the documentation of this file.
1 /*
2  * Copyright © 2025, Niklas Haas
3  * Copyright © 2018, VideoLAN and dav1d authors
4  * Copyright © 2018, Two Orioles, LLC
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "checkasm_config.h"
31 
32 #if HAVE_PTHREAD_SETAFFINITY_NP
33  /* _GNU_SOURCE is required for pthread_setaffinity_np and CPU_SET on glibc. */
34  #ifndef _GNU_SOURCE
35  #define _GNU_SOURCE
36  #endif
37 #endif
38 
39 #include <assert.h>
40 #include <errno.h>
41 #include <inttypes.h>
42 #include <limits.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include "checkasm/checkasm.h"
49 #include "checkasm/test.h"
50 #include "cpu.h"
51 #include "function.h"
52 #include "html_data.h"
53 #include "internal.h"
54 #include "stats.h"
55 
56 #ifndef _WIN32
57  #if HAVE_PTHREAD_SETAFFINITY_NP
58  #include <pthread.h>
59  #if HAVE_PTHREAD_NP_H
60  #include <pthread_np.h>
61  #endif
62  #endif
63 #endif
64 
65 #ifdef _WIN32
66  #include <windows.h>
67 #endif
68 
69 #if HAVE_PRCTL
70  #include <sys/prctl.h>
71 #endif
72 
73 /* Internal state */
75 static CheckasmStats stats; /* temporary buffer for function measurements */
76 
77 /* Current function/test state, reset after each test run */
78 static struct {
80 
81  /* (Re)set by check_cpu_flag() */
86  const char *test_name;
89 
90  /* (Re)set per function (check_func, bench_finish) */
93  char *func_variant;
94  uint64_t cycles;
95 
96  /* Overall stats for this test run */
97  int num_funcs; /* known functions */
98  int num_checked; /* checked versions */
99  int num_failed; /* failed versions */
100  int num_benched; /* benched versions */
101  int prev_checked, prev_failed; /* reset by report() */
102  int saved_checked, saved_failed; /* for restoring after a crash */
103  double var_sum, var_max;
104 } current;
105 
106 /* Global state for the entire checkasm_run() call */
107 static struct {
108  /* Miscellaneous global state (cosmetic) */
111 
112  /* Timing code measurements (aggregated over multiple trials) */
115 
116  /* Runtime constants */
117  uint64_t target_cycles;
119 } state;
120 
122 {
123  return current.cpu_flags;
124 }
125 
127 {
128  return current.cpu;
129 }
130 
131 /* Get the suffix of the specified cpu flag */
132 static const char *cpu_suffix(const CheckasmCpuInfo *cpu)
133 {
134  return cpu ? cpu->suffix : "c";
135 }
136 
137 static const char *ver_suffix(const CheckasmFuncVersion *ver)
138 {
139  return ver->suffix ? ver->suffix : cpu_suffix(ver->cpu);
140 }
141 
142 /* Returns the coefficient of variation (CV) */
143 static double relative_error(double lvar)
144 {
145  return sqrt(exp(lvar) - 1.0);
146 }
147 
148 static inline char separator(CheckasmFormat format)
149 {
150  switch (format) {
151  case CHECKASM_FORMAT_CSV: return ',';
152  case CHECKASM_FORMAT_TSV: return '\t';
153  default: return 0;
154  }
155 }
156 
157 static void json_var(CheckasmJson *json, const char *key, const char *unit,
158  const CheckasmVar var)
159 {
160  if (key)
161  checkasm_json_push(json, key, '{');
162  if (unit)
163  checkasm_json_str(json, "unit", unit);
164  checkasm_json(json, "mode", "%g", checkasm_mode(var));
165  checkasm_json(json, "median", "%g", checkasm_median(var));
166  checkasm_json(json, "mean", "%g", checkasm_mean(var));
167  checkasm_json(json, "lowerCI", "%g", checkasm_sample(var, -1.96));
168  checkasm_json(json, "upperCI", "%g", checkasm_sample(var, 1.96));
169  checkasm_json(json, "stdDev", "%g", checkasm_stddev(var));
170  checkasm_json(json, "logMean", "%g", var.lmean);
171  checkasm_json(json, "logVar", "%g", var.lvar);
172  if (key)
173  checkasm_json_pop(json, '}');
174 }
175 
176 static void json_measurement(CheckasmJson *json, const char *key, const char *unit,
177  const CheckasmMeasurement measurement)
178 {
179  const CheckasmVar result = checkasm_measurement_result(measurement);
180  if (key)
181  checkasm_json_push(json, key, '{');
182  json_var(json, NULL, unit, result);
183  checkasm_json(json, "numMeasurements", "%d", measurement.nb_measurements);
184 
185  if (measurement.stats.nb_samples) {
186  json_var(json, "regressionSlope", unit,
187  checkasm_stats_estimate(&measurement.stats));
188  checkasm_json_push(json, "rawData", '[');
189  for (int i = 0; i < measurement.stats.nb_samples; i++) {
190  const CheckasmSample s = measurement.stats.samples[i];
191  checkasm_json(json, NULL, "{ \"iters\": %d, \"cycles\": %" PRIu64 " }",
192  s.count, s.sum);
193  }
194  checkasm_json_pop(json, ']');
195  }
196 
197  if (key)
198  checkasm_json_pop(json, '}');
199 }
200 
201 static void cpu_info_json(void *priv, const char *fmt, ...)
202 {
203  CheckasmJson *json = priv;
204  char buf[128];
205  va_list ap;
206  va_start(ap, fmt);
207  vsnprintf(buf, sizeof(buf), fmt, ap);
208  va_end(ap);
209 
210  checkasm_json_str(json, NULL, buf);
211 }
212 
213 struct IterState {
214  const char *test;
215  const char *report;
217 };
218 
219 static void print_bench_header(struct IterState *const iter)
220 {
224  CheckasmJson *const json = &iter->json;
225 
226  switch (cfg.format) {
227  case CHECKASM_FORMAT_TSV:
228  case CHECKASM_FORMAT_CSV:
229  if (cfg.verbose) {
230  const char sep = separator(cfg.format);
231  printf("name%csuffix%c%ss%cstddev%cnanoseconds\n", sep, sep,
232  checkasm_perf.unit, sep, sep);
233  printf("nop%c%c%.4f%c%.5f%c%.4f\n", sep, sep, checkasm_mode(nop_cycles), sep,
234  checkasm_stddev(nop_cycles), sep, checkasm_mode(nop_time));
235  }
236  break;
238  printf("<!doctype html>\n"
239  "<html>\n"
240  "<head>\n"
241  " <meta charset=\"utf-8\"/>\n"
242  " <title>checkasm report</title>\n"
243  " <script type=\"module\">\n"
244  " %s"
245  " %s"
246  " </script>\n"
247  " <style>\n"
248  " %s"
249  " </style>\n"
250  " <script type=\"application/json\" id=\"report-data\">\n",
252  FALLTHROUGH;
254  checkasm_json_push(json, NULL, '{');
255  checkasm_json_str(json, "checkasmVersion", CHECKASM_VERSION);
256  checkasm_json(json, "numChecked", "%d", current.num_checked);
257  checkasm_json(json, "numFailed", "%d", current.num_failed);
258  checkasm_json(json, "targetCycles", "%" PRIu64, state.target_cycles);
259  checkasm_json(json, "numBenchmarks", "%d", current.num_benched);
260  checkasm_json_push(json, "config", '{');
261  if (cfg.test_pattern)
262  checkasm_json_str(json, "testPattern", cfg.test_pattern);
263  if (cfg.function_pattern)
264  checkasm_json_str(json, "functionPattern", cfg.function_pattern);
265  checkasm_json(json, "benchUsec", "%u", cfg.bench_usec);
266  checkasm_json(json, "seed", "%u", cfg.seed);
267  checkasm_json(json, "repeat", "%u", cfg.repeat);
268  if (cfg.cpu_affinity_set)
269  checkasm_json(json, "cpuAffinity", "%u", cfg.cpu_affinity);
270  checkasm_json_pop(json, '}'); /* close config */
271  checkasm_json_push(json, "cpuInfo", '[');
273  checkasm_json_pop(json, ']');
274  checkasm_json_push(json, "cpuFlags", '{');
275  for (const CheckasmCpuInfo *info = cfg.cpu_flags; info->flag; info++) {
276  const int available = (cfg.cpu & info->flag) == info->flag;
277  checkasm_json_push(json, info->suffix, '{');
278  checkasm_json_str(json, "name", info->name);
279  checkasm_json(json, "available", available ? "true" : "false");
280  checkasm_json_pop(json, '}');
281  }
282  checkasm_json_pop(json, '}'); /* close cpuFlags */
283  checkasm_json_push(json, "tests", '[');
284  for (const CheckasmTest *test = cfg.tests; test->func; test++)
285  checkasm_json_str(json, NULL, test->name);
286  checkasm_json_pop(json, ']'); /* close tests */
287  char perf_scale_unit[32];
288  snprintf(perf_scale_unit, sizeof(perf_scale_unit), "nsec/%s", checkasm_perf.unit);
289  json_measurement(json, "nopCycles", checkasm_perf.unit, state.nop_cycles);
290  json_measurement(json, "timerScale", perf_scale_unit, state.perf_scale);
291  json_var(json, "nopTime", checkasm_perf.unit, nop_time);
292  checkasm_json(json, "numFunctions", "%d", current.num_funcs);
293  checkasm_json_push(json, "functions", '{');
294  break;
296  checkasm_fprintf(stdout, COLOR_YELLOW, "Benchmark results:\n");
297  checkasm_fprintf(stdout, COLOR_GREEN, " name%*ss",
298  5 + state.max_function_name_length, checkasm_perf.unit);
299  if (cfg.verbose) {
300  checkasm_fprintf(stdout, COLOR_GREEN, " +/- stddev %*s", 26,
301  "time (nanoseconds)");
302  }
303  checkasm_fprintf(stdout, COLOR_GREEN, " (vs ref)\n");
304  if (cfg.verbose) {
305  printf(" nop:%*.1f +/- %-7.1f %11.1f ns +/- %-6.1f\n",
306  6 + state.max_function_name_length, checkasm_mode(nop_cycles),
308  checkasm_stddev(nop_time));
309  }
310  break;
311  }
312 }
313 
314 static void print_bench_footer(struct IterState *const iter)
315 {
316  const double err_rel = relative_error(current.var_sum / current.num_benched);
317  const double err_max = relative_error(current.var_max);
318  CheckasmJson *const json = &iter->json;
319 
320  switch (cfg.format) {
321  case CHECKASM_FORMAT_TSV:
322  case CHECKASM_FORMAT_CSV: break;
324  if (cfg.verbose) {
325  printf(" - average timing error: %.3f%% across %d benchmarks "
326  "(maximum %.3f%%)\n",
327  100.0 * err_rel, current.num_benched, 100.0 * err_max);
328  }
329  break;
332  checkasm_json_pop(json, '}'); /* close functions */
333  checkasm_json(json, "averageError", "%g", err_rel);
334  checkasm_json(json, "maximumError", "%g", err_max);
335  checkasm_json_pop(json, '}'); /* close root */
336 
338  printf(" </script>\n"
339  " <meta name=\"viewport\" content=\"width=device-width, "
340  "initial-scale=1\">\n"
341  "</head>\n"
342  "%s"
343  "</html>\n",
345  }
346  break;
347  }
348 }
349 
350 static void print_bench_iter(const CheckasmFunc *const f, struct IterState *const iter)
351 {
352  CheckasmJson *const json = &iter->json;
353  const char sep = separator(cfg.format);
354  if (!f)
355  return;
356 
357  print_bench_iter(f->child[0], iter);
358 
359  const CheckasmFuncVersion *ref = &f->versions;
360  const CheckasmFuncVersion *v = ref;
363 
364  /* Defer pushing the function header until we know that we have at least one
365  * benchmark to report */
366  int json_func_pushed = 0;
367 
368  do {
369  if (v->cycles.nb_measurements) {
371  const CheckasmVar raw_ref = checkasm_measurement_result(ref->cycles);
372 
374  const CheckasmVar cycles_ref = checkasm_var_sub(raw_ref, nop_cycles);
375  const CheckasmVar ratio = checkasm_var_div(cycles_ref, cycles);
376  const CheckasmVar raw_time = checkasm_var_mul(raw, perf_scale);
378 
379  switch (cfg.format) {
382  if (!json_func_pushed) {
383  checkasm_json_push(json, f->name, '{');
384  checkasm_json_str(json, "testName", f->test_name);
385  if (f->report_name)
386  checkasm_json_str(json, "reportName", f->report_name);
387  checkasm_json_push(json, "versions", '{');
388  json_func_pushed = 1;
389  }
390 
391  checkasm_json_push(json, ver_suffix(v), '{');
392  json_measurement(json, "rawCycles", checkasm_perf.unit, v->cycles);
393  json_var(json, "rawTime", "nsec", raw_time);
394  json_var(json, "adjustedCycles", checkasm_perf.unit, cycles);
395  json_var(json, "adjustedTime", "nsec", time);
396  if (v != ref && ref->cycles.nb_measurements)
397  json_var(json, "ratio", NULL, checkasm_var_div(cycles_ref, cycles));
398  checkasm_json_pop(json, '}'); /* close version */
399  break;
400  case CHECKASM_FORMAT_TSV:
401  case CHECKASM_FORMAT_CSV:
402  printf("%s%c%s%c%.4f%c%.5f%c%.4f\n", f->name, sep, ver_suffix(v),
403  sep, checkasm_mode(cycles), sep, checkasm_stddev(cycles), sep,
404  checkasm_mode(time));
405  break;
407  const int pad = 12 + state.max_function_name_length
408  - printf(" %s_%s:", f->name, ver_suffix(v));
409  printf("%*.1f", imax(pad, 0), checkasm_mode(cycles));
410  if (cfg.verbose) {
411  printf(" +/- %-7.1f %11.1f ns +/- %-6.1f", checkasm_stddev(cycles),
412  checkasm_mode(time), checkasm_stddev(time));
413  }
414  if (v != ref && ref->cycles.nb_measurements) {
415  const double ratio_lo = checkasm_sample(ratio, -1.0);
416  const double ratio_hi = checkasm_sample(ratio, 1.0);
417  const int color = ratio_lo >= 10.0 ? COLOR_GREEN
418  : ratio_hi >= 1.1 && ratio_lo >= 1.0 ? COLOR_DEFAULT
419  : ratio_hi >= 1.0 ? COLOR_YELLOW
420  : COLOR_RED;
421  printf(" (");
422  checkasm_fprintf(stdout, color, "%5.2fx", checkasm_mode(ratio));
423  printf(")");
424  }
425  printf("\n");
426  break;
427  }
428  }
429  } while ((v = v->next));
430 
431  if (json_func_pushed) {
432  checkasm_json_pop(json, '}'); /* close versions */
433  checkasm_json_pop(json, '}'); /* close function */
434  }
435 
436  print_bench_iter(f->child[1], iter);
437 }
438 
439 static void print_benchmarks(void)
440 {
441  struct IterState iter = { .json.file = stdout };
442  print_bench_header(&iter);
443  print_bench_iter(current.tree.root, &iter);
444  print_bench_footer(&iter);
445  assert(iter.json.level == 0);
446 }
447 
448 /* Decide whether or not the current function needs to be benchmarked */
450 {
451  return !current.num_failed && cfg.bench && !checkasm_interrupted;
452 }
453 
455 {
457  return 0;
458 
459  /* This limit should be impossible to hit in practice */
461  return 0;
462 
463  /* Try and gather at least 30 samples for statistical validity, even if
464  * it means exceeding the time budget */
465  if (current.cycles < state.target_cycles || stats.nb_samples < 30)
466  return stats.next_count;
467  else
468  return 0;
469 }
470 
471 /* Update benchmark results of the current function */
472 void checkasm_bench_update(const int iterations, const uint64_t cycles)
473 {
474  checkasm_stats_add(&stats, (CheckasmSample) { cycles, iterations });
475  checkasm_stats_count_grow(&stats, cycles, state.target_cycles);
476  current.cycles += cycles;
477 
478  /* Emit this periodically while benchmarking, to avoid the SIMD
479  * units turning on and off during long bench runs of non-SIMD
480  * functions */
481 #if ARCH_X86
482  checkasm_simd_warmup();
483 #endif
484 }
485 
487 {
488  CheckasmFuncVersion *const v = current.func_ver;
489  if (v && current.cycles) {
491 
492  /* Accumulate multiple bench_new() calls */
494 
495  /* Keep track of min/max/avg (log) variance */
496  current.var_sum += cycles.lvar;
497  current.var_max = fmax(current.var_max, cycles.lvar);
498  current.num_benched++;
499  }
500 
502  current.cycles = 0;
503 }
504 
505 /* Compares a string with a wildcard pattern. */
506 static int wildstrcmp(const char *str, const char *pattern)
507 {
508  const char *wild = strchr(pattern, '*');
509  if (wild) {
510  const size_t len = wild - pattern;
511  if (strncmp(str, pattern, len))
512  return 1;
513  while (*++wild == '*')
514  ;
515  if (!*wild)
516  return 0;
517  str += len;
518  while (*str && wildstrcmp(str, wild))
519  str++;
520  return !*str;
521  }
522  return strcmp(str, pattern);
523 }
524 
525 static void handle_interrupt(void);
526 
527 /* Perform tests and benchmarks for the specified
528  * cpu flag if supported by the host */
529 static void check_cpu_flag(const CheckasmCpuInfo *cpu)
530 {
531  const CheckasmCpu prev_cpu_flags = current.cpu_flags;
532  if (cpu) {
533  current.cpu_flags |= cpu->flag & cfg.cpu;
534  } else {
535  /* Also include any CPU flags not related to the CPU flags list */
536  current.cpu_flags = cfg.cpu;
537  for (const CheckasmCpuInfo *info = cfg.cpu_flags; info->flag; info++)
538  current.cpu_flags &= ~info->flag;
539  }
540 
541  if (cpu && current.cpu_flags == prev_cpu_flags)
542  return;
543 
544  current.func = NULL;
545  current.report_idx = 1;
546  current.cpu = cpu;
547  current.cpu_name_printed = 0;
548  current.cpu_suffix_length = (int) strlen(cpu_suffix(cpu)) + 1;
549  if (cfg.set_cpu_flags)
550  cfg.set_cpu_flags(current.cpu_flags);
551 
552  for (const CheckasmTest *test = cfg.tests; test->func; test++) {
554  continue;
555  current.test_name = test->name;
556 
558  const char *signal = checkasm_get_last_signal_desc();
560  checkasm_fail_func("%s", signal);
561 
562  /* We want to associate this (and any prior) failures with the
563  * correct report group, so remember the failure state until we
564  * reach the same position in the test() function again */
565  current.func_ver->state = CHECKASM_FUNC_CRASHED;
566  current.saved_checked = current.num_checked - current.prev_checked;
567  current.saved_failed = current.num_failed - current.prev_failed;
568  current.num_failed = current.prev_failed;
569  current.num_checked = current.prev_checked;
570  current.func = NULL;
571  }
572 
574  current.should_fail = 0; // reset between tests
575  test->func();
576  checkasm_report(NULL); // catch any un-reported functions
577 
578  if (cfg.bench && !state.skip_tests) {
579  /* Measure NOP and perf scale after each test+CPU flag configuration */
581  checkasm_measure_nop_cycles(&state.nop_cycles, state.target_cycles);
583  checkasm_measure_perf_scale(&state.perf_scale);
584  }
585 
586  free(current.func_variant);
587  current.func_variant = NULL;
588  }
589 }
590 
591 /* Print the name of the current CPU flag, but only do it once */
592 static void print_cpu_name(void)
593 {
594  if (!current.cpu_name_printed) {
595  checkasm_fprintf(stderr, COLOR_YELLOW, "%s:\n",
596  current.cpu ? current.cpu->name : "C");
597  current.cpu_name_printed = 1;
598  }
599 }
600 
601 int checkasm_run_on_all_cores(void (*func)(void))
602 {
603 #if HAVE_PTHREAD_SETAFFINITY_NP && defined(CPU_SET)
604  cpu_set_t mask;
605  if (pthread_getaffinity_np(pthread_self(), sizeof(mask), &mask))
606  return 1;
607 
608  int ret = 0;
609  for (int c = 0; c < CPU_SETSIZE; c++) {
610  if (CPU_ISSET(c, &mask)) {
611  cpu_set_t set;
612  CPU_ZERO(&set);
613  CPU_SET(c, &set);
614  if (pthread_setaffinity_np(pthread_self(), sizeof(set), &set)) {
615  ret = 1;
616  break;
617  }
618  func();
619  }
620  }
621  pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask);
622  return ret;
623 #else
624  return 1;
625 #endif
626 }
627 
628 static int set_cpu_affinity(const unsigned affinity)
629 {
630  int affinity_err;
631 
632 #ifdef _WIN32
633  HANDLE process = GetCurrentProcess();
634  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
635  BOOL(WINAPI * spdcs)(HANDLE, const ULONG *, ULONG) = (void *) GetProcAddress(
636  GetModuleHandleW(L"kernel32.dll"), "SetProcessDefaultCpuSets");
637  if (spdcs)
638  affinity_err = !spdcs(process, (ULONG[]) { (ULONG) affinity + 256 }, 1);
639  else
640  #endif
641  {
642  if (affinity < sizeof(DWORD_PTR) * 8)
643  affinity_err = !SetProcessAffinityMask(process, (DWORD_PTR) 1 << affinity);
644  else
645  affinity_err = 1;
646  }
647 #elif HAVE_PTHREAD_SETAFFINITY_NP && defined(CPU_SET)
648  cpu_set_t set;
649  CPU_ZERO(&set);
650  CPU_SET(affinity, &set);
651  affinity_err = pthread_setaffinity_np(pthread_self(), sizeof(set), &set);
652 #else
653  (void) affinity;
654  (void) affinity_err;
655  fprintf(stderr, "checkasm: --affinity is not supported on your system\n");
656  return 1;
657 #endif
658 
659  if (affinity_err) {
660  fprintf(stderr, "checkasm: invalid cpu affinity (%u)\n", affinity);
661  return 1;
662  } else {
663  fprintf(stderr, "checkasm: running on cpu %u\n", affinity);
664  return 0;
665  }
666 }
667 
669 {
671 
672  for (const CheckasmCpuInfo *info = cfg->cpu_flags; info->flag; info++) {
673  if ((cfg->cpu & info->flag) == info->flag)
674  checkasm_fprintf(stdout, COLOR_GREEN, "%s", info->suffix);
675  else
676  checkasm_fprintf(stdout, COLOR_RED, "~%s", info->suffix);
677  printf(info[1].flag ? ", " : "\n");
678  }
679 }
680 
682 {
683  for (const CheckasmTest *test = config->tests; test->func; test++)
684  printf("%s\n", test->name);
685 }
686 
687 static void print_functions(const CheckasmFunc *const f)
688 {
689  if (f) {
690  print_functions(f->child[0]);
691  const CheckasmFuncVersion *v = &f->versions;
692  printf("%s (%s", f->name, ver_suffix(v));
693  while ((v = v->next))
694  printf(", %s", ver_suffix(v));
695  printf(")\n");
696  print_functions(f->child[1]);
697  }
698 }
699 
701 {
702  memset(&state, 0, sizeof(state));
703  memset(&current, 0, sizeof(current));
704  state.skip_tests = 1;
705  cfg = *config;
706 
708  for (const CheckasmCpuInfo *info = cfg.cpu_flags; info->flag; info++)
710 
711  print_functions(current.tree.root);
713 }
714 
715 static void cpu_fprintf(void *priv, const char *fmt, ...)
716 {
717  FILE *f = priv;
718 
719  va_list ap;
720  va_start(ap, fmt);
721  fprintf(f, " - CPU: ");
722  vfprintf(f, fmt, ap);
723  fprintf(f, "\n");
724  va_end(ap);
725 }
726 
727 static COLD void print_info(void)
728 {
729  checkasm_fprintf(stderr, COLOR_YELLOW, "checkasm:\n");
730  checkasm_cpu_info(cpu_fprintf, stderr, &cfg);
731 
732  if (cfg.bench) {
733  fprintf(stderr, " - Timing source: %s\n", checkasm_perf.name);
734  if (cfg.verbose) {
738  fprintf(stderr,
739  " - Timing resolution: %.4f +/- %.3f ns/%s (%.0f +/- %.1f "
740  "MHz) (provisional)\n",
743 
744  fprintf(stderr,
745  " - No-op overhead: %.2f +/- %.3f %ss per call (provisional)\n",
748  }
749  fprintf(stderr, " - Bench duration: %d µs per function (%" PRIu64 " %ss)\n",
750  cfg.bench_usec, state.target_cycles, checkasm_perf.unit);
751  }
752  fprintf(stderr, " - Random seed: %u\n", cfg.seed);
753 }
754 
755 static int print_summary(void)
756 {
757  /* Exclude C/ref versions from count reported to user */
758  const int num_checked_asm = current.num_checked - current.num_funcs;
759  if (current.num_failed) {
760  fprintf(stderr, "checkasm: %d of %d tests failed\n", current.num_failed,
761  num_checked_asm);
762  } else if (num_checked_asm) {
763  fprintf(stderr, "checkasm: all %d tests passed\n", num_checked_asm);
764  } else {
765  fprintf(stderr, "checkasm: no tests to perform\n");
766  }
767 
768  if (current.num_benched && !current.num_failed)
770 
771  return current.num_failed > 0;
772 }
773 
774 static void handle_interrupt(void)
775 {
776  if (checkasm_interrupted) {
777  fprintf(stderr, "checkasm: interrupted\n");
778  print_summary();
779  exit(128 + checkasm_interrupted);
780  }
781 }
782 
784 {
785 #if !HAVE_HTML_DATA
787  fprintf(stderr, "checkasm: built without HTML support\n");
788  return 1;
789  }
790 #endif
791 
792  memset(&state, 0, sizeof(state));
793  memset(&current, 0, sizeof(current));
794  cfg = *config;
795 
797 #if HAVE_PRCTL && defined(PR_SET_UNALIGN)
798  prctl(PR_SET_UNALIGN, PR_UNALIGN_SIGBUS);
799 #endif
800  if (cfg.cpu_affinity_set)
803 
804  if (!cfg.seed && !cfg.seed_set)
805  cfg.seed = checkasm_seed();
806  if (!cfg.repeat)
807  cfg.repeat = 1;
808  if (!cfg.bench_usec)
809  cfg.bench_usec = 1000;
810 
811  if (cfg.bench) {
812  if (checkasm_perf_init())
813  return 1;
814 
816  checkasm_measurement_init(&state.nop_cycles);
817  checkasm_measurement_init(&state.perf_scale);
818  checkasm_measure_perf_scale(&state.perf_scale);
819 
820  /* Use the low estimate to compute the number of target cycles, to
821  * ensure we reach the required number of cycles with confidence */
823  const double low_estimate = checkasm_sample(perf_scale, -1.0);
824  if (low_estimate <= 0.0) {
825  fprintf(stderr,
826  "checkasm: cycle counter seems to be non-functional "
827  "(invalid timer scale: %.4f %ss/nsec)\n",
829  return 1;
830  }
831 
832  state.target_cycles = (uint64_t) (1e3 * cfg.bench_usec / low_estimate);
833  checkasm_measure_nop_cycles(&state.nop_cycles, state.target_cycles);
834  }
835 
837 
838  print_info();
839 
840  for (unsigned i = 0; i < cfg.repeat; i++) {
841  if (i > 0) {
842  checkasm_fprintf(stderr, COLOR_YELLOW, "\nTest #%d:\n", i + 1);
843  fprintf(stderr, " - Random seed: %u\n", cfg.seed);
844  }
845 
847  for (const CheckasmCpuInfo *info = cfg.cpu_flags; info->flag; info++)
849 
850  int res = print_summary();
852  if (res)
853  return res;
854 
855  memset(&current, 0, sizeof(current));
856  cfg.seed++;
857  }
858 
859  return 0;
860 }
861 
862 /* Decide whether or not the specified function needs to be tested and
863  * allocate/initialize data structures if needed. Returns a pointer to a
864  * reference function if the function should be tested, otherwise NULL */
865 CheckasmKey checkasm_check_key(const CheckasmKey version, const char *const name, ...)
866 {
867  char name_buf[256];
868  va_list arg;
869 
871  goto skip;
872 
873  va_start(arg, name);
874  int name_length = vsnprintf(name_buf, sizeof(name_buf), name, arg);
875  va_end(arg);
876 
877  if (!version || name_length <= 0 || (size_t) name_length >= sizeof(name_buf)
879  goto skip;
880 
881  CheckasmFunc *const f = checkasm_func_get(&current.tree, name_buf);
882  CheckasmFuncVersion *v = &f->versions;
884 
885  if (v->key) {
886  CheckasmFuncVersion *prev;
887  do {
888  if (v->state == CHECKASM_FUNC_CRASHED) {
889  /* This function threw a signal last time; so restore the
890  * retained test state for the next report() call */
892  current.num_checked += current.saved_checked;
893  current.num_failed += current.saved_failed;
894  current.saved_checked = 0;
895  current.saved_failed = 0;
896  current.func = f;
897  current.func_ver = v;
898  for (CheckasmFunc *fp = f; fp; fp = fp->prev)
899  fp->report_idx = current.report_idx;
900  }
901 
902  /* Skip functions without a working reference */
903  if (!v->cpu && v->state != CHECKASM_FUNC_OK)
904  goto skip;
905 
906  /* Only test functions that haven't already been tested */
907  if (v->key == version)
908  goto skip;
909 
910  /* Exclude failed or variant functions from being used as ref */
911  if (v->state == CHECKASM_FUNC_OK && !v->suffix)
912  ref = v->key;
913 
914  prev = v;
915  } while ((v = v->next));
916 
917  v = prev->next = checkasm_mallocz(sizeof(CheckasmFuncVersion));
918  }
919 
920  if (current.func_variant) {
921  v->suffix = current.func_variant;
922  current.func_variant = NULL;
923  name_length += (int) strlen(v->suffix) + 1;
924  } else {
925  name_length += current.cpu_suffix_length;
926  }
927 
928  if (name_length > state.max_function_name_length)
929  state.max_function_name_length = name_length;
930 
931  v->key = version;
932  v->state = CHECKASM_FUNC_OK;
933  v->cpu = current.cpu;
934  if (ref == version)
935  current.num_funcs++;
936 
937  if (state.skip_tests)
938  goto skip;
939 
940  /* Associate this function with each other function that was last used
941  * as part of the same report group */
942  if (f->report_idx < current.report_idx) {
943  f->report_idx = current.report_idx;
944  f->prev = current.func;
945  f->test_name = current.test_name;
946  }
947 
948  current.func = f;
949  current.func_ver = v;
950  current.num_checked++;
952 
953  if (cfg.bench) {
954 #if ARCH_X86
955  checkasm_simd_warmup();
956 #endif
958  }
959 
960  return ref;
961 
962 skip:
963  free(current.func_variant);
964  current.func_variant = NULL;
965  return 0;
966 }
967 
968 void checkasm_set_func_variant(const char *id_fmt, ...)
969 {
970  va_list arg;
971  va_start(arg, id_fmt);
972  assert(!current.func_variant);
973  current.func_variant = checkasm_vasprintf(id_fmt, arg);
974  va_end(arg);
975 }
976 
977 /* Indicate that the current test has failed, return whether verbose printing
978  * is requested. */
979 static int fail_internal(const char *const msg, va_list arg)
980 {
981  CheckasmFuncVersion *const v = current.func_ver;
982  if (v && v->state == CHECKASM_FUNC_OK) {
983  if (!current.should_fail) {
984  print_cpu_name();
985  checkasm_fprintf(stderr, COLOR_RED, "FAILURE:");
986  fprintf(stderr, " %s_%s (", current.func->name, ver_suffix(v));
987  vfprintf(stderr, msg, arg);
988  fputs(")\n", stderr);
989  }
990 
992  current.num_failed++;
993  }
994  return cfg.verbose && !current.should_fail;
995 }
996 
997 int checkasm_fail_func(const char *const msg, ...)
998 {
999  va_list arg;
1000  va_start(arg, msg);
1001  const int ret = fail_internal(msg, arg);
1002  va_end(arg);
1003  return ret;
1004 }
1005 
1006 void checkasm_fail_abort(const char *const msg, ...)
1007 {
1008  va_list arg;
1009  va_start(arg, msg);
1010  fail_internal(msg, arg);
1011  va_end(arg);
1012 
1014  abort(); // in case we don't have a longjmp implementation
1015 }
1016 
1018 {
1019  current.should_fail = !!(current.cpu_flags & cpu_flags);
1020 
1021 #if CHECKASM_HAVE_LONGJMP
1022  return 1; /* we can catch any crashes */
1023 #else
1024  /* If our signal handler isn't working, we shouldn't run tests that
1025  * are expected to fail, as they may rely on the signal handler. */
1026  return !current.should_fail;
1027 #endif
1028 }
1029 
1030 /* Print the outcome of all tests performed since
1031  * the last time this function was called */
1032 void checkasm_report(const char *const name, ...)
1033 {
1034  char report_name[256];
1035 
1036  /* Calculate the amount of padding required to make the output vertically aligned */
1037  int length = (int) strlen(current.test_name);
1038  if (name) {
1039  va_list arg;
1040  va_start(arg, name);
1041  length += 1 + vsnprintf(report_name, sizeof(report_name), name, arg);
1042  va_end(arg);
1043  }
1044 
1045  if (length > state.max_report_name_length)
1046  state.max_report_name_length = length;
1047 
1048  const int new_checked = current.num_checked - current.prev_checked;
1049  if (new_checked) {
1050  int pad_length = (int) state.max_report_name_length + 3; // strlen(" - ")
1051  assert(!state.skip_tests);
1052 
1053  int fails = current.num_failed - current.prev_failed;
1054  if (current.should_fail)
1055  current.num_failed = current.prev_failed + (new_checked - fails);
1056 
1057  /* Omit "OK" for non-verbose non-benchmark C function successes */
1058  const int want_print = current.num_failed != current.prev_failed
1059  || current.should_fail || cfg.verbose || cfg.bench
1060  || current.cpu;
1061 
1062  if (want_print) {
1063  print_cpu_name();
1064  if (name) {
1065  pad_length -= fprintf(stderr, " - %s.%s", current.test_name, report_name);
1066  } else {
1067  pad_length -= fprintf(stderr, " - %s", current.test_name);
1068  }
1069  fprintf(stderr, "%*c", imax(pad_length, 0) + 2, '[');
1070 
1071  if (current.num_failed == current.prev_failed) {
1072  checkasm_fprintf(stderr, COLOR_GREEN,
1073  current.should_fail ? "EXPECTED" : "OK");
1074  } else if (!current.should_fail)
1075  checkasm_fprintf(stderr, COLOR_RED, "FAILED");
1076  else
1077  checkasm_fprintf(stderr, COLOR_RED, "%d/%d EXPECTED", fails, new_checked);
1078  fprintf(stderr, "]\n");
1079  }
1080 
1081  current.prev_checked = current.num_checked;
1082  current.prev_failed = current.num_failed;
1083  }
1084 
1085  /* Store the report name with each function in this report group */
1086  CheckasmFunc *func = current.func;
1087  while (func) {
1088  if (name && !func->report_name)
1089  func->report_name = checkasm_strdup(report_name);
1090  func = func->prev;
1091  }
1092 
1093  current.func = NULL; /* reset current function for new report */
1094  current.report_idx++;
1095  handle_interrupt();
1096 }
1097 
1098 static void print_usage(const char *const progname)
1099 {
1100  fprintf(stderr,
1101  "Usage: %s [options...] <random seed>\n"
1102  " <random seed> Use fixed value to seed the PRNG\n"
1103  "Options:\n"
1104  " --affinity=<cpu> Run the process on CPU <cpu>\n"
1105  " --bench -b Benchmark the tested functions\n"
1106  " --csv, --tsv, --json, Choose output format for benchmarks\n"
1107  " --html\n"
1108  " --function=<pattern> -f Test only the functions matching "
1109  "<pattern>\n"
1110  " --help -h Print this usage info\n"
1111  " --list-cpu-flags List available cpu flags\n"
1112  " --list-functions List available functions\n"
1113  " --list-tests List available tests\n"
1114  " --duration=<μs> Benchmark duration (per function) in "
1115  "μs\n"
1116  " --repeat[=<N>] Repeat tests N times, on successive seeds\n"
1117  " --test=<pattern> -t Test only <pattern>\n"
1118  " --verbose -v Print verbose timing info and failure "
1119  "data\n",
1120  progname);
1121 }
1122 
1123 static int parseu(unsigned *const dst, const char *const str, const int base)
1124 {
1125  unsigned long val;
1126  char *end;
1127  errno = 0;
1128  val = strtoul(str, &end, base);
1129  if (errno || end == str || *end)
1130  return 0;
1131 #if !defined(__SIZEOF_LONG__) || !defined(__SIZEOF_INT__) || __SIZEOF_LONG__ > __SIZEOF_INT__
1132  /* This condition is split out; it can cause -Wtype-limits warnings on
1133  * 32 bit platforms and on Windows:
1134  * warning: result of comparison 'unsigned long' > 4294967295 is always false [-Wtautological-type-limit-compare] */
1135  if (val > (unsigned) -1)
1136  return 0;
1137 #endif
1138  *dst = (unsigned) val;
1139  return 1;
1140 }
1141 
1142 int checkasm_main(CheckasmConfig *config, int argc, const char *argv[])
1143 {
1144  while (argc > 1) {
1145  if (!strncmp(argv[1], "--help", 6) || !strcmp(argv[1], "-h")) {
1146  print_usage(argv[0]);
1147  return 0;
1148  } else if (!strcmp(argv[1], "--list-cpu-flags")
1149  || !strcmp(argv[1], "--list-cpuflags")) {
1151  return 0;
1152  } else if (!strcmp(argv[1], "--list-tests")) {
1154  return 0;
1155  } else if (!strcmp(argv[1], "--list-functions")) {
1157  return 0;
1158  } else if (!strcmp(argv[1], "--bench") || !strcmp(argv[1], "-b")) {
1159  config->bench = 1;
1160  } else if (!strncmp(argv[1], "--bench=", 8)) {
1161  config->bench = 1;
1162  config->function_pattern = argv[1] + 8;
1163  } else if (!strcmp(argv[1], "--csv")) {
1164  config->format = CHECKASM_FORMAT_CSV;
1165  } else if (!strcmp(argv[1], "--tsv")) {
1166  config->format = CHECKASM_FORMAT_TSV;
1167  } else if (!strcmp(argv[1], "--json")) {
1168  config->format = CHECKASM_FORMAT_JSON;
1169  } else if (!strcmp(argv[1], "--html")) {
1170 #if HAVE_HTML_DATA
1171  config->format = CHECKASM_FORMAT_HTML;
1172 #else
1173  fprintf(stderr, "checkasm: built without HTML support\n");
1174  return 1;
1175 #endif
1176  } else if (!strncmp(argv[1], "--duration=", 11)) {
1177  const char *const s = argv[1] + 11;
1178  if (!parseu(&config->bench_usec, s, 10)) {
1179  fprintf(stderr, "checkasm: invalid duration (%s)\n", s);
1180  print_usage(argv[0]);
1181  return 1;
1182  }
1183  } else if (!strncmp(argv[1], "--test=", 7)) {
1184  config->test_pattern = argv[1] + 7;
1185  } else if (!strcmp(argv[1], "-t")) {
1186  config->test_pattern = argc > 1 ? argv[2] : "";
1187  argc--;
1188  argv++;
1189  } else if (!strncmp(argv[1], "--function=", 11)) {
1190  config->function_pattern = argv[1] + 11;
1191  } else if (!strcmp(argv[1], "-f")) {
1192  config->function_pattern = argc > 1 ? argv[2] : "";
1193  argc--;
1194  argv++;
1195  } else if (!strcmp(argv[1], "--verbose") || !strcmp(argv[1], "-v")) {
1196  config->verbose = 1;
1197  } else if (!strncmp(argv[1], "--affinity=", 11)) {
1198  const char *const s = argv[1] + 11;
1199  config->cpu_affinity_set = 1;
1200  if (!parseu(&config->cpu_affinity, s, 16)) {
1201  fprintf(stderr, "checkasm: invalid cpu affinity (%s)\n", s);
1202  print_usage(argv[0]);
1203  return 1;
1204  }
1205  } else if (!strncmp(argv[1], "--repeat=", 9)) {
1206  const char *const s = argv[1] + 9;
1207  if (!parseu(&config->repeat, s, 10)) {
1208  fprintf(stderr, "checkasm: invalid number of repetitions (%s)\n", s);
1209  print_usage(argv[0]);
1210  return 1;
1211  }
1212  } else if (!strcmp(argv[1], "--repeat")) {
1213  config->repeat = UINT_MAX;
1214  } else {
1215  config->seed_set = 1;
1216  if (!parseu(&config->seed, argv[1], 10)) {
1217  fprintf(stderr, "checkasm: unknown option (%s)\n", argv[1]);
1218  print_usage(argv[0]);
1219  return 1;
1220  }
1221  }
1222 
1223  argc--;
1224  argv++;
1225  }
1226 
1227  return checkasm_run(config);
1228 }
func_variant
char * func_variant
Definition: checkasm.c:93
COLD
#define COLD
Definition: internal.h:45
CheckasmStats::next_count
int next_count
Definition: stats.h:91
num_failed
int num_failed
Definition: checkasm.c:99
process
static void process(NormalizeContext *s, AVFrame *in, AVFrame *out)
Definition: vf_normalize.c:155
checkasm_interrupted
volatile sig_atomic_t checkasm_interrupted
Definition: signal.c:50
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
printf
__device__ int printf(const char *,...)
CheckasmConfig::cpu_affinity
unsigned cpu_affinity
CPU core ID for process pinning.
Definition: checkasm.h:288
flag
int flag
Definition: cpu.c:40
checkasm_cpu_info
COLD void checkasm_cpu_info(void(*info_cb)(void *priv, const char *fmt,...), void *priv, const CheckasmConfig *config)
Definition: cpu.c:83
checkasm_config.h
ver_suffix
static const char * ver_suffix(const CheckasmFuncVersion *ver)
Definition: checkasm.c:137
color
Definition: vf_paletteuse.c:513
CheckasmJson::level
int level
Definition: internal.h:118
test_name
const char * test_name
Definition: checkasm.c:86
CheckasmStats::samples
CheckasmSample samples[CHECKASM_STATS_SAMPLES]
Definition: stats.h:89
CheckasmFunc
Definition: function.h:50
should_fail
int should_fail
Definition: checkasm.c:87
checkasm_context
checkasm_jmp_buf checkasm_context
Definition: signal.c:46
checkasm_js
static const char checkasm_js[]
Definition: html_data.h:63
var_max
double var_max
Definition: checkasm.c:103
IterState::report
const char * report
Definition: checkasm.c:215
checkasm_check_key
CheckasmKey checkasm_check_key(const CheckasmKey version, const char *const name,...)
Definition: checkasm.c:865
state
static struct @583 state
mask
int mask
Definition: mediacodecdec_common.c:154
checkasm_perf_init
int checkasm_perf_init(void)
Definition: perf.c:59
CheckasmFuncVersion::suffix
char * suffix
Definition: function.h:44
checkasm_save_context
#define checkasm_save_context(ctx)
Definition: longjmp.h:67
CHECKASM_VERSION
#define CHECKASM_VERSION
Definition: checkasm_config.h:89
CheckasmMeasurement::stats
CheckasmStats stats
Definition: stats.h:125
CheckasmConfig::bench
int bench
Enable benchmarking.
Definition: checkasm.h:223
test
Definition: idctdsp.c:35
saved_checked
int saved_checked
Definition: checkasm.c:102
checkasm_measure_nop_cycles
void checkasm_measure_nop_cycles(CheckasmMeasurement *meas, uint64_t target_cycles)
Definition: perf.c:176
CheckasmFuncVersion::key
CheckasmKey key
Definition: function.h:45
base
uint8_t base
Definition: vp3data.h:128
checkasm_list_cpu_flags
void checkasm_list_cpu_flags(const CheckasmConfig *cfg)
Print available CPU flags to stdout.
Definition: checkasm.c:668
cpu_info_json
static void cpu_info_json(void *priv, const char *fmt,...)
Definition: checkasm.c:201
checkasm_list_tests
void checkasm_list_tests(const CheckasmConfig *config)
Print available tests.
Definition: checkasm.c:681
CheckasmConfig::test_pattern
const char * test_pattern
Pattern for filtering which tests to run.
Definition: checkasm.h:206
CheckasmMeasurement::nb_measurements
int nb_measurements
Definition: stats.h:124
CheckasmJson::file
FILE * file
Definition: internal.h:117
cpu_suffix_length
int cpu_suffix_length
Definition: checkasm.c:85
tf_sess_config.config
config
Definition: tf_sess_config.py:33
fail_internal
static int fail_internal(const char *const msg, va_list arg)
Definition: checkasm.c:979
CHECKASM_STATS_SAMPLES
#define CHECKASM_STATS_SAMPLES
Definition: stats.h:88
report_idx
int report_idx
Definition: checkasm.c:88
checkasm_chart_js
static const char checkasm_chart_js[]
Definition: html_data.h:62
checkasm_set_func_variant
void checkasm_set_func_variant(const char *id_fmt,...)
Definition: checkasm.c:968
checkasm_perf
CheckasmPerf checkasm_perf
Definition: perf.c:52
handle_interrupt
static void handle_interrupt(void)
Definition: checkasm.c:774
checkasm_fprintf
void checkasm_fprintf(FILE *const f, const int color, const char *const fmt,...) CHECKASM_PRINTF(3
CheckasmFormat
CheckasmFormat
Output format for benchmark results.
Definition: checkasm.h:129
IterState::json
CheckasmJson json
Definition: checkasm.c:216
CHECKASM_FORMAT_JSON
@ CHECKASM_FORMAT_JSON
JSON structured output with all measurement data.
Definition: checkasm.h:133
checkasm_load_context
#define checkasm_load_context(ctx)
Definition: longjmp.h:68
print_bench_iter
static void print_bench_iter(const CheckasmFunc *const f, struct IterState *const iter)
Definition: checkasm.c:350
IterState
Definition: checkasm.c:213
checkasm_run_on_all_cores
int checkasm_run_on_all_cores(void(*func)(void))
Definition: checkasm.c:601
CheckasmConfig::cpu_flags
const CheckasmCpuInfo * cpu_flags
List of CPU flags understood by the implementation.
Definition: checkasm.h:168
checkasm_func_tree_uninit
void checkasm_func_tree_uninit(CheckasmFuncTree *tree)
Definition: function.c:59
CheckasmConfig::tests
const CheckasmTest * tests
Array of test functions to execute.
Definition: checkasm.h:176
imax
static int imax(const int a, const int b)
Definition: internal.h:160
CheckasmPerf::name
const char * name
Name of the timing mechanism (e.g., "clock_gettime")
Definition: test.h:543
val
static double val(void *priv, double ch)
Definition: aeval.c:77
max_function_name_length
int max_function_name_length
Definition: checkasm.c:109
check_cpu_flag
static void check_cpu_flag(const CheckasmCpuInfo *cpu)
Definition: checkasm.c:529
CheckasmCpuInfo
Describes a CPU feature flag/capability.
Definition: checkasm.h:105
num_funcs
int num_funcs
Definition: checkasm.c:97
checkasm_measurement_result
static CheckasmVar checkasm_measurement_result(const CheckasmMeasurement measurement)
Definition: stats.h:147
checkasm_mode
static double checkasm_mode(const CheckasmVar x)
Definition: stats.h:50
CheckasmConfig::function_pattern
const char * function_pattern
Pattern for filtering which functions within tests to run.
Definition: checkasm.h:215
target_cycles
uint64_t target_cycles
Definition: checkasm.c:117
checkasm_should_fail
int checkasm_should_fail(CheckasmCpu cpu_flags)
Mark a block of tests as expected to fail.
Definition: checkasm.c:1017
CheckasmFuncVersion
Definition: function.h:41
FALLTHROUGH
#define FALLTHROUGH
Definition: internal.h:92
num_benched
int num_benched
Definition: checkasm.c:100
checkasm_json
void checkasm_json(CheckasmJson *json, const char *key, const char *fmt,...) CHECKASM_PRINTF(3
set
static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v)
Definition: swresample.c:57
checkasm_mallocz
static void * checkasm_mallocz(const size_t size)
Definition: internal.h:180
parseu
static int parseu(unsigned *const dst, const char *const str, const int base)
Definition: checkasm.c:1123
checkasm_list_functions
void checkasm_list_functions(const CheckasmConfig *config)
Print available functions within tests.
Definition: checkasm.c:700
s
#define s(width, name)
Definition: cbs_vp9.c:198
COLOR_YELLOW
#define COLOR_YELLOW
Definition: internal.h:104
cpu_name_printed
int cpu_name_printed
Definition: checkasm.c:83
checkasm_set_signal_handlers
void checkasm_set_signal_handlers(void)
Definition: signal.c:132
checkasm_bench_update
void checkasm_bench_update(const int iterations, const uint64_t cycles)
Update benchmark statistics with timing results.
Definition: checkasm.c:472
CheckasmFuncTree
Definition: function.h:61
info
MIPS optimizations info
Definition: mips.txt:2
checkasm_mean
static double checkasm_mean(const CheckasmVar x)
Definition: stats.h:55
limits.h
CheckasmJson
Definition: internal.h:116
checkasm_var_const
static CheckasmVar checkasm_var_const(double x)
Definition: stats.h:65
key
const char * key
Definition: hwcontext_opencl.c:189
CheckasmFunc::prev
struct CheckasmFunc * prev
Definition: function.h:52
stats.h
arg
const char * arg
Definition: jacosubdec.c:65
CheckasmConfig::seed
unsigned seed
Random number generator seed.
Definition: checkasm.h:262
set_cpu_affinity
static int set_cpu_affinity(const unsigned affinity)
Definition: checkasm.c:628
print_bench_footer
static void print_bench_footer(struct IterState *const iter)
Definition: checkasm.c:314
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
NULL
#define NULL
Definition: coverity.c:32
CheckasmConfig::bench_usec
unsigned bench_usec
Target benchmark duration in microseconds.
Definition: checkasm.h:234
cycles
uint64_t cycles
Definition: checkasm.c:94
format
New swscale design to change SwsGraph is what coordinates multiple passes These can include cascaded scaling error diffusion and so on Or we could have separate passes for the vertical and horizontal scaling In between each SwsPass lies a fully allocated image buffer Graph passes may have different levels of e g we can have a single threaded error diffusion pass following a multi threaded scaling pass SwsGraph is internally recreated whenever the image format
Definition: swscale-v2.txt:14
prev_checked
int prev_checked
Definition: checkasm.c:101
CheckasmTest
Describes a single test function.
Definition: checkasm.h:117
checkasm_measure_perf_scale
void checkasm_measure_perf_scale(CheckasmMeasurement *meas)
Definition: perf.c:209
CHECKASM_FORMAT_PRETTY
@ CHECKASM_FORMAT_PRETTY
Pretty-printed (colored) text output (default)
Definition: checkasm.h:130
exp
int8_t exp
Definition: eval.c:76
test::name
const char * name
Definition: idctdsp.c:36
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
CHECKASM_FORMAT_TSV
@ CHECKASM_FORMAT_TSV
Tab-separated values with optional header.
Definition: checkasm.h:132
checkasm_var_mul
CheckasmVar checkasm_var_mul(CheckasmVar a, CheckasmVar b)
Definition: stats.c:78
print_benchmarks
static void print_benchmarks(void)
Definition: checkasm.c:439
CHECKASM_FUNC_OK
@ CHECKASM_FUNC_OK
Definition: function.h:36
cfg
static CheckasmConfig cfg
Definition: checkasm.c:74
CheckasmCpuInfo::suffix
const char * suffix
Short suffix for function names (e.g., "sse2", "avx2")
Definition: checkasm.h:107
func_ver
CheckasmFuncVersion * func_ver
Definition: checkasm.c:92
CHECKASM_FUNC_FAILED
@ CHECKASM_FUNC_FAILED
Definition: function.h:37
f
f
Definition: af_crystalizer.c:122
func
CheckasmFunc * func
Definition: checkasm.c:91
checkasm_stats_estimate
CheckasmVar checkasm_stats_estimate(const CheckasmStats *const stats)
Definition: stats.c:102
checkasm_html_body
static const char checkasm_html_body[]
Definition: html_data.h:65
checkasm_measurement_init
static void checkasm_measurement_init(CheckasmMeasurement *measurement)
Definition: stats.h:128
CheckasmFunc::report_name
char * report_name
Definition: function.h:55
print_summary
static int print_summary(void)
Definition: checkasm.c:755
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
checkasm_strdup
static char * checkasm_strdup(const char *str)
Definition: internal.h:185
COLOR_GREEN
#define COLOR_GREEN
Definition: internal.h:103
CheckasmConfig
Configuration structure for the checkasm test suite.
Definition: checkasm.h:158
test.h
Test writing API for checkasm.
checkasm_init_cpu
COLD void checkasm_init_cpu(void)
Definition: cpu.c:42
relative_error
static double relative_error(double lvar)
Definition: checkasm.c:143
cpu.h
CheckasmFuncVersion::cpu
const CheckasmCpuInfo * cpu
Definition: function.h:43
stats
static CheckasmStats stats
Definition: checkasm.c:75
checkasm_fail_abort
void checkasm_fail_abort(const char *const msg,...)
Definition: checkasm.c:1006
CHECKASM_FORMAT_CSV
@ CHECKASM_FORMAT_CSV
Comma-separated values with optional header.
Definition: checkasm.h:131
CHECKASM_FORMAT_HTML
@ CHECKASM_FORMAT_HTML
Interactive HTML report for web viewing.
Definition: checkasm.h:134
checkasm_get_cpu_flags
CheckasmCpu checkasm_get_cpu_flags(void)
Get the current active set of CPU flags.
Definition: checkasm.c:121
cpu_flags
CheckasmCpu cpu_flags
Definition: checkasm.c:84
print_functions
static void print_functions(const CheckasmFunc *const f)
Definition: checkasm.c:687
checkasm_var_sub
CheckasmVar checkasm_var_sub(CheckasmVar a, CheckasmVar b)
Definition: stats.c:64
version
version
Definition: libkvazaar.c:313
checkasm_setup_fprintf
void checkasm_setup_fprintf(void)
Definition: utils.c:404
cpu_fprintf
static void cpu_fprintf(void *priv, const char *fmt,...)
Definition: checkasm.c:715
checkasm_bench_func
int checkasm_bench_func(void)
Check if current function should be benchmarked.
Definition: checkasm.c:449
print_cpu_name
static void print_cpu_name(void)
Definition: checkasm.c:592
checkasm_var_div
CheckasmVar checkasm_var_div(CheckasmVar a, CheckasmVar b)
Definition: stats.c:94
perf_scale
CheckasmMeasurement perf_scale
Definition: checkasm.c:114
checkasm_seed
unsigned checkasm_seed(void)
Definition: utils.c:117
wildstrcmp
static int wildstrcmp(const char *str, const char *pattern)
Definition: checkasm.c:506
prev_failed
int prev_failed
Definition: checkasm.c:101
function.h
COLOR_DEFAULT
#define COLOR_DEFAULT
Definition: internal.h:101
checkasm_run
int checkasm_run(const CheckasmConfig *config)
Run all tests and benchmarks matching the specified patterns.
Definition: checkasm.c:783
available
if no frame is available
Definition: filter_design.txt:166
CheckasmMeasurement
Definition: stats.h:122
CheckasmFuncVersion::next
struct CheckasmFuncVersion * next
Definition: function.h:42
vsnprintf
#define vsnprintf
Definition: snprintf.h:36
json_measurement
static void json_measurement(CheckasmJson *json, const char *key, const char *unit, const CheckasmMeasurement measurement)
Definition: checkasm.c:176
max_report_name_length
int max_report_name_length
Definition: checkasm.c:110
CheckasmCpuInfo::flag
CheckasmCpu flag
Bitmask flag value for this CPU feature.
Definition: checkasm.h:108
cpu
const CheckasmCpuInfo * cpu
Definition: checkasm.c:82
checkasm_srand
void checkasm_srand(unsigned seed)
Definition: utils.c:127
checkasm_median
static double checkasm_median(const CheckasmVar x)
Definition: stats.h:45
checkasm_json_pop
void checkasm_json_pop(CheckasmJson *json, char type)
Definition: utils.c:485
print_info
static COLD void print_info(void)
Definition: checkasm.c:727
checkasm_stats_count_grow
static void checkasm_stats_count_grow(CheckasmStats *const stats, uint64_t cycles, uint64_t target_cycles)
Definition: stats.h:108
len
int len
Definition: vorbis_enc_data.h:426
CheckasmPerf::unit
const char * unit
Unit of measurement (e.g., "ns", "cycles")
Definition: test.h:546
checkasm_main
int checkasm_main(CheckasmConfig *config, int argc, const char *argv[])
Main entry point for checkasm test programs.
Definition: checkasm.c:1142
checkasm_stddev
static double checkasm_stddev(const CheckasmVar x)
Definition: stats.h:60
checkasm_json_str
void void checkasm_json_str(CheckasmJson *json, const char *key, const char *str)
Definition: utils.c:444
CheckasmConfig::cpu_affinity_set
int cpu_affinity_set
Enable process pinning via cpu_affinity.
Definition: checkasm.h:281
checkasm_css
static const char checkasm_css[]
Definition: html_data.h:64
html_data.h
CHECKASM_FUNC_CRASHED
@ CHECKASM_FUNC_CRASHED
Definition: function.h:38
ret
ret
Definition: filter_design.txt:187
CheckasmVar::lmean
double lmean
Definition: stats.h:36
checkasm_get_cpu_info
const CheckasmCpuInfo * checkasm_get_cpu_info(void)
Get the CPU flag currently being tested.
Definition: checkasm.c:126
checkasm_bench_runs
int checkasm_bench_runs(void)
Get number of iterations for current benchmark run.
Definition: checkasm.c:454
checkasm_json_push
void checkasm_json_push(CheckasmJson *json, const char *const key, char type)
Definition: utils.c:469
CheckasmKey
uintptr_t CheckasmKey
Opaque type used to identify function implementations.
Definition: checkasm.h:96
fmax
double fmax(double, double)
checkasm_get_last_signal_desc
const char * checkasm_get_last_signal_desc(void)
Definition: signal.c:167
CheckasmConfig::seed_set
int seed_set
Enable using the seed value.
Definition: checkasm.h:253
CheckasmConfig::repeat
unsigned repeat
Number of times to repeat tests.
Definition: checkasm.h:271
separator
static char separator(CheckasmFormat format)
Definition: checkasm.c:148
cpu_suffix
static const char * cpu_suffix(const CheckasmCpuInfo *cpu)
Definition: checkasm.c:132
CheckasmVar
Definition: stats.h:35
saved_failed
int saved_failed
Definition: checkasm.c:102
tree
CheckasmFuncTree tree
Definition: checkasm.c:79
CheckasmSample
Definition: stats.h:80
checkasm_stats_reset
static void checkasm_stats_reset(CheckasmStats *const stats)
Definition: stats.h:94
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:117
L
#define L(x)
Definition: vpx_arith.h:36
internal.h
CheckasmStats::nb_samples
int nb_samples
Definition: stats.h:90
print_bench_header
static void print_bench_header(struct IterState *const iter)
Definition: checkasm.c:219
CheckasmStats
Definition: stats.h:85
checkasm_report
void checkasm_report(const char *const name,...)
Definition: checkasm.c:1032
checkasm_vasprintf
char * checkasm_vasprintf(const char *fmt, va_list arg)
Definition: utils.c:711
checkasm_bench_finish
void checkasm_bench_finish(void)
Finalize and store benchmark results.
Definition: checkasm.c:486
CheckasmConfig::cpu
CheckasmCpu cpu
Detected CPU flags for the current system.
Definition: checkasm.h:186
num_checked
int num_checked
Definition: checkasm.c:98
IterState::test
const char * test
Definition: checkasm.c:214
checkasm_measurement_update
static void checkasm_measurement_update(CheckasmMeasurement *measurement, const CheckasmStats stats)
Definition: stats.h:135
CheckasmVar::lvar
double lvar
Definition: stats.h:36
checkasm_func_get
CheckasmFunc * checkasm_func_get(CheckasmFuncTree *tree, const char *const name)
Definition: function.c:141
checkasm_sample
static double checkasm_sample(const CheckasmVar x, const double q)
Definition: stats.h:40
CheckasmConfig::format
CheckasmFormat format
Output format for benchmark results.
Definition: checkasm.h:237
checkasm_fail_func
int checkasm_fail_func(const char *const msg,...)
Definition: checkasm.c:997
json_var
static void json_var(CheckasmJson *json, const char *key, const char *unit, const CheckasmVar var)
Definition: checkasm.c:157
current
static struct @582 current
CheckasmCpu
uint64_t CheckasmCpu
Opaque type representing a set of CPU feature flags.
Definition: checkasm.h:88
skip_tests
int skip_tests
Definition: checkasm.c:118
print_usage
static void print_usage(const char *const progname)
Definition: checkasm.c:1098
CheckasmFuncVersion::cycles
CheckasmMeasurement cycles
Definition: function.h:46
checkasm_stats_add
static void checkasm_stats_add(CheckasmStats *const stats, const CheckasmSample s)
Definition: stats.h:100
CheckasmConfig::set_cpu_flags
void(* set_cpu_flags)(CheckasmCpu new_flags)
Callback invoked when active CPU flags change.
Definition: checkasm.h:198
COLOR_RED
#define COLOR_RED
Definition: internal.h:102
snprintf
#define snprintf
Definition: snprintf.h:34
CheckasmConfig::verbose
int verbose
Enable verbose output.
Definition: checkasm.h:246
skip
static void BS_FUNC() skip(BSCTX *bc, unsigned int n)
Skip n bits in the buffer.
Definition: bitstream_template.h:383
nop_cycles
CheckasmMeasurement nop_cycles
Definition: checkasm.c:113
var_sum
double var_sum
Definition: checkasm.c:103
CheckasmFuncVersion::state
CheckasmFuncState state
Definition: function.h:47