FFmpeg
generic.c
Go to the documentation of this file.
1 /*
2  * Copyright © 2024, Marvin Scholz
3  * Copyright © 2019, VideoLAN and dav1d authors
4  * Copyright © 2019, 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 <float.h>
30 #include <math.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "tests.h"
36 
37 void selftest_test_copy(copy_func fun, const char *name, const int min_width)
38 {
39 #define WIDTH 256
40  BUF_RECT(uint8_t, c_dst, WIDTH, 1);
41  BUF_RECT(uint8_t, a_dst, WIDTH, 1);
42 
43  CHECKASM_ALIGN(uint8_t src[WIDTH]);
45 
46  checkasm_declare(void, uint8_t *dest, const uint8_t *src, size_t n);
47 
48  for (int w = min_width; w <= WIDTH; w *= 2) {
49  if (checkasm_check_func(fun, "%s_%d", name, w)) {
50  CLEAR_BUF_RECT(c_dst);
51  CLEAR_BUF_RECT(a_dst);
52 
53  /* Make sure that the destination buffer actually differs from
54  * the source buffer, to make sure that a skipped write does
55  * trigger a failure. */
56  for (int i = 0; i < w; i++)
57  c_dst[i] = a_dst[i] = ~src[i];
58  checkasm_call_ref(c_dst, src, w);
59  checkasm_call_new(a_dst, src, w);
60 
61  /* Test all checkasm_check() variants */
62  checkasm_check1d(uint8_t, c_dst, a_dst, w, "1d");
63  checkasm_check2d(uint8_t, c_dst, 0, a_dst, 0, w, 1, "2d");
64  checkasm_check_rect(c_dst, c_dst_stride, a_dst, a_dst_stride, w, 1, "rect");
65 
66  checkasm_check1d_padded(uint8_t, c_dst, a_dst, w, "1d_padded", 1, 64);
67  checkasm_check2d_padded(uint8_t, c_dst, 0, a_dst, 0, w, 1,
68  "2d_padded", 1, 1, 16);
69  checkasm_check_rect_padded(c_dst, c_dst_stride, a_dst, a_dst_stride, w, 1,
70  "rect_padded");
71 
72  checkasm_check_rect_padded_align(c_dst, c_dst_stride, a_dst, a_dst_stride, w, 1,
73  "rect_align", 1, 1);
74 
75  checkasm_bench_new(a_dst, src, w);
76  }
77  }
78 
79  checkasm_report("%s", name);
80 #undef WIDTH
81 }
82 
83 void selftest_test_noop(noop_func fun, const char *name)
84 {
85  checkasm_declare(void, int);
86 
87  if (checkasm_check_func(fun, "%s", name)) {
88  /* don't call unchecked because some of these functions are designed to
89  * e.g. intentionally corrupt the stack */
90  (void) checkasm_func_ref;
92  }
93 
94  checkasm_report("%s", name);
95 }
96 
97 void selftest_test_float(float_func fun, const char *name, const float input)
98 {
99  checkasm_declare(float, float);
100 
101  if (checkasm_check_func(fun, "%s", name)) {
102  float x = checkasm_call_ref(input);
103  float y = checkasm_call_new(input);
104  if (!checkasm_float_near_abs_eps(x, y, FLT_EPSILON)) {
105  if (checkasm_fail())
106  fprintf(stderr, "expected %f, got %f\n", x, y);
107  }
108  }
109 
110  checkasm_report("%s", name);
111 }
112 
113 static void selftest_test_double(double_func fun, const char *name,
114  const double input)
115 {
116  checkasm_declare(double, double);
117 
118  if (checkasm_check_func(fun, "%s", name)) {
119  double x = checkasm_call_ref(input);
120  double y = checkasm_call_new(input);
121 
122  if (!checkasm_double_near_abs_eps(x, y, DBL_EPSILON)) {
123  if (checkasm_fail())
124  fprintf(stderr, "expected %f, got %f\n", x, y);
125  }
126  }
127 
128  checkasm_report("%s", name);
129 }
130 
131 static DEF_COPY_FUNC(overwrite_left)
132 {
133  memcpy(dst, src, size);
134  dst[-1] = dst[-2] = dst[-3] = dst[-4] = 0xAC;
135 }
136 
137 static DEF_COPY_FUNC(overwrite_right)
138 {
139  memcpy(dst, src, size);
140  dst[size] = dst[size + 1] = dst[size + 2] = dst[size + 3] = 0xAC;
141 }
142 
143 static DEF_COPY_FUNC(underwrite)
144 {
145  if (size < 4)
146  return;
147  memcpy(dst, src, size - 4);
148 }
149 
150 static DEF_NOOP_FUNC(segfault)
151 {
152  volatile int *bad = NULL;
153  *bad = 0;
154 }
155 
156 static DEF_FLOAT_FUNC(sqrt)
157 {
158  return sqrtf(input);
159 }
160 
161 static int identity_ref(const int x)
162 {
163  return x;
164 }
165 
166 /* Just make this a separate function to test the checked wrappers */
167 static int identity_new(const int x)
168 {
169  return x;
170 }
171 
172 static void selftest_test_retval(void)
173 {
174  const uint64_t flags = checkasm_get_cpu_flags();
175 
176  checkasm_declare(int, int);
177 
178  if (checkasm_check_func(flags ? identity_new : identity_ref, "identity")) {
179  for (int i = 0; i < 10; i++) {
180  int x = checkasm_call_ref(i);
181  int y = checkasm_call_new(i);
182  if (x != y) {
183  if (checkasm_fail())
184  fprintf(stderr, "expected %d, got %d\n", x, y);
185  }
186  }
187  }
188 
189  checkasm_report("identity");
190 }
191 
192 static int truncate_c(const float x)
193 {
194  return (int) x;
195 }
196 
197 static void selftest_test_float_arg(void)
198 {
199  checkasm_declare(int, float);
200 
201  if (checkasm_check_func(truncate_c, "truncate")) {
202  for (float f = 0.0f; f <= 10.0f; f += 0.5f) {
203  int x = checkasm_call_ref(f);
204  int y = checkasm_call_new(f);
205  if (x != y) {
206  if (checkasm_fail())
207  fprintf(stderr, "expected %d, got %d\n", x, y);
208  }
209  }
210  }
211 
212  checkasm_report("truncate");
213 }
214 
215 static void selftest_test_double_arg(void)
216 {
217  checkasm_declare(long, double);
218 
219  if (checkasm_check_func(lrint, "lrint")) {
220  for (float f = 0.0f; f <= 10.0f; f += 0.5f) {
221  long x = checkasm_call_ref(f);
222  long y = checkasm_call_new(f);
223 
224  if (x != y) {
225  if (checkasm_fail())
226  fprintf(stderr, "expected %ld, got %ld\n", x, y);
227  }
228  }
229  }
230 
231  checkasm_report("lrint");
232 }
233 
238 
239 /* Ensure we can call declare_func() inside check_func() */
241 {
242  /* Pick a function that will actually crash, to ensure the error
243  * handling still works in this case */
244  noop_func *func = get_segfault();
245 
246  if (checkasm_check_func(func, "check_declare")) {
247  checkasm_declare(void, int);
248 
251  }
252 
253  checkasm_report("check_declare");
254 }
255 
256 typedef int (int_func)(int);
257 static int wrapper(int_func *func, int arg)
258 {
259  return func(arg);
260 }
261 
262 static void selftest_test_wrappers(void)
263 {
264  if (checkasm_check_func(identity_ref, "override_funcs")) {
265  checkasm_declare(int, int);
266  int x = checkasm_call(identity_ref, 12345);
267  int y = checkasm_call_checked(identity_new, 12345);
268  if (x != y)
269  checkasm_fail();
270  }
271 
272  if (checkasm_check_func(identity_ref, "wrapper_func")) {
273  checkasm_declare(int, int_func *, int); // type of wrapper
274  int x = checkasm_call(wrapper, (int_func *) checkasm_key_ref, 12345);
276  if (x != y)
277  checkasm_fail();
278  }
279 
280  checkasm_report("wrappers");
281 }
282 
283 static void selftest_test_variants(void)
284 {
285  for (int i = 0; i < 2; i++) {
286  checkasm_set_func_variant(i ? "new" : "ref");
287  if (checkasm_check_func(i ? identity_new : identity_ref, "func_id")) {
288  checkasm_declare(int, int);
289  int x = checkasm_call_ref(12345);
290  int y = checkasm_call_new(12345);
291  if (x != y)
292  checkasm_fail();
293  checkasm_bench_new(12345);
294  }
295  }
296 
297  checkasm_report("func_id");
298 }
299 
301 {
302  selftest_test_copy(selftest_copy_c, "copy_generic", 1);
303  selftest_test_float(selftest_sqrt, "sqrt_generic", 2.0f);
305  selftest_test_double(sqrt, "sqrt", 2.);
310 
312  return;
313 
314  selftest_test_copy(get_overwrite_left(), "overwrite_left", 1);
315  selftest_test_copy(get_overwrite_right(), "overwrite_right", 1);
316  selftest_test_copy(get_underwrite(), "underwrite", 1);
317  selftest_test_noop(get_segfault(), "segfault");
319 }
flags
const SwsFlags flags[]
Definition: swscale.c:85
selftest_test_double_arg
static void selftest_test_double_arg(void)
Definition: generic.c:215
func
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition: jacosubdec.c:66
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
checkasm_check_func
#define checkasm_check_func(func,...)
Check if a function should be tested and set up function references.
Definition: test.h:77
checkasm_key_new
static CheckasmKey checkasm_key_new
Key identifying the implementation being tested.
Definition: test.h:327
checkasm_call_checked
#define checkasm_call_checked(func,...)
Definition: aarch64.h:93
DEF_COPY_GETTER
#define DEF_COPY_GETTER(FLAG, NAME)
Definition: tests.h:81
CHECKASM_ALIGN
#define CHECKASM_ALIGN(x)
Declare a variable with platform-specific alignment requirements.
Definition: utils.h:408
checkasm_check_rect
#define checkasm_check_rect(rect1,...)
Compare two rectangular buffers.
Definition: utils.h:648
INITIALIZE_BUF
#define INITIALIZE_BUF(buf)
Fill a fixed size buffer with pathological test data (convenience macro)
Definition: utils.h:269
float.h
selftest_test_float_arg
static void selftest_test_float_arg(void)
Definition: generic.c:197
selftest_test_retval
static void selftest_test_retval(void)
Definition: generic.c:172
selftest_test_check_declare
static void selftest_test_check_declare(void)
Definition: generic.c:240
checkasm_call
#define checkasm_call(func,...)
Call a function with signal handling.
Definition: test.h:252
checkasm_float_near_abs_eps
CHECKASM_API int checkasm_float_near_abs_eps(float a, float b, float eps)
Compare floats using absolute epsilon tolerance.
Definition: utils.c:537
checkasm_set_func_variant
CHECKASM_API CheckasmKey CHECKASM_API void checkasm_set_func_variant(const char *id,...) CHECKASM_PRINTF(1
Set a custom variant identifier for the next checkasm_check_func() call.
lrint
#define lrint
Definition: tablegen.h:53
selftest_test_float
void selftest_test_float(float_func fun, const char *name, const float input)
Definition: generic.c:97
DEF_NOOP_FUNC
static DEF_NOOP_FUNC(segfault)
Definition: generic.c:150
DEF_COPY_FUNC
static DEF_COPY_FUNC(overwrite_left)
Definition: generic.c:131
arg
const char * arg
Definition: jacosubdec.c:65
identity_ref
static int identity_ref(const int x)
Definition: generic.c:161
checkasm_check2d_padded
#define checkasm_check2d_padded(type,...)
Compare two 2D buffers, including padding regions (detect over-write)
Definition: utils.h:504
NULL
#define NULL
Definition: coverity.c:32
checkasm_key_ref
static CheckasmKey checkasm_key_ref
Key identifying the reference implementation.
Definition: test.h:317
checkasm_func_ref
#define checkasm_func_ref
Function pointer to the reference implementation.
Definition: test.h:338
checkasm_check_rect_padded
#define checkasm_check_rect_padded(rect1,...)
Compare two rectangular buffers including padding.
Definition: utils.h:657
checkasm_call_ref
#define checkasm_call_ref(...)
Call the reference implementation.
Definition: test.h:366
sqrtf
static __device__ float sqrtf(float a)
Definition: cuda_runtime.h:184
noop_func
void() noop_func(int unused)
Do nothing.
Definition: tests.h:94
truncate_c
static int truncate_c(const float x)
Definition: generic.c:192
f
f
Definition: af_crystalizer.c:122
selftest_test_copy
void selftest_test_copy(copy_func fun, const char *name, const int min_width)
Definition: generic.c:37
SELFTEST_CPU_FLAG_BAD_C
@ SELFTEST_CPU_FLAG_BAD_C
Definition: tests.h:40
checkasm_fail
#define checkasm_fail()
Mark the current test as failed.
Definition: test.h:155
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
wrapper
static int wrapper(int_func *func, int arg)
Definition: generic.c:257
size
int size
Definition: twinvq_data.h:10344
identity_new
static int identity_new(const int x)
Definition: generic.c:167
int_func
int() int_func(int)
Definition: generic.c:256
DEF_FLOAT_FUNC
static DEF_FLOAT_FUNC(sqrt)
Definition: generic.c:156
selftest_test_double
static void selftest_test_double(double_func fun, const char *name, const double input)
Definition: generic.c:113
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
checkasm_declare
#define checkasm_declare(ret,...)
Declare a function signature for testing.
Definition: test.h:205
checkasm_report
CHECKASM_API void checkasm_report(const char *name,...) CHECKASM_PRINTF(1
Report test outcome for a named group of functions.
double_func
double() double_func(double input)
Definition: tests.h:102
checkasm_get_cpu_flags
CHECKASM_API CheckasmCpu checkasm_get_cpu_flags(void)
Get the current active set of CPU flags.
Definition: checkasm.c:121
selftest_test_wrappers
static void selftest_test_wrappers(void)
Definition: generic.c:262
selftest_check_generic
void selftest_check_generic(void)
Definition: generic.c:300
checkasm_check2d
#define checkasm_check2d(type,...)
Compare two 2D buffers and fail test if different.
Definition: utils.h:482
tests.h
DEF_NOOP_GETTER
#define DEF_NOOP_GETTER(FLAG, NAME)
Definition: tests.h:98
float_func
float() float_func(float input)
Definition: tests.h:101
selftest_test_noop
void selftest_test_noop(noop_func fun, const char *name)
Definition: generic.c:83
checkasm_double_near_abs_eps
CHECKASM_API int checkasm_double_near_abs_eps(double a, double b, double eps)
Compare doubles using absolute epsilon tolerance.
Definition: utils.c:569
bad
static int bad(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:130
w
uint8_t w
Definition: llvidencdsp.c:39
checkasm_should_fail
CHECKASM_API int checkasm_should_fail(CheckasmCpu cpu_flags)
Mark a block of tests as expected to fail.
Definition: checkasm.c:1017
checkasm_call_new
#define checkasm_call_new(...)
Call the implementation being tested with validation.
Definition: test.h:381
checkasm_check_rect_padded_align
#define checkasm_check_rect_padded_align(rect1,...)
Compare two rectangular buffers, with custom alignment (over-write)
Definition: utils.h:673
selftest_test_variants
static void selftest_test_variants(void)
Definition: generic.c:283
WIDTH
#define WIDTH
copy_func
void() copy_func(uint8_t *dst, const uint8_t *src, size_t size)
Copy size (power-of-two) bytes from aligned buffers src to dst.
Definition: tests.h:75
BUF_RECT
#define BUF_RECT(type, name, w, h)
Definition: utils.h:605
CLEAR_BUF_RECT
#define CLEAR_BUF_RECT(name)
Clear a rectangular buffer (including padding)
Definition: utils.h:623
src
#define src
Definition: vp8dsp.c:248
checkasm_bench_new
#define checkasm_bench_new(...)
Benchmark the optimized implementation.
Definition: test.h:446