libstdc++: Implement P2905R2 "Runtime format strings" for C++20
[official-gcc.git] / libbacktrace / zstdtest.c
blobb9552ab1b8823c85570c23c93c6513b2d33abe36
1 /* ztest.c -- Test for libbacktrace zstd code.
2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 (2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
17 (3) The name of the author may not be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
33 #include "config.h"
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
43 #ifdef HAVE_ZSTD
44 #include <zstd.h>
45 #endif
47 #include "backtrace.h"
48 #include "backtrace-supported.h"
50 #include "internal.h"
51 #include "testlib.h"
53 #ifndef HAVE_CLOCK_GETTIME
55 typedef int xclockid_t;
57 static int
58 xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED,
59 struct timespec *ts ATTRIBUTE_UNUSED)
61 errno = EINVAL;
62 return -1;
65 #define clockid_t xclockid_t
66 #define clock_gettime xclock_gettime
67 #undef CLOCK_REALTIME
68 #define CLOCK_REALTIME 0
70 #endif /* !defined(HAVE_CLOCK_GETTIME) */
72 #ifdef CLOCK_PROCESS_CPUTIME_ID
73 #define ZSTD_CLOCK_GETTIME_ARG CLOCK_PROCESS_CPUTIME_ID
74 #else
75 #define ZSTD_CLOCK_GETTIME_ARG CLOCK_REALTIME
76 #endif
78 /* Some tests for the local zstd inflation code. */
80 struct zstd_test
82 const char *name;
83 const char *uncompressed;
84 size_t uncompressed_len;
85 const char *compressed;
86 size_t compressed_len;
89 /* Error callback. */
91 static void
92 error_callback_compress (void *vdata ATTRIBUTE_UNUSED, const char *msg,
93 int errnum)
95 fprintf (stderr, "%s", msg);
96 if (errnum > 0)
97 fprintf (stderr, ": %s", strerror (errnum));
98 fprintf (stderr, "\n");
99 exit (EXIT_FAILURE);
102 static const struct zstd_test tests[] =
105 "empty",
108 "\x28\xb5\x2f\xfd\x24\x00\x01\x00\x00\x99\xe9\xd8\x51",
112 "hello",
113 "hello, world\n",
115 ("\x28\xb5\x2f\xfd\x24\x0d\x69\x00\x00\x68\x65\x6c\x6c\x6f\x2c\x20"
116 "\x77\x6f\x72\x6c\x64\x0a\x4c\x1f\xf9\xf1"),
120 "goodbye",
121 "goodbye, world",
123 ("\x28\xb5\x2f\xfd\x24\x0e\x71\x00\x00\x67\x6f\x6f\x64\x62\x79\x65"
124 "\x2c\x20\x77\x6f\x72\x6c\x64\x61\x7b\x4b\x83"),
128 "ranges",
129 ("\xcc\x11\x00\x00\x00\x00\x00\x00\xd5\x13\x00\x00\x00\x00\x00\x00"
130 "\x1c\x14\x00\x00\x00\x00\x00\x00\x72\x14\x00\x00\x00\x00\x00\x00"
131 "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00"
132 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
133 "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00"
134 "\x0c\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00"
135 "\x29\x14\x00\x00\x00\x00\x00\x00\x4e\x14\x00\x00\x00\x00\x00\x00"
136 "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00"
137 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
138 "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00"
139 "\x67\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00"
140 "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00"
141 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
142 "\x5f\x0b\x00\x00\x00\x00\x00\x00\x6c\x0b\x00\x00\x00\x00\x00\x00"
143 "\x7d\x0b\x00\x00\x00\x00\x00\x00\x7e\x0c\x00\x00\x00\x00\x00\x00"
144 "\x38\x0f\x00\x00\x00\x00\x00\x00\x5c\x0f\x00\x00\x00\x00\x00\x00"
145 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
146 "\x83\x0c\x00\x00\x00\x00\x00\x00\xfa\x0c\x00\x00\x00\x00\x00\x00"
147 "\xfd\x0d\x00\x00\x00\x00\x00\x00\xef\x0e\x00\x00\x00\x00\x00\x00"
148 "\x14\x0f\x00\x00\x00\x00\x00\x00\x38\x0f\x00\x00\x00\x00\x00\x00"
149 "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00"
150 "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00"
151 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
152 "\xfd\x0d\x00\x00\x00\x00\x00\x00\xd8\x0e\x00\x00\x00\x00\x00\x00"
153 "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00"
154 "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00"
155 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
156 "\xfa\x0c\x00\x00\x00\x00\x00\x00\xea\x0d\x00\x00\x00\x00\x00\x00"
157 "\xef\x0e\x00\x00\x00\x00\x00\x00\x14\x0f\x00\x00\x00\x00\x00\x00"
158 "\x5c\x0f\x00\x00\x00\x00\x00\x00\x9f\x0f\x00\x00\x00\x00\x00\x00"
159 "\xac\x0f\x00\x00\x00\x00\x00\x00\xdb\x0f\x00\x00\x00\x00\x00\x00"
160 "\xff\x0f\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00"
161 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
162 "\x60\x11\x00\x00\x00\x00\x00\x00\xd1\x16\x00\x00\x00\x00\x00\x00"
163 "\x40\x0b\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00"
164 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
165 "\x7a\x00\x00\x00\x00\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x00\x00"
166 "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00"
167 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
168 "\x7a\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00"
169 "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00"
170 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
171 672,
172 ("\x28\xb5\x2f\xfd\x64\xa0\x01\x2d\x05\x00\xc4\x04\xcc\x11\x00\xd5"
173 "\x13\x00\x1c\x14\x00\x72\x9d\xd5\xfb\x12\x00\x09\x0c\x13\xcb\x13"
174 "\x29\x4e\x67\x5f\x0b\x6c\x0b\x7d\x0b\x7e\x0c\x38\x0f\x5c\x0f\x83"
175 "\x0c\xfa\x0c\xfd\x0d\xef\x0e\x14\x38\x9f\x0f\xac\x0f\xdb\x0f\xff"
176 "\x0f\xd8\x9f\xac\xdb\xff\xea\x5c\x2c\x10\x60\xd1\x16\x40\x0b\x7a"
177 "\x00\xb6\x00\x9f\x01\xa7\x01\xa9\x36\x20\xa0\x83\x14\x34\x63\x4a"
178 "\x21\x70\x8c\x07\x46\x03\x4e\x10\x62\x3c\x06\x4e\xc8\x8c\xb0\x32"
179 "\x2a\x59\xad\xb2\xf1\x02\x82\x7c\x33\xcb\x92\x6f\x32\x4f\x9b\xb0"
180 "\xa2\x30\xf0\xc0\x06\x1e\x98\x99\x2c\x06\x1e\xd8\xc0\x03\x56\xd8"
181 "\xc0\x03\x0f\x6c\xe0\x01\xf1\xf0\xee\x9a\xc6\xc8\x97\x99\xd1\x6c"
182 "\xb4\x21\x45\x3b\x10\xe4\x7b\x99\x4d\x8a\x36\x64\x5c\x77\x08\x02"
183 "\xcb\xe0\xce"),
184 179,
188 /* Test the hand coded samples. */
190 static void
191 test_samples (struct backtrace_state *state)
193 size_t i;
195 for (i = 0; i < sizeof tests / sizeof tests[0]; ++i)
197 unsigned char *uncompressed;
198 size_t uncompressed_len;
200 uncompressed_len = tests[i].uncompressed_len;
201 if (uncompressed_len == 0)
202 uncompressed_len = strlen (tests[i].uncompressed);
204 uncompressed = (unsigned char *) malloc (uncompressed_len);
205 if (uncompressed == NULL)
207 perror ("malloc");
208 fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
209 ++failures;
210 continue;
213 if (!backtrace_uncompress_zstd (state,
214 ((const unsigned char *)
215 tests[i].compressed),
216 tests[i].compressed_len,
217 error_callback_compress, NULL,
218 uncompressed, uncompressed_len))
220 fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
221 ++failures;
223 else
225 if (memcmp (tests[i].uncompressed, uncompressed, uncompressed_len)
226 != 0)
228 size_t j;
230 fprintf (stderr, "test %s: uncompressed data mismatch\n",
231 tests[i].name);
232 for (j = 0; j < uncompressed_len; ++j)
233 if (tests[i].uncompressed[j] != uncompressed[j])
234 fprintf (stderr, " %zu: got %#x want %#x\n", j,
235 uncompressed[j], tests[i].uncompressed[j]);
236 ++failures;
238 else
239 printf ("PASS: uncompress %s\n", tests[i].name);
242 free (uncompressed);
246 #ifdef HAVE_ZSTD
248 /* Given a set of TRIALS timings, discard the lowest and highest
249 values and return the mean average of the rest. */
251 static size_t
252 average_time (const size_t *times, size_t trials)
254 size_t imax;
255 size_t max;
256 size_t imin;
257 size_t min;
258 size_t i;
259 size_t sum;
261 imin = 0;
262 imax = 0;
263 min = times[0];
264 max = times[0];
265 for (i = 1; i < trials; ++i)
267 if (times[i] < min)
269 imin = i;
270 min = times[i];
272 if (times[i] > max)
274 imax = i;
275 max = times[i];
279 sum = 0;
280 for (i = 0; i < trials; ++i)
282 if (i != imax && i != imin)
283 sum += times[i];
285 return sum / (trials - 2);
288 #endif
290 /* Test a larger text, if available. */
292 static void
293 test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
295 #ifdef HAVE_ZSTD
296 unsigned char *orig_buf;
297 size_t orig_bufsize;
298 size_t i;
299 char *compressed_buf;
300 size_t compressed_bufsize;
301 size_t compressed_size;
302 unsigned char *uncompressed_buf;
303 size_t r;
304 clockid_t cid;
305 struct timespec ts1;
306 struct timespec ts2;
307 size_t ctime;
308 size_t ztime;
309 const size_t trials = 16;
310 size_t ctimes[16];
311 size_t ztimes[16];
312 static const char * const names[] = {
313 "Isaac.Newton-Opticks.txt",
314 "../libgo/go/testdata/Isaac.Newton-Opticks.txt",
317 orig_buf = NULL;
318 orig_bufsize = 0;
319 uncompressed_buf = NULL;
320 compressed_buf = NULL;
322 for (i = 0; i < sizeof names / sizeof names[0]; ++i)
324 size_t len;
325 char *namebuf;
326 FILE *e;
327 struct stat st;
328 char *rbuf;
329 size_t got;
331 len = strlen (SRCDIR) + strlen (names[i]) + 2;
332 namebuf = malloc (len);
333 if (namebuf == NULL)
335 perror ("malloc");
336 goto fail;
338 snprintf (namebuf, len, "%s/%s", SRCDIR, names[i]);
339 e = fopen (namebuf, "r");
340 free (namebuf);
341 if (e == NULL)
342 continue;
343 if (fstat (fileno (e), &st) < 0)
345 perror ("fstat");
346 fclose (e);
347 continue;
349 rbuf = malloc (st.st_size);
350 if (rbuf == NULL)
352 perror ("malloc");
353 goto fail;
355 got = fread (rbuf, 1, st.st_size, e);
356 fclose (e);
357 if (got > 0)
359 orig_buf = (unsigned char *) rbuf;
360 orig_bufsize = got;
361 break;
363 free (rbuf);
366 if (orig_buf == NULL)
368 /* We couldn't find an input file. */
369 printf ("UNSUPPORTED: zstd large\n");
370 return;
373 compressed_bufsize = ZSTD_compressBound (orig_bufsize);
374 compressed_buf = malloc (compressed_bufsize);
375 if (compressed_buf == NULL)
377 perror ("malloc");
378 goto fail;
381 r = ZSTD_compress (compressed_buf, compressed_bufsize,
382 orig_buf, orig_bufsize,
383 ZSTD_CLEVEL_DEFAULT);
384 if (ZSTD_isError (r))
386 fprintf (stderr, "zstd compress failed: %s\n", ZSTD_getErrorName (r));
387 goto fail;
389 compressed_size = r;
391 uncompressed_buf = malloc (orig_bufsize);
392 if (uncompressed_buf == NULL)
394 perror ("malloc");
395 goto fail;
398 if (!backtrace_uncompress_zstd (state, (unsigned char *) compressed_buf,
399 compressed_size,
400 error_callback_compress, NULL,
401 uncompressed_buf, orig_bufsize))
403 fprintf (stderr, "zstd large: backtrace_uncompress_zstd failed\n");
404 goto fail;
407 if (memcmp (uncompressed_buf, orig_buf, orig_bufsize) != 0)
409 size_t j;
411 fprintf (stderr, "zstd large: uncompressed data mismatch\n");
412 for (j = 0; j < orig_bufsize; ++j)
413 if (orig_buf[j] != uncompressed_buf[j])
414 fprintf (stderr, " %zu: got %#x want %#x\n", j,
415 uncompressed_buf[j], orig_buf[j]);
416 goto fail;
419 printf ("PASS: zstd large\n");
421 for (i = 0; i < trials; ++i)
423 cid = ZSTD_CLOCK_GETTIME_ARG;
424 if (clock_gettime (cid, &ts1) < 0)
426 if (errno == EINVAL)
427 return;
428 perror ("clock_gettime");
429 return;
432 if (!backtrace_uncompress_zstd (state,
433 (unsigned char *) compressed_buf,
434 compressed_size,
435 error_callback_compress, NULL,
436 uncompressed_buf,
437 orig_bufsize))
439 fprintf (stderr,
440 ("zstd large: "
441 "benchmark backtrace_uncompress_zstd failed\n"));
442 return;
445 if (clock_gettime (cid, &ts2) < 0)
447 perror ("clock_gettime");
448 return;
451 ctime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
452 ctime += ts2.tv_nsec - ts1.tv_nsec;
453 ctimes[i] = ctime;
455 if (clock_gettime (cid, &ts1) < 0)
457 perror("clock_gettime");
458 return;
461 r = ZSTD_decompress (uncompressed_buf, orig_bufsize,
462 compressed_buf, compressed_size);
464 if (clock_gettime (cid, &ts2) < 0)
466 perror ("clock_gettime");
467 return;
470 if (ZSTD_isError (r))
472 fprintf (stderr,
473 "zstd large: benchmark zlib uncompress failed: %s\n",
474 ZSTD_getErrorName (r));
475 return;
478 ztime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
479 ztime += ts2.tv_nsec - ts1.tv_nsec;
480 ztimes[i] = ztime;
483 /* Toss the highest and lowest times and average the rest. */
484 ctime = average_time (ctimes, trials);
485 ztime = average_time (ztimes, trials);
487 printf ("backtrace: %zu ns\n", ctime);
488 printf ("zstd : %zu ns\n", ztime);
489 printf ("ratio : %g\n", (double) ztime / (double) ctime);
491 return;
493 fail:
494 printf ("FAIL: zstd large\n");
495 ++failures;
497 if (orig_buf != NULL)
498 free (orig_buf);
499 if (compressed_buf != NULL)
500 free (compressed_buf);
501 if (uncompressed_buf != NULL)
502 free (uncompressed_buf);
504 #else /* !HAVE_ZSTD */
506 printf ("UNSUPPORTED: zstd large\n");
508 #endif /* !HAVE_ZSTD */
512 main (int argc ATTRIBUTE_UNUSED, char **argv)
514 struct backtrace_state *state;
516 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
517 error_callback_create, NULL);
519 test_samples (state);
520 test_large (state);
522 exit (failures != 0 ? EXIT_FAILURE : EXIT_SUCCESS);