• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
run_volume_test(pa_do_volume_func_t func,pa_do_volume_func_t orig_func,int align,int channels,bool correct,bool perf)39 static 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__)
START_TEST(svolume_mmx_test)104 START_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 }
129 END_TEST
130 
START_TEST(svolume_sse_test)131 START_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 }
156 END_TEST
157 #endif /* defined (__i386__) || defined (__amd64__) */
158 
159 #if defined (__arm__) && defined (__linux__)
START_TEST(svolume_arm_test)160 START_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 }
185 END_TEST
186 #endif /* defined (__arm__) && defined (__linux__) */
187 
START_TEST(svolume_orc_test)188 START_TEST (svolume_orc_test) {
189     pa_do_volume_func_t orig_func, orc_func;
190     pa_cpu_info cpu_info;
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 }
216 END_TEST
217 
main(int argc,char * argv[])218 int 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