mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-02 09:01:46 -05:00
On cpu-volume-test, cpu_info is initialized only on i386/amd64 systems, and otherwise passed on to pa_cpu_init_orc() uninitialized. If one was unlucky enough, they could end up with cpu_info.cpu_type == PA_CPU_X86 on a non-x86 system, and use and test the Orc codepath without that being functional, and thus with the test failing. This has been observed in the wild on the ppc64el Debian buildds. See Debian bug #982740 for more context. Define cpu_info here in the same way as in other tests. Signed-off-by: Faidon Liambotis <paravoid@debian.org> Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/511>
247 lines
7.4 KiB
C
247 lines
7.4 KiB
C
/***
|
|
This file is part of PulseAudio.
|
|
|
|
PulseAudio is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published
|
|
by the Free Software Foundation; either version 2.1 of the License,
|
|
or (at your option) any later version.
|
|
|
|
PulseAudio is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
|
***/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <check.h>
|
|
|
|
#include <pulsecore/cpu-arm.h>
|
|
#include <pulsecore/cpu-x86.h>
|
|
#include <pulsecore/cpu-orc.h>
|
|
#include <pulsecore/random.h>
|
|
#include <pulsecore/macro.h>
|
|
#include <pulsecore/sample-util.h>
|
|
|
|
#include "runtime-test-util.h"
|
|
|
|
/* Common defines for svolume tests */
|
|
#define SAMPLES 1028
|
|
#define TIMES 1000
|
|
#define TIMES2 100
|
|
#define PADDING 16
|
|
|
|
static void run_volume_test(
|
|
pa_do_volume_func_t func,
|
|
pa_do_volume_func_t orig_func,
|
|
int align,
|
|
int channels,
|
|
bool correct,
|
|
bool perf) {
|
|
|
|
PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES]) = { 0 };
|
|
PA_DECLARE_ALIGNED(8, int16_t, s_ref[SAMPLES]) = { 0 };
|
|
PA_DECLARE_ALIGNED(8, int16_t, s_orig[SAMPLES]) = { 0 };
|
|
int32_t volumes[channels + PADDING];
|
|
int16_t *samples, *samples_ref, *samples_orig;
|
|
int i, padding, nsamples, size;
|
|
|
|
/* Force sample alignment as requested */
|
|
samples = s + (8 - align);
|
|
samples_ref = s_ref + (8 - align);
|
|
samples_orig = s_orig + (8 - align);
|
|
nsamples = SAMPLES - (8 - align);
|
|
if (nsamples % channels)
|
|
nsamples -= nsamples % channels;
|
|
size = nsamples * sizeof(int16_t);
|
|
|
|
pa_random(samples, size);
|
|
memcpy(samples_ref, samples, size);
|
|
memcpy(samples_orig, samples, size);
|
|
|
|
for (i = 0; i < channels; i++)
|
|
volumes[i] = PA_CLAMP_VOLUME((pa_volume_t)(rand() >> 15));
|
|
for (padding = 0; padding < PADDING; padding++, i++)
|
|
volumes[i] = volumes[padding];
|
|
|
|
if (correct) {
|
|
orig_func(samples_ref, volumes, channels, size);
|
|
func(samples, volumes, channels, size);
|
|
|
|
for (i = 0; i < nsamples; i++) {
|
|
if (samples[i] != samples_ref[i]) {
|
|
pa_log_debug("Correctness test failed: align=%d, channels=%d", align, channels);
|
|
pa_log_debug("%d: %04hx != %04hx (%04hx * %08x)", i, samples[i], samples_ref[i],
|
|
samples_orig[i], volumes[i % channels]);
|
|
ck_abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (perf) {
|
|
pa_log_debug("Testing svolume %dch performance with %d sample alignment", channels, align);
|
|
|
|
PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
|
|
memcpy(samples, samples_orig, size);
|
|
func(samples, volumes, channels, size);
|
|
} PA_RUNTIME_TEST_RUN_STOP
|
|
|
|
PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
|
|
memcpy(samples_ref, samples_orig, size);
|
|
orig_func(samples_ref, volumes, channels, size);
|
|
} PA_RUNTIME_TEST_RUN_STOP
|
|
|
|
fail_unless(memcmp(samples_ref, samples, size) == 0);
|
|
}
|
|
}
|
|
|
|
#if defined (__i386__) || defined (__amd64__)
|
|
START_TEST (svolume_mmx_test) {
|
|
pa_do_volume_func_t orig_func, mmx_func;
|
|
pa_cpu_x86_flag_t flags = 0;
|
|
int i, j;
|
|
|
|
pa_cpu_get_x86_flags(&flags);
|
|
|
|
if (!((flags & PA_CPU_X86_MMX) && (flags & PA_CPU_X86_CMOV))) {
|
|
pa_log_info("MMX/CMOV not supported. Skipping");
|
|
return;
|
|
}
|
|
|
|
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
pa_volume_func_init_mmx(flags);
|
|
mmx_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
|
|
pa_log_debug("Checking MMX svolume");
|
|
for (i = 1; i <= 3; i++) {
|
|
for (j = 0; j < 7; j++)
|
|
run_volume_test(mmx_func, orig_func, j, i, true, false);
|
|
}
|
|
run_volume_test(mmx_func, orig_func, 7, 1, true, true);
|
|
run_volume_test(mmx_func, orig_func, 7, 2, true, true);
|
|
run_volume_test(mmx_func, orig_func, 7, 3, true, true);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST (svolume_sse_test) {
|
|
pa_do_volume_func_t orig_func, sse_func;
|
|
pa_cpu_x86_flag_t flags = 0;
|
|
int i, j;
|
|
|
|
pa_cpu_get_x86_flags(&flags);
|
|
|
|
if (!(flags & PA_CPU_X86_SSE2)) {
|
|
pa_log_info("SSE2 not supported. Skipping");
|
|
return;
|
|
}
|
|
|
|
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
pa_volume_func_init_sse(flags);
|
|
sse_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
|
|
pa_log_debug("Checking SSE2 svolume");
|
|
for (i = 1; i <= 3; i++) {
|
|
for (j = 0; j < 7; j++)
|
|
run_volume_test(sse_func, orig_func, j, i, true, false);
|
|
}
|
|
run_volume_test(sse_func, orig_func, 7, 1, true, true);
|
|
run_volume_test(sse_func, orig_func, 7, 2, true, true);
|
|
run_volume_test(sse_func, orig_func, 7, 3, true, true);
|
|
}
|
|
END_TEST
|
|
#endif /* defined (__i386__) || defined (__amd64__) */
|
|
|
|
#if defined (__arm__) && defined (__linux__)
|
|
START_TEST (svolume_arm_test) {
|
|
pa_do_volume_func_t orig_func, arm_func;
|
|
pa_cpu_arm_flag_t flags = 0;
|
|
int i, j;
|
|
|
|
pa_cpu_get_arm_flags(&flags);
|
|
|
|
if (!(flags & PA_CPU_ARM_V6)) {
|
|
pa_log_info("ARMv6 instructions not supported. Skipping");
|
|
return;
|
|
}
|
|
|
|
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
pa_volume_func_init_arm(flags);
|
|
arm_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
|
|
pa_log_debug("Checking ARM svolume");
|
|
for (i = 1; i <= 3; i++) {
|
|
for (j = 0; j < 7; j++)
|
|
run_volume_test(arm_func, orig_func, j, i, true, false);
|
|
}
|
|
run_volume_test(arm_func, orig_func, 7, 1, true, true);
|
|
run_volume_test(arm_func, orig_func, 7, 2, true, true);
|
|
run_volume_test(arm_func, orig_func, 7, 3, true, true);
|
|
}
|
|
END_TEST
|
|
#endif /* defined (__arm__) && defined (__linux__) */
|
|
|
|
START_TEST (svolume_orc_test) {
|
|
pa_do_volume_func_t orig_func, orc_func;
|
|
pa_cpu_info cpu_info = { PA_CPU_UNDEFINED, {}, false };
|
|
int i, j;
|
|
|
|
#if defined (__i386__) || defined (__amd64__)
|
|
pa_zero(cpu_info);
|
|
cpu_info.cpu_type = PA_CPU_X86;
|
|
pa_cpu_get_x86_flags(&cpu_info.flags.x86);
|
|
#endif
|
|
|
|
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
|
|
if (!pa_cpu_init_orc(cpu_info)) {
|
|
pa_log_info("Orc not supported. Skipping");
|
|
return;
|
|
}
|
|
|
|
orc_func = pa_get_volume_func(PA_SAMPLE_S16NE);
|
|
|
|
pa_log_debug("Checking Orc svolume");
|
|
for (i = 1; i <= 2; i++) {
|
|
for (j = 0; j < 7; j++)
|
|
run_volume_test(orc_func, orig_func, j, i, true, false);
|
|
}
|
|
run_volume_test(orc_func, orig_func, 7, 1, true, true);
|
|
run_volume_test(orc_func, orig_func, 7, 2, true, true);
|
|
}
|
|
END_TEST
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int failed = 0;
|
|
Suite *s;
|
|
TCase *tc;
|
|
SRunner *sr;
|
|
|
|
if (!getenv("MAKE_CHECK"))
|
|
pa_log_set_level(PA_LOG_DEBUG);
|
|
|
|
s = suite_create("CPU");
|
|
|
|
tc = tcase_create("svolume");
|
|
#if defined (__i386__) || defined (__amd64__)
|
|
tcase_add_test(tc, svolume_mmx_test);
|
|
tcase_add_test(tc, svolume_sse_test);
|
|
#endif
|
|
#if defined (__arm__) && defined (__linux__)
|
|
tcase_add_test(tc, svolume_arm_test);
|
|
#endif
|
|
tcase_add_test(tc, svolume_orc_test);
|
|
tcase_set_timeout(tc, 120);
|
|
suite_add_tcase(s, tc);
|
|
|
|
sr = srunner_create(s);
|
|
srunner_run_all(sr, CK_NORMAL);
|
|
failed = srunner_ntests_failed(sr);
|
|
srunner_free(sr);
|
|
|
|
return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|