]>
Commit | Line | Data |
---|---|---|
cb2f668d | 1 | /* Measure math inline functions. |
04277e02 | 2 | Copyright (C) 2015-2019 Free Software Foundation, Inc. |
cb2f668d WD |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #define SIZE 1024 | |
20 | #define TEST_MAIN | |
21 | #define TEST_NAME "math-inlines" | |
22 | #define TEST_FUNCTION test_main () | |
23 | #include "bench-timing.h" | |
24 | #include "json-lib.h" | |
25 | #include "bench-util.h" | |
26 | ||
27 | #include <stdlib.h> | |
28 | #include <math.h> | |
29 | #include <stdint.h> | |
30 | ||
31 | #define BOOLTEST(func) \ | |
32 | static int __attribute__((noinline)) \ | |
33 | func ## _f (double d, int i) \ | |
34 | { \ | |
35 | if (func (d)) \ | |
36 | return (int) d + i; \ | |
37 | else \ | |
38 | return 5; \ | |
39 | } \ | |
40 | static int \ | |
41 | func ## _t (volatile double *p, size_t n, size_t iters) \ | |
42 | { \ | |
43 | int i, j; \ | |
44 | int res = 0; \ | |
45 | for (j = 0; j < iters; j++) \ | |
46 | for (i = 0; i < n; i++) \ | |
47 | if (func ## _f (p[i] * 2.0, i) != 0) \ | |
48 | res += 5; \ | |
49 | return res; \ | |
50 | } | |
51 | ||
52 | #define VALUETEST(func) \ | |
53 | static int __attribute__((noinline)) \ | |
54 | func ## _f (double d) \ | |
55 | { \ | |
56 | return func (d); \ | |
57 | } \ | |
58 | static int \ | |
59 | func ## _t (volatile double *p, size_t n, size_t iters) \ | |
60 | { \ | |
61 | int i, j; \ | |
62 | int res = 0; \ | |
63 | for (j = 0; j < iters; j++) \ | |
64 | for (i = 0; i < n; i++) \ | |
65 | res += func ## _f (p[i] * 2.0); \ | |
66 | return res; \ | |
67 | } | |
68 | ||
69 | typedef union | |
70 | { | |
71 | double value; | |
72 | uint64_t word; | |
73 | } ieee_double_shape_type; | |
74 | ||
75 | #define EXTRACT_WORDS64(i,d) \ | |
76 | do { \ | |
77 | ieee_double_shape_type gh_u; \ | |
78 | gh_u.value = (d); \ | |
79 | (i) = gh_u.word; \ | |
80 | } while (0) | |
81 | ||
82 | /* Inlines similar to existing math_private.h versions. */ | |
83 | ||
84 | static __always_inline int | |
85 | __isnan_inl (double d) | |
86 | { | |
87 | uint64_t di; | |
88 | EXTRACT_WORDS64 (di, d); | |
89 | return (di & 0x7fffffffffffffffull) > 0x7ff0000000000000ull; | |
90 | } | |
91 | ||
92 | static __always_inline int | |
93 | __isinf_ns2 (double d) | |
94 | { | |
95 | uint64_t di; | |
96 | EXTRACT_WORDS64 (di, d); | |
97 | return (di & 0x7fffffffffffffffull) == 0x7ff0000000000000ull; | |
98 | } | |
99 | ||
100 | static __always_inline int | |
101 | __finite_inl (double d) | |
102 | { | |
103 | uint64_t di; | |
104 | EXTRACT_WORDS64 (di, d); | |
105 | return (di & 0x7fffffffffffffffull) < 0x7ff0000000000000ull; | |
106 | } | |
107 | ||
108 | #define __isnormal_inl(X) (__fpclassify (X) == FP_NORMAL) | |
109 | ||
110 | /* Inlines for the builtin functions. */ | |
111 | ||
112 | #define __isnan_builtin(X) __builtin_isnan (X) | |
113 | #define __isinf_ns_builtin(X) __builtin_isinf (X) | |
114 | #define __isinf_builtin(X) __builtin_isinf_sign (X) | |
115 | #define __isfinite_builtin(X) __builtin_isfinite (X) | |
116 | #define __isnormal_builtin(X) __builtin_isnormal (X) | |
117 | #define __fpclassify_builtin(X) __builtin_fpclassify (FP_NAN, FP_INFINITE, \ | |
118 | FP_NORMAL, FP_SUBNORMAL, FP_ZERO, (X)) | |
119 | ||
120 | static double __attribute ((noinline)) | |
121 | kernel_standard (double x, double y, int z) | |
122 | { | |
123 | return x * y + z; | |
124 | } | |
125 | ||
126 | volatile double rem1 = 2.5; | |
127 | ||
128 | static __always_inline double | |
129 | remainder_test1 (double x) | |
130 | { | |
131 | double y = rem1; | |
132 | if (((__builtin_expect (y == 0.0, 0) && !__isnan_inl (x)) | |
133 | || (__builtin_expect (__isinf_ns2 (x), 0) && !__isnan_inl (y)))) | |
134 | return kernel_standard (x, y, 10); | |
135 | ||
136 | return remainder (x, y); | |
137 | } | |
138 | ||
139 | static __always_inline double | |
140 | remainder_test2 (double x) | |
141 | { | |
142 | double y = rem1; | |
143 | if (((__builtin_expect (y == 0.0, 0) && !__builtin_isnan (x)) | |
144 | || (__builtin_expect (__builtin_isinf (x), 0) && !__builtin_isnan (y)))) | |
145 | return kernel_standard (x, y, 10); | |
146 | ||
147 | return remainder (x, y); | |
148 | } | |
149 | ||
150 | /* Create test functions for each possibility. */ | |
151 | ||
152 | BOOLTEST (__isnan) | |
153 | BOOLTEST (__isnan_inl) | |
154 | BOOLTEST (__isnan_builtin) | |
155 | BOOLTEST (isnan) | |
156 | ||
157 | BOOLTEST (__isinf) | |
158 | BOOLTEST (__isinf_builtin) | |
159 | BOOLTEST (__isinf_ns2) | |
160 | BOOLTEST (__isinf_ns_builtin) | |
161 | BOOLTEST (isinf) | |
162 | ||
163 | BOOLTEST (__finite) | |
164 | BOOLTEST (__finite_inl) | |
165 | BOOLTEST (__isfinite_builtin) | |
166 | BOOLTEST (isfinite) | |
167 | ||
168 | BOOLTEST (__isnormal_inl) | |
169 | BOOLTEST (__isnormal_builtin) | |
170 | BOOLTEST (isnormal) | |
171 | ||
172 | VALUETEST (__fpclassify) | |
173 | VALUETEST (__fpclassify_builtin) | |
174 | VALUETEST (fpclassify) | |
175 | ||
176 | VALUETEST (remainder_test1) | |
177 | VALUETEST (remainder_test2) | |
178 | ||
179 | typedef int (*proto_t) (volatile double *p, size_t n, size_t iters); | |
180 | ||
181 | typedef struct | |
182 | { | |
183 | const char *name; | |
184 | proto_t fn; | |
185 | } impl_t; | |
186 | ||
187 | #define IMPL(name) { #name, name ## _t } | |
188 | ||
189 | static impl_t test_list[] = | |
190 | { | |
191 | IMPL (__isnan), | |
192 | IMPL (__isnan_inl), | |
193 | IMPL (__isnan_builtin), | |
194 | IMPL (isnan), | |
195 | ||
196 | IMPL (__isinf), | |
197 | IMPL (__isinf_ns2), | |
198 | IMPL (__isinf_ns_builtin), | |
199 | IMPL (__isinf_builtin), | |
200 | IMPL (isinf), | |
201 | ||
202 | IMPL (__finite), | |
203 | IMPL (__finite_inl), | |
204 | IMPL (__isfinite_builtin), | |
205 | IMPL (isfinite), | |
206 | ||
207 | IMPL (__isnormal_inl), | |
208 | IMPL (__isnormal_builtin), | |
209 | IMPL (isnormal), | |
210 | ||
211 | IMPL (__fpclassify), | |
212 | IMPL (__fpclassify_builtin), | |
213 | IMPL (fpclassify), | |
214 | ||
215 | IMPL (remainder_test1), | |
216 | IMPL (remainder_test2) | |
217 | }; | |
218 | ||
219 | static void | |
220 | do_one_test (json_ctx_t *json_ctx, proto_t test_fn, volatile double *arr, | |
221 | size_t len, const char *testname) | |
222 | { | |
223 | size_t iters = 500; | |
224 | timing_t start, stop, cur; | |
225 | ||
226 | json_attr_object_begin (json_ctx, testname); | |
227 | ||
228 | TIMING_NOW (start); | |
229 | test_fn (arr, len, iters); | |
230 | TIMING_NOW (stop); | |
231 | TIMING_DIFF (cur, start, stop); | |
232 | ||
233 | json_attr_double (json_ctx, "duration", cur); | |
234 | json_attr_double (json_ctx, "iterations", iters); | |
235 | json_attr_double (json_ctx, "mean", cur / iters); | |
236 | json_attr_object_end (json_ctx); | |
237 | } | |
238 | ||
239 | static volatile double arr1[SIZE]; | |
240 | static volatile double arr2[SIZE]; | |
241 | ||
242 | int | |
243 | test_main (void) | |
244 | { | |
245 | json_ctx_t json_ctx; | |
246 | size_t i; | |
247 | ||
248 | bench_start (); | |
249 | ||
250 | json_init (&json_ctx, 2, stdout); | |
251 | json_attr_object_begin (&json_ctx, TEST_NAME); | |
252 | ||
253 | /* Create 2 test arrays, one with 10% zeroes, 10% negative values, | |
254 | 79% positive values and 1% infinity/NaN. The other contains | |
255 | 50% inf, 50% NaN. This relies on rand behaving correctly. */ | |
256 | ||
257 | for (i = 0; i < SIZE; i++) | |
258 | { | |
259 | int x = rand () & 255; | |
260 | arr1[i] = (x < 25) ? 0.0 : ((x < 50) ? -1 : 100); | |
261 | if (x == 255) arr1[i] = __builtin_inf (); | |
262 | if (x == 254) arr1[i] = __builtin_nan ("0"); | |
263 | arr2[i] = (x < 128) ? __builtin_inf () : __builtin_nan ("0"); | |
264 | } | |
265 | ||
266 | for (i = 0; i < sizeof (test_list) / sizeof (test_list[0]); i++) | |
267 | { | |
268 | json_attr_object_begin (&json_ctx, test_list[i].name); | |
269 | do_one_test (&json_ctx, test_list[i].fn, arr2, SIZE, "inf/nan"); | |
270 | json_attr_object_end (&json_ctx); | |
271 | } | |
272 | ||
273 | for (i = 0; i < sizeof (test_list) / sizeof (test_list[0]); i++) | |
274 | { | |
275 | json_attr_object_begin (&json_ctx, test_list[i].name); | |
276 | do_one_test (&json_ctx, test_list[i].fn, arr1, SIZE, "normal"); | |
277 | json_attr_object_end (&json_ctx); | |
278 | } | |
279 | ||
280 | json_attr_object_end (&json_ctx); | |
281 | return 0; | |
282 | } | |
283 | ||
284 | #include "bench-util.c" | |
285 | #include "../test-skeleton.c" |