]>
Commit | Line | Data |
---|---|---|
97020474 | 1 | /* Measure strcmp and wcscmp functions. |
2b778ceb | 2 | Copyright (C) 2013-2021 Free Software Foundation, Inc. |
97020474 SP |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
97020474 SP |
18 | |
19 | #define TEST_MAIN | |
20 | #ifdef WIDE | |
21 | # define TEST_NAME "wcscmp" | |
22 | #else | |
23 | # define TEST_NAME "strcmp" | |
24 | #endif | |
25 | #include "bench-string.h" | |
26 | ||
27 | #ifdef WIDE | |
97020474 | 28 | # define L(str) L##str |
97020474 | 29 | # define SIMPLE_STRCMP simple_wcscmp |
97020474 | 30 | # define CHARBYTESLOG 2 |
97020474 SP |
31 | # define MIDCHAR 0x7fffffff |
32 | # define LARGECHAR 0xfffffffe | |
97020474 SP |
33 | |
34 | /* Wcscmp uses signed semantics for comparison, not unsigned */ | |
35 | /* Avoid using substraction since possible overflow */ | |
36 | ||
37 | int | |
38 | simple_wcscmp (const wchar_t *s1, const wchar_t *s2) | |
39 | { | |
40 | wchar_t c1, c2; | |
41 | do | |
42 | { | |
43 | c1 = *s1++; | |
44 | c2 = *s2++; | |
45 | if (c2 == L'\0') | |
46 | return c1 - c2; | |
47 | } | |
48 | while (c1 == c2); | |
49 | ||
50 | return c1 < c2 ? -1 : 1; | |
51 | } | |
52 | ||
97020474 SP |
53 | #else |
54 | # include <limits.h> | |
55 | ||
56 | # define L(str) str | |
97020474 | 57 | # define SIMPLE_STRCMP simple_strcmp |
97020474 | 58 | # define CHARBYTESLOG 0 |
97020474 SP |
59 | # define MIDCHAR 0x7f |
60 | # define LARGECHAR 0xfe | |
97020474 SP |
61 | |
62 | /* Strcmp uses unsigned semantics for comparison. */ | |
63 | int | |
64 | simple_strcmp (const char *s1, const char *s2) | |
65 | { | |
66 | int ret; | |
67 | ||
68 | while ((ret = *(unsigned char *) s1 - *(unsigned char*) s2++) == 0 && *s1++); | |
69 | return ret; | |
70 | } | |
71 | ||
97020474 SP |
72 | #endif |
73 | ||
5f1603c3 SP |
74 | # include "json-lib.h" |
75 | ||
97020474 SP |
76 | typedef int (*proto_t) (const CHAR *, const CHAR *); |
77 | ||
97020474 SP |
78 | IMPL (SIMPLE_STRCMP, 1) |
79 | IMPL (STRCMP, 1) | |
80 | ||
81 | static void | |
5f1603c3 | 82 | do_one_test (json_ctx_t *json_ctx, impl_t *impl, |
97020474 SP |
83 | const CHAR *s1, const CHAR *s2, |
84 | int exp_result) | |
85 | { | |
d0645912 | 86 | size_t i, iters = INNER_LOOP_ITERS8; |
44558701 WN |
87 | timing_t start, stop, cur; |
88 | ||
89 | TIMING_NOW (start); | |
90 | for (i = 0; i < iters; ++i) | |
97020474 | 91 | { |
44558701 | 92 | CALL (impl, s1, s2); |
97020474 | 93 | } |
44558701 WN |
94 | TIMING_NOW (stop); |
95 | ||
96 | TIMING_DIFF (cur, start, stop); | |
97 | ||
5f1603c3 | 98 | json_element_double (json_ctx, (double) cur / (double) iters); |
97020474 SP |
99 | } |
100 | ||
101 | static void | |
5f1603c3 SP |
102 | do_test (json_ctx_t *json_ctx, size_t align1, size_t align2, size_t len, int |
103 | max_char, int exp_result) | |
97020474 SP |
104 | { |
105 | size_t i; | |
106 | ||
107 | CHAR *s1, *s2; | |
108 | ||
109 | if (len == 0) | |
110 | return; | |
111 | ||
112 | align1 &= 63; | |
113 | if (align1 + (len + 1) * CHARBYTES >= page_size) | |
114 | return; | |
115 | ||
116 | align2 &= 63; | |
117 | if (align2 + (len + 1) * CHARBYTES >= page_size) | |
118 | return; | |
119 | ||
120 | /* Put them close to the end of page. */ | |
121 | i = align1 + CHARBYTES * (len + 2); | |
122 | s1 = (CHAR *) (buf1 + ((page_size - i) / 16 * 16) + align1); | |
123 | i = align2 + CHARBYTES * (len + 2); | |
124 | s2 = (CHAR *) (buf2 + ((page_size - i) / 16 * 16) + align2); | |
125 | ||
126 | for (i = 0; i < len; i++) | |
127 | s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % max_char; | |
128 | ||
129 | s1[len] = s2[len] = 0; | |
130 | s1[len + 1] = 23; | |
131 | s2[len + 1] = 24 + exp_result; | |
132 | s2[len - 1] -= exp_result; | |
133 | ||
5f1603c3 SP |
134 | json_element_object_begin (json_ctx); |
135 | json_attr_uint (json_ctx, "length", (double) len); | |
136 | json_attr_uint (json_ctx, "align1", (double) align1); | |
137 | json_attr_uint (json_ctx, "align2", (double) align2); | |
138 | json_array_begin (json_ctx, "timings"); | |
97020474 SP |
139 | |
140 | FOR_EACH_IMPL (impl, 0) | |
5f1603c3 | 141 | do_one_test (json_ctx, impl, s1, s2, exp_result); |
97020474 | 142 | |
5f1603c3 SP |
143 | json_array_end (json_ctx); |
144 | json_element_object_end (json_ctx); | |
97020474 SP |
145 | } |
146 | ||
06e95b93 L |
147 | static void |
148 | do_one_test_page_boundary (json_ctx_t *json_ctx, CHAR *s1, CHAR *s2, | |
149 | size_t align1, size_t align2, size_t len, | |
150 | int exp_result) | |
151 | { | |
152 | json_element_object_begin (json_ctx); | |
153 | json_attr_uint (json_ctx, "length", (double) len); | |
154 | json_attr_uint (json_ctx, "align1", (double) align1); | |
155 | json_attr_uint (json_ctx, "align2", (double) align2); | |
156 | json_array_begin (json_ctx, "timings"); | |
157 | FOR_EACH_IMPL (impl, 0) | |
158 | do_one_test (json_ctx, impl, s1, s2, exp_result); | |
159 | json_array_end (json_ctx); | |
160 | json_element_object_end (json_ctx); | |
161 | } | |
162 | ||
163 | static void | |
164 | do_test_page_boundary (json_ctx_t *json_ctx) | |
165 | { | |
166 | /* To trigger bug 25933, we need a size that is equal to the vector | |
167 | length times 4. In the case of AVX2 for Intel, we need 32 * 4. We | |
168 | make this test generic and run it for all architectures as additional | |
169 | boundary testing for such related algorithms. */ | |
170 | size_t size = 32 * 4; | |
171 | size_t len; | |
172 | CHAR *s1 = (CHAR *) (buf1 + (BUF1PAGES - 1) * page_size); | |
173 | CHAR *s2 = (CHAR *) (buf2 + (BUF1PAGES - 1) * page_size); | |
174 | int exp_result; | |
175 | ||
176 | memset (s1, 'a', page_size); | |
177 | memset (s2, 'a', page_size); | |
178 | ||
179 | s1[(page_size / CHARBYTES) - 1] = (CHAR) 0; | |
180 | s2[(page_size / CHARBYTES) - 1] = (CHAR) 0; | |
181 | ||
182 | /* Iterate over a size that is just below where we expect the bug to | |
183 | trigger up to the size we expect will trigger the bug e.g. [99-128]. | |
184 | Likewise iterate the start of two strings between 30 and 31 bytes | |
185 | away from the boundary to simulate alignment changes. */ | |
186 | for (size_t s = 99; s <= size; s++) | |
187 | for (size_t s1a = 30; s1a < 32; s1a++) | |
188 | for (size_t s2a = 30; s2a < 32; s2a++) | |
189 | { | |
190 | size_t align1 = (page_size / CHARBYTES - s) - s1a; | |
191 | size_t align2 = (page_size / CHARBYTES - s) - s2a; | |
192 | CHAR *s1p = s1 + align1; | |
193 | CHAR *s2p = s2 + align2; | |
194 | len = (page_size / CHARBYTES) - 1 - align1; | |
195 | exp_result = SIMPLE_STRCMP (s1p, s2p); | |
196 | do_one_test_page_boundary (json_ctx, s1p, s2p, align1, align2, | |
197 | len, exp_result); | |
198 | } | |
199 | } | |
200 | ||
97020474 SP |
201 | int |
202 | test_main (void) | |
203 | { | |
5f1603c3 | 204 | json_ctx_t json_ctx; |
97020474 SP |
205 | size_t i; |
206 | ||
207 | test_init (); | |
208 | ||
5f1603c3 SP |
209 | json_init (&json_ctx, 0, stdout); |
210 | ||
211 | json_document_begin (&json_ctx); | |
212 | json_attr_string (&json_ctx, "timing_type", TIMING_TYPE); | |
213 | ||
214 | json_attr_object_begin (&json_ctx, "functions"); | |
215 | json_attr_object_begin (&json_ctx, TEST_NAME); | |
216 | json_attr_string (&json_ctx, "bench-variant", "default"); | |
217 | ||
218 | json_array_begin (&json_ctx, "ifuncs"); | |
97020474 | 219 | FOR_EACH_IMPL (impl, 0) |
5f1603c3 SP |
220 | json_element_string (&json_ctx, impl->name); |
221 | json_array_end (&json_ctx); | |
222 | ||
223 | json_array_begin (&json_ctx, "results"); | |
97020474 SP |
224 | |
225 | for (i = 1; i < 32; ++i) | |
226 | { | |
5f1603c3 SP |
227 | do_test (&json_ctx, CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, 0); |
228 | do_test (&json_ctx, CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, 1); | |
229 | do_test (&json_ctx, CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, -1); | |
97020474 SP |
230 | } |
231 | ||
232 | for (i = 1; i < 10 + CHARBYTESLOG; ++i) | |
233 | { | |
5f1603c3 SP |
234 | do_test (&json_ctx, 0, 0, 2 << i, MIDCHAR, 0); |
235 | do_test (&json_ctx, 0, 0, 2 << i, LARGECHAR, 0); | |
236 | do_test (&json_ctx, 0, 0, 2 << i, MIDCHAR, 1); | |
237 | do_test (&json_ctx, 0, 0, 2 << i, LARGECHAR, 1); | |
238 | do_test (&json_ctx, 0, 0, 2 << i, MIDCHAR, -1); | |
239 | do_test (&json_ctx, 0, 0, 2 << i, LARGECHAR, -1); | |
240 | do_test (&json_ctx, 0, CHARBYTES * i, 2 << i, MIDCHAR, 1); | |
241 | do_test (&json_ctx, CHARBYTES * i, CHARBYTES * (i + 1), 2 << i, LARGECHAR, 1); | |
97020474 SP |
242 | } |
243 | ||
244 | for (i = 1; i < 8; ++i) | |
245 | { | |
5f1603c3 SP |
246 | do_test (&json_ctx, CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, 0); |
247 | do_test (&json_ctx, 2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, 0); | |
248 | do_test (&json_ctx, CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, 1); | |
249 | do_test (&json_ctx, 2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, 1); | |
250 | do_test (&json_ctx, CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, -1); | |
251 | do_test (&json_ctx, 2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, -1); | |
97020474 SP |
252 | } |
253 | ||
06e95b93 L |
254 | do_test_page_boundary (&json_ctx); |
255 | ||
5f1603c3 SP |
256 | json_array_end (&json_ctx); |
257 | json_attr_object_end (&json_ctx); | |
258 | json_attr_object_end (&json_ctx); | |
259 | json_document_end (&json_ctx); | |
260 | ||
97020474 SP |
261 | return ret; |
262 | } | |
263 | ||
b598e134 | 264 | #include <support/test-driver.c> |