]> git.ipfire.org Git - thirdparty/gcc.git/blame - libbacktrace/zstdtest.c
libiberty: Fix error return value in pex_unix_exec_child [PR113957].
[thirdparty/gcc.git] / libbacktrace / zstdtest.c
CommitLineData
9df1ba9a 1/* ztest.c -- Test for libbacktrace zstd code.
a945c346 2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
9df1ba9a
ILT
3 Written by Ian Lance Taylor, Google.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
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.
16
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.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31POSSIBILITY OF SUCH DAMAGE. */
32
33#include "config.h"
34
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>
42
43#ifdef HAVE_ZSTD
44#include <zstd.h>
45#endif
46
47#include "backtrace.h"
48#include "backtrace-supported.h"
49
50#include "internal.h"
51#include "testlib.h"
52
53#ifndef HAVE_CLOCK_GETTIME
54
55typedef int xclockid_t;
56
57static int
58xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED,
59 struct timespec *ts ATTRIBUTE_UNUSED)
60{
61 errno = EINVAL;
62 return -1;
63}
64
65#define clockid_t xclockid_t
66#define clock_gettime xclock_gettime
67#undef CLOCK_REALTIME
68#define CLOCK_REALTIME 0
69
70#endif /* !defined(HAVE_CLOCK_GETTIME) */
71
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
77
78/* Some tests for the local zstd inflation code. */
79
80struct zstd_test
81{
82 const char *name;
83 const char *uncompressed;
84 size_t uncompressed_len;
85 const char *compressed;
86 size_t compressed_len;
87};
88
89/* Error callback. */
90
91static void
92error_callback_compress (void *vdata ATTRIBUTE_UNUSED, const char *msg,
93 int errnum)
94{
95 fprintf (stderr, "%s", msg);
96 if (errnum > 0)
97 fprintf (stderr, ": %s", strerror (errnum));
98 fprintf (stderr, "\n");
99 exit (EXIT_FAILURE);
100}
101
102static const struct zstd_test tests[] =
103{
104 {
105 "empty",
106 "",
107 0,
108 "\x28\xb5\x2f\xfd\x24\x00\x01\x00\x00\x99\xe9\xd8\x51",
109 13,
110 },
111 {
112 "hello",
113 "hello, world\n",
114 0,
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"),
117 26,
118 },
119 {
120 "goodbye",
121 "goodbye, world",
122 0,
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"),
125 27,
126 },
127 {
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,
185 }
186};
187
188/* Test the hand coded samples. */
189
190static void
191test_samples (struct backtrace_state *state)
192{
193 size_t i;
194
195 for (i = 0; i < sizeof tests / sizeof tests[0]; ++i)
196 {
197 unsigned char *uncompressed;
198 size_t uncompressed_len;
199
a9b60439
RB
200 uncompressed_len = tests[i].uncompressed_len;
201 if (uncompressed_len == 0)
202 uncompressed_len = strlen (tests[i].uncompressed);
203
204 uncompressed = (unsigned char *) malloc (uncompressed_len);
9df1ba9a
ILT
205 if (uncompressed == NULL)
206 {
207 perror ("malloc");
208 fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
209 ++failures;
210 continue;
211 }
212
9df1ba9a
ILT
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))
219 {
220 fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
221 ++failures;
222 }
223 else
224 {
225 if (memcmp (tests[i].uncompressed, uncompressed, uncompressed_len)
226 != 0)
227 {
228 size_t j;
229
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;
237 }
238 else
239 printf ("PASS: uncompress %s\n", tests[i].name);
240 }
241
242 free (uncompressed);
243 }
244}
245
246#ifdef HAVE_ZSTD
247
248/* Given a set of TRIALS timings, discard the lowest and highest
249 values and return the mean average of the rest. */
250
251static size_t
252average_time (const size_t *times, size_t trials)
253{
254 size_t imax;
255 size_t max;
256 size_t imin;
257 size_t min;
258 size_t i;
259 size_t sum;
260
261 imin = 0;
262 imax = 0;
263 min = times[0];
264 max = times[0];
265 for (i = 1; i < trials; ++i)
266 {
267 if (times[i] < min)
268 {
269 imin = i;
270 min = times[i];
271 }
272 if (times[i] > max)
273 {
274 imax = i;
275 max = times[i];
276 }
277 }
278
279 sum = 0;
280 for (i = 0; i < trials; ++i)
281 {
282 if (i != imax && i != imin)
283 sum += times[i];
284 }
285 return sum / (trials - 2);
286}
287
288#endif
289
290/* Test a larger text, if available. */
291
292static void
293test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
294{
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",
315 };
316
317 orig_buf = NULL;
318 orig_bufsize = 0;
319 uncompressed_buf = NULL;
320 compressed_buf = NULL;
321
322 for (i = 0; i < sizeof names / sizeof names[0]; ++i)
323 {
324 size_t len;
325 char *namebuf;
326 FILE *e;
327 struct stat st;
328 char *rbuf;
329 size_t got;
330
331 len = strlen (SRCDIR) + strlen (names[i]) + 2;
332 namebuf = malloc (len);
333 if (namebuf == NULL)
334 {
335 perror ("malloc");
336 goto fail;
337 }
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)
344 {
345 perror ("fstat");
346 fclose (e);
347 continue;
348 }
349 rbuf = malloc (st.st_size);
350 if (rbuf == NULL)
351 {
352 perror ("malloc");
353 goto fail;
354 }
355 got = fread (rbuf, 1, st.st_size, e);
356 fclose (e);
357 if (got > 0)
358 {
359 orig_buf = (unsigned char *) rbuf;
360 orig_bufsize = got;
361 break;
362 }
363 free (rbuf);
364 }
365
366 if (orig_buf == NULL)
367 {
368 /* We couldn't find an input file. */
369 printf ("UNSUPPORTED: zstd large\n");
370 return;
371 }
372
373 compressed_bufsize = ZSTD_compressBound (orig_bufsize);
374 compressed_buf = malloc (compressed_bufsize);
375 if (compressed_buf == NULL)
376 {
377 perror ("malloc");
378 goto fail;
379 }
380
381 r = ZSTD_compress (compressed_buf, compressed_bufsize,
382 orig_buf, orig_bufsize,
383 ZSTD_CLEVEL_DEFAULT);
384 if (ZSTD_isError (r))
385 {
386 fprintf (stderr, "zstd compress failed: %s\n", ZSTD_getErrorName (r));
387 goto fail;
388 }
389 compressed_size = r;
390
391 uncompressed_buf = malloc (orig_bufsize);
392 if (uncompressed_buf == NULL)
393 {
394 perror ("malloc");
395 goto fail;
396 }
397
398 if (!backtrace_uncompress_zstd (state, (unsigned char *) compressed_buf,
399 compressed_size,
400 error_callback_compress, NULL,
401 uncompressed_buf, orig_bufsize))
402 {
403 fprintf (stderr, "zstd large: backtrace_uncompress_zstd failed\n");
404 goto fail;
405 }
406
407 if (memcmp (uncompressed_buf, orig_buf, orig_bufsize) != 0)
408 {
409 size_t j;
410
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;
417 }
418
419 printf ("PASS: zstd large\n");
420
421 for (i = 0; i < trials; ++i)
422 {
423 cid = ZSTD_CLOCK_GETTIME_ARG;
424 if (clock_gettime (cid, &ts1) < 0)
425 {
426 if (errno == EINVAL)
427 return;
428 perror ("clock_gettime");
429 return;
430 }
431
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))
438 {
439 fprintf (stderr,
440 ("zstd large: "
441 "benchmark backtrace_uncompress_zstd failed\n"));
442 return;
443 }
444
445 if (clock_gettime (cid, &ts2) < 0)
446 {
447 perror ("clock_gettime");
448 return;
449 }
450
451 ctime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
452 ctime += ts2.tv_nsec - ts1.tv_nsec;
453 ctimes[i] = ctime;
454
455 if (clock_gettime (cid, &ts1) < 0)
456 {
457 perror("clock_gettime");
458 return;
459 }
460
461 r = ZSTD_decompress (uncompressed_buf, orig_bufsize,
462 compressed_buf, compressed_size);
463
464 if (clock_gettime (cid, &ts2) < 0)
465 {
466 perror ("clock_gettime");
467 return;
468 }
469
470 if (ZSTD_isError (r))
471 {
472 fprintf (stderr,
473 "zstd large: benchmark zlib uncompress failed: %s\n",
474 ZSTD_getErrorName (r));
475 return;
476 }
477
478 ztime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
479 ztime += ts2.tv_nsec - ts1.tv_nsec;
480 ztimes[i] = ztime;
481 }
482
483 /* Toss the highest and lowest times and average the rest. */
484 ctime = average_time (ctimes, trials);
485 ztime = average_time (ztimes, trials);
486
487 printf ("backtrace: %zu ns\n", ctime);
488 printf ("zstd : %zu ns\n", ztime);
489 printf ("ratio : %g\n", (double) ztime / (double) ctime);
490
491 return;
492
493 fail:
494 printf ("FAIL: zstd large\n");
495 ++failures;
496
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);
503
504#else /* !HAVE_ZSTD */
505
506 printf ("UNSUPPORTED: zstd large\n");
507
508#endif /* !HAVE_ZSTD */
509}
510
511int
512main (int argc ATTRIBUTE_UNUSED, char **argv)
513{
514 struct backtrace_state *state;
515
516 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
517 error_callback_create, NULL);
518
519 test_samples (state);
520 test_large (state);
521
522 exit (failures != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
523}