From a44bea0b6a770d4cc2d51b6958c535f74e6dc351 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jun 2020 08:00:00 +0200 Subject: [PATCH] tests: check cpu flags Use the support plugin to load the CPU detection API and check for the right CPU flags before running the test. Fixes #246 --- spa/plugins/audioconvert/benchmark-fmt-ops.c | 64 ++++++++++---- spa/plugins/audioconvert/benchmark-resample.c | 72 ++++++++------- spa/plugins/audioconvert/test-fmt-ops.c | 33 +++++-- spa/plugins/audioconvert/test-helper.h | 87 +++++++++++++++++++ 4 files changed, 202 insertions(+), 54 deletions(-) create mode 100644 spa/plugins/audioconvert/test-helper.h diff --git a/spa/plugins/audioconvert/benchmark-fmt-ops.c b/spa/plugins/audioconvert/benchmark-fmt-ops.c index 693ae7b27..887919193 100644 --- a/spa/plugins/audioconvert/benchmark-fmt-ops.c +++ b/spa/plugins/audioconvert/benchmark-fmt-ops.c @@ -29,8 +29,11 @@ #include #include +#include "test-helper.h" #include "fmt-ops.h" +static uint32_t cpu_flags; + typedef void (*convert_func_t) (struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_samples); @@ -140,13 +143,17 @@ static void test_f32_s16(void) run_test("test_f32_s16", "c", true, true, conv_f32_to_s16_c); run_test("test_f32d_s16", "c", false, true, conv_f32d_to_s16_c); #if defined (HAVE_SSE2) - run_test("test_f32d_s16", "sse2", false, true, conv_f32d_to_s16_sse2); - run_testc("test_f32d_s16_2", "sse2", false, true, conv_f32d_to_s16_2_sse2, 2); + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_f32d_s16", "sse2", false, true, conv_f32d_to_s16_sse2); + run_testc("test_f32d_s16_2", "sse2", false, true, conv_f32d_to_s16_2_sse2, 2); + } #endif #if defined (HAVE_AVX2) - run_test("test_f32d_s16", "avx2", false, true, conv_f32d_to_s16_avx2); - run_testc("test_f32d_s16_2", "avx2", false, true, conv_f32d_to_s16_2_avx2, 2); - run_testc("test_f32d_s16_4", "avx2", false, true, conv_f32d_to_s16_4_avx2, 4); + if (cpu_flags & SPA_CPU_FLAG_AVX2) { + run_test("test_f32d_s16", "avx2", false, true, conv_f32d_to_s16_avx2); + run_testc("test_f32d_s16_2", "avx2", false, true, conv_f32d_to_s16_2_avx2, 2); + run_testc("test_f32d_s16_4", "avx2", false, true, conv_f32d_to_s16_4_avx2, 4); + } #endif run_test("test_f32_s16d", "c", true, false, conv_f32_to_s16d_c); run_test("test_f32d_s16d", "c", false, false, conv_f32d_to_s16d_c); @@ -158,12 +165,16 @@ static void test_s16_f32(void) run_test("test_s16d_f32", "c", false, true, conv_s16d_to_f32_c); run_test("test_s16_f32d", "c", true, false, conv_s16_to_f32d_c); #if defined (HAVE_SSE2) - run_test("test_s16_f32d", "sse2", true, false, conv_s16_to_f32d_sse2); - run_testc("test_s16_f32d_2", "sse2", true, false, conv_s16_to_f32d_2_sse2, 2); + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_s16_f32d", "sse2", true, false, conv_s16_to_f32d_sse2); + run_testc("test_s16_f32d_2", "sse2", true, false, conv_s16_to_f32d_2_sse2, 2); + } #endif #if defined (HAVE_AVX2) - run_test("test_s16_f32d", "avx2", true, false, conv_s16_to_f32d_avx2); - run_testc("test_s16_f32d_2", "avx2", true, false, conv_s16_to_f32d_2_avx2, 2); + if (cpu_flags & SPA_CPU_FLAG_AVX2) { + run_test("test_s16_f32d", "avx2", true, false, conv_s16_to_f32d_avx2); + run_testc("test_s16_f32d_2", "avx2", true, false, conv_s16_to_f32d_2_avx2, 2); + } #endif run_test("test_s16d_f32d", "c", false, false, conv_s16d_to_f32d_c); } @@ -173,10 +184,14 @@ static void test_f32_s32(void) run_test("test_f32_s32", "c", true, true, conv_f32_to_s32_c); run_test("test_f32d_s32", "c", false, true, conv_f32d_to_s32_c); #if defined (HAVE_SSE2) - run_test("test_f32d_s32", "sse2", false, true, conv_f32d_to_s32_sse2); + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_f32d_s32", "sse2", false, true, conv_f32d_to_s32_sse2); + } #endif #if defined (HAVE_AVX2) - run_test("test_f32d_s32", "avx2", false, true, conv_f32d_to_s32_avx2); + if (cpu_flags & SPA_CPU_FLAG_AVX2) { + run_test("test_f32d_s32", "avx2", false, true, conv_f32d_to_s32_avx2); + } #endif run_test("test_f32_s32d", "c", true, false, conv_f32_to_s32d_c); run_test("test_f32d_s32d", "c", false, false, conv_f32d_to_s32d_c); @@ -187,10 +202,14 @@ static void test_s32_f32(void) run_test("test_s32_f32", "c", true, true, conv_s32_to_f32_c); run_test("test_s32d_f32", "c", false, true, conv_s32d_to_f32_c); #if defined (HAVE_SSE2) - run_test("test_s32_f32d", "sse2", true, false, conv_s32_to_f32d_sse2); + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_s32_f32d", "sse2", true, false, conv_s32_to_f32d_sse2); + } #endif #if defined (HAVE_AVX2) - run_test("test_s32_f32d", "avx2", true, false, conv_s32_to_f32d_avx2); + if (cpu_flags & SPA_CPU_FLAG_AVX2) { + run_test("test_s32_f32d", "avx2", true, false, conv_s32_to_f32d_avx2); + } #endif run_test("test_s32_f32d", "c", true, false, conv_s32_to_f32d_c); run_test("test_s32d_f32d", "c", false, false, conv_s32d_to_f32d_c); @@ -210,16 +229,24 @@ static void test_s24_f32(void) run_test("test_s24d_f32", "c", false, true, conv_s24d_to_f32_c); run_test("test_s24_f32d", "c", true, false, conv_s24_to_f32d_c); #if defined (HAVE_SSE2) - run_test("test_s24_f32d", "sse2", true, false, conv_s24_to_f32d_sse2); + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_s24_f32d", "sse2", true, false, conv_s24_to_f32d_sse2); + } #endif #if defined (HAVE_AVX2) - run_test("test_s24_f32d", "avx2", true, false, conv_s24_to_f32d_avx2); + if (cpu_flags & SPA_CPU_FLAG_AVX2) { + run_test("test_s24_f32d", "avx2", true, false, conv_s24_to_f32d_avx2); + } #endif #if defined (HAVE_SSSE3) - run_test("test_s24_f32d", "ssse3", true, false, conv_s24_to_f32d_ssse3); + if (cpu_flags & SPA_CPU_FLAG_SSSE3) { + run_test("test_s24_f32d", "ssse3", true, false, conv_s24_to_f32d_ssse3); + } #endif #if defined (HAVE_SSE41) - run_test("test_s24_f32d", "sse41", true, false, conv_s24_to_f32d_sse41); + if (cpu_flags & SPA_CPU_FLAG_SSE41) { + run_test("test_s24_f32d", "sse41", true, false, conv_s24_to_f32d_sse41); + } #endif run_test("test_s24d_f32d", "c", false, false, conv_s24d_to_f32d_c); } @@ -271,6 +298,9 @@ int main(int argc, char *argv[]) { uint32_t i; + cpu_flags = get_cpu_flags(); + printf("got get CPU flags %d\n", cpu_flags); + test_f32_u8(); test_u8_f32(); test_f32_s16(); diff --git a/spa/plugins/audioconvert/benchmark-resample.c b/spa/plugins/audioconvert/benchmark-resample.c index 38eb218f9..975b1e20f 100644 --- a/spa/plugins/audioconvert/benchmark-resample.c +++ b/spa/plugins/audioconvert/benchmark-resample.c @@ -29,6 +29,7 @@ #include #include +#include "test-helper.h" #include "resample.h" #define MAX_SAMPLES 4096 @@ -36,6 +37,8 @@ #define MAX_COUNT 200 +static uint32_t cpu_flags; + struct stats { uint32_t in_rate; uint32_t out_rate; @@ -127,6 +130,9 @@ int main(int argc, char *argv[]) struct resample r; uint32_t i; + cpu_flags = get_cpu_flags(); + printf("got get CPU flags %d\n", cpu_flags); + for (i = 0; i < SPA_N_ELEMENTS(in_rates); i++) { spa_zero(r); r.channels = 2; @@ -139,42 +145,48 @@ int main(int argc, char *argv[]) resample_free(&r); } #if defined (HAVE_SSE) - for (i = 0; i < SPA_N_ELEMENTS(in_rates); i++) { - spa_zero(r); - r.channels = 2; - r.cpu_flags = SPA_CPU_FLAG_SSE; - r.i_rate = in_rates[i]; - r.o_rate = out_rates[i]; - r.quality = RESAMPLE_DEFAULT_QUALITY; - resample_native_init(&r); - run_test("native", "sse", &r); - resample_free(&r); + if (cpu_flags & SPA_CPU_FLAG_SSE) { + for (i = 0; i < SPA_N_ELEMENTS(in_rates); i++) { + spa_zero(r); + r.channels = 2; + r.cpu_flags = SPA_CPU_FLAG_SSE; + r.i_rate = in_rates[i]; + r.o_rate = out_rates[i]; + r.quality = RESAMPLE_DEFAULT_QUALITY; + resample_native_init(&r); + run_test("native", "sse", &r); + resample_free(&r); + } } #endif #if defined (HAVE_SSSE3) - for (i = 0; i < SPA_N_ELEMENTS(in_rates); i++) { - spa_zero(r); - r.channels = 2; - r.cpu_flags = SPA_CPU_FLAG_SSSE3 | SPA_CPU_FLAG_SLOW_UNALIGNED; - r.i_rate = in_rates[i]; - r.o_rate = out_rates[i]; - r.quality = RESAMPLE_DEFAULT_QUALITY; - resample_native_init(&r); - run_test("native", "ssse3", &r); - resample_free(&r); + if (cpu_flags & SPA_CPU_FLAG_SSSE3) { + for (i = 0; i < SPA_N_ELEMENTS(in_rates); i++) { + spa_zero(r); + r.channels = 2; + r.cpu_flags = SPA_CPU_FLAG_SSSE3 | SPA_CPU_FLAG_SLOW_UNALIGNED; + r.i_rate = in_rates[i]; + r.o_rate = out_rates[i]; + r.quality = RESAMPLE_DEFAULT_QUALITY; + resample_native_init(&r); + run_test("native", "ssse3", &r); + resample_free(&r); + } } #endif #if defined (HAVE_AVX) && defined(HAVE_FMA) - for (i = 0; i < SPA_N_ELEMENTS(in_rates); i++) { - spa_zero(r); - r.channels = 2; - r.cpu_flags = SPA_CPU_FLAG_AVX | SPA_CPU_FLAG_FMA3; - r.i_rate = in_rates[i]; - r.o_rate = out_rates[i]; - r.quality = RESAMPLE_DEFAULT_QUALITY; - resample_native_init(&r); - run_test("native", "avx", &r); - resample_free(&r); + if (SPA_FLAG_IS_SET(cpu_flags, SPA_CPU_FLAG_AVX | SPA_CPU_FLAG_FMA3)) { + for (i = 0; i < SPA_N_ELEMENTS(in_rates); i++) { + spa_zero(r); + r.channels = 2; + r.cpu_flags = SPA_CPU_FLAG_AVX | SPA_CPU_FLAG_FMA3; + r.i_rate = in_rates[i]; + r.o_rate = out_rates[i]; + r.quality = RESAMPLE_DEFAULT_QUALITY; + resample_native_init(&r); + run_test("native", "avx", &r); + resample_free(&r); + } } #endif diff --git a/spa/plugins/audioconvert/test-fmt-ops.c b/spa/plugins/audioconvert/test-fmt-ops.c index 0cc03a109..507f01976 100644 --- a/spa/plugins/audioconvert/test-fmt-ops.c +++ b/spa/plugins/audioconvert/test-fmt-ops.c @@ -31,11 +31,14 @@ #include +#include "test-helper.h" #include "fmt-ops.c" #define N_SAMPLES 253 #define N_CHANNELS 11 +static uint32_t cpu_flags; + static uint8_t samp_in[N_SAMPLES * 4]; static uint8_t samp_out[N_SAMPLES * 4]; static uint8_t temp_in[N_SAMPLES * N_CHANNELS * 4]; @@ -161,8 +164,10 @@ static void test_f32_s16(void) run_test("test_f32d_s16d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), false, false, conv_f32d_to_s16d_c); #if defined(HAVE_SSE2) - run_test("test_f32d_s16_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_f32d_s16_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), false, true, conv_f32d_to_s16_sse2); + } #endif } @@ -180,8 +185,10 @@ static void test_s16_f32(void) run_test("test_s16d_f32d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), false, false, conv_s16d_to_f32d_c); #if defined(HAVE_SSE2) - run_test("test_s16_f32d_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_s16_f32d_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), true, false, conv_s16_to_f32d_sse2); + } #endif } @@ -200,8 +207,10 @@ static void test_f32_s32(void) run_test("test_f32d_s32d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), false, false, conv_f32d_to_s32d_c); #if defined(HAVE_SSE2) - run_test("test_f32d_s32_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_f32d_s32_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), false, true, conv_f32d_to_s32_sse2); + } #endif } @@ -219,8 +228,10 @@ static void test_s32_f32(void) run_test("test_s32d_f32d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), false, false, conv_s32d_to_f32d_c); #if defined(HAVE_SSE2) - run_test("test_s32_f32d_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_s32_f32d_sse2", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), true, false, conv_s32_to_f32d_sse2); + } #endif } @@ -265,16 +276,22 @@ static void test_s24_f32(void) run_test("test_s24d_f32d", in, 3, out, sizeof(out[0]), SPA_N_ELEMENTS(out), false, false, conv_s24d_to_f32d_c); #if defined(HAVE_SSE2) - run_test("test_s24_f32d_sse2", in, 3, out, sizeof(out[0]), SPA_N_ELEMENTS(out), + if (cpu_flags & SPA_CPU_FLAG_SSE2) { + run_test("test_s24_f32d_sse2", in, 3, out, sizeof(out[0]), SPA_N_ELEMENTS(out), true, false, conv_s24_to_f32d_sse2); + } #endif #if defined(HAVE_SSSE3) - run_test("test_s24_f32d_ssse3", in, 3, out, sizeof(out[0]), SPA_N_ELEMENTS(out), + if (cpu_flags & SPA_CPU_FLAG_SSSE3) { + run_test("test_s24_f32d_ssse3", in, 3, out, sizeof(out[0]), SPA_N_ELEMENTS(out), true, false, conv_s24_to_f32d_ssse3); + } #endif #if defined(HAVE_SSE41) - run_test("test_s24_f32d_sse41", in, 3, out, sizeof(out[0]), SPA_N_ELEMENTS(out), + if (cpu_flags & SPA_CPU_FLAG_SSE41) { + run_test("test_s24_f32d_sse41", in, 3, out, sizeof(out[0]), SPA_N_ELEMENTS(out), true, false, conv_s24_to_f32d_sse41); + } #endif } @@ -311,6 +328,8 @@ static void test_s24_32_f32(void) int main(int argc, char *argv[]) { + cpu_flags = get_cpu_flags(); + printf("got get CPU flags %d\n", cpu_flags); test_f32_u8(); test_u8_f32(); diff --git a/spa/plugins/audioconvert/test-helper.h b/spa/plugins/audioconvert/test-helper.h new file mode 100644 index 000000000..8f7b7206f --- /dev/null +++ b/spa/plugins/audioconvert/test-helper.h @@ -0,0 +1,87 @@ +#include + +#include +#include +#include +#include +#include + +static inline const struct spa_handle_factory *get_factory(spa_handle_factory_enum_func_t enum_func, + const char *name, uint32_t version) +{ + uint32_t i; + int res; + const struct spa_handle_factory *factory; + + for (i = 0;;) { + if ((res = enum_func(&factory, &i)) <= 0) { + if (res < 0) + errno = -res; + break; + } + if (factory->version >= version && + !strcmp(factory->name, name)) + return factory; + } + return NULL; +} + +static inline struct spa_handle *load_handle(const struct spa_support *support, + uint32_t n_support, const char *lib, const char *name) +{ + int res, len; + void *hnd; + spa_handle_factory_enum_func_t enum_func; + const struct spa_handle_factory *factory; + struct spa_handle *handle; + const char *str; + char *path; + + if ((str = getenv("SPA_PLUGIN_DIR")) == NULL) + str = "."; + + len = strlen(str) + strlen(lib) + 2; + path = alloca(len); + snprintf(path, len, "%s/%s", str, lib); + + if ((hnd = dlopen(path, RTLD_NOW)) == NULL) { + fprintf(stderr, "can't load %s: %s\n", lib, dlerror()); + errno = -ENOENT; + return NULL; + } + if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) { + fprintf(stderr, "can't find enum function\n"); + errno = -ENOENT; + return NULL; + } + + if ((factory = get_factory(enum_func, name, SPA_VERSION_HANDLE_FACTORY)) == NULL) { + fprintf(stderr, "can't find factory\n"); + errno = -ENOENT; + return NULL; + } + handle = calloc(1, spa_handle_factory_get_size(factory, NULL)); + if ((res = spa_handle_factory_init(factory, handle, + NULL, support, n_support)) < 0) { + fprintf(stderr, "can't make factory instance: %d\n", res); + errno = -res; + return NULL; + } + return handle; +} + +static inline uint32_t get_cpu_flags(void) +{ + struct spa_handle *handle; + void *iface; + int res; + + handle = load_handle(NULL, 0, "support/libspa-support.so", SPA_NAME_SUPPORT_CPU); + if (handle == NULL) + return 0; + if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_CPU, &iface)) < 0) { + fprintf(stderr, "can't get CPU interface %s\n", spa_strerror(res)); + return 0; + } + return spa_cpu_get_flags((struct spa_cpu*)iface); +}