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