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

source code of glibc/benchtests/bench-strcmp.c