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/sample-util.h>
37 /* Common defines for svolume tests */
44 static void run_volume_test(pa_do_volume_func_t func
, pa_do_volume_func_t orig_func
) {
45 int16_t samples
[SAMPLES
];
46 int16_t samples_ref
[SAMPLES
];
47 int16_t samples_orig
[SAMPLES
];
48 int32_t volumes
[CHANNELS
+ PADDING
];
50 pa_usec_t start
, stop
;
52 pa_usec_t min
= INT_MAX
, max
= 0;
53 double s1
= 0, s2
= 0;
56 pa_random(samples
, sizeof(samples
));
57 memcpy(samples_ref
, samples
, sizeof(samples
));
58 memcpy(samples_orig
, samples
, sizeof(samples
));
60 for (i
= 0; i
< CHANNELS
; i
++)
61 volumes
[i
] = PA_CLAMP_VOLUME((pa_volume_t
)(rand() >> 15));
62 for (padding
= 0; padding
< PADDING
; padding
++, i
++)
63 volumes
[i
] = volumes
[padding
];
65 orig_func(samples_ref
, volumes
, CHANNELS
, sizeof(samples
));
66 func(samples
, volumes
, CHANNELS
, sizeof(samples
));
67 for (i
= 0; i
< SAMPLES
; i
++) {
68 if (samples
[i
] != samples_ref
[i
]) {
69 printf("%d: %04x != %04x (%04x * %08x)\n", i
, samples
[i
], samples_ref
[i
],
70 samples_orig
[i
], volumes
[i
% CHANNELS
]);
75 for (k
= 0; k
< TIMES2
; k
++) {
76 start
= pa_rtclock_now();
77 for (j
= 0; j
< TIMES
; j
++) {
78 memcpy(samples
, samples_orig
, sizeof(samples
));
79 func(samples
, volumes
, CHANNELS
, sizeof(samples
));
81 stop
= pa_rtclock_now();
83 if (min
> (stop
- start
)) min
= stop
- start
;
84 if (max
< (stop
- start
)) max
= stop
- start
;
86 s2
+= (stop
- start
) * (stop
- start
);
88 pa_log_debug("func: %llu usec (min = %llu, max = %llu, stddev = %g).", (long long unsigned int)s1
,
89 (long long unsigned int)min
, (long long unsigned int)max
, sqrt(TIMES2
* s2
- s1
* s1
) / TIMES2
);
91 min
= INT_MAX
; max
= 0;
93 for (k
= 0; k
< TIMES2
; k
++) {
94 start
= pa_rtclock_now();
95 for (j
= 0; j
< TIMES
; j
++) {
96 memcpy(samples_ref
, samples_orig
, sizeof(samples
));
97 orig_func(samples_ref
, volumes
, CHANNELS
, sizeof(samples
));
99 stop
= pa_rtclock_now();
101 if (min
> (stop
- start
)) min
= stop
- start
;
102 if (max
< (stop
- start
)) max
= stop
- start
;
104 s2
+= (stop
- start
) * (stop
- start
);
106 pa_log_debug("orig: %llu usec (min = %llu, max = %llu, stddev = %g).", (long long unsigned int)s1
,
107 (long long unsigned int)min
, (long long unsigned int)max
, sqrt(TIMES2
* s2
- s1
* s1
) / TIMES2
);
109 fail_unless(memcmp(samples_ref
, samples
, sizeof(samples
)) == 0);
112 #if defined (__i386__) || defined (__amd64__)
113 START_TEST (svolume_mmx_test
) {
114 pa_do_volume_func_t orig_func
, mmx_func
;
115 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 run_volume_test(mmx_func
, orig_func
);
133 START_TEST (svolume_sse_test
) {
134 pa_do_volume_func_t orig_func
, sse_func
;
135 pa_cpu_x86_flag_t flags
= 0;
137 pa_cpu_get_x86_flags(&flags
);
139 if (!(flags
& PA_CPU_X86_SSE2
)) {
140 pa_log_info("SSE2 not supported. Skipping");
144 orig_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
145 pa_volume_func_init_sse(flags
);
146 sse_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
148 pa_log_debug("Checking SSE2 svolume");
149 run_volume_test(sse_func
, orig_func
);
152 #endif /* defined (__i386__) || defined (__amd64__) */
154 #if defined (__arm__) && defined (__linux__)
155 START_TEST (svolume_arm_test
) {
156 pa_do_volume_func_t orig_func
, arm_func
;
157 pa_cpu_arm_flag_t flags
= 0;
159 pa_cpu_get_arm_flags(&flags
);
161 if (!(flags
& PA_CPU_ARM_V6
)) {
162 pa_log_info("ARMv6 instructions not supported. Skipping");
166 orig_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
167 pa_volume_func_init_arm(flags
);
168 arm_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
170 pa_log_debug("Checking ARM svolume");
171 run_volume_test(arm_func
, orig_func
);
174 #endif /* defined (__arm__) && defined (__linux__) */
176 START_TEST (svolume_orc_test
) {
177 pa_do_volume_func_t orig_func
, orc_func
;
178 pa_cpu_info cpu_info
;
180 #if defined (__i386__) || defined (__amd64__)
182 cpu_info
.cpu_type
= PA_CPU_X86
;
183 pa_cpu_get_x86_flags(&cpu_info
.flags
.x86
);
186 orig_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
188 if (!pa_cpu_init_orc(cpu_info
)) {
189 pa_log_info("Orc not supported. Skipping");
193 orc_func
= pa_get_volume_func(PA_SAMPLE_S16NE
);
195 pa_log_debug("Checking Orc svolume");
196 run_volume_test(orc_func
, orig_func
);
205 /* End svolume tests */
207 /* Start conversion tests */
208 #if defined (__i386__) || defined (__amd64__)
209 START_TEST (sconv_sse_test
) {
213 int16_t samples
[SAMPLES
];
214 int16_t samples_ref
[SAMPLES
];
215 float floats
[SAMPLES
];
217 pa_usec_t start
, stop
;
218 pa_convert_func_t orig_func
, sse_func
;
219 pa_cpu_x86_flag_t flags
= 0;
221 pa_cpu_get_x86_flags(&flags
);
223 if (!(flags
& PA_CPU_X86_SSE2
)) {
224 pa_log_info("SSE2 not supported. Skipping");
228 pa_log_debug("Checking SSE sconv (%zd)\n", sizeof(samples
));
230 memset(samples_ref
, 0, sizeof(samples_ref
));
231 memset(samples
, 0, sizeof(samples
));
233 for (i
= 0; i
< SAMPLES
; i
++) {
234 floats
[i
] = 2.1f
* (rand()/(float) RAND_MAX
- 0.5f
);
237 orig_func
= pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE
);
238 pa_convert_func_init_sse(flags
);
239 sse_func
= pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE
);
241 orig_func(SAMPLES
, floats
, samples_ref
);
242 sse_func(SAMPLES
, floats
, samples
);
244 for (i
= 0; i
< SAMPLES
; i
++) {
245 if (samples
[i
] != samples_ref
[i
]) {
246 printf ("%d: %04x != %04x (%f)\n", i
, samples
[i
], samples_ref
[i
],
252 start
= pa_rtclock_now();
253 for (i
= 0; i
< TIMES
; i
++) {
254 sse_func(SAMPLES
, floats
, samples
);
256 stop
= pa_rtclock_now();
257 pa_log_debug("SSE: %llu usec.", (long long unsigned int)(stop
- start
));
259 start
= pa_rtclock_now();
260 for (i
= 0; i
< TIMES
; i
++) {
261 orig_func(SAMPLES
, floats
, samples_ref
);
263 stop
= pa_rtclock_now();
264 pa_log_debug("ref: %llu usec.", (long long unsigned int)(stop
- start
));
270 #endif /* defined (__i386__) || defined (__amd64__) */
271 /* End conversion tests */
273 int main(int argc
, char *argv
[]) {
279 if (!getenv("MAKE_CHECK"))
280 pa_log_set_level(PA_LOG_DEBUG
);
282 s
= suite_create("CPU");
285 tc
= tcase_create("svolume");
286 #if defined (__i386__) || defined (__amd64__)
287 tcase_add_test(tc
, svolume_mmx_test
);
288 tcase_add_test(tc
, svolume_sse_test
);
290 #if defined (__arm__) && defined (__linux__)
291 tcase_add_test(tc
, svolume_arm_test
);
293 tcase_add_test(tc
, svolume_orc_test
);
294 suite_add_tcase(s
, tc
);
296 /* Converstion tests */
297 tc
= tcase_create("sconv");
298 #if defined (__i386__) || defined (__amd64__)
299 tcase_add_test(tc
, sconv_sse_test
);
301 suite_add_tcase(s
, tc
);
303 sr
= srunner_create(s
);
304 srunner_run_all(sr
, CK_NORMAL
);
305 failed
= srunner_ntests_failed(sr
);
308 return (failed
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;