Automatic date update in version.in
[binutils-gdb.git] / libbacktrace / xztest.c
blob6c60ff5015917c7df73b98519350f1d6ac651247
1 /* xztest.c -- Test for libbacktrace LZMA decoder.
2 Copyright (C) 2020-2021 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 <limits.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
44 #ifdef HAVE_LIBLZMA
45 #include <lzma.h>
46 #endif
48 #include "backtrace.h"
49 #include "backtrace-supported.h"
51 #include "internal.h"
52 #include "testlib.h"
54 #ifndef HAVE_CLOCK_GETTIME
56 typedef int xclockid_t;
58 static int
59 xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED,
60 struct timespec *ts ATTRIBUTE_UNUSED)
62 errno = EINVAL;
63 return -1;
66 #define clockid_t xclockid_t
67 #define clock_gettime xclock_gettime
68 #undef CLOCK_REALTIME
69 #define CLOCK_REALTIME 0
71 #endif /* !defined(HAVE_CLOCK_GETTIME) */
73 #ifdef CLOCK_PROCESS_CPUTIME_ID
74 #define LIBLZMA_CLOCK_GETTIME_ARG CLOCK_PROCESS_CPUTIME_ID
75 #else
76 #define LIBLZMA_CLOCK_GETTIME_ARG CLOCK_REALTIME
77 #endif
79 /* Some tests for the local lzma inflation code. */
81 struct lzma_test
83 const char *name;
84 const char *uncompressed;
85 size_t uncompressed_len;
86 const char *compressed;
87 size_t compressed_len;
90 /* Error callback. */
92 static void
93 error_callback_compress (void *vdata ATTRIBUTE_UNUSED, const char *msg,
94 int errnum)
96 fprintf (stderr, "%s", msg);
97 if (errnum > 0)
98 fprintf (stderr, ": %s", strerror (errnum));
99 fprintf (stderr, "\n");
100 exit (EXIT_FAILURE);
103 static const struct lzma_test tests[] =
106 "empty",
109 ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x00\x00\x00\x00"
110 "\x1c\xdf\x44\x21\x1f\xb6\xf3\x7d\x01\x00\x00\x00\x00\x04\x59\x5a"),
114 "hello",
115 "hello, world\n",
117 ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21\x01"
118 "\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x0c\x68\x65\x6c\x6c\x6f"
119 "\x2c\x20\x77\x6f\x72\x6c\x64\x0a\x00\x00\x00\x00\x7b\x46\x5a\x81"
120 "\xc9\x12\xb8\xea\x00\x01\x25\x0d\x71\x19\xc4\xb6\x1f\xb6\xf3\x7d"
121 "\x01\x00\x00\x00\x00\x04\x59\x5a"),
125 "goodbye",
126 "goodbye, world",
128 ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21\x01"
129 "\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x0d\x67\x6f\x6f\x64\x62"
130 "\x79\x65\x2c\x20\x77\x6f\x72\x6c\x64\x00\x00\x00\xf6\xf8\xa3\x33"
131 "\x8c\x4e\xc9\x68\x00\x01\x26\x0e\x08\x1b\xe0\x04\x1f\xb6\xf3\x7d"
132 "\x01\x00\x00\x00\x00\x04\x59\x5a"),
137 /* Test the hand coded samples. */
139 static void
140 test_samples (struct backtrace_state *state)
142 size_t i;
144 for (i = 0; i < sizeof tests / sizeof tests[0]; ++i)
146 unsigned char *uncompressed;
147 size_t uncompressed_len;
149 uncompressed = NULL;
150 uncompressed_len = 0;
151 if (!backtrace_uncompress_lzma (state,
152 ((const unsigned char *)
153 tests[i].compressed),
154 tests[i].compressed_len,
155 error_callback_compress, NULL,
156 &uncompressed, &uncompressed_len))
158 fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
159 ++failures;
161 else
163 size_t v;
165 v = tests[i].uncompressed_len;
166 if (v == 0)
167 v = strlen (tests[i].uncompressed);
168 if (uncompressed_len != v)
170 fprintf (stderr,
171 "test %s: got uncompressed length %zu, want %zu\n",
172 tests[i].name, uncompressed_len, v);
173 ++failures;
175 else if (v > 0 && memcmp (tests[i].uncompressed, uncompressed, v) != 0)
177 size_t j;
179 fprintf (stderr, "test %s: uncompressed data mismatch\n",
180 tests[i].name);
181 for (j = 0; j < v; ++j)
182 if (tests[i].uncompressed[j] != uncompressed[j])
183 fprintf (stderr, " %zu: got %#x want %#x\n", j,
184 uncompressed[j], tests[i].uncompressed[j]);
185 ++failures;
187 else
188 printf ("PASS: lzma %s\n", tests[i].name);
190 backtrace_free (state, uncompressed, uncompressed_len,
191 error_callback_compress, NULL);
196 #if HAVE_LIBLZMA
198 /* Given a set of TRIALS timings, discard the lowest and highest
199 values and return the mean average of the rest. */
201 static size_t
202 average_time (const size_t *times, size_t trials)
204 size_t imax;
205 size_t max;
206 size_t imin;
207 size_t min;
208 size_t i;
209 size_t sum;
211 imin = 0;
212 imax = 0;
213 min = times[0];
214 max = times[0];
215 for (i = 1; i < trials; ++i)
217 if (times[i] < min)
219 imin = i;
220 min = times[i];
222 if (times[i] > max)
224 imax = i;
225 max = times[i];
229 sum = 0;
230 for (i = 0; i < trials; ++i)
232 if (i != imax && i != imin)
233 sum += times[i];
235 return sum / (trials - 2);
238 #endif
240 /* Test a larger text, if available. */
242 static void
243 test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
245 #if HAVE_LIBLZMA
246 unsigned char *orig_buf;
247 size_t orig_bufsize;
248 size_t i;
249 lzma_stream initial_stream = LZMA_STREAM_INIT;
250 lzma_stream stream;
251 unsigned char *compressed_buf;
252 size_t compressed_bufsize;
253 unsigned char *uncompressed_buf;
254 size_t uncompressed_bufsize;
255 unsigned char *spare_buf;
256 int r;
257 clockid_t cid;
258 struct timespec ts1;
259 struct timespec ts2;
260 size_t ctime;
261 size_t ztime;
262 const size_t trials = 16;
263 size_t ctimes[16];
264 size_t ztimes[16];
265 static const char * const names[] = {
266 "Isaac.Newton-Opticks.txt",
267 "../libgo/go/testdata/Isaac.Newton-Opticks.txt",
270 orig_buf = NULL;
271 orig_bufsize = 0;
272 uncompressed_buf = NULL;
273 compressed_buf = NULL;
275 for (i = 0; i < sizeof names / sizeof names[0]; ++i)
277 size_t len;
278 char *namebuf;
279 FILE *e;
280 struct stat st;
281 char *rbuf;
282 size_t got;
284 len = strlen (SRCDIR) + strlen (names[i]) + 2;
285 namebuf = malloc (len);
286 if (namebuf == NULL)
288 perror ("malloc");
289 goto fail;
291 snprintf (namebuf, len, "%s/%s", SRCDIR, names[i]);
292 e = fopen (namebuf, "r");
293 free (namebuf);
294 if (e == NULL)
295 continue;
296 if (fstat (fileno (e), &st) < 0)
298 perror ("fstat");
299 fclose (e);
300 continue;
302 rbuf = malloc (st.st_size);
303 if (rbuf == NULL)
305 perror ("malloc");
306 goto fail;
308 got = fread (rbuf, 1, st.st_size, e);
309 fclose (e);
310 if (got > 0)
312 orig_buf = (unsigned char *) rbuf;
313 orig_bufsize = got;
314 break;
316 free (rbuf);
319 if (orig_buf == NULL)
321 /* We couldn't find an input file. */
322 printf ("UNSUPPORTED: lzma large\n");
323 return;
326 stream = initial_stream;
327 r = lzma_easy_encoder (&stream, 6, LZMA_CHECK_CRC32);
328 if (r != LZMA_OK)
330 fprintf (stderr, "lzma_easy_encoder failed: %d\n", r);
331 goto fail;
334 compressed_bufsize = orig_bufsize + 100;
335 compressed_buf = malloc (compressed_bufsize);
336 if (compressed_buf == NULL)
338 perror ("malloc");
339 goto fail;
342 stream.next_in = orig_buf;
343 stream.avail_in = orig_bufsize;
344 stream.next_out = compressed_buf;
345 stream.avail_out = compressed_bufsize;
349 r = lzma_code (&stream, LZMA_FINISH);
350 if (r != LZMA_OK && r != LZMA_STREAM_END)
352 fprintf (stderr, "lzma_code failed: %d\n", r);
353 goto fail;
356 while (r != LZMA_STREAM_END);
358 compressed_bufsize = stream.total_out;
360 if (!backtrace_uncompress_lzma (state, (unsigned char *) compressed_buf,
361 compressed_bufsize,
362 error_callback_compress, NULL,
363 &uncompressed_buf, &uncompressed_bufsize))
365 fprintf (stderr, "lzma large: backtrace_uncompress_lzma failed\n");
366 goto fail;
369 if (uncompressed_bufsize != orig_bufsize)
371 fprintf (stderr,
372 "lzma large: got uncompressed length %zu, want %zu\n",
373 uncompressed_bufsize, orig_bufsize);
374 goto fail;
377 if (memcmp (uncompressed_buf, orig_buf, uncompressed_bufsize) != 0)
379 fprintf (stderr, "lzma large: uncompressed data mismatch\n");
380 goto fail;
383 printf ("PASS: lzma large\n");
385 spare_buf = malloc (orig_bufsize);
386 if (spare_buf == NULL)
388 perror ("malloc");
389 goto fail;
392 for (i = 0; i < trials; ++i)
394 cid = LIBLZMA_CLOCK_GETTIME_ARG;
395 if (clock_gettime (cid, &ts1) < 0)
397 if (errno == EINVAL)
398 return;
399 perror ("clock_gettime");
400 return;
403 if (!backtrace_uncompress_lzma (state,
404 (unsigned char *) compressed_buf,
405 compressed_bufsize,
406 error_callback_compress, NULL,
407 &uncompressed_buf,
408 &uncompressed_bufsize))
410 fprintf (stderr,
411 ("lzma large: "
412 "benchmark backtrace_uncompress_lzma failed\n"));
413 return;
416 if (clock_gettime (cid, &ts2) < 0)
418 perror ("clock_gettime");
419 return;
422 ctime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
423 ctime += ts2.tv_nsec - ts1.tv_nsec;
424 ctimes[i] = ctime;
426 stream = initial_stream;
428 r = lzma_auto_decoder (&stream, UINT64_MAX, 0);
429 if (r != LZMA_OK)
431 fprintf (stderr, "lzma_stream_decoder failed: %d\n", r);
432 goto fail;
435 stream.next_in = compressed_buf;
436 stream.avail_in = compressed_bufsize;
437 stream.next_out = spare_buf;
438 stream.avail_out = orig_bufsize;
440 if (clock_gettime (cid, &ts1) < 0)
442 perror("clock_gettime");
443 return;
448 r = lzma_code (&stream, LZMA_FINISH);
449 if (r != LZMA_OK && r != LZMA_STREAM_END)
451 fprintf (stderr, "lzma_code failed: %d\n", r);
452 goto fail;
455 while (r != LZMA_STREAM_END);
457 if (clock_gettime (cid, &ts2) < 0)
459 perror ("clock_gettime");
460 return;
463 ztime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
464 ztime += ts2.tv_nsec - ts1.tv_nsec;
465 ztimes[i] = ztime;
468 /* Toss the highest and lowest times and average the rest. */
469 ctime = average_time (ctimes, trials);
470 ztime = average_time (ztimes, trials);
472 printf ("backtrace: %zu ns\n", ctime);
473 printf ("liblzma : %zu ns\n", ztime);
474 printf ("ratio : %g\n", (double) ztime / (double) ctime);
476 return;
478 fail:
479 printf ("FAIL: lzma large\n");
480 ++failures;
482 if (orig_buf != NULL)
483 free (orig_buf);
484 if (compressed_buf != NULL)
485 free (compressed_buf);
486 if (uncompressed_buf != NULL)
487 free (uncompressed_buf);
489 #else /* !HAVE_LIBLZMA */
491 printf ("UNSUPPORTED: lzma large\n");
493 #endif /* !HAVE_LIBLZMA */
497 main (int argc ATTRIBUTE_UNUSED, char **argv)
499 struct backtrace_state *state;
501 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
502 error_callback_create, NULL);
504 test_samples (state);
505 test_large (state);
507 exit (failures != 0 ? EXIT_FAILURE : EXIT_SUCCESS);