blob: 168c8474c7bc6153109f5bd79953603c0bebb64e [file] [log] [blame]
Sylvain Munaut3733ed52018-12-21 16:38:31 +01001#include <stdint.h>
Philipp Maierdfe0aef2017-03-16 18:43:33 +01002#include <stdio.h>
Pau Espin Pedrol4ebb2892018-01-10 11:54:34 +01003#include <stdlib.h>
Sylvain Munaut3733ed52018-12-21 16:38:31 +01004#include <string.h>
5#include <math.h>
6
Pau Espin Pedrol43fedb62018-04-24 15:22:57 +02007#include "convolve.h"
Philipp Maierdfe0aef2017-03-16 18:43:33 +01008
Philipp Maierdfe0aef2017-03-16 18:43:33 +01009
Sylvain Munaut3733ed52018-12-21 16:38:31 +010010// ---------------------------------------------------------------------------
11// Misc utils
12// ---------------------------------------------------------------------------
Philipp Maierdfe0aef2017-03-16 18:43:33 +010013
14/* Generate some random values for testing */
Sylvain Munaut3733ed52018-12-21 16:38:31 +010015static unsigned long rand_state = 0;
16
17static void
18rand_reset(void)
Philipp Maierdfe0aef2017-03-16 18:43:33 +010019{
Sylvain Munaut3733ed52018-12-21 16:38:31 +010020 rand_state = 0;
Philipp Maierdfe0aef2017-03-16 18:43:33 +010021}
22
Sylvain Munaut3733ed52018-12-21 16:38:31 +010023static unsigned long
24rand_int(void)
Philipp Maierdfe0aef2017-03-16 18:43:33 +010025{
Sylvain Munaut3733ed52018-12-21 16:38:31 +010026 rand_state = (1103515245UL * rand_state + 12345UL) & 0x7fffffffUL;
27 return rand_state;
28}
Philipp Maierdfe0aef2017-03-16 18:43:33 +010029
Sylvain Munaut3733ed52018-12-21 16:38:31 +010030static float
31rand_float(void)
32{
33 union {
34 uint32_t u;
35 float f;
36 } r;
37 uint32_t u = rand_int();
38 int e = 112 + ((u ^ (u>>8)) & 15);
Philipp Maierdfe0aef2017-03-16 18:43:33 +010039
Sylvain Munaut3733ed52018-12-21 16:38:31 +010040 r.u = u & 0x007fffffUL; // Mantissa
41 r.u |= (u & 0x00800000UL) << 8; // Sign
42 r.u |= (e & 0xffUL) << 23; // Exponent
43
44 return r.f;
45}
46
47static void
48gen_floats(float *vect, int len)
49{
50 int i;
51 for (i = 0; i < len; i++)
52 vect[i] = rand_float();
Philipp Maierdfe0aef2017-03-16 18:43:33 +010053}
54
55/* Show float vector data cut and paste friendly */
Sylvain Munaut3733ed52018-12-21 16:38:31 +010056static void
57dump_floats(float *vect, int len, char *name)
Philipp Maierdfe0aef2017-03-16 18:43:33 +010058{
59 int i;
60
Sylvain Munaut3733ed52018-12-21 16:38:31 +010061 printf("static const float %s[] = {\n\t", name);
Pau Espin Pedrol4d179ab2018-09-10 10:36:04 +020062 for(i = 0; i < len; i++) {
Sylvain Munaut3733ed52018-12-21 16:38:31 +010063 char *end;
64 if (i == len-1)
65 end = "\n";
66 else if ((i&3) == 3)
67 end = ",\n\t";
68 else
69 end = ", ";
70 printf("%14.7ef%s", vect[i], end);
Philipp Maierdfe0aef2017-03-16 18:43:33 +010071 }
Sylvain Munaut3733ed52018-12-21 16:38:31 +010072 printf("};\n");
Philipp Maierdfe0aef2017-03-16 18:43:33 +010073}
74
Sylvain Munaut3733ed52018-12-21 16:38:31 +010075/* Compare float with tolerance of delta (absolute) and epsilon (relative) */
76static int
77compare_floats(const float *v0, const float *v1, int len, float delta, float epsilon)
78{
79 int i;
80
81 for (i=0; i<len; i++)
82 {
83 float a = v0[i];
84 float b = v1[i];
85
86 if (fabsf(a - b) < delta)
87 continue;
88
89 if (fabsf(1.0f - (a/b)) < epsilon)
90 continue;
91
92 return 1;
93 }
94
95 return 0;
96}
97
98
99// ---------------------------------------------------------------------------
100// Golden reference results
101// ---------------------------------------------------------------------------
102
103#include "convolve_test_golden.h"
104
105enum test_type {
106 CONV_REAL_BASE = 0,
107 CONV_REAL_OPT = 1,
108 CONV_COMPLEX_BASE = 2,
109 CONV_COMPLEX_OPT = 3
110};
111
112struct test_data {
113 enum test_type type;
114 int h_len;
115 const float *y_ref;
116};
117
118static const char *type_name[] = {
119 "real_base", "real_opt", "complex_base", "complex_opt",
120};
121
122static const struct test_data tests[] = {
123 { CONV_REAL_BASE, 4, y_ref_real_base_4 },
124 { CONV_REAL_BASE, 8, y_ref_real_base_8 },
125 { CONV_REAL_BASE, 12, y_ref_real_base_12 },
126 { CONV_REAL_BASE, 16, y_ref_real_base_16 },
127 { CONV_REAL_BASE, 20, y_ref_real_base_20 },
128 { CONV_REAL_BASE, 24, y_ref_real_base_24 },
129 { CONV_COMPLEX_BASE, 4, y_ref_complex_base_4 },
130 { CONV_COMPLEX_BASE, 8, y_ref_complex_base_8 },
131 { CONV_COMPLEX_BASE, 12, y_ref_complex_base_12 },
132 { CONV_COMPLEX_BASE, 16, y_ref_complex_base_16 },
133 { CONV_COMPLEX_BASE, 20, y_ref_complex_base_20 },
134 { CONV_COMPLEX_BASE, 24, y_ref_complex_base_24 },
135 { 0, 0, NULL },
136};
137
138
139// ---------------------------------------------------------------------------
140// Main testing logic
141// ---------------------------------------------------------------------------
142
143struct test_vec
144{
145 float *x;
146 float *h;
147 float *y;
148
Martin Hauke066fd042019-10-13 19:08:00 +0200149 int x_len; /* These are in # of _floats_ ! */
150 int h_len; /* These are in # of _floats_ ! */
151 int y_len; /* These are in # of _floats_ ! */
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100152};
153
154/* Reset test vectors */
155static void
156test_vec_reset(struct test_vec *tv, int seed)
157{
158 rand_reset();
159
160 memset(tv->x, 0, tv->x_len * sizeof(float));
161 memset(tv->h, 0, tv->h_len * sizeof(float));
162 memset(tv->y, 0, tv->y_len * sizeof(float));
163
164 gen_floats(tv->x, tv->x_len);
165 gen_floats(tv->h, tv->h_len);
166}
167
168/* Allocate test vectors */
169static struct test_vec *
170test_vec_alloc(int x_len, int h_len)
171{
172 struct test_vec *tv;
173
174 tv = calloc(1, sizeof(struct test_vec));
175 if (!tv)
176 return NULL;
177
178 tv->x_len = x_len;
179 tv->h_len = h_len;
180 tv->y_len = x_len; /* Results can never be longer than x */
181
182 tv->x = convolve_h_alloc(x_len);
183 tv->h = convolve_h_alloc(h_len);
184 tv->y = convolve_h_alloc(tv->y_len);
185
186 test_vec_reset(tv, 0);
187
188 return tv;
189}
190
191/* Release test vectors */
192static void
193test_vec_release(struct test_vec *tv)
194{
195 if (!tv)
196 return;
197
198 free(tv->x);
199 free(tv->h);
200 free(tv->y);
201
202 free(tv);
203}
204
205/* Run convolution */
206static int
207run_convolve(struct test_vec *tv, int h_len, enum test_type type)
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100208{
209 int x_len;
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100210 int start, len;
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100211
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100212 test_vec_reset(tv, 0);
213
214 /* Compute params that fit within our test vectors */
215 x_len = tv->x_len / 2; /* float vs complex */
216 start = h_len - 1;
217 len = x_len - start;
218
219 /* Run implementation */
220 switch (type) {
221 case CONV_REAL_BASE:
222 base_convolve_real(
223 tv->x, x_len,
224 tv->h, h_len,
225 tv->y, tv->y_len,
226 start, len
227 );
228 break;
229
230 case CONV_REAL_OPT:
231 convolve_real(
232 tv->x, x_len,
233 tv->h, h_len,
234 tv->y, tv->y_len,
235 start, len
236 );
237 break;
238
239 case CONV_COMPLEX_BASE:
240 base_convolve_complex(
241 tv->x, x_len,
242 tv->h, h_len,
243 tv->y, tv->y_len,
244 start, len
245 );
246 break;
247
248 case CONV_COMPLEX_OPT:
249 convolve_complex(
250 tv->x, x_len,
251 tv->h, h_len,
252 tv->y, tv->y_len,
253 start, len
254 );
255 break;
256 }
257
258 return len * 2;
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100259}
260
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100261
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100262int main(int argc, char *argv[])
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100263{
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100264 struct test_vec *tv;
265 int gen_ref_mode = 0;
266 char name[80];
267 int i, j, len;
268
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100269 convolve_init();
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100270
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100271 /* Mode */
272 gen_ref_mode = (argc == 2) && !strcmp("genref", argv[1]);
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100273
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100274 /* Alloc test vectors */
275 /* All *2 is to account for the facts all vectors are actually
276 * complex and need two floats */
277 tv = test_vec_alloc(100*2, 25*2);
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100278
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100279 /* Dump all input data to make sure we work off the same input data */
280 if (!gen_ref_mode) {
281 printf("==== TEST INPUT DATA ====\n");
282 dump_floats(tv->x, tv->x_len, "x");
283 dump_floats(tv->h, tv->h_len, "h");
284 printf("\n");
285 printf("\n");
286 }
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100287
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100288 /* Run through all the tests */
289 if (!gen_ref_mode)
290 printf("==== TEST ====\n");
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100291
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100292 for (i=0; tests[i].h_len; i++)
293 {
294 for (j=0; j<(gen_ref_mode ? 1 : 2); j++)
295 {
296 len = run_convolve(tv, tests[i].h_len, tests[i].type + j);
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100297
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100298 snprintf(name, sizeof(name)-1, "y_ref_%s_%d", type_name[tests[i].type + j], tests[i].h_len);
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100299
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100300 if (gen_ref_mode)
301 {
302 /* If in generate mode, output data */
303 dump_floats(tv->y, len, name);
304 } else {
305 /* If in test mode, compare with data */
306 printf("%s: %s\n",
307 name,
308 compare_floats(tests[i].y_ref, tv->y, len, 1e-5f, 1e-5f) ? "FAIL" : "PASS"
309 );
310 }
311 }
312 }
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100313
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100314 if (!gen_ref_mode) {
315 printf("\n");
316 printf("\n");
317 }
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100318
Sylvain Munaut3733ed52018-12-21 16:38:31 +0100319 /* All done ! */
320 test_vec_release(tv);
Philipp Maierdfe0aef2017-03-16 18:43:33 +0100321
322 return 0;
323}