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 #include "runtime-test-util.h"
41 /* Common defines for svolume tests */
47 static void run_volume_test(
48 pa_do_volume_func_t func
,
49 pa_do_volume_func_t orig_func
,
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
;
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);
71 pa_random(samples
, size
);
72 memcpy(samples_ref
, samples
, size
);
73 memcpy(samples_orig
, samples
, size
);
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
];
81 orig_func(samples_ref
, volumes
, channels
, size
);
82 func(samples
, volumes
, channels
, size
);
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
]);
95 pa_log_debug("Testing svolume %dch performance with %d sample alignment", channels
, align
);
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
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
107 fail_unless(memcmp(samples_ref
, samples
, size
) == 0);
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;
117 pa_cpu_get_x86_flags(&flags
);
119 if (!((flags
& PA_CPU_X86_MMX
) && (flags
& PA_CPU_X86_CMOV
))) {
120 pa_log_info("MMX/CMOV not supported. Skipping");
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
);
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);
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);
139 START_TEST (svolume_sse_test
) {
140 pa_do_volume_func_t orig_func
, sse_func
;
141 pa_cpu_x86_flag_t flags
= 0;
144 pa_cpu_get_x86_flags(&flags
);
146 if (!(flags
& PA_CPU_X86_SSE2
)) {
147 pa_log_info("SSE2 not supported. Skipping");
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
);
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);
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);
165 #endif /* defined (__i386__) || defined (__amd64__) */
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;
173 pa_cpu_get_arm_flags(&flags
);
175 if (!(flags
& PA_CPU_ARM_V6
)) {
176 pa_log_info("ARMv6 instructions not supported. Skipping");
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
);
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);
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);
194 #endif /* defined (__arm__) && defined (__linux__) */
196 START_TEST (svolume_orc_test
) {
197 pa_do_volume_func_t orig_func
, orc_func
;
198 pa_cpu_info cpu_info
;
201 #if defined (__i386__) || defined (__amd64__)
203 cpu_info
.cpu_type
= PA_CPU_X86
;
204 pa_cpu_get_x86_flags(&cpu_info
.flags
.x86
);
207 orig_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
209 if (!pa_cpu_init_orc(cpu_info
)) {
210 pa_log_info("Orc not supported. Skipping");
214 orc_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
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);
221 run_volume_test(orc_func
, orig_func
, 7, 1, true, true);
222 run_volume_test(orc_func
, orig_func
, 7, 2, true, true);
230 /* End svolume tests */
232 /* Start conversion tests */
237 static void run_conv_test_float_to_s16(
238 pa_convert_func_t func
,
239 pa_convert_func_t orig_func
,
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
;
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
);
257 for (i
= 0; i
< nsamples
; i
++) {
258 floats
[i
] = 2.1f
* (rand()/(float) RAND_MAX
- 0.5f
);
262 orig_func(nsamples
, floats
, samples_ref
);
263 func(nsamples
, floats
, samples
);
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
]);
275 pa_log_debug("Testing sconv performance with %d sample alignment", align
);
277 PA_RUNTIME_TEST_RUN_START("func", TIMES
, TIMES2
) {
278 func(nsamples
, floats
, samples
);
279 } PA_RUNTIME_TEST_RUN_STOP
281 PA_RUNTIME_TEST_RUN_START("orig", TIMES
, TIMES2
) {
282 orig_func(nsamples
, floats
, samples_ref
);
283 } PA_RUNTIME_TEST_RUN_STOP
287 /* This test is currently only run under NEON */
288 #if defined (__arm__) && defined (__linux__)
290 static void run_conv_test_s16_to_float(
291 pa_convert_func_t func
,
292 pa_convert_func_t orig_func
,
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
;
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
);
310 pa_random(samples
, nsamples
* sizeof(int16_t));
313 orig_func(nsamples
, samples
, floats_ref
);
314 func(nsamples
, samples
, floats
);
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
]);
326 pa_log_debug("Testing sconv performance with %d sample alignment", align
);
328 PA_RUNTIME_TEST_RUN_START("func", TIMES
, TIMES2
) {
329 func(nsamples
, samples
, floats
);
330 } PA_RUNTIME_TEST_RUN_STOP
332 PA_RUNTIME_TEST_RUN_START("orig", TIMES
, TIMES2
) {
333 orig_func(nsamples
, samples
, floats_ref
);
334 } PA_RUNTIME_TEST_RUN_STOP
337 #endif /* HAVE_NEON */
338 #endif /* defined (__arm__) && defined (__linux__) */
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
;
345 pa_cpu_get_x86_flags(&flags
);
347 if (!(flags
& PA_CPU_X86_SSE2
)) {
348 pa_log_info("SSE2 not supported. Skipping");
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
);
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);
368 START_TEST (sconv_sse_test
) {
369 pa_cpu_x86_flag_t flags
= 0;
370 pa_convert_func_t orig_func
, sse_func
;
372 pa_cpu_get_x86_flags(&flags
);
374 if (!(flags
& PA_CPU_X86_SSE
)) {
375 pa_log_info("SSE not supported. Skipping");
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
);
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);
394 #endif /* defined (__i386__) || defined (__amd64__) */
396 #if defined (__arm__) && defined (__linux__)
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
;
403 pa_cpu_get_arm_flags(&flags
);
405 if (!(flags
& PA_CPU_ARM_NEON
)) {
406 pa_log_info("NEON not supported. Skipping");
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
);
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);
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);
437 #endif /* HAVE_NEON */
438 #endif /* defined (__arm__) && defined (__linux__) */
442 /* End conversion tests */
444 /* Start remap tests */
449 static void run_remap_test_mono_stereo_float(
451 pa_do_remap_func_t func
,
452 pa_do_remap_func_t orig_func
,
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
;
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
);
470 for (i
= 0; i
< nsamples
; i
++)
471 mono
[i
] = 2.1f
* (rand()/(float) RAND_MAX
- 0.5f
);
474 orig_func(remap
, stereo_ref
, mono
, nsamples
);
475 func(remap
, stereo
, mono
, nsamples
);
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
]);
487 pa_log_debug("Testing remap performance with %d sample alignment", align
);
489 PA_RUNTIME_TEST_RUN_START("func", TIMES
, TIMES2
) {
490 func(remap
, stereo
, mono
, nsamples
);
491 } PA_RUNTIME_TEST_RUN_STOP
493 PA_RUNTIME_TEST_RUN_START("orig", TIMES
, TIMES2
) {
494 orig_func(remap
, stereo_ref
, mono
, nsamples
);
495 } PA_RUNTIME_TEST_RUN_STOP
499 static void run_remap_test_mono_stereo_s16(
501 pa_do_remap_func_t func
,
502 pa_do_remap_func_t orig_func
,
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
;
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
);
520 pa_random(mono
, nsamples
* sizeof(int16_t));
523 orig_func(remap
, stereo_ref
, mono
, nsamples
);
524 func(remap
, stereo
, mono
, nsamples
);
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
]);
536 pa_log_debug("Testing remap performance with %d sample alignment", align
);
538 PA_RUNTIME_TEST_RUN_START("func", TIMES
, TIMES2
) {
539 func(remap
, stereo
, mono
, nsamples
);
540 } PA_RUNTIME_TEST_RUN_STOP
542 PA_RUNTIME_TEST_RUN_START("orig", TIMES
, TIMES2
) {
543 orig_func(remap
, stereo_ref
, mono
, nsamples
);
544 } PA_RUNTIME_TEST_RUN_STOP
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
) {
553 pa_do_remap_func_t orig_func
, func
;
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
;
565 pa_log_warn("No reference remapping function, abort test");
570 func
= remap
.do_remap
;
571 if (!func
|| func
== orig_func
) {
572 pa_log_warn("No remapping function, abort test");
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);
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
) {
587 pa_do_remap_func_t orig_func
, func
;
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
;
599 pa_log_warn("No reference remapping function, abort test");
604 func
= remap
.do_remap
;
605 if (!func
|| func
== orig_func
) {
606 pa_log_warn("No remapping function, abort test");
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);
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
;
621 pa_cpu_get_x86_flags(&flags
);
622 if (!(flags
& PA_CPU_X86_MMX
)) {
623 pa_log_info("MMX not supported. Skipping");
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
);
633 pa_log_debug("Checking MMX remap (s16, mono->stereo)");
634 remap_test_mono_stereo_s16(init_func
, orig_init_func
);
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
;
642 pa_cpu_get_x86_flags(&flags
);
643 if (!(flags
& PA_CPU_X86_SSE2
)) {
644 pa_log_info("SSE2 not supported. Skipping");
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
);
654 pa_log_debug("Checking SSE2 remap (s16, mono->stereo)");
655 remap_test_mono_stereo_s16(init_func
, orig_init_func
);
658 #endif /* defined (__i386__) || defined (__amd64__) */
663 /* End remap tests */
665 /* Start mix tests */
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__)
676 static void acquire_mix_streams(pa_mix_info streams
[], unsigned nstreams
) {
679 for (i
= 0; i
< nstreams
; i
++)
680 streams
[i
].ptr
= pa_memblock_acquire_chunk(&streams
[i
].chunk
);
683 static void release_mix_streams(pa_mix_info streams
[], unsigned nstreams
) {
686 for (i
= 0; i
< nstreams
; i
++)
687 pa_memblock_release(streams
[i
].chunk
.memblock
);
690 static void run_mix_test(
691 pa_do_mix_func_t func
,
692 pa_do_mix_func_t orig_func
,
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
;
710 pa_assert(channels
== 1 || channels
== 2 || channels
== 4);
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
));
719 fail_unless((pool
= pa_mempool_new(false, 0)) != NULL
, NULL
);
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
);
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
);
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;
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;
746 acquire_mix_streams(m
, 2);
747 orig_func(m
, 2, channels
, samples_ref
, nsamples
* sizeof(int16_t));
748 release_mix_streams(m
, 2);
750 acquire_mix_streams(m
, 2);
751 func(m
, 2, channels
, samples
, nsamples
* sizeof(int16_t));
752 release_mix_streams(m
, 2);
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",
759 samples
[i
], samples_ref
[i
],
760 samples0
[i
], samples1
[i
]);
767 pa_log_debug("Testing %d-channel mixing performance with %d sample alignment", channels
, align
);
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
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
782 pa_memblock_unref(c0
.memblock
);
783 pa_memblock_unref(c1
.memblock
);
785 pa_mempool_free(pool
);
787 #endif /* HAVE_NEON */
788 #endif /* defined (__arm__) && defined (__linux__) */
790 #if defined (__arm__) && defined (__linux__)
792 START_TEST (mix_neon_test
) {
793 pa_do_mix_func_t orig_func
, neon_func
;
794 pa_cpu_arm_flag_t flags
= 0;
796 pa_cpu_get_arm_flags(&flags
);
798 if (!(flags
& PA_CPU_ARM_NEON
)) {
799 pa_log_info("NEON not supported. Skipping");
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
);
807 pa_log_debug("Checking NEON mix");
808 run_mix_test(neon_func
, orig_func
, 7, 2, true, true);
811 #endif /* HAVE_NEON */
812 #endif /* defined (__arm__) && defined (__linux__) */
815 int main(int argc
, char *argv
[]) {
821 if (!getenv("MAKE_CHECK"))
822 pa_log_set_level(PA_LOG_DEBUG
);
824 s
= suite_create("CPU");
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
);
832 #if defined (__arm__) && defined (__linux__)
833 tcase_add_test(tc
, svolume_arm_test
);
835 tcase_add_test(tc
, svolume_orc_test
);
836 tcase_set_timeout(tc
, 120);
837 suite_add_tcase(s
, tc
);
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
);
845 #if defined (__arm__) && defined (__linux__)
847 tcase_add_test(tc
, sconv_neon_test
);
850 tcase_set_timeout(tc
, 120);
851 suite_add_tcase(s
, tc
);
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
);
859 tcase_set_timeout(tc
, 120);
860 suite_add_tcase(s
, tc
);
862 tc
= tcase_create("mix");
863 #if defined (__arm__) && defined (__linux__)
865 tcase_add_test(tc
, mix_neon_test
);
868 tcase_set_timeout(tc
, 120);
869 suite_add_tcase(s
, tc
);
871 sr
= srunner_create(s
);
872 srunner_run_all(sr
, CK_NORMAL
);
873 failed
= srunner_ntests_failed(sr
);
876 return (failed
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;