FFmpeg
utils.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, this
11  * 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" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <assert.h>
30 #include <inttypes.h>
31 #include <limits.h>
32 #include <math.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <time.h>
38 
39 #include "checkasm_config.h"
40 
41 #ifdef _WIN32
42  #include <windows.h>
43  #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
44  #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x04
45  #endif
46 #else
47  #if HAVE_ISATTY
48  #include <unistd.h>
49  #endif
50  #if HAVE_IOCTL
51  #include <sys/ioctl.h>
52  #endif
53 #endif
54 
55 #if defined(__APPLE__) && defined(__MACH__)
56  #include <mach/mach_time.h>
57 #endif
58 
59 #include "checkasm/test.h"
60 #include "checkasm/utils.h"
61 #include "internal.h"
62 
63 NOINLINE void checkasm_noop(void *ptr)
64 {
65  (void) ptr;
66 }
67 
68 static ALWAYS_INLINE uint64_t gettime_nsec(int is_seed)
69 {
70 #ifdef _WIN32
71  static LARGE_INTEGER freq;
72  LARGE_INTEGER ts;
73  if (!freq.QuadPart) {
74  if (!QueryPerformanceFrequency(&freq))
75  return -1;
76  }
77  if (!QueryPerformanceCounter(&ts))
78  return -1;
79  return UINT64_C(1000000000) * ts.QuadPart / freq.QuadPart;
80 #elif defined(__APPLE__) && defined(__MACH__)
81  static mach_timebase_info_data_t tb_info;
82  if (!tb_info.denom) {
83  if (mach_timebase_info(&tb_info) != KERN_SUCCESS)
84  return -1;
85  }
86  return mach_absolute_time() * tb_info.numer / tb_info.denom;
87 #elif HAVE_CLOCK_GETTIME
88  struct timespec ts;
89  clockid_t id;
90  if (!is_seed) {
91  #ifdef CLOCK_MONOTONIC_RAW
92  id = CLOCK_MONOTONIC_RAW;
93  #else
94  id = CLOCK_MONOTONIC;
95  #endif
96  } else {
97  id = CLOCK_REALTIME;
98  }
99  if (clock_gettime(id, &ts) < 0)
100  return -1;
101  return UINT64_C(1000000000) * ts.tv_sec + ts.tv_nsec;
102 #else
103  return -1;
104 #endif
105 }
106 
107 uint64_t checkasm_gettime_nsec(void)
108 {
109  return gettime_nsec(0);
110 }
111 
112 uint64_t checkasm_gettime_nsec_diff(uint64_t t)
113 {
114  return gettime_nsec(0) - t;
115 }
116 
117 unsigned checkasm_seed(void)
118 {
119  return (unsigned) gettime_nsec(1);
120 }
121 
122 // xor128 from Marsaglia, George (July 2003). "Xorshift RNGs".
123 // Journal of Statistical Software. 8 (14).
124 // doi:10.18637/jss.v008.i14.
125 static uint32_t xs_state[4];
126 
127 void checkasm_srand(unsigned seed)
128 {
129  xs_state[0] = seed;
130  xs_state[1] = (seed & 0xffff0000) | (~seed & 0x0000ffff);
131  xs_state[2] = (~seed & 0xffff0000) | (seed & 0x0000ffff);
132  xs_state[3] = ~seed;
133 }
134 
135 uint32_t checkasm_rand_uint32(void)
136 {
137  const uint32_t x = xs_state[0];
138  const uint32_t t = x ^ (x << 11);
139 
140  xs_state[0] = xs_state[1];
141  xs_state[1] = xs_state[2];
142  xs_state[2] = xs_state[3];
143  uint32_t w = xs_state[3];
144 
145  return xs_state[3] = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
146 }
147 
149 {
150  union {
151  uint32_t u;
152  int32_t i;
153  } res;
154 
155  res.u = checkasm_rand_uint32();
156  return res.i;
157 }
158 
159 int checkasm_rand(void)
160 {
161  static_assert(sizeof(int) <= sizeof(uint32_t), "int larger than 32 bits");
162  return checkasm_rand_uint32() & INT_MAX;
163 }
164 
165 double checkasm_randf(void)
166 {
167  return checkasm_rand_uint32() / (double) UINT32_MAX;
168 }
169 
170 /* Marsaglia polar method */
171 static inline double marsaglia(double *z2)
172 {
173  double u1, u2, w;
174  do {
175  u1 = 2.0 / UINT32_MAX * checkasm_rand_uint32() - 1.0;
176  u2 = 2.0 / UINT32_MAX * checkasm_rand_uint32() - 1.0;
177  w = u1 * u1 + u2 * u2;
178  } while (w >= 1.0);
179 
180  w = sqrt((-2.0 * log(w)) / w);
181  *z2 = u2 * w;
182  return u1 * w;
183 }
184 
185 double checkasm_rand_norm(void)
186 {
187  static int cached;
188  static double cache;
189  if ((cached = !cached)) {
190  return marsaglia(&cache);
191  } else {
192  return cache;
193  }
194 }
195 
197 {
198  return dist.mean + dist.stddev * checkasm_rand_norm();
199 }
200 
201 void checkasm_randomize(void *bufp, size_t bytes)
202 {
203  uint8_t *buf = bufp;
204  while (bytes--)
205  *buf++ = checkasm_rand_uint32() & 0xFF;
206 }
207 
208 void checkasm_randomize_mask8(uint8_t *buf, int width, uint8_t mask)
209 {
210  while (width--)
211  *buf++ = checkasm_rand_uint32() & mask;
212 }
213 
214 void checkasm_randomize_mask16(uint16_t *buf, int width, uint16_t mask)
215 {
216  while (width--)
217  *buf++ = checkasm_rand_uint32() & mask;
218 }
219 
220 void checkasm_randomize_range(double *buf, int width, double range)
221 {
222  while (width--)
223  *buf++ = checkasm_randf() * range;
224 }
225 
226 void checkasm_randomize_rangef(float *buf, int width, float range)
227 {
228  while (width--)
229  *buf++ = (float) (checkasm_randf() * range);
230 }
231 
232 #define RANDOMIZE_DIST(buf, ftype, width, mean, stddev) \
233  do { \
234  if ((width) & 1) { \
235  *(buf)++ = (ftype) ((mean) + (stddev) * checkasm_rand_norm()); \
236  (width) ^= 1; \
237  } \
238  \
239  for (; width; width -= 2) { \
240  double z1, z2; \
241  z1 = marsaglia(&z2); \
242  *(buf)++ = (ftype) ((mean) + (stddev) * z1); \
243  *(buf)++ = (ftype) ((mean) + (stddev) * z2); \
244  } \
245  } while (0)
246 
247 void checkasm_randomize_dist(double *buf, int width, CheckasmDist dist)
248 {
249  RANDOMIZE_DIST(buf, double, width, dist.mean, dist.stddev);
250 }
251 
252 void checkasm_randomize_distf(float *buf, int width, CheckasmDist dist)
253 {
254  RANDOMIZE_DIST(buf, float, width, dist.mean, dist.stddev);
255 }
256 
257 void checkasm_randomize_norm(double *buf, int width)
258 {
259  RANDOMIZE_DIST(buf, double, width, 0.0, 1.0);
260 }
261 
262 void checkasm_randomize_normf(float *buf, int width)
263 {
264  RANDOMIZE_DIST(buf, float, width, 0.0, 1.0);
265 }
266 
267 void checkasm_clear(void *buf, size_t bytes)
268 {
269  memset(buf, 0xAA, bytes);
270 }
271 
272 void checkasm_clear8(uint8_t *buf, int width, uint8_t val)
273 {
274  memset(buf, val, width);
275 }
276 
277 void checkasm_clear16(uint16_t *buf, int width, uint16_t val)
278 {
279  while (width--)
280  *buf++ = val;
281 }
282 
283 #if HAVE_STDBIT_H
284  #include <stdbit.h>
285 
286 static inline int clz(const unsigned int mask)
287 {
288  return stdc_leading_zeros_ui(mask);
289 }
290 
291 #elif defined(_MSC_VER) && !defined(__clang__)
292  #include <intrin.h>
293 
294 static inline int clz(const unsigned int mask)
295 {
296  unsigned long leading_zero = 0;
297  _BitScanReverse(&leading_zero, mask);
298  return (31 - leading_zero);
299 }
300 
301 #else /* !_MSC_VER */
302 static inline int clz(const unsigned int mask)
303 {
304  return __builtin_clz(mask);
305 }
306 #endif /* !_MSC_VER */
307 
308 /* Randomly downshift an integer */
309 static int shift_rand(int x)
310 {
311  const int bits = 8 * sizeof(x) - clz(x);
312  return x ? (x >> (checkasm_rand() % bits)) : 0;
313 }
314 
315 enum {
316  PAT_ZERO, // all zero
317  PAT_ONE, // all one
318  PAT_RAND, // random data
319  PAT_LOW, // all low
320  PAT_HIGH, // all high
321  PAT_ALTLO, // alternating low and high
322  PAT_ALTHI, // alternating high and low
323  PAT_MIX, // random mix of low and high
324 };
325 
326 void checkasm_init(void *buf, size_t bytes)
327 {
328  checkasm_init_mask8(buf, (int) bytes, 0xFF);
329 }
330 
331 #define DEF_CHECKASM_INIT_MASK(BITS, PIXEL) \
332  void checkasm_init_mask##BITS(PIXEL *buf, const int width, const PIXEL mask_pixel) \
333  { \
334  if (!width) \
335  return; \
336  \
337  int step = 0, mode = 0, mask = mask_pixel; \
338  for (int i = 0; i < width; i++, step--) { \
339  if (!step) { \
340  step = imax(shift_rand(width), 1); \
341  mode = checkasm_rand() & 7; \
342  mask = shift_rand(mask_pixel); \
343  } \
344  \
345  const PIXEL low = checkasm_rand_uint32() & mask; \
346  const PIXEL high = mask_pixel - low; \
347  switch (mode) { \
348  case PAT_ZERO: buf[i] = 0; break; \
349  case PAT_ONE: buf[i] = mask_pixel; break; \
350  case PAT_RAND: buf[i] = checkasm_rand_uint32() & mask_pixel; break; \
351  case PAT_LOW: buf[i] = low; break; \
352  case PAT_HIGH: buf[i] = high; break; \
353  case PAT_ALTLO: buf[i] = (i & 1) ? high : low; break; \
354  case PAT_ALTHI: buf[i] = (i & 1) ? low : high; break; \
355  case PAT_MIX: buf[i] = (checkasm_rand() & 1) ? low : high; break; \
356  } \
357  } \
358  }
359 
360 DEF_CHECKASM_INIT_MASK(8, uint8_t)
361 DEF_CHECKASM_INIT_MASK(16, uint16_t)
362 
363 static int use_printf_color[2];
364 
365 /* Print colored text to stderr if the terminal supports it */
366 void checkasm_fprintf(FILE *const f, const int color, const char *const fmt, ...)
367 {
368  va_list arg;
369  int use_color = use_printf_color[f == stderr];
370 
371  if (color >= 0 && use_color)
372  fprintf(f, "\x1b[0;%dm", color);
373 
374  va_start(arg, fmt);
375  vfprintf(f, fmt, arg);
376  va_end(arg);
377 
378  if (color >= 0 && use_color)
379  fprintf(f, "\x1b[0m");
380 }
381 
382 static COLD int should_use_color(FILE *const f)
383 {
384 #ifdef _WIN32
385  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
386  HANDLE con = GetStdHandle(f == stderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
387  DWORD con_mode = 0;
388  return con && con != INVALID_HANDLE_VALUE && GetConsoleMode(con, &con_mode)
389  && SetConsoleMode(con, con_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
390  #else
391  return 0;
392  #endif
393 #elif HAVE_ISATTY
394  if (isatty(f == stderr ? 2 : 1)) {
395  const char *const term = getenv("TERM");
396  return term && strcmp(term, "dumb");
397  }
398  return 0;
399 #else
400  return 0;
401 #endif
402 }
403 
405 {
406  use_printf_color[0] = should_use_color(stdout);
407  use_printf_color[1] = should_use_color(stderr);
408 }
409 
410 static int get_terminal_width(void)
411 {
412 #ifdef _WIN32
413  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
414  CONSOLE_SCREEN_BUFFER_INFO csbi;
415  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
416  return csbi.srWindow.Right - csbi.srWindow.Left + 1;
417  #endif
418 #elif defined(__OS2__)
419  int dst[2];
420  _scrsize(dst);
421  return dst[0];
422 #elif HAVE_IOCTL && defined(TIOCGWINSZ)
423  struct winsize w;
424  if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
425  return w.ws_col;
426 #endif
427  return 80;
428 }
429 
430 void checkasm_json(CheckasmJson *json, const char *key, const char *const fmt, ...)
431 {
432  assert(json->level > 0);
433  fputs(json->nonempty ? ",\n" : "\n", json->file);
434  for (int i = 0; i < json->level; i++)
435  fputc(' ', json->file);
436 
437  va_list ap;
438  va_start(ap, fmt);
439  if (key)
440  fprintf(json->file, "\"%s\": ", key);
441  vfprintf(json->file, fmt, ap);
442  va_end(ap);
443  json->nonempty = 1;
444 }
445 
446 void checkasm_json_str(CheckasmJson *json, const char *key, const char *str)
447 {
448  assert(json->level > 0);
449  fputs(json->nonempty ? ",\n" : "\n", json->file);
450  for (int i = 0; i < json->level; i++)
451  fputc(' ', json->file);
452 
453  if (key)
454  fprintf(json->file, "\"%s\": \"", key);
455  else
456  fputc('"', json->file);
457 
458  while (*str) {
459  switch (*str) {
460  case '\\': fputs("\\\\", json->file); break;
461  case '"': fputs("\\\"", json->file); break;
462  case '\n': fputs("\\n", json->file); break;
463  default: fputc(*str, json->file); break;
464  }
465  str++;
466  }
467  fputc('"', json->file);
468  json->nonempty = 1;
469 }
470 
471 void checkasm_json_push(CheckasmJson *json, const char *const key, const char type)
472 {
473  fputs(json->nonempty ? ",\n" : "\n", json->file);
474  for (int i = 0; i < json->level; i++)
475  fputc(' ', json->file);
476 
477  if (key) {
478  fprintf(json->file, "\"%s\": %c", key, type);
479  } else {
480  fputc(type, json->file);
481  }
482 
483  json->level += 2;
484  json->nonempty = 0;
485 }
486 
488 {
489  assert(json->level >= 2);
490  json->level -= 2;
491  if (json->nonempty) {
492  fputc('\n', json->file);
493  for (int i = 0; i < json->level; i++)
494  fputc(' ', json->file);
495  }
496  fputc(type, json->file);
497  json->nonempty = 1;
498 }
499 
500 /* float compare support code */
501 typedef union {
502  float f;
503  uint32_t i;
504 } intfloat;
505 
506 static int is_negative(const intfloat u)
507 {
508  return u.i >> 31;
509 }
510 
511 int checkasm_float_near_ulp(const float a, const float b, const unsigned max_ulp)
512 {
513  intfloat x, y;
514 
515  x.f = a;
516  y.f = b;
517 
518  if (is_negative(x) != is_negative(y)) {
519  // handle -0.0 == +0.0
520  return a == b;
521  }
522 
523  if (llabs((int64_t) x.i - y.i) <= max_ulp)
524  return 1;
525 
526  return 0;
527 }
528 
529 int checkasm_float_near_ulp_array(const float *const a, const float *const b,
530  const unsigned max_ulp, const int len)
531 {
532  for (int i = 0; i < len; i++)
533  if (!float_near_ulp(a[i], b[i], max_ulp))
534  return 0;
535 
536  return 1;
537 }
538 
539 int checkasm_float_near_abs_eps(const float a, const float b, const float eps)
540 {
541  return fabsf(a - b) < eps;
542 }
543 
544 int checkasm_float_near_abs_eps_array(const float *const a, const float *const b,
545  const float eps, const int len)
546 {
547  for (int i = 0; i < len; i++)
548  if (!float_near_abs_eps(a[i], b[i], eps))
549  return 0;
550 
551  return 1;
552 }
553 
554 int checkasm_float_near_abs_eps_ulp(const float a, const float b, const float eps,
555  const unsigned max_ulp)
556 {
557  return float_near_ulp(a, b, max_ulp) || float_near_abs_eps(a, b, eps);
558 }
559 
560 int checkasm_float_near_abs_eps_array_ulp(const float *const a, const float *const b,
561  const float eps, const unsigned max_ulp,
562  const int len)
563 {
564  for (int i = 0; i < len; i++)
565  if (!float_near_abs_eps_ulp(a[i], b[i], eps, max_ulp))
566  return 0;
567 
568  return 1;
569 }
570 
571 int checkasm_double_near_abs_eps(const double a, const double b, const double eps)
572 {
573  return fabs(a - b) < eps;
574 }
575 
576 int checkasm_double_near_abs_eps_array(const double *const a, const double *const b,
577  const double eps, const unsigned len)
578 {
579  for (unsigned i = 0; i < len; i++)
580  if (!double_near_abs_eps(a[i], b[i], eps))
581  return 0;
582 
583  return 1;
584 }
585 
586 static int check_err(const char *const file, const int line, const char *const name,
587  const int w, const int h, int *const err)
588 {
589  if (*err)
590  return 0;
591  if (!checkasm_fail_func("%s:%d", file, line))
592  return 1;
593  *err = 1;
594  fprintf(stderr, "%s (%dx%d):\n", name, w, h);
595  return 0;
596 }
597 
598 #define PRINT_LINE(buf1, buf2, xstart, xend, xpad, fmt, fmtw) \
599  do { \
600  for (int x = xstart; x < xend; x++) { \
601  if (buf1[x] != buf2[x]) \
602  checkasm_fprintf(stderr, COLOR_RED, " " fmt, buf1[x]); \
603  else \
604  fprintf(stderr, " " fmt, buf1[x]); \
605  } \
606  for (int pad = xend; pad < xstart + xpad; pad++) \
607  fprintf(stderr, &" "[9 - fmtw]); \
608  } while (0)
609 
610 #define PRINT_RECT(type, buf1, buf2, ystart, yend, xstart, xend, fmt, fmtw) \
611  do { \
612  const type *ptr1 = (buf1) + ystart * stride1; \
613  const type *ptr2 = (buf2) + ystart * stride1; \
614  const int elem_size = 2 * (fmtw + 1) + 1; \
615  const int display_elems = imin(term_width / elem_size, xend - xstart); \
616  for (int y = ystart; y < yend; y++) { \
617  for (int xpos = xstart; xpos < xend; xpos += display_elems) { \
618  const int xstep = imin(xpos + display_elems, xend); \
619  if (xpos == xstart) /* line change */ \
620  checkasm_fprintf(stderr, COLOR_BLUE, "%3d: ", y); \
621  else \
622  fprintf(stderr, " "); \
623  PRINT_LINE(ptr1, ptr2, xpos, xstep, display_elems, fmt, fmtw); \
624  fprintf(stderr, " "); \
625  PRINT_LINE(ptr2, ptr1, xpos, xstep, display_elems, fmt, fmtw); \
626  fprintf(stderr, " "); \
627  for (int x = xpos; x < xstep; x++) { \
628  if (ptr1[x] != ptr2[x]) \
629  checkasm_fprintf(stderr, COLOR_RED, "x"); \
630  else \
631  fprintf(stderr, "."); \
632  } \
633  fprintf(stderr, "\n"); \
634  } \
635  ptr1 += stride1; \
636  ptr2 += stride2; \
637  } \
638  } while (0)
639 
640 #define CHECK_RECT(buf1, buf2, ystart, yend, xstart, xend, msg, compare, type, fmt, \
641  fmtw) \
642  do { \
643  const int xw = xend - xstart; \
644  for (int y = ystart; y < yend; y++) { \
645  if (compare(&buf1[y * stride1 + xstart], &buf2[y * stride2 + xstart], xw)) \
646  continue; \
647  if (check_err(file, line, name, w, h, &err)) \
648  return 1; \
649  /* Exclude unneeded lines on overwrite above */ \
650  int yprint = y < 0 ? y : ystart; \
651  if (msg[0]) \
652  fprintf(stderr, " %s (%dx%d, from idx [%d]):\n", msg, xend - xstart, \
653  yend - yprint, xstart); \
654  PRINT_RECT(type, buf1, buf2, yprint, yend, xstart, xend, fmt, fmtw); \
655  break; \
656  } \
657  } while (0)
658 
659 #define DEF_CHECKASM_CHECK_BODY(compare, type, fmt, fmtw) \
660  do { \
661  const int overhead = 5 + 3 + 3; \
662  const int term_width = get_terminal_width() - overhead; \
663  const int aligned_w = (w + align_w - 1) & ~(align_w - 1); \
664  stride1 /= sizeof(type); \
665  stride2 /= sizeof(type); \
666  \
667  int err = 0; \
668  CHECK_RECT(buf1, buf2, 0, h, 0, w, "", compare, type, fmt, fmtw); \
669  if (align_h >= 1) { \
670  const int aligned_h = (h + align_h - 1) & ~(align_h - 1); \
671  CHECK_RECT(buf1, buf2, -padding, 0, -padding, w + padding, "overwrite top", \
672  compare, type, fmt, fmtw); \
673  CHECK_RECT(buf1, buf2, aligned_h, aligned_h + padding, -padding, \
674  w + padding, "overwrite bottom", compare, type, fmt, fmtw); \
675  } \
676  CHECK_RECT(buf1, buf2, 0, h, -padding, 0, "overwrite left", compare, type, fmt, \
677  fmtw); \
678  CHECK_RECT(buf1, buf2, 0, h, aligned_w, aligned_w + padding, "overwrite right", \
679  compare, type, fmt, fmtw); \
680  return err; \
681  } while (0)
682 
683 #define cmp_int(a, b, len) (!memcmp(a, b, (len) * sizeof(*(a))))
684 #define DEF_CHECKASM_CHECK_FUNC(type, fmt, fmtw) \
685  int checkasm_check_impl_##type(const char *file, int line, const type *buf1, \
686  ptrdiff_t stride1, const type *buf2, \
687  ptrdiff_t stride2, int w, int h, const char *name, \
688  int align_w, int align_h, int padding) \
689  { \
690  DEF_CHECKASM_CHECK_BODY(cmp_int, type, fmt, fmtw); \
691  }
692 
693 DEF_CHECKASM_CHECK_FUNC(int, "%9d", 9)
694 DEF_CHECKASM_CHECK_FUNC(int8_t, "%4" PRId8, 4)
695 DEF_CHECKASM_CHECK_FUNC(int16_t, "%6" PRId16, 6)
696 DEF_CHECKASM_CHECK_FUNC(int32_t, "%9" PRId32, 9)
697 
698 DEF_CHECKASM_CHECK_FUNC(unsigned, "%08x", 8)
699 DEF_CHECKASM_CHECK_FUNC(uint8_t, "%02" PRIx8, 2)
700 DEF_CHECKASM_CHECK_FUNC(uint16_t, "%04" PRIx16, 4)
701 DEF_CHECKASM_CHECK_FUNC(uint32_t, "%08" PRIx32, 8)
702 
703 int checkasm_check_impl_float_ulp(const char *file, int line, const float *buf1,
704  ptrdiff_t stride1, const float *buf2, ptrdiff_t stride2,
705  int w, int h, const char *name, unsigned max_ulp,
706  int align_w, int align_h, int padding)
707 {
708 #define cmp_float(a, b, len) float_near_ulp_array(a, b, max_ulp, len)
709  DEF_CHECKASM_CHECK_BODY(cmp_float, float, "%7g", 7);
710 #undef cmp_float
711 }
712 
713 char *checkasm_vasprintf(const char *fmt, va_list arg)
714 {
715  va_list arg2;
716  va_copy(arg2, arg);
717  int len = vsnprintf(NULL, 0, fmt, arg2);
718  va_end(arg2);
719  if (len < 0)
720  return NULL;
721 
722  char *buf = checkasm_mallocz(len + 1);
723  vsnprintf(buf, len + 1, fmt, arg);
724  return buf;
725 }
COLD
#define COLD
Definition: internal.h:45
clz
static int clz(const unsigned int mask)
Definition: utils.c:302
checkasm_randomize_distf
void checkasm_randomize_distf(float *buf, int width, CheckasmDist dist)
Fill a float buffer with normally distributed random values.
Definition: utils.c:252
checkasm_randomize_dist
void checkasm_randomize_dist(double *buf, int width, CheckasmDist dist)
Fill a double buffer with normally distributed random values.
Definition: utils.c:247
CheckasmDist::stddev
double stddev
Standard deviation (spread) of the distribution.
Definition: utils.h:91
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
marsaglia
static double marsaglia(double *z2)
Definition: utils.c:171
checkasm_randomize_mask16
void checkasm_randomize_mask16(uint16_t *buf, int width, uint16_t mask)
Fill a uint16_t buffer with random values chosen uniformly within a mask.
Definition: utils.c:214
DEF_CHECKASM_CHECK_FUNC
#define DEF_CHECKASM_CHECK_FUNC(type, fmt, fmtw)
Definition: utils.c:684
checkasm_config.h
checkasm_srand
void checkasm_srand(unsigned seed)
Definition: utils.c:127
color
Definition: vf_paletteuse.c:513
CheckasmJson::level
int level
Definition: internal.h:118
PAT_MIX
@ PAT_MIX
Definition: utils.c:323
int64_t
long long int64_t
Definition: coverity.c:34
checkasm_float_near_abs_eps_array_ulp
int checkasm_float_near_abs_eps_array_ulp(const float *const a, const float *const b, const float eps, const unsigned max_ulp, const int len)
Compare float arrays using both epsilon and ULP tolerances.
Definition: utils.c:560
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
PAT_RAND
@ PAT_RAND
Definition: utils.c:318
get_terminal_width
static int get_terminal_width(void)
Definition: utils.c:410
u
#define u(width, name, range_min, range_max)
Definition: cbs_apv.c:68
b
#define b
Definition: input.c:43
checkasm_clear8
void checkasm_clear8(uint8_t *buf, int width, uint8_t val)
Fill a uint8_t buffer with a constant value.
Definition: utils.c:272
checkasm_float_near_abs_eps_ulp
int checkasm_float_near_abs_eps_ulp(const float a, const float b, const float eps, const unsigned max_ulp)
Compare floats using both epsilon and ULP tolerances.
Definition: utils.c:554
check_err
static int check_err(const char *const file, const int line, const char *const name, const int w, const int h, int *const err)
Definition: utils.c:586
checkasm_randomize_mask8
void checkasm_randomize_mask8(uint8_t *buf, int width, uint8_t mask)
Fill a uint8_t buffer with random values chosen uniformly within a mask.
Definition: utils.c:208
CheckasmJson::file
FILE * file
Definition: internal.h:117
checkasm_randf
double checkasm_randf(void)
Generate a random double-precision floating-point number.
Definition: utils.c:165
checkasm_randomize_range
void checkasm_randomize_range(double *buf, int width, double range)
Fill a double buffer with random values chosen uniformly below a limit.
Definition: utils.c:220
should_use_color
static COLD int should_use_color(FILE *const f)
Definition: utils.c:382
checkasm_fail_func
CHECKASM_API CheckasmKey CHECKASM_API void CHECKASM_API int checkasm_fail_func(const char *msg,...) CHECKASM_PRINTF(1
Mark the current function as failed with a custom message.
val
static double val(void *priv, double ch)
Definition: aeval.c:77
type
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 type
Definition: writing_filters.txt:86
checkasm_json
void checkasm_json(CheckasmJson *json, const char *key, const char *const fmt,...)
Definition: utils.c:430
fabsf
static __device__ float fabsf(float a)
Definition: cuda_runtime.h:181
PAT_ONE
@ PAT_ONE
Definition: utils.c:317
checkasm_float_near_abs_eps
int checkasm_float_near_abs_eps(const float a, const float b, const float eps)
Compare floats using absolute epsilon tolerance.
Definition: utils.c:539
intfloat::f
float f
Definition: utils.c:502
checkasm_mallocz
static void * checkasm_mallocz(const size_t size)
Definition: internal.h:180
checkasm_randomize_norm
void checkasm_randomize_norm(double *buf, int width)
Fill a double buffer with values from a standard normal distribution.
Definition: utils.c:257
float
float
Definition: af_crystalizer.c:122
checkasm_rand_int32
int32_t checkasm_rand_int32(void)
Generate a random 32-bit signed integer.
Definition: utils.c:148
checkasm_init
void checkasm_init(void *buf, size_t bytes)
Initialize a buffer with pathological test patterns.
Definition: utils.c:326
bits
uint8_t bits
Definition: vp3data.h:128
use_printf_color
static int use_printf_color[2]
Definition: utils.c:363
limits.h
CheckasmJson
Definition: internal.h:116
checkasm_float_near_abs_eps_array
int checkasm_float_near_abs_eps_array(const float *const a, const float *const b, const float eps, const int len)
Compare float arrays using absolute epsilon tolerance.
Definition: utils.c:544
key
const char * key
Definition: hwcontext_opencl.c:189
DEF_CHECKASM_CHECK_BODY
#define DEF_CHECKASM_CHECK_BODY(compare, type, fmt, fmtw)
Definition: utils.c:659
checkasm_gettime_nsec
uint64_t checkasm_gettime_nsec(void)
Definition: utils.c:107
arg
const char * arg
Definition: jacosubdec.c:65
ALWAYS_INLINE
#define ALWAYS_INLINE
Definition: internal.h:72
float_near_abs_eps
#define float_near_abs_eps
Definition: utils.h:371
checkasm_randomize
void checkasm_randomize(void *bufp, size_t bytes)
Fill a buffer with uniformly chosen random bytes.
Definition: utils.c:201
fabs
static __device__ float fabs(float a)
Definition: cuda_runtime.h:182
NULL
#define NULL
Definition: coverity.c:32
CheckasmDist::mean
double mean
Mean (center) of the distribution.
Definition: utils.h:90
cmp_float
#define cmp_float(a, b, len)
checkasm_rand_norm
double checkasm_rand_norm(void)
Generate a random number from the standard normal distribution.
Definition: utils.c:185
double
double
Definition: af_crystalizer.c:132
time.h
intfloat
Definition: utils.c:501
seed
static unsigned int seed
Definition: videogen.c:78
checkasm_check_impl_float_ulp
int checkasm_check_impl_float_ulp(const char *file, int line, const float *buf1, ptrdiff_t stride1, const float *buf2, ptrdiff_t stride2, int w, int h, const char *name, unsigned max_ulp, int align_w, int align_h, int padding)
Compare float buffers with ULP tolerance.
Definition: utils.c:703
checkasm_double_near_abs_eps_array
int checkasm_double_near_abs_eps_array(const double *const a, const double *const b, const double eps, const unsigned len)
Compare double arrays using absolute epsilon tolerance.
Definition: utils.c:576
checkasm_seed
unsigned checkasm_seed(void)
Definition: utils.c:117
f
f
Definition: af_crystalizer.c:122
is_negative
static int is_negative(const intfloat u)
Definition: utils.c:506
checkasm_json_push
void checkasm_json_push(CheckasmJson *json, const char *const key, const char type)
Definition: utils.c:471
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
NOINLINE
#define NOINLINE
Definition: internal.h:59
test.h
Test writing API for checkasm.
checkasm_randomize_normf
void checkasm_randomize_normf(float *buf, int width)
Fill a float buffer with values from a standard normal distribution.
Definition: utils.c:262
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2594
checkasm_noop
NOINLINE void checkasm_noop(void *ptr)
Definition: utils.c:63
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
PAT_HIGH
@ PAT_HIGH
Definition: utils.c:320
line
Definition: graph2dot.c:48
checkasm_init_mask8
CHECKASM_API void checkasm_init_mask8(uint8_t *buf, int width, uint8_t mask)
Initialize a uint8_t buffer with pathological values within a mask.
va_copy
#define va_copy(dst, src)
Definition: va_copy.h:31
PAT_ALTHI
@ PAT_ALTHI
Definition: utils.c:322
gettime_nsec
static ALWAYS_INLINE uint64_t gettime_nsec(int is_seed)
Definition: utils.c:68
checkasm_gettime_nsec_diff
uint64_t checkasm_gettime_nsec_diff(uint64_t t)
Definition: utils.c:112
CheckasmJson::nonempty
int nonempty
Definition: internal.h:119
stdc_leading_zeros_ui
static unsigned int stdc_leading_zeros_ui(unsigned int value)
Definition: stdbit.h:61
RANDOMIZE_DIST
#define RANDOMIZE_DIST(buf, ftype, width, mean, stddev)
Definition: utils.c:232
width
static int width
Definition: utils.c:158
checkasm_json_pop
void checkasm_json_pop(CheckasmJson *json, char type)
Definition: utils.c:487
CheckasmDist
Describes a normal (Gaussian) distribution.
Definition: utils.h:89
utils.h
Utility functions for checkasm tests.
vsnprintf
#define vsnprintf
Definition: snprintf.h:36
use_color
static int use_color
Definition: log.c:128
PAT_ZERO
@ PAT_ZERO
Definition: utils.c:316
len
int len
Definition: vorbis_enc_data.h:426
checkasm_float_near_ulp_array
int checkasm_float_near_ulp_array(const float *const a, const float *const b, const unsigned max_ulp, const int len)
Compare float arrays using ULP tolerance.
Definition: utils.c:529
double_near_abs_eps
#define double_near_abs_eps
Definition: utils.h:376
checkasm_float_near_ulp
int checkasm_float_near_ulp(const float a, const float b, const unsigned max_ulp)
Compare floats using ULP (Units in Last Place) tolerance.
Definition: utils.c:511
checkasm_setup_fprintf
COLD void checkasm_setup_fprintf(void)
Definition: utils.c:404
shift_rand
static int shift_rand(int x)
Definition: utils.c:309
checkasm_randomize_rangef
void checkasm_randomize_rangef(float *buf, int width, float range)
Fill a float buffer with random values chosen uniformly below a limit.
Definition: utils.c:226
id
enum AVCodecID id
Definition: dts2pts.c:578
checkasm_rand
int checkasm_rand(void)
Generate a random non-negative integer.
Definition: utils.c:159
xs_state
static uint32_t xs_state[4]
Definition: utils.c:125
PAT_LOW
@ PAT_LOW
Definition: utils.c:319
checkasm_clear
void checkasm_clear(void *buf, size_t bytes)
Clear a buffer to a pre-determined pattern (currently 0xAA)
Definition: utils.c:267
DEF_CHECKASM_INIT_MASK
#define DEF_CHECKASM_INIT_MASK(BITS, PIXEL)
Definition: utils.c:331
checkasm_clear16
void checkasm_clear16(uint16_t *buf, int width, uint16_t val)
Fill a uint16_t buffer with a constant value.
Definition: utils.c:277
internal.h
checkasm_double_near_abs_eps
int checkasm_double_near_abs_eps(const double a, const double b, const double eps)
Compare doubles using absolute epsilon tolerance.
Definition: utils.c:571
checkasm_rand_uint32
uint32_t checkasm_rand_uint32(void)
Generate a random 32-bit unsigned integer.
Definition: utils.c:135
w
uint8_t w
Definition: llvidencdsp.c:39
checkasm_json_str
void checkasm_json_str(CheckasmJson *json, const char *key, const char *str)
Definition: utils.c:446
intfloat::i
uint32_t i
Definition: utils.c:503
int32_t
int32_t
Definition: audioconvert.c:56
checkasm_fprintf
void checkasm_fprintf(FILE *const f, const int color, const char *const fmt,...)
Definition: utils.c:366
h
h
Definition: vp9dsp_template.c:2070
float_near_abs_eps_ulp
#define float_near_abs_eps_ulp
Definition: utils.h:372
checkasm_rand_dist
double checkasm_rand_dist(CheckasmDist dist)
Generate a normally distributed random number.
Definition: utils.c:196
PAT_ALTLO
@ PAT_ALTLO
Definition: utils.c:321
checkasm_vasprintf
char * checkasm_vasprintf(const char *fmt, va_list arg)
Definition: utils.c:713
float_near_ulp
#define float_near_ulp
Definition: utils.h:370
stdbit.h