openat: don’t close (-1)
[gnulib.git] / tests / bench-mcel.c
blob0ec712cacb5c2888ec2e74ec51b5b17356d6a1f2
1 /* Benchmark mcel and some alternatives
2 Copyright 2023-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 #include <config.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <locale.h>
23 #include <uchar.h>
25 #include "bench.h"
26 #include "bench-multibyte.h"
27 #include "mbiter.h"
28 #include "mbiterf.h"
29 #include "mbuiter.h"
30 #include "mbuiterf.h"
31 #include "mcel.h"
33 typedef unsigned long long (*test_function) (char const *, char const *, int);
35 static unsigned long long
36 noop_test (char const *text, char const *text_end, int repeat)
38 unsigned long long sum = 0;
40 for (int count = 0; count < repeat; count++)
42 char const *iter;
43 for (iter = text; iter < text_end; iter++)
44 sum += (uintptr_t) iter;
47 return sum;
50 static unsigned long long
51 single_test (char const *text, char const *text_end, int repeat)
53 unsigned long long sum = 0;
55 for (int count = 0; count < repeat; count++)
56 for (char const *iter = text; iter < text_end; )
58 unsigned char c = *iter++;
59 sum += c;
62 return sum;
65 static unsigned long long
66 mbiter_test (char const *text, char const *text_end, int repeat)
68 unsigned long long sum = 0;
70 size_t text_len = text_end - text;
71 for (int count = 0; count < repeat; count++)
73 mbi_iterator_t iter;
74 for (mbi_init (iter, text, text_len); mbi_avail (iter); )
76 mbchar_t cur = mbi_cur (iter);
77 mbi_advance (iter);
78 sum += cur.wc_valid ? cur.wc : (unsigned char) *mb_ptr (cur) << 16;
82 return sum;
85 static unsigned long long
86 mbiterf_test (char const *text, char const *text_end, int repeat)
88 unsigned long long sum = 0;
90 for (int count = 0; count < repeat; count++)
92 mbif_state_t state;
93 char const *iter;
94 for (mbif_init (state), iter = text; mbif_avail (state, iter, text_end); )
96 mbchar_t cur = mbif_next (state, iter, text_end);
97 iter += mb_len (cur);
98 sum += cur.wc_valid ? cur.wc : (unsigned char) *mb_ptr (cur) << 16;
102 return sum;
105 static unsigned long long
106 mbuiter_test (char const *text, char const *text_end, int repeat)
108 unsigned long long sum = 0;
110 for (int count = 0; count < repeat; count++)
111 for (char const *t = text; t < text_end; t++)
113 mbui_iterator_t iter;
114 for (mbui_init (iter, t); mbui_avail (iter); )
116 mbchar_t cur = mbui_cur (iter);
117 mbui_advance (iter);
118 sum += cur.wc_valid ? cur.wc : (unsigned char) *mb_ptr (cur) << 16;
120 t = mbui_cur_ptr (iter);
123 return sum;
126 static unsigned long long
127 mbuiterf_test (char const *text, _GL_UNUSED char const *text_end, int repeat)
129 unsigned long long sum = 0;
131 for (int count = 0; count < repeat; count++)
132 for (char const *t = text; t < text_end; t++)
134 mbuif_state_t state;
135 char const *iter;
136 for (mbuif_init (state), iter = t; mbuif_avail (state, iter); )
138 mbchar_t cur = mbuif_next (state, iter);
139 iter += mb_len (cur);
140 sum += cur.wc_valid ? cur.wc : (unsigned char) *mb_ptr (cur) << 16;
142 t = iter;
145 return sum;
148 static unsigned long long
149 mcel_test (char const *text, char const *text_end, int repeat)
151 unsigned long long sum = 0;
153 for (int count = 0; count < repeat; count++)
154 for (char const *iter = text; iter < text_end; )
156 mcel_t g = mcel_scan (iter, text_end);
157 iter += g.len;
158 sum += g.ch | (g.err << 16);
161 return sum;
164 static unsigned long long
165 mcuel_test (char const *text, char const *text_end, int repeat)
167 unsigned long long sum = 0;
169 for (int count = 0; count < repeat; count++)
170 for (char const *t = text; t < text_end; t++)
172 char const *iter = t;
173 while (*iter)
175 mcel_t g = mcel_scanz (iter);
176 iter += g.len;
177 sum += g.ch | (g.err << 16);
179 t = iter;
182 return sum;
185 static unsigned long long
186 do_1_test (test_function test, char const *text,
187 char const *text_end, int repeat, struct timings_state *ts)
189 timing_start (ts);
190 unsigned long long sum = test (text, text_end, repeat);
191 timing_end (ts);
192 return sum;
195 static void
196 do_test (char test, int repeat, char const *locale_name,
197 char const *text, size_t text_len)
199 if (setlocale (LC_ALL, locale_name) != NULL)
201 char const *text_end = text + text_len;
203 static struct
205 char const *name;
206 test_function fn;
207 struct timings_state ts;
208 unsigned long long volatile sum;
209 } testdesc[] = {
210 { "noop", noop_test },
211 { "single", single_test },
212 { "mbiter", mbiter_test },
213 { "mbiterf", mbiterf_test },
214 { "mbuiter", mbuiter_test },
215 { "mbuiterf", mbuiterf_test },
216 { "mcel", mcel_test },
217 { "mcuel", mcuel_test },
219 int ntestdesc = sizeof testdesc / sizeof *testdesc;
220 for (int i = 0; i < ntestdesc; i++)
221 testdesc[i].sum =
222 do_1_test (testdesc[i].fn, text, text_end, repeat, &testdesc[i].ts);
224 setlocale (LC_ALL, "C");
226 static bool header_printed;
227 if (!header_printed)
229 printf (" ");
230 for (int i = 0; i < ntestdesc; i++)
231 printf (" %8s", testdesc[i].name);
232 printf ("\n");
233 header_printed = true;
236 printf ("%c", test);
237 for (int i = 0; i < ntestdesc; i++)
239 double user_usec = testdesc[i].ts.user_usec;
240 double sys_usec = testdesc[i].ts.sys_usec;
241 printf (" %8.3f", (user_usec + sys_usec) / 1e6);
243 printf ("\n");
245 else
247 printf ("Skipping test: locale %s not installed.\n", locale_name);
251 /* Performs some or all of the following tests:
252 A - ASCII text, C locale
253 B - ASCII text, UTF-8 locale
254 C - French text, C locale
255 D - French text, ISO-8859-1 locale
256 E - French text, UTF-8 locale
257 F - Greek text, C locale
258 G - Greek text, ISO-8859-7 locale
259 H - Greek text, UTF-8 locale
260 I - Chinese text, UTF-8 locale
261 J - Chinese text, GB18030 locale
262 K - Random bytes, C locale
263 L - Random bytes, UTF-8 locale
264 a - short ASCII text, C locale
265 b - short ASCII text, UTF-8 locale
266 e - short French text, UTF-8 locale
267 h - short Greek text, UTF-8 locale
268 i - short Chinese text, UTF-8 locale
269 Pass the tests to be performed as first argument. */
271 main (int argc, char *argv[])
273 if (argc != 3)
275 fprintf (stderr, "Usage: %s TESTS REPETITIONS\n", argv[0]);
277 fprintf (stderr, "Example: %s ABCDEFGHIJKLabehi 100000\n", argv[0]);
278 exit (1);
281 char const *tests = argv[1];
282 int repeat = atoi (argv[2]);
284 text_init ();
286 /* Execute each test. */
287 size_t i;
288 for (i = 0; i < strlen (tests); i++)
290 char test = tests[i];
292 switch (test)
294 case 'A':
295 do_test (test, repeat, "C", text_latin_ascii,
296 strlen (text_latin_ascii));
297 break;
298 case 'a':
299 do_test (test, repeat, "C", TEXT_LATIN_ASCII_LINE1,
300 strlen (TEXT_LATIN_ASCII_LINE1));
301 break;
302 case 'B':
303 do_test (test, repeat, "en_US.UTF-8", text_latin_ascii,
304 strlen (text_latin_ascii));
305 break;
306 case 'b':
307 do_test (test, repeat, "en_US.UTF-8", TEXT_LATIN_ASCII_LINE1,
308 strlen (TEXT_LATIN_ASCII_LINE1));
309 break;
310 case 'C':
311 do_test (test, repeat, "C", text_french_iso8859,
312 strlen (text_french_iso8859));
313 break;
314 case 'D':
315 do_test (test, repeat, "fr_FR.ISO-8859-1", text_french_iso8859,
316 strlen (text_french_iso8859));
317 break;
318 case 'E':
319 do_test (test, repeat, "en_US.UTF-8", text_french_utf8,
320 strlen (text_french_utf8));
321 break;
322 case 'e':
323 do_test (test, repeat, "en_US.UTF-8", TEXT_FRENCH_UTF8_LINE1,
324 strlen (TEXT_FRENCH_UTF8_LINE1));
325 break;
326 case 'F':
327 do_test (test, repeat, "C", text_greek_iso8859,
328 strlen (text_greek_iso8859));
329 break;
330 case 'G':
331 do_test (test, repeat, "el_GR.ISO-8859-7", text_greek_iso8859,
332 strlen (text_greek_iso8859));
333 break;
334 case 'H':
335 do_test (test, repeat, "en_US.UTF-8", text_greek_utf8,
336 strlen (text_greek_utf8));
337 break;
338 case 'h':
339 do_test (test, repeat, "en_US.UTF-8", TEXT_GREEK_UTF8_LINE1,
340 strlen (TEXT_GREEK_UTF8_LINE1));
341 break;
342 case 'I':
343 do_test (test, repeat, "en_US.UTF-8", text_chinese_utf8,
344 strlen (text_chinese_utf8));
345 break;
346 case 'i':
347 do_test (test, repeat, "en_US.UTF-8", TEXT_CHINESE_UTF8_LINE1,
348 strlen (TEXT_CHINESE_UTF8_LINE1));
349 break;
350 case 'J':
351 do_test (test, repeat, "zh_CN.GB18030", text_chinese_gb18030,
352 strlen (text_chinese_gb18030));
353 break;
354 case 'K':
355 do_test (test, repeat, "C", text_random_bytes,
356 sizeof text_random_bytes - 1);
357 break;
358 case 'L':
359 do_test (test, repeat, "en_US.UTF-8", text_random_bytes,
360 sizeof text_random_bytes - 1);
361 break;
362 default:
363 /* Ignore. */
368 return 0;