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
) {
552 pa_sample_format_t sf
;
554 pa_sample_spec iss
, oss
;
555 pa_do_remap_func_t orig_func
, func
;
557 iss
.format
= oss
.format
= sf
= PA_SAMPLE_FLOAT32NE
;
563 remap
.map_table_f
[0][0] = 1.0;
564 remap
.map_table_f
[1][0] = 1.0;
565 remap
.map_table_i
[0][0] = 0x10000;
566 remap
.map_table_i
[1][0] = 0x10000;
567 orig_init_func(&remap
);
568 orig_func
= remap
.do_remap
;
570 pa_log_warn("No reference remapping function, abort test");
575 func
= remap
.do_remap
;
576 if (!func
|| func
== orig_func
) {
577 pa_log_warn("No remapping function, abort test");
581 run_remap_test_mono_stereo_float(&remap
, func
, orig_func
, 0, true, false);
582 run_remap_test_mono_stereo_float(&remap
, func
, orig_func
, 1, true, false);
583 run_remap_test_mono_stereo_float(&remap
, func
, orig_func
, 2, true, false);
584 run_remap_test_mono_stereo_float(&remap
, func
, orig_func
, 3, true, true);
587 static void remap_test_mono_stereo_s16(
588 pa_init_remap_func_t init_func
,
589 pa_init_remap_func_t orig_init_func
) {
591 pa_sample_format_t sf
;
593 pa_sample_spec iss
, oss
;
594 pa_do_remap_func_t orig_func
, func
;
596 iss
.format
= oss
.format
= sf
= PA_SAMPLE_S16NE
;
602 remap
.map_table_f
[0][0] = 1.0;
603 remap
.map_table_f
[1][0] = 1.0;
604 remap
.map_table_i
[0][0] = 0x10000;
605 remap
.map_table_i
[1][0] = 0x10000;
606 orig_init_func(&remap
);
607 orig_func
= remap
.do_remap
;
609 pa_log_warn("No reference remapping function, abort test");
614 func
= remap
.do_remap
;
615 if (!func
|| func
== orig_func
) {
616 pa_log_warn("No remapping function, abort test");
620 run_remap_test_mono_stereo_s16(&remap
, func
, orig_func
, 0, true, false);
621 run_remap_test_mono_stereo_s16(&remap
, func
, orig_func
, 1, true, false);
622 run_remap_test_mono_stereo_s16(&remap
, func
, orig_func
, 2, true, false);
623 run_remap_test_mono_stereo_s16(&remap
, func
, orig_func
, 3, true, true);
626 #if defined (__i386__) || defined (__amd64__)
627 START_TEST (remap_mmx_test
) {
628 pa_cpu_x86_flag_t flags
= 0;
629 pa_init_remap_func_t init_func
, orig_init_func
;
631 pa_cpu_get_x86_flags(&flags
);
632 if (!(flags
& PA_CPU_X86_MMX
)) {
633 pa_log_info("MMX not supported. Skipping");
637 pa_log_debug("Checking MMX remap (float, mono->stereo)");
638 orig_init_func
= pa_get_init_remap_func();
639 pa_remap_func_init_mmx(flags
);
640 init_func
= pa_get_init_remap_func();
641 remap_test_mono_stereo_float(init_func
, orig_init_func
);
643 pa_log_debug("Checking MMX remap (s16, mono->stereo)");
644 remap_test_mono_stereo_s16(init_func
, orig_init_func
);
648 START_TEST (remap_sse2_test
) {
649 pa_cpu_x86_flag_t flags
= 0;
650 pa_init_remap_func_t init_func
, orig_init_func
;
652 pa_cpu_get_x86_flags(&flags
);
653 if (!(flags
& PA_CPU_X86_SSE2
)) {
654 pa_log_info("SSE2 not supported. Skipping");
658 pa_log_debug("Checking SSE2 remap (float, mono->stereo)");
659 orig_init_func
= pa_get_init_remap_func();
660 pa_remap_func_init_sse(flags
);
661 init_func
= pa_get_init_remap_func();
662 remap_test_mono_stereo_float(init_func
, orig_init_func
);
664 pa_log_debug("Checking SSE2 remap (s16, mono->stereo)");
665 remap_test_mono_stereo_s16(init_func
, orig_init_func
);
668 #endif /* defined (__i386__) || defined (__amd64__) */
673 /* End remap tests */
675 /* Start mix tests */
677 /* Only ARM NEON has mix tests, so disable the related functions for other
678 * architectures for now to avoid compiler warnings about unused functions. */
679 #if defined (__arm__) && defined (__linux__)
686 static void acquire_mix_streams(pa_mix_info streams
[], unsigned nstreams
) {
689 for (i
= 0; i
< nstreams
; i
++)
690 streams
[i
].ptr
= pa_memblock_acquire_chunk(&streams
[i
].chunk
);
693 static void release_mix_streams(pa_mix_info streams
[], unsigned nstreams
) {
696 for (i
= 0; i
< nstreams
; i
++)
697 pa_memblock_release(streams
[i
].chunk
.memblock
);
700 static void run_mix_test(
701 pa_do_mix_func_t func
,
702 pa_do_mix_func_t orig_func
,
708 PA_DECLARE_ALIGNED(8, int16_t, in0
[SAMPLES
* 4]) = { 0 };
709 PA_DECLARE_ALIGNED(8, int16_t, in1
[SAMPLES
* 4]) = { 0 };
710 PA_DECLARE_ALIGNED(8, int16_t, out
[SAMPLES
* 4]) = { 0 };
711 PA_DECLARE_ALIGNED(8, int16_t, out_ref
[SAMPLES
* 4]) = { 0 };
712 int16_t *samples0
, *samples1
;
713 int16_t *samples
, *samples_ref
;
720 pa_assert(channels
== 1 || channels
== 2 || channels
== 4);
722 /* Force sample alignment as requested */
723 samples0
= in0
+ (8 - align
);
724 samples1
= in1
+ (8 - align
);
725 samples
= out
+ (8 - align
);
726 samples_ref
= out_ref
+ (8 - align
);
727 nsamples
= channels
* (SAMPLES
- (8 - align
));
729 fail_unless((pool
= pa_mempool_new(false, 0)) != NULL
, NULL
);
731 pa_random(samples0
, nsamples
* sizeof(int16_t));
732 c0
.memblock
= pa_memblock_new_fixed(pool
, samples0
, nsamples
* sizeof(int16_t), false);
733 c0
.length
= pa_memblock_get_length(c0
.memblock
);
736 pa_random(samples1
, nsamples
* sizeof(int16_t));
737 c1
.memblock
= pa_memblock_new_fixed(pool
, samples1
, nsamples
* sizeof(int16_t), false);
738 c1
.length
= pa_memblock_get_length(c1
.memblock
);
742 m
[0].volume
.channels
= channels
;
743 for (i
= 0; i
< channels
; i
++) {
744 m
[0].volume
.values
[i
] = PA_VOLUME_NORM
;
745 m
[0].linear
[i
].i
= 0x5555;
749 m
[1].volume
.channels
= channels
;
750 for (i
= 0; i
< channels
; i
++) {
751 m
[1].volume
.values
[i
] = PA_VOLUME_NORM
;
752 m
[1].linear
[i
].i
= 0x6789;
756 acquire_mix_streams(m
, 2);
757 orig_func(m
, 2, channels
, samples_ref
, nsamples
* sizeof(int16_t));
758 release_mix_streams(m
, 2);
760 acquire_mix_streams(m
, 2);
761 func(m
, 2, channels
, samples
, nsamples
* sizeof(int16_t));
762 release_mix_streams(m
, 2);
764 for (i
= 0; i
< nsamples
; i
++) {
765 if (samples
[i
] != samples_ref
[i
]) {
766 pa_log_debug("Correctness test failed: align=%d, channels=%d", align
, channels
);
767 pa_log_debug("%d: %hd != %04hd (%hd + %hd)\n",
769 samples
[i
], samples_ref
[i
],
770 samples0
[i
], samples1
[i
]);
777 pa_log_debug("Testing %d-channel mixing performance with %d sample alignment", channels
, align
);
779 PA_RUNTIME_TEST_RUN_START("func", TIMES
, TIMES2
) {
780 acquire_mix_streams(m
, 2);
781 func(m
, 2, channels
, samples
, nsamples
* sizeof(int16_t));
782 release_mix_streams(m
, 2);
783 } PA_RUNTIME_TEST_RUN_STOP
785 PA_RUNTIME_TEST_RUN_START("orig", TIMES
, TIMES2
) {
786 acquire_mix_streams(m
, 2);
787 orig_func(m
, 2, channels
, samples_ref
, nsamples
* sizeof(int16_t));
788 release_mix_streams(m
, 2);
789 } PA_RUNTIME_TEST_RUN_STOP
792 pa_memblock_unref(c0
.memblock
);
793 pa_memblock_unref(c1
.memblock
);
795 pa_mempool_free(pool
);
797 #endif /* HAVE_NEON */
798 #endif /* defined (__arm__) && defined (__linux__) */
800 #if defined (__arm__) && defined (__linux__)
802 START_TEST (mix_neon_test
) {
803 pa_do_mix_func_t orig_func
, neon_func
;
804 pa_cpu_arm_flag_t flags
= 0;
806 pa_cpu_get_arm_flags(&flags
);
808 if (!(flags
& PA_CPU_ARM_NEON
)) {
809 pa_log_info("NEON not supported. Skipping");
813 orig_func
= pa_get_mix_func(PA_SAMPLE_S16NE
);
814 pa_mix_func_init_neon(flags
);
815 neon_func
= pa_get_mix_func(PA_SAMPLE_S16NE
);
817 pa_log_debug("Checking NEON mix");
818 run_mix_test(neon_func
, orig_func
, 7, 2, true, true);
821 #endif /* HAVE_NEON */
822 #endif /* defined (__arm__) && defined (__linux__) */
825 int main(int argc
, char *argv
[]) {
831 if (!getenv("MAKE_CHECK"))
832 pa_log_set_level(PA_LOG_DEBUG
);
834 s
= suite_create("CPU");
837 tc
= tcase_create("svolume");
838 #if defined (__i386__) || defined (__amd64__)
839 tcase_add_test(tc
, svolume_mmx_test
);
840 tcase_add_test(tc
, svolume_sse_test
);
842 #if defined (__arm__) && defined (__linux__)
843 tcase_add_test(tc
, svolume_arm_test
);
845 tcase_add_test(tc
, svolume_orc_test
);
846 tcase_set_timeout(tc
, 120);
847 suite_add_tcase(s
, tc
);
849 /* Conversion tests */
850 tc
= tcase_create("sconv");
851 #if defined (__i386__) || defined (__amd64__)
852 tcase_add_test(tc
, sconv_sse2_test
);
853 tcase_add_test(tc
, sconv_sse_test
);
855 #if defined (__arm__) && defined (__linux__)
857 tcase_add_test(tc
, sconv_neon_test
);
860 tcase_set_timeout(tc
, 120);
861 suite_add_tcase(s
, tc
);
864 tc
= tcase_create("remap");
865 #if defined (__i386__) || defined (__amd64__)
866 tcase_add_test(tc
, remap_mmx_test
);
867 tcase_add_test(tc
, remap_sse2_test
);
869 tcase_set_timeout(tc
, 120);
870 suite_add_tcase(s
, tc
);
872 tc
= tcase_create("mix");
873 #if defined (__arm__) && defined (__linux__)
875 tcase_add_test(tc
, mix_neon_test
);
878 tcase_set_timeout(tc
, 120);
879 suite_add_tcase(s
, tc
);
881 sr
= srunner_create(s
);
882 srunner_run_all(sr
, CK_NORMAL
);
883 failed
= srunner_ntests_failed(sr
);
886 return (failed
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;