1/*** 2 This file is part of PulseAudio. 3 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. 8 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. 13 14 You should have received a copy of the GNU Lesser General Public License 15 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 16***/ 17 18#ifdef HAVE_CONFIG_H 19#include <config.h> 20#endif 21 22#include <check.h> 23 24#include <pulsecore/cpu-arm.h> 25#include <pulsecore/cpu-x86.h> 26#include <pulsecore/cpu-orc.h> 27#include <pulsecore/random.h> 28#include <pulsecore/macro.h> 29#include <pulsecore/sample-util.h> 30 31#include "runtime-test-util.h" 32 33/* Common defines for svolume tests */ 34#define SAMPLES 1028 35#define TIMES 1000 36#define TIMES2 100 37#define PADDING 16 38 39static void run_volume_test( 40 pa_do_volume_func_t func, 41 pa_do_volume_func_t orig_func, 42 int align, 43 int channels, 44 bool correct, 45 bool perf) { 46 47 PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES]) = { 0 }; 48 PA_DECLARE_ALIGNED(8, int16_t, s_ref[SAMPLES]) = { 0 }; 49 PA_DECLARE_ALIGNED(8, int16_t, s_orig[SAMPLES]) = { 0 }; 50 int32_t volumes[channels + PADDING]; 51 int16_t *samples, *samples_ref, *samples_orig; 52 int i, padding, nsamples, size; 53 54 /* Force sample alignment as requested */ 55 samples = s + (8 - align); 56 samples_ref = s_ref + (8 - align); 57 samples_orig = s_orig + (8 - align); 58 nsamples = SAMPLES - (8 - align); 59 if (nsamples % channels) 60 nsamples -= nsamples % channels; 61 size = nsamples * sizeof(int16_t); 62 63 pa_random(samples, size); 64 memcpy(samples_ref, samples, size); 65 memcpy(samples_orig, samples, size); 66 67 for (i = 0; i < channels; i++) 68 volumes[i] = PA_CLAMP_VOLUME((pa_volume_t)(rand() >> 15)); 69 for (padding = 0; padding < PADDING; padding++, i++) 70 volumes[i] = volumes[padding]; 71 72 if (correct) { 73 orig_func(samples_ref, volumes, channels, size); 74 func(samples, volumes, channels, size); 75 76 for (i = 0; i < nsamples; i++) { 77 if (samples[i] != samples_ref[i]) { 78 pa_log_debug("Correctness test failed: align=%d, channels=%d", align, channels); 79 pa_log_debug("%d: %04hx != %04hx (%04hx * %08x)", i, samples[i], samples_ref[i], 80 samples_orig[i], volumes[i % channels]); 81 ck_abort(); 82 } 83 } 84 } 85 86 if (perf) { 87 pa_log_debug("Testing svolume %dch performance with %d sample alignment", channels, align); 88 89 PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) { 90 memcpy(samples, samples_orig, size); 91 func(samples, volumes, channels, size); 92 } PA_RUNTIME_TEST_RUN_STOP 93 94 PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) { 95 memcpy(samples_ref, samples_orig, size); 96 orig_func(samples_ref, volumes, channels, size); 97 } PA_RUNTIME_TEST_RUN_STOP 98 99 fail_unless(memcmp(samples_ref, samples, size) == 0); 100 } 101} 102 103#if defined (__i386__) || defined (__amd64__) 104START_TEST (svolume_mmx_test) { 105 pa_do_volume_func_t orig_func, mmx_func; 106 pa_cpu_x86_flag_t flags = 0; 107 int i, j; 108 109 pa_cpu_get_x86_flags(&flags); 110 111 if (!((flags & PA_CPU_X86_MMX) && (flags & PA_CPU_X86_CMOV))) { 112 pa_log_info("MMX/CMOV not supported. Skipping"); 113 return; 114 } 115 116 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE); 117 pa_volume_func_init_mmx(flags); 118 mmx_func = pa_get_volume_func(PA_SAMPLE_S16NE); 119 120 pa_log_debug("Checking MMX svolume"); 121 for (i = 1; i <= 3; i++) { 122 for (j = 0; j < 7; j++) 123 run_volume_test(mmx_func, orig_func, j, i, true, false); 124 } 125 run_volume_test(mmx_func, orig_func, 7, 1, true, true); 126 run_volume_test(mmx_func, orig_func, 7, 2, true, true); 127 run_volume_test(mmx_func, orig_func, 7, 3, true, true); 128} 129END_TEST 130 131START_TEST (svolume_sse_test) { 132 pa_do_volume_func_t orig_func, sse_func; 133 pa_cpu_x86_flag_t flags = 0; 134 int i, j; 135 136 pa_cpu_get_x86_flags(&flags); 137 138 if (!(flags & PA_CPU_X86_SSE2)) { 139 pa_log_info("SSE2 not supported. Skipping"); 140 return; 141 } 142 143 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE); 144 pa_volume_func_init_sse(flags); 145 sse_func = pa_get_volume_func(PA_SAMPLE_S16NE); 146 147 pa_log_debug("Checking SSE2 svolume"); 148 for (i = 1; i <= 3; i++) { 149 for (j = 0; j < 7; j++) 150 run_volume_test(sse_func, orig_func, j, i, true, false); 151 } 152 run_volume_test(sse_func, orig_func, 7, 1, true, true); 153 run_volume_test(sse_func, orig_func, 7, 2, true, true); 154 run_volume_test(sse_func, orig_func, 7, 3, true, true); 155} 156END_TEST 157#endif /* defined (__i386__) || defined (__amd64__) */ 158 159#if defined (__arm__) && defined (__linux__) 160START_TEST (svolume_arm_test) { 161 pa_do_volume_func_t orig_func, arm_func; 162 pa_cpu_arm_flag_t flags = 0; 163 int i, j; 164 165 pa_cpu_get_arm_flags(&flags); 166 167 if (!(flags & PA_CPU_ARM_V6)) { 168 pa_log_info("ARMv6 instructions not supported. Skipping"); 169 return; 170 } 171 172 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE); 173 pa_volume_func_init_arm(flags); 174 arm_func = pa_get_volume_func(PA_SAMPLE_S16NE); 175 176 pa_log_debug("Checking ARM svolume"); 177 for (i = 1; i <= 3; i++) { 178 for (j = 0; j < 7; j++) 179 run_volume_test(arm_func, orig_func, j, i, true, false); 180 } 181 run_volume_test(arm_func, orig_func, 7, 1, true, true); 182 run_volume_test(arm_func, orig_func, 7, 2, true, true); 183 run_volume_test(arm_func, orig_func, 7, 3, true, true); 184} 185END_TEST 186#endif /* defined (__arm__) && defined (__linux__) */ 187 188START_TEST (svolume_orc_test) { 189 pa_do_volume_func_t orig_func, orc_func; 190 pa_cpu_info cpu_info = { PA_CPU_UNDEFINED, {}, false }; 191 int i, j; 192 193#if defined (__i386__) || defined (__amd64__) 194 pa_zero(cpu_info); 195 cpu_info.cpu_type = PA_CPU_X86; 196 pa_cpu_get_x86_flags(&cpu_info.flags.x86); 197#endif 198 199 orig_func = pa_get_volume_func(PA_SAMPLE_S16NE); 200 201 if (!pa_cpu_init_orc(cpu_info)) { 202 pa_log_info("Orc not supported. Skipping"); 203 return; 204 } 205 206 orc_func = pa_get_volume_func(PA_SAMPLE_S16NE); 207 208 pa_log_debug("Checking Orc svolume"); 209 for (i = 1; i <= 2; i++) { 210 for (j = 0; j < 7; j++) 211 run_volume_test(orc_func, orig_func, j, i, true, false); 212 } 213 run_volume_test(orc_func, orig_func, 7, 1, true, true); 214 run_volume_test(orc_func, orig_func, 7, 2, true, true); 215} 216END_TEST 217 218int main(int argc, char *argv[]) { 219 int failed = 0; 220 Suite *s; 221 TCase *tc; 222 SRunner *sr; 223 224 if (!getenv("MAKE_CHECK")) 225 pa_log_set_level(PA_LOG_DEBUG); 226 227 s = suite_create("CPU"); 228 229 tc = tcase_create("svolume"); 230#if defined (__i386__) || defined (__amd64__) 231 tcase_add_test(tc, svolume_mmx_test); 232 tcase_add_test(tc, svolume_sse_test); 233#endif 234#if defined (__arm__) && defined (__linux__) 235 tcase_add_test(tc, svolume_arm_test); 236#endif 237 tcase_add_test(tc, svolume_orc_test); 238 tcase_set_timeout(tc, 120); 239 suite_add_tcase(s, tc); 240 241 sr = srunner_create(s); 242 srunner_run_all(sr, CK_NORMAL); 243 failed = srunner_ntests_failed(sr); 244 srunner_free(sr); 245 246 return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 247} 248