]> code.delx.au - pulseaudio/blob - src/tests/cpu-test.c
remap: Make resampler's remap structure more self-contained
[pulseaudio] / src / tests / cpu-test.c
1 /***
2 This file is part of PulseAudio.
3
4 PulseAudio is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published
6 by the Free Software Foundation; either version 2.1 of the License,
7 or (at your option) any later version.
8
9 PulseAudio is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with PulseAudio; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <check.h>
25 #include <unistd.h>
26 #include <math.h>
27
28 #include <pulse/rtclock.h>
29 #include <pulsecore/cpu-x86.h>
30 #include <pulsecore/cpu-orc.h>
31 #include <pulsecore/random.h>
32 #include <pulsecore/macro.h>
33 #include <pulsecore/endianmacros.h>
34 #include <pulsecore/sconv.h>
35 #include <pulsecore/remap.h>
36 #include <pulsecore/sample-util.h>
37 #include <pulsecore/mix.h>
38
39 #include "runtime-test-util.h"
40
41 /* Common defines for svolume tests */
42 #define SAMPLES 1028
43 #define TIMES 1000
44 #define TIMES2 100
45 #define PADDING 16
46
47 static void run_volume_test(
48 pa_do_volume_func_t func,
49 pa_do_volume_func_t orig_func,
50 int align,
51 int channels,
52 bool correct,
53 bool perf) {
54
55 PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES]) = { 0 };
56 PA_DECLARE_ALIGNED(8, int16_t, s_ref[SAMPLES]) = { 0 };
57 PA_DECLARE_ALIGNED(8, int16_t, s_orig[SAMPLES]) = { 0 };
58 int32_t volumes[channels + PADDING];
59 int16_t *samples, *samples_ref, *samples_orig;
60 int i, padding, nsamples, size;
61
62 /* Force sample alignment as requested */
63 samples = s + (8 - align);
64 samples_ref = s_ref + (8 - align);
65 samples_orig = s_orig + (8 - align);
66 nsamples = SAMPLES - (8 - align);
67 if (nsamples % channels)
68 nsamples -= nsamples % channels;
69 size = nsamples * sizeof(int16_t);
70
71 pa_random(samples, size);
72 memcpy(samples_ref, samples, size);
73 memcpy(samples_orig, samples, size);
74
75 for (i = 0; i < channels; i++)
76 volumes[i] = PA_CLAMP_VOLUME((pa_volume_t)(rand() >> 15));
77 for (padding = 0; padding < PADDING; padding++, i++)
78 volumes[i] = volumes[padding];
79
80 if (correct) {
81 orig_func(samples_ref, volumes, channels, size);
82 func(samples, volumes, channels, size);
83
84 for (i = 0; i < nsamples; i++) {
85 if (samples[i] != samples_ref[i]) {
86 pa_log_debug("Correctness test failed: align=%d, channels=%d", align, channels);
87 pa_log_debug("%d: %04hx != %04hx (%04hx * %08x)\n", i, samples[i], samples_ref[i],
88 samples_orig[i], volumes[i % channels]);
89 fail();
90 }
91 }
92 }
93
94 if (perf) {
95 pa_log_debug("Testing svolume %dch performance with %d sample alignment", channels, align);
96
97 PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
98 memcpy(samples, samples_orig, size);
99 func(samples, volumes, channels, size);
100 } PA_RUNTIME_TEST_RUN_STOP
101
102 PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
103 memcpy(samples_ref, samples_orig, size);
104 orig_func(samples_ref, volumes, channels, size);
105 } PA_RUNTIME_TEST_RUN_STOP
106
107 fail_unless(memcmp(samples_ref, samples, size) == 0);
108 }
109 }
110
111 #if defined (__i386__) || defined (__amd64__)
112 START_TEST (svolume_mmx_test) {
113 pa_do_volume_func_t orig_func, mmx_func;
114 pa_cpu_x86_flag_t flags = 0;
115 int i, j;
116
117 pa_cpu_get_x86_flags(&flags);
118
119 if (!((flags & PA_CPU_X86_MMX) && (flags & PA_CPU_X86_CMOV))) {
120 pa_log_info("MMX/CMOV not supported. Skipping");
121 return;
122 }
123
124 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
125 pa_volume_func_init_mmx(flags);
126 mmx_func = pa_get_volume_func(PA_SAMPLE_S16NE);
127
128 pa_log_debug("Checking MMX svolume");
129 for (i = 1; i <= 3; i++) {
130 for (j = 0; j < 7; j++)
131 run_volume_test(mmx_func, orig_func, j, i, true, false);
132 }
133 run_volume_test(mmx_func, orig_func, 7, 1, true, true);
134 run_volume_test(mmx_func, orig_func, 7, 2, true, true);
135 run_volume_test(mmx_func, orig_func, 7, 3, true, true);
136 }
137 END_TEST
138
139 START_TEST (svolume_sse_test) {
140 pa_do_volume_func_t orig_func, sse_func;
141 pa_cpu_x86_flag_t flags = 0;
142 int i, j;
143
144 pa_cpu_get_x86_flags(&flags);
145
146 if (!(flags & PA_CPU_X86_SSE2)) {
147 pa_log_info("SSE2 not supported. Skipping");
148 return;
149 }
150
151 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
152 pa_volume_func_init_sse(flags);
153 sse_func = pa_get_volume_func(PA_SAMPLE_S16NE);
154
155 pa_log_debug("Checking SSE2 svolume");
156 for (i = 1; i <= 3; i++) {
157 for (j = 0; j < 7; j++)
158 run_volume_test(sse_func, orig_func, j, i, true, false);
159 }
160 run_volume_test(sse_func, orig_func, 7, 1, true, true);
161 run_volume_test(sse_func, orig_func, 7, 2, true, true);
162 run_volume_test(sse_func, orig_func, 7, 3, true, true);
163 }
164 END_TEST
165 #endif /* defined (__i386__) || defined (__amd64__) */
166
167 #if defined (__arm__) && defined (__linux__)
168 START_TEST (svolume_arm_test) {
169 pa_do_volume_func_t orig_func, arm_func;
170 pa_cpu_arm_flag_t flags = 0;
171 int i, j;
172
173 pa_cpu_get_arm_flags(&flags);
174
175 if (!(flags & PA_CPU_ARM_V6)) {
176 pa_log_info("ARMv6 instructions not supported. Skipping");
177 return;
178 }
179
180 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
181 pa_volume_func_init_arm(flags);
182 arm_func = pa_get_volume_func(PA_SAMPLE_S16NE);
183
184 pa_log_debug("Checking ARM svolume");
185 for (i = 1; i <= 3; i++) {
186 for (j = 0; j < 7; j++)
187 run_volume_test(arm_func, orig_func, j, i, true, false);
188 }
189 run_volume_test(arm_func, orig_func, 7, 1, true, true);
190 run_volume_test(arm_func, orig_func, 7, 2, true, true);
191 run_volume_test(arm_func, orig_func, 7, 3, true, true);
192 }
193 END_TEST
194 #endif /* defined (__arm__) && defined (__linux__) */
195
196 START_TEST (svolume_orc_test) {
197 pa_do_volume_func_t orig_func, orc_func;
198 pa_cpu_info cpu_info;
199 int i, j;
200
201 #if defined (__i386__) || defined (__amd64__)
202 pa_zero(cpu_info);
203 cpu_info.cpu_type = PA_CPU_X86;
204 pa_cpu_get_x86_flags(&cpu_info.flags.x86);
205 #endif
206
207 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
208
209 if (!pa_cpu_init_orc(cpu_info)) {
210 pa_log_info("Orc not supported. Skipping");
211 return;
212 }
213
214 orc_func = pa_get_volume_func(PA_SAMPLE_S16NE);
215
216 pa_log_debug("Checking Orc svolume");
217 for (i = 1; i <= 2; i++) {
218 for (j = 0; j < 7; j++)
219 run_volume_test(orc_func, orig_func, j, i, true, false);
220 }
221 run_volume_test(orc_func, orig_func, 7, 1, true, true);
222 run_volume_test(orc_func, orig_func, 7, 2, true, true);
223 }
224 END_TEST
225
226 #undef SAMPLES
227 #undef TIMES
228 #undef TIMES2
229 #undef PADDING
230 /* End svolume tests */
231
232 /* Start conversion tests */
233 #define SAMPLES 1028
234 #define TIMES 1000
235 #define TIMES2 100
236
237 static void run_conv_test_float_to_s16(
238 pa_convert_func_t func,
239 pa_convert_func_t orig_func,
240 int align,
241 bool correct,
242 bool perf) {
243
244 PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES]) = { 0 };
245 PA_DECLARE_ALIGNED(8, int16_t, s_ref[SAMPLES]) = { 0 };
246 PA_DECLARE_ALIGNED(8, float, f[SAMPLES]);
247 int16_t *samples, *samples_ref;
248 float *floats;
249 int i, nsamples;
250
251 /* Force sample alignment as requested */
252 samples = s + (8 - align);
253 samples_ref = s_ref + (8 - align);
254 floats = f + (8 - align);
255 nsamples = SAMPLES - (8 - align);
256
257 for (i = 0; i < nsamples; i++) {
258 floats[i] = 2.1f * (rand()/(float) RAND_MAX - 0.5f);
259 }
260
261 if (correct) {
262 orig_func(nsamples, floats, samples_ref);
263 func(nsamples, floats, samples);
264
265 for (i = 0; i < nsamples; i++) {
266 if (abs(samples[i] - samples_ref[i]) > 1) {
267 pa_log_debug("Correctness test failed: align=%d", align);
268 pa_log_debug("%d: %04hx != %04hx (%.24f)\n", i, samples[i], samples_ref[i], floats[i]);
269 fail();
270 }
271 }
272 }
273
274 if (perf) {
275 pa_log_debug("Testing sconv performance with %d sample alignment", align);
276
277 PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
278 func(nsamples, floats, samples);
279 } PA_RUNTIME_TEST_RUN_STOP
280
281 PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
282 orig_func(nsamples, floats, samples_ref);
283 } PA_RUNTIME_TEST_RUN_STOP
284 }
285 }
286
287 /* This test is currently only run under NEON */
288 #if defined (__arm__) && defined (__linux__)
289 #ifdef HAVE_NEON
290 static void run_conv_test_s16_to_float(
291 pa_convert_func_t func,
292 pa_convert_func_t orig_func,
293 int align,
294 bool correct,
295 bool perf) {
296
297 PA_DECLARE_ALIGNED(8, float, f[SAMPLES]) = { 0 };
298 PA_DECLARE_ALIGNED(8, float, f_ref[SAMPLES]) = { 0 };
299 PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES]);
300 float *floats, *floats_ref;
301 int16_t *samples;
302 int i, nsamples;
303
304 /* Force sample alignment as requested */
305 floats = f + (8 - align);
306 floats_ref = f_ref + (8 - align);
307 samples = s + (8 - align);
308 nsamples = SAMPLES - (8 - align);
309
310 pa_random(samples, nsamples * sizeof(int16_t));
311
312 if (correct) {
313 orig_func(nsamples, samples, floats_ref);
314 func(nsamples, samples, floats);
315
316 for (i = 0; i < nsamples; i++) {
317 if (fabsf(floats[i] - floats_ref[i]) > 0.0001) {
318 pa_log_debug("Correctness test failed: align=%d", align);
319 pa_log_debug("%d: %.24f != %.24f (%d)\n", i, floats[i], floats_ref[i], samples[i]);
320 fail();
321 }
322 }
323 }
324
325 if (perf) {
326 pa_log_debug("Testing sconv performance with %d sample alignment", align);
327
328 PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
329 func(nsamples, samples, floats);
330 } PA_RUNTIME_TEST_RUN_STOP
331
332 PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
333 orig_func(nsamples, samples, floats_ref);
334 } PA_RUNTIME_TEST_RUN_STOP
335 }
336 }
337 #endif /* HAVE_NEON */
338 #endif /* defined (__arm__) && defined (__linux__) */
339
340 #if defined (__i386__) || defined (__amd64__)
341 START_TEST (sconv_sse2_test) {
342 pa_cpu_x86_flag_t flags = 0;
343 pa_convert_func_t orig_func, sse2_func;
344
345 pa_cpu_get_x86_flags(&flags);
346
347 if (!(flags & PA_CPU_X86_SSE2)) {
348 pa_log_info("SSE2 not supported. Skipping");
349 return;
350 }
351
352 orig_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
353 pa_convert_func_init_sse(PA_CPU_X86_SSE2);
354 sse2_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
355
356 pa_log_debug("Checking SSE2 sconv (float -> s16)");
357 run_conv_test_float_to_s16(sse2_func, orig_func, 0, true, false);
358 run_conv_test_float_to_s16(sse2_func, orig_func, 1, true, false);
359 run_conv_test_float_to_s16(sse2_func, orig_func, 2, true, false);
360 run_conv_test_float_to_s16(sse2_func, orig_func, 3, true, false);
361 run_conv_test_float_to_s16(sse2_func, orig_func, 4, true, false);
362 run_conv_test_float_to_s16(sse2_func, orig_func, 5, true, false);
363 run_conv_test_float_to_s16(sse2_func, orig_func, 6, true, false);
364 run_conv_test_float_to_s16(sse2_func, orig_func, 7, true, true);
365 }
366 END_TEST
367
368 START_TEST (sconv_sse_test) {
369 pa_cpu_x86_flag_t flags = 0;
370 pa_convert_func_t orig_func, sse_func;
371
372 pa_cpu_get_x86_flags(&flags);
373
374 if (!(flags & PA_CPU_X86_SSE)) {
375 pa_log_info("SSE not supported. Skipping");
376 return;
377 }
378
379 orig_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
380 pa_convert_func_init_sse(PA_CPU_X86_SSE);
381 sse_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
382
383 pa_log_debug("Checking SSE sconv (float -> s16)");
384 run_conv_test_float_to_s16(sse_func, orig_func, 0, true, false);
385 run_conv_test_float_to_s16(sse_func, orig_func, 1, true, false);
386 run_conv_test_float_to_s16(sse_func, orig_func, 2, true, false);
387 run_conv_test_float_to_s16(sse_func, orig_func, 3, true, false);
388 run_conv_test_float_to_s16(sse_func, orig_func, 4, true, false);
389 run_conv_test_float_to_s16(sse_func, orig_func, 5, true, false);
390 run_conv_test_float_to_s16(sse_func, orig_func, 6, true, false);
391 run_conv_test_float_to_s16(sse_func, orig_func, 7, true, true);
392 }
393 END_TEST
394 #endif /* defined (__i386__) || defined (__amd64__) */
395
396 #if defined (__arm__) && defined (__linux__)
397 #ifdef HAVE_NEON
398 START_TEST (sconv_neon_test) {
399 pa_cpu_arm_flag_t flags = 0;
400 pa_convert_func_t orig_from_func, neon_from_func;
401 pa_convert_func_t orig_to_func, neon_to_func;
402
403 pa_cpu_get_arm_flags(&flags);
404
405 if (!(flags & PA_CPU_ARM_NEON)) {
406 pa_log_info("NEON not supported. Skipping");
407 return;
408 }
409
410 orig_from_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
411 orig_to_func = pa_get_convert_to_float32ne_function(PA_SAMPLE_S16LE);
412 pa_convert_func_init_neon(flags);
413 neon_from_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
414 neon_to_func = pa_get_convert_to_float32ne_function(PA_SAMPLE_S16LE);
415
416 pa_log_debug("Checking NEON sconv (float -> s16)");
417 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 0, true, false);
418 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 1, true, false);
419 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 2, true, false);
420 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 3, true, false);
421 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 4, true, false);
422 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 5, true, false);
423 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 6, true, false);
424 run_conv_test_float_to_s16(neon_from_func, orig_from_func, 7, true, true);
425
426 pa_log_debug("Checking NEON sconv (s16 -> float)");
427 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 0, true, false);
428 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 1, true, false);
429 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 2, true, false);
430 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 3, true, false);
431 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 4, true, false);
432 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 5, true, false);
433 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 6, true, false);
434 run_conv_test_s16_to_float(neon_to_func, orig_to_func, 7, true, true);
435 }
436 END_TEST
437 #endif /* HAVE_NEON */
438 #endif /* defined (__arm__) && defined (__linux__) */
439
440 #undef SAMPLES
441 #undef TIMES
442 /* End conversion tests */
443
444 /* Start remap tests */
445 #define SAMPLES 1028
446 #define TIMES 1000
447 #define TIMES2 100
448
449 static void run_remap_test_mono_stereo_float(
450 pa_remap_t *remap,
451 pa_do_remap_func_t func,
452 pa_do_remap_func_t orig_func,
453 int align,
454 bool correct,
455 bool perf) {
456
457 PA_DECLARE_ALIGNED(8, float, s_ref[SAMPLES*2]) = { 0 };
458 PA_DECLARE_ALIGNED(8, float, s[SAMPLES*2]) = { 0 };
459 PA_DECLARE_ALIGNED(8, float, m[SAMPLES]);
460 float *stereo, *stereo_ref;
461 float *mono;
462 int i, nsamples;
463
464 /* Force sample alignment as requested */
465 stereo = s + (8 - align);
466 stereo_ref = s_ref + (8 - align);
467 mono = m + (8 - align);
468 nsamples = SAMPLES - (8 - align);
469
470 for (i = 0; i < nsamples; i++)
471 mono[i] = 2.1f * (rand()/(float) RAND_MAX - 0.5f);
472
473 if (correct) {
474 orig_func(remap, stereo_ref, mono, nsamples);
475 func(remap, stereo, mono, nsamples);
476
477 for (i = 0; i < nsamples * 2; i++) {
478 if (fabsf(stereo[i] - stereo_ref[i]) > 0.0001) {
479 pa_log_debug("Correctness test failed: align=%d", align);
480 pa_log_debug("%d: %.24f != %.24f (%.24f)\n", i, stereo[i], stereo_ref[i], mono[i]);
481 fail();
482 }
483 }
484 }
485
486 if (perf) {
487 pa_log_debug("Testing remap performance with %d sample alignment", align);
488
489 PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
490 func(remap, stereo, mono, nsamples);
491 } PA_RUNTIME_TEST_RUN_STOP
492
493 PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
494 orig_func(remap, stereo_ref, mono, nsamples);
495 } PA_RUNTIME_TEST_RUN_STOP
496 }
497 }
498
499 static void run_remap_test_mono_stereo_s16(
500 pa_remap_t *remap,
501 pa_do_remap_func_t func,
502 pa_do_remap_func_t orig_func,
503 int align,
504 bool correct,
505 bool perf) {
506
507 PA_DECLARE_ALIGNED(8, int16_t, s_ref[SAMPLES*2]) = { 0 };
508 PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES*2]) = { 0 };
509 PA_DECLARE_ALIGNED(8, int16_t, m[SAMPLES]);
510 int16_t *stereo, *stereo_ref;
511 int16_t *mono;
512 int i, nsamples;
513
514 /* Force sample alignment as requested */
515 stereo = s + (8 - align);
516 stereo_ref = s_ref + (8 - align);
517 mono = m + (8 - align);
518 nsamples = SAMPLES - (8 - align);
519
520 pa_random(mono, nsamples * sizeof(int16_t));
521
522 if (correct) {
523 orig_func(remap, stereo_ref, mono, nsamples);
524 func(remap, stereo, mono, nsamples);
525
526 for (i = 0; i < nsamples * 2; i++) {
527 if (abs(stereo[i] - stereo_ref[i]) > 1) {
528 pa_log_debug("Correctness test failed: align=%d", align);
529 pa_log_debug("%d: %d != %d (%d)\n", i, stereo[i], stereo_ref[i], mono[i]);
530 fail();
531 }
532 }
533 }
534
535 if (perf) {
536 pa_log_debug("Testing remap performance with %d sample alignment", align);
537
538 PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
539 func(remap, stereo, mono, nsamples);
540 } PA_RUNTIME_TEST_RUN_STOP
541
542 PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
543 orig_func(remap, stereo_ref, mono, nsamples);
544 } PA_RUNTIME_TEST_RUN_STOP
545 }
546 }
547
548 static void remap_test_mono_stereo_float(
549 pa_init_remap_func_t init_func,
550 pa_init_remap_func_t orig_init_func) {
551
552 pa_remap_t remap;
553 pa_do_remap_func_t orig_func, func;
554
555 remap.format = PA_SAMPLE_FLOAT32NE;
556 remap.i_ss.channels = 1;
557 remap.o_ss.channels = 2;
558 remap.map_table_f[0][0] = 1.0;
559 remap.map_table_f[1][0] = 1.0;
560 remap.map_table_i[0][0] = 0x10000;
561 remap.map_table_i[1][0] = 0x10000;
562 orig_init_func(&remap);
563 orig_func = remap.do_remap;
564 if (!orig_func) {
565 pa_log_warn("No reference remapping function, abort test");
566 return;
567 }
568
569 init_func(&remap);
570 func = remap.do_remap;
571 if (!func || func == orig_func) {
572 pa_log_warn("No remapping function, abort test");
573 return;
574 }
575
576 run_remap_test_mono_stereo_float(&remap, func, orig_func, 0, true, false);
577 run_remap_test_mono_stereo_float(&remap, func, orig_func, 1, true, false);
578 run_remap_test_mono_stereo_float(&remap, func, orig_func, 2, true, false);
579 run_remap_test_mono_stereo_float(&remap, func, orig_func, 3, true, true);
580 }
581
582 static void remap_test_mono_stereo_s16(
583 pa_init_remap_func_t init_func,
584 pa_init_remap_func_t orig_init_func) {
585
586 pa_remap_t remap;
587 pa_do_remap_func_t orig_func, func;
588
589 remap.format = PA_SAMPLE_S16NE;
590 remap.i_ss.channels = 1;
591 remap.o_ss.channels = 2;
592 remap.map_table_f[0][0] = 1.0;
593 remap.map_table_f[1][0] = 1.0;
594 remap.map_table_i[0][0] = 0x10000;
595 remap.map_table_i[1][0] = 0x10000;
596 orig_init_func(&remap);
597 orig_func = remap.do_remap;
598 if (!orig_func) {
599 pa_log_warn("No reference remapping function, abort test");
600 return;
601 }
602
603 init_func(&remap);
604 func = remap.do_remap;
605 if (!func || func == orig_func) {
606 pa_log_warn("No remapping function, abort test");
607 return;
608 }
609
610 run_remap_test_mono_stereo_s16(&remap, func, orig_func, 0, true, false);
611 run_remap_test_mono_stereo_s16(&remap, func, orig_func, 1, true, false);
612 run_remap_test_mono_stereo_s16(&remap, func, orig_func, 2, true, false);
613 run_remap_test_mono_stereo_s16(&remap, func, orig_func, 3, true, true);
614 }
615
616 #if defined (__i386__) || defined (__amd64__)
617 START_TEST (remap_mmx_test) {
618 pa_cpu_x86_flag_t flags = 0;
619 pa_init_remap_func_t init_func, orig_init_func;
620
621 pa_cpu_get_x86_flags(&flags);
622 if (!(flags & PA_CPU_X86_MMX)) {
623 pa_log_info("MMX not supported. Skipping");
624 return;
625 }
626
627 pa_log_debug("Checking MMX remap (float, mono->stereo)");
628 orig_init_func = pa_get_init_remap_func();
629 pa_remap_func_init_mmx(flags);
630 init_func = pa_get_init_remap_func();
631 remap_test_mono_stereo_float(init_func, orig_init_func);
632
633 pa_log_debug("Checking MMX remap (s16, mono->stereo)");
634 remap_test_mono_stereo_s16(init_func, orig_init_func);
635 }
636 END_TEST
637
638 START_TEST (remap_sse2_test) {
639 pa_cpu_x86_flag_t flags = 0;
640 pa_init_remap_func_t init_func, orig_init_func;
641
642 pa_cpu_get_x86_flags(&flags);
643 if (!(flags & PA_CPU_X86_SSE2)) {
644 pa_log_info("SSE2 not supported. Skipping");
645 return;
646 }
647
648 pa_log_debug("Checking SSE2 remap (float, mono->stereo)");
649 orig_init_func = pa_get_init_remap_func();
650 pa_remap_func_init_sse(flags);
651 init_func = pa_get_init_remap_func();
652 remap_test_mono_stereo_float(init_func, orig_init_func);
653
654 pa_log_debug("Checking SSE2 remap (s16, mono->stereo)");
655 remap_test_mono_stereo_s16(init_func, orig_init_func);
656 }
657 END_TEST
658 #endif /* defined (__i386__) || defined (__amd64__) */
659
660 #undef SAMPLES
661 #undef TIMES
662 #undef TIMES2
663 /* End remap tests */
664
665 /* Start mix tests */
666
667 /* Only ARM NEON has mix tests, so disable the related functions for other
668 * architectures for now to avoid compiler warnings about unused functions. */
669 #if defined (__arm__) && defined (__linux__)
670 #ifdef HAVE_NEON
671
672 #define SAMPLES 1028
673 #define TIMES 1000
674 #define TIMES2 100
675
676 static void acquire_mix_streams(pa_mix_info streams[], unsigned nstreams) {
677 unsigned i;
678
679 for (i = 0; i < nstreams; i++)
680 streams[i].ptr = pa_memblock_acquire_chunk(&streams[i].chunk);
681 }
682
683 static void release_mix_streams(pa_mix_info streams[], unsigned nstreams) {
684 unsigned i;
685
686 for (i = 0; i < nstreams; i++)
687 pa_memblock_release(streams[i].chunk.memblock);
688 }
689
690 static void run_mix_test(
691 pa_do_mix_func_t func,
692 pa_do_mix_func_t orig_func,
693 int align,
694 int channels,
695 bool correct,
696 bool perf) {
697
698 PA_DECLARE_ALIGNED(8, int16_t, in0[SAMPLES * 4]) = { 0 };
699 PA_DECLARE_ALIGNED(8, int16_t, in1[SAMPLES * 4]) = { 0 };
700 PA_DECLARE_ALIGNED(8, int16_t, out[SAMPLES * 4]) = { 0 };
701 PA_DECLARE_ALIGNED(8, int16_t, out_ref[SAMPLES * 4]) = { 0 };
702 int16_t *samples0, *samples1;
703 int16_t *samples, *samples_ref;
704 int nsamples;
705 pa_mempool *pool;
706 pa_memchunk c0, c1;
707 pa_mix_info m[2];
708 int i;
709
710 pa_assert(channels == 1 || channels == 2 || channels == 4);
711
712 /* Force sample alignment as requested */
713 samples0 = in0 + (8 - align);
714 samples1 = in1 + (8 - align);
715 samples = out + (8 - align);
716 samples_ref = out_ref + (8 - align);
717 nsamples = channels * (SAMPLES - (8 - align));
718
719 fail_unless((pool = pa_mempool_new(false, 0)) != NULL, NULL);
720
721 pa_random(samples0, nsamples * sizeof(int16_t));
722 c0.memblock = pa_memblock_new_fixed(pool, samples0, nsamples * sizeof(int16_t), false);
723 c0.length = pa_memblock_get_length(c0.memblock);
724 c0.index = 0;
725
726 pa_random(samples1, nsamples * sizeof(int16_t));
727 c1.memblock = pa_memblock_new_fixed(pool, samples1, nsamples * sizeof(int16_t), false);
728 c1.length = pa_memblock_get_length(c1.memblock);
729 c1.index = 0;
730
731 m[0].chunk = c0;
732 m[0].volume.channels = channels;
733 for (i = 0; i < channels; i++) {
734 m[0].volume.values[i] = PA_VOLUME_NORM;
735 m[0].linear[i].i = 0x5555;
736 }
737
738 m[1].chunk = c1;
739 m[1].volume.channels = channels;
740 for (i = 0; i < channels; i++) {
741 m[1].volume.values[i] = PA_VOLUME_NORM;
742 m[1].linear[i].i = 0x6789;
743 }
744
745 if (correct) {
746 acquire_mix_streams(m, 2);
747 orig_func(m, 2, channels, samples_ref, nsamples * sizeof(int16_t));
748 release_mix_streams(m, 2);
749
750 acquire_mix_streams(m, 2);
751 func(m, 2, channels, samples, nsamples * sizeof(int16_t));
752 release_mix_streams(m, 2);
753
754 for (i = 0; i < nsamples; i++) {
755 if (samples[i] != samples_ref[i]) {
756 pa_log_debug("Correctness test failed: align=%d, channels=%d", align, channels);
757 pa_log_debug("%d: %hd != %04hd (%hd + %hd)\n",
758 i,
759 samples[i], samples_ref[i],
760 samples0[i], samples1[i]);
761 fail();
762 }
763 }
764 }
765
766 if (perf) {
767 pa_log_debug("Testing %d-channel mixing performance with %d sample alignment", channels, align);
768
769 PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
770 acquire_mix_streams(m, 2);
771 func(m, 2, channels, samples, nsamples * sizeof(int16_t));
772 release_mix_streams(m, 2);
773 } PA_RUNTIME_TEST_RUN_STOP
774
775 PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
776 acquire_mix_streams(m, 2);
777 orig_func(m, 2, channels, samples_ref, nsamples * sizeof(int16_t));
778 release_mix_streams(m, 2);
779 } PA_RUNTIME_TEST_RUN_STOP
780 }
781
782 pa_memblock_unref(c0.memblock);
783 pa_memblock_unref(c1.memblock);
784
785 pa_mempool_free(pool);
786 }
787 #endif /* HAVE_NEON */
788 #endif /* defined (__arm__) && defined (__linux__) */
789
790 #if defined (__arm__) && defined (__linux__)
791 #ifdef HAVE_NEON
792 START_TEST (mix_neon_test) {
793 pa_do_mix_func_t orig_func, neon_func;
794 pa_cpu_arm_flag_t flags = 0;
795
796 pa_cpu_get_arm_flags(&flags);
797
798 if (!(flags & PA_CPU_ARM_NEON)) {
799 pa_log_info("NEON not supported. Skipping");
800 return;
801 }
802
803 orig_func = pa_get_mix_func(PA_SAMPLE_S16NE);
804 pa_mix_func_init_neon(flags);
805 neon_func = pa_get_mix_func(PA_SAMPLE_S16NE);
806
807 pa_log_debug("Checking NEON mix");
808 run_mix_test(neon_func, orig_func, 7, 2, true, true);
809 }
810 END_TEST
811 #endif /* HAVE_NEON */
812 #endif /* defined (__arm__) && defined (__linux__) */
813 /* End mix tests */
814
815 int main(int argc, char *argv[]) {
816 int failed = 0;
817 Suite *s;
818 TCase *tc;
819 SRunner *sr;
820
821 if (!getenv("MAKE_CHECK"))
822 pa_log_set_level(PA_LOG_DEBUG);
823
824 s = suite_create("CPU");
825
826 /* Volume tests */
827 tc = tcase_create("svolume");
828 #if defined (__i386__) || defined (__amd64__)
829 tcase_add_test(tc, svolume_mmx_test);
830 tcase_add_test(tc, svolume_sse_test);
831 #endif
832 #if defined (__arm__) && defined (__linux__)
833 tcase_add_test(tc, svolume_arm_test);
834 #endif
835 tcase_add_test(tc, svolume_orc_test);
836 tcase_set_timeout(tc, 120);
837 suite_add_tcase(s, tc);
838
839 /* Conversion tests */
840 tc = tcase_create("sconv");
841 #if defined (__i386__) || defined (__amd64__)
842 tcase_add_test(tc, sconv_sse2_test);
843 tcase_add_test(tc, sconv_sse_test);
844 #endif
845 #if defined (__arm__) && defined (__linux__)
846 #if HAVE_NEON
847 tcase_add_test(tc, sconv_neon_test);
848 #endif
849 #endif
850 tcase_set_timeout(tc, 120);
851 suite_add_tcase(s, tc);
852
853 /* Remap tests */
854 tc = tcase_create("remap");
855 #if defined (__i386__) || defined (__amd64__)
856 tcase_add_test(tc, remap_mmx_test);
857 tcase_add_test(tc, remap_sse2_test);
858 #endif
859 tcase_set_timeout(tc, 120);
860 suite_add_tcase(s, tc);
861 /* Mix tests */
862 tc = tcase_create("mix");
863 #if defined (__arm__) && defined (__linux__)
864 #if HAVE_NEON
865 tcase_add_test(tc, mix_neon_test);
866 #endif
867 #endif
868 tcase_set_timeout(tc, 120);
869 suite_add_tcase(s, tc);
870
871 sr = srunner_create(s);
872 srunner_run_all(sr, CK_NORMAL);
873 failed = srunner_ntests_failed(sr);
874 srunner_free(sr);
875
876 return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
877 }