2 This file is part of PulseAudio.
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.
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.
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
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>
39 #define PA_CPU_TEST_RUN_START(l, t1, t2) \
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); \
48 for (_k = 0; _k < _times2; _k++) { \
49 _start = pa_rtclock_now(); \
50 for (_j = 0; _j < _times; _j++)
52 #define PA_CPU_TEST_RUN_STOP \
53 _stop = pa_rtclock_now(); \
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); \
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); \
68 /* Common defines for svolume tests */
74 static void run_volume_test(
75 pa_do_volume_func_t func,
76 pa_do_volume_func_t orig_func,
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;
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);
98 pa_random(samples, size);
99 memcpy(samples_ref, samples, size);
100 memcpy(samples_orig, samples, size);
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];
108 orig_func(samples_ref, volumes, channels, size);
109 func(samples, volumes, channels, size);
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]);
122 pa_log_debug("Testing svolume %dch performance with %d sample alignment", channels, align);
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
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
134 fail_unless(memcmp(samples_ref, samples, size) == 0);
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;
144 pa_cpu_get_x86_flags(&flags);
146 if (!((flags & PA_CPU_X86_MMX) && (flags & PA_CPU_X86_CMOV))) {
147 pa_log_info("MMX/CMOV not supported. Skipping");
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);
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);
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);
166 START_TEST (svolume_sse_test) {
167 pa_do_volume_func_t orig_func, sse_func;
168 pa_cpu_x86_flag_t flags = 0;
171 pa_cpu_get_x86_flags(&flags);
173 if (!(flags & PA_CPU_X86_SSE2)) {
174 pa_log_info("SSE2 not supported. Skipping");
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);
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);
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);
192 #endif /* defined (__i386__) || defined (__amd64__) */
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;
200 pa_cpu_get_arm_flags(&flags);
202 if (!(flags & PA_CPU_ARM_V6)) {
203 pa_log_info("ARMv6 instructions not supported. Skipping");
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);
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);
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);
221 #endif /* defined (__arm__) && defined (__linux__) */
223 START_TEST (svolume_orc_test) {
224 pa_do_volume_func_t orig_func, orc_func;
225 pa_cpu_info cpu_info;
228 #if defined (__i386__) || defined (__amd64__)
230 cpu_info.cpu_type = PA_CPU_X86;
231 pa_cpu_get_x86_flags(&cpu_info.flags.x86);
234 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
236 if (!pa_cpu_init_orc(cpu_info)) {
237 pa_log_info("Orc not supported. Skipping");
241 orc_func = pa_get_volume_func(PA_SAMPLE_S16NE);
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);
248 run_volume_test(orc_func, orig_func, 7, 1, TRUE, TRUE);
249 run_volume_test(orc_func, orig_func, 7, 2, TRUE, TRUE);
257 /* End svolume tests */
259 /* Start conversion tests */
264 static void run_conv_test_float_to_s16(
265 pa_convert_func_t func,
266 pa_convert_func_t orig_func,
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;
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);
284 for (i = 0; i < nsamples; i++) {
285 floats[i] = 2.1f * (rand()/(float) RAND_MAX - 0.5f);
289 orig_func(nsamples, floats, samples_ref);
290 func(nsamples, floats, samples);
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]);
302 pa_log_debug("Testing sconv performance with %d sample alignment", align);
304 PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
305 func(nsamples, floats, samples);
306 } PA_CPU_TEST_RUN_STOP
308 PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
309 orig_func(nsamples, floats, samples_ref);
310 } PA_CPU_TEST_RUN_STOP
314 /* This test is currently only run under NEON */
315 #if defined (__arm__) && defined (__linux__)
317 static void run_conv_test_s16_to_float(
318 pa_convert_func_t func,
319 pa_convert_func_t orig_func,
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;
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);
337 pa_random(samples, nsamples * sizeof(int16_t));
340 orig_func(nsamples, samples, floats_ref);
341 func(nsamples, samples, floats);
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]);
353 pa_log_debug("Testing sconv performance with %d sample alignment", align);
355 PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
356 func(nsamples, samples, floats);
357 } PA_CPU_TEST_RUN_STOP
359 PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
360 orig_func(nsamples, samples, floats_ref);
361 } PA_CPU_TEST_RUN_STOP
364 #endif /* HAVE_NEON */
365 #endif /* defined (__arm__) && defined (__linux__) */
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;
372 pa_cpu_get_x86_flags(&flags);
374 if (!(flags & PA_CPU_X86_SSE2)) {
375 pa_log_info("SSE2 not supported. Skipping");
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);
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);
395 START_TEST (sconv_sse_test) {
396 pa_cpu_x86_flag_t flags = 0;
397 pa_convert_func_t orig_func, sse_func;
399 pa_cpu_get_x86_flags(&flags);
401 if (!(flags & PA_CPU_X86_SSE)) {
402 pa_log_info("SSE not supported. Skipping");
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);
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);
421 #endif /* defined (__i386__) || defined (__amd64__) */
423 #if defined (__arm__) && defined (__linux__)
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;
430 pa_cpu_get_arm_flags(&flags);
432 if (!(flags & PA_CPU_ARM_NEON)) {
433 pa_log_info("NEON not supported. Skipping");
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);
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);
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);
464 #endif /* HAVE_NEON */
465 #endif /* defined (__arm__) && defined (__linux__) */
469 /* End conversion tests */
471 /* Start remap tests */
476 static void run_remap_test_mono_stereo_float(
478 pa_do_remap_func_t func,
479 pa_do_remap_func_t orig_func,
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;
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);
497 for (i = 0; i < nsamples; i++)
498 mono[i] = 2.1f * (rand()/(float) RAND_MAX - 0.5f);
501 orig_func(remap, stereo_ref, mono, nsamples);
502 func(remap, stereo, mono, nsamples);
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]);
514 pa_log_debug("Testing remap performance with %d sample alignment", align);
516 PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
517 func(remap, stereo, mono, nsamples);
518 } PA_CPU_TEST_RUN_STOP
520 PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
521 orig_func(remap, stereo_ref, mono, nsamples);
522 } PA_CPU_TEST_RUN_STOP
526 static void run_remap_test_mono_stereo_s16(
528 pa_do_remap_func_t func,
529 pa_do_remap_func_t orig_func,
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;
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);
547 pa_random(mono, nsamples * sizeof(int16_t));
550 orig_func(remap, stereo_ref, mono, nsamples);
551 func(remap, stereo, mono, nsamples);
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]);
563 pa_log_debug("Testing remap performance with %d sample alignment", align);
565 PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
566 func(remap, stereo, mono, nsamples);
567 } PA_CPU_TEST_RUN_STOP
569 PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
570 orig_func(remap, stereo_ref, mono, nsamples);
571 } PA_CPU_TEST_RUN_STOP
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) {
579 pa_sample_format_t sf;
581 pa_sample_spec iss, oss;
582 pa_do_remap_func_t orig_func, func;
584 iss.format = oss.format = sf = PA_SAMPLE_FLOAT32NE;
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;
597 pa_log_warn("No reference remapping function, abort test");
602 func = remap.do_remap;
603 if (!func || func == orig_func) {
604 pa_log_warn("No remapping function, abort test");
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);
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) {
618 pa_sample_format_t sf;
620 pa_sample_spec iss, oss;
621 pa_do_remap_func_t orig_func, func;
623 iss.format = oss.format = sf = PA_SAMPLE_S16NE;
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;
636 pa_log_warn("No reference remapping function, abort test");
641 func = remap.do_remap;
642 if (!func || func == orig_func) {
643 pa_log_warn("No remapping function, abort test");
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);
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;
658 pa_cpu_get_x86_flags(&flags);
659 if (!(flags & PA_CPU_X86_MMX)) {
660 pa_log_info("MMX not supported. Skipping");
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);
670 pa_log_debug("Checking MMX remap (s16, mono->stereo)");
671 remap_test_mono_stereo_s16(init_func, orig_init_func);
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;
679 pa_cpu_get_x86_flags(&flags);
680 if (!(flags & PA_CPU_X86_SSE2)) {
681 pa_log_info("SSE2 not supported. Skipping");
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);
691 pa_log_debug("Checking SSE2 remap (s16, mono->stereo)");
692 remap_test_mono_stereo_s16(init_func, orig_init_func);
695 #endif /* defined (__i386__) || defined (__amd64__) */
700 /* End remap tests */
702 /* Start mix tests */
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__)
713 static void acquire_mix_streams(pa_mix_info streams[], unsigned nstreams) {
716 for (i = 0; i < nstreams; i++)
717 streams[i].ptr = pa_memblock_acquire_chunk(&streams[i].chunk);
720 static void release_mix_streams(pa_mix_info streams[], unsigned nstreams) {
723 for (i = 0; i < nstreams; i++)
724 pa_memblock_release(streams[i].chunk.memblock);
727 static void run_mix_test(
728 pa_do_mix_func_t func,
729 pa_do_mix_func_t orig_func,
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;
747 pa_assert(channels == 1 || channels == 2 || channels == 4);
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));
756 fail_unless((pool = pa_mempool_new(FALSE, 0)) != NULL, NULL);
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);
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);
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;
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;
783 acquire_mix_streams(m, 2);
784 orig_func(m, 2, channels, samples_ref, nsamples * sizeof(int16_t));
785 release_mix_streams(m, 2);
787 acquire_mix_streams(m, 2);
788 func(m, 2, channels, samples, nsamples * sizeof(int16_t));
789 release_mix_streams(m, 2);
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",
796 samples[i], samples_ref[i],
797 samples0[i], samples1[i]);
804 pa_log_debug("Testing %d-channel mixing performance with %d sample alignment", channels, align);
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
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
819 pa_memblock_unref(c0.memblock);
820 pa_memblock_unref(c1.memblock);
822 pa_mempool_free(pool);
824 #endif /* HAVE_NEON */
825 #endif /* defined (__arm__) && defined (__linux__) */
827 #if defined (__arm__) && defined (__linux__)
829 START_TEST (mix_neon_test) {
830 pa_do_mix_func_t orig_func, neon_func;
831 pa_cpu_arm_flag_t flags = 0;
833 pa_cpu_get_arm_flags(&flags);
835 if (!(flags & PA_CPU_ARM_NEON)) {
836 pa_log_info("NEON not supported. Skipping");
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);
844 pa_log_debug("Checking NEON mix");
845 run_mix_test(neon_func, orig_func, 7, 2, TRUE, TRUE);
848 #endif /* HAVE_NEON */
849 #endif /* defined (__arm__) && defined (__linux__) */
852 int main(int argc, char *argv[]) {
858 if (!getenv("MAKE_CHECK"))
859 pa_log_set_level(PA_LOG_DEBUG);
861 s = suite_create("CPU");
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);
869 #if defined (__arm__) && defined (__linux__)
870 tcase_add_test(tc, svolume_arm_test);
872 tcase_add_test(tc, svolume_orc_test);
873 tcase_set_timeout(tc, 120);
874 suite_add_tcase(s, tc);
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);
882 #if defined (__arm__) && defined (__linux__)
884 tcase_add_test(tc, sconv_neon_test);
887 tcase_set_timeout(tc, 120);
888 suite_add_tcase(s, tc);
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);
896 tcase_set_timeout(tc, 120);
897 suite_add_tcase(s, tc);
899 tc = tcase_create("mix");
900 #if defined (__arm__) && defined (__linux__)
902 tcase_add_test(tc, mix_neon_test);
905 tcase_set_timeout(tc, 120);
906 suite_add_tcase(s, tc);
908 sr = srunner_create(s);
909 srunner_run_all(sr, CK_NORMAL);
910 failed = srunner_ntests_failed(sr);
913 return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;