]> git.ipfire.org Git - thirdparty/gcc.git/blame - libbacktrace/xztest.c
Update copyright years.
[thirdparty/gcc.git] / libbacktrace / xztest.c
CommitLineData
05f40bc4 1/* xztest.c -- Test for libbacktrace LZMA decoder.
99dee823 2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
05f40bc4
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 <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>
43
44#ifdef HAVE_LIBLZMA
45#include <lzma.h>
46#endif
47
48#include "backtrace.h"
49#include "backtrace-supported.h"
50
51#include "internal.h"
52#include "testlib.h"
53
54#ifndef HAVE_CLOCK_GETTIME
55
56typedef int xclockid_t;
57
58static int
59xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED,
60 struct timespec *ts ATTRIBUTE_UNUSED)
61{
62 errno = EINVAL;
63 return -1;
64}
65
66#define clockid_t xclockid_t
67#define clock_gettime xclock_gettime
68#undef CLOCK_REALTIME
69#define CLOCK_REALTIME 0
70
71#endif /* !defined(HAVE_CLOCK_GETTIME) */
72
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
78
79/* Some tests for the local lzma inflation code. */
80
81struct lzma_test
82{
83 const char *name;
84 const char *uncompressed;
85 size_t uncompressed_len;
86 const char *compressed;
87 size_t compressed_len;
88};
89
90/* Error callback. */
91
92static void
93error_callback_compress (void *vdata ATTRIBUTE_UNUSED, const char *msg,
94 int errnum)
95{
96 fprintf (stderr, "%s", msg);
97 if (errnum > 0)
98 fprintf (stderr, ": %s", strerror (errnum));
99 fprintf (stderr, "\n");
100 exit (EXIT_FAILURE);
101}
102
103static const struct lzma_test tests[] =
104{
105 {
106 "empty",
107 "",
108 0,
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"),
111 32,
112 },
113 {
114 "hello",
115 "hello, world\n",
116 0,
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"),
122 72,
123 },
124 {
125 "goodbye",
126 "goodbye, world",
127 0,
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"),
133 72,
134 },
135};
136
137/* Test the hand coded samples. */
138
139static void
140test_samples (struct backtrace_state *state)
141{
142 size_t i;
143
144 for (i = 0; i < sizeof tests / sizeof tests[0]; ++i)
145 {
146 unsigned char *uncompressed;
147 size_t uncompressed_len;
148
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))
157 {
158 fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
159 ++failures;
160 }
161 else
162 {
163 size_t v;
164
165 v = tests[i].uncompressed_len;
166 if (v == 0)
167 v = strlen (tests[i].uncompressed);
168 if (uncompressed_len != v)
169 {
170 fprintf (stderr,
171 "test %s: got uncompressed length %zu, want %zu\n",
172 tests[i].name, uncompressed_len, v);
173 ++failures;
174 }
175 else if (memcmp (tests[i].uncompressed, uncompressed, v) != 0)
176 {
177 size_t j;
178
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;
186 }
187 else
188 printf ("PASS: lzma %s\n", tests[i].name);
189
190 backtrace_free (state, uncompressed, uncompressed_len,
191 error_callback_compress, NULL);
192 }
193 }
194}
195
196#if HAVE_LIBLZMA
197
198/* Given a set of TRIALS timings, discard the lowest and highest
199 values and return the mean average of the rest. */
200
201static size_t
202average_time (const size_t *times, size_t trials)
203{
204 size_t imax;
205 size_t max;
206 size_t imin;
207 size_t min;
208 size_t i;
209 size_t sum;
210
211 imin = 0;
212 imax = 0;
213 min = times[0];
214 max = times[0];
215 for (i = 1; i < trials; ++i)
216 {
217 if (times[i] < min)
218 {
219 imin = i;
220 min = times[i];
221 }
222 if (times[i] > max)
223 {
224 imax = i;
225 max = times[i];
226 }
227 }
228
229 sum = 0;
230 for (i = 0; i < trials; ++i)
231 {
232 if (i != imax && i != imin)
233 sum += times[i];
234 }
235 return sum / (trials - 2);
236}
237
238#endif
239
240/* Test a larger text, if available. */
241
242static void
243test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
244{
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",
268 };
269
270 orig_buf = NULL;
271 orig_bufsize = 0;
272 uncompressed_buf = NULL;
273 compressed_buf = NULL;
274
275 for (i = 0; i < sizeof names / sizeof names[0]; ++i)
276 {
277 size_t len;
278 char *namebuf;
279 FILE *e;
280 struct stat st;
281 char *rbuf;
282 size_t got;
283
284 len = strlen (SRCDIR) + strlen (names[i]) + 2;
285 namebuf = malloc (len);
286 if (namebuf == NULL)
287 {
288 perror ("malloc");
289 goto fail;
290 }
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)
297 {
298 perror ("fstat");
299 fclose (e);
300 continue;
301 }
302 rbuf = malloc (st.st_size);
303 if (rbuf == NULL)
304 {
305 perror ("malloc");
306 goto fail;
307 }
308 got = fread (rbuf, 1, st.st_size, e);
309 fclose (e);
310 if (got > 0)
311 {
312 orig_buf = (unsigned char *) rbuf;
313 orig_bufsize = got;
314 break;
315 }
316 free (rbuf);
317 }
318
319 if (orig_buf == NULL)
320 {
321 /* We couldn't find an input file. */
322 printf ("UNSUPPORTED: lzma large\n");
323 return;
324 }
325
326 stream = initial_stream;
327 r = lzma_easy_encoder (&stream, 6, LZMA_CHECK_CRC32);
328 if (r != LZMA_OK)
329 {
330 fprintf (stderr, "lzma_easy_encoder failed: %d\n", r);
331 goto fail;
332 }
333
334 compressed_bufsize = orig_bufsize + 100;
335 compressed_buf = malloc (compressed_bufsize);
336 if (compressed_buf == NULL)
337 {
338 perror ("malloc");
339 goto fail;
340 }
341
342 stream.next_in = orig_buf;
343 stream.avail_in = orig_bufsize;
344 stream.next_out = compressed_buf;
345 stream.avail_out = compressed_bufsize;
346
347 do
348 {
349 r = lzma_code (&stream, LZMA_FINISH);
350 if (r != LZMA_OK && r != LZMA_STREAM_END)
351 {
352 fprintf (stderr, "lzma_code failed: %d\n", r);
353 goto fail;
354 }
355 }
356 while (r != LZMA_STREAM_END);
357
358 compressed_bufsize = stream.total_out;
359
360 if (!backtrace_uncompress_lzma (state, (unsigned char *) compressed_buf,
361 compressed_bufsize,
362 error_callback_compress, NULL,
363 &uncompressed_buf, &uncompressed_bufsize))
364 {
365 fprintf (stderr, "lzma large: backtrace_uncompress_lzma failed\n");
366 goto fail;
367 }
368
369 if (uncompressed_bufsize != orig_bufsize)
370 {
371 fprintf (stderr,
372 "lzma large: got uncompressed length %zu, want %zu\n",
373 uncompressed_bufsize, orig_bufsize);
374 goto fail;
375 }
376
377 if (memcmp (uncompressed_buf, orig_buf, uncompressed_bufsize) != 0)
378 {
379 fprintf (stderr, "lzma large: uncompressed data mismatch\n");
380 goto fail;
381 }
382
383 printf ("PASS: lzma large\n");
384
385 spare_buf = malloc (orig_bufsize);
386 if (spare_buf == NULL)
387 {
388 perror ("malloc");
389 goto fail;
390 }
391
392 for (i = 0; i < trials; ++i)
393 {
394 cid = LIBLZMA_CLOCK_GETTIME_ARG;
395 if (clock_gettime (cid, &ts1) < 0)
396 {
397 if (errno == EINVAL)
398 return;
399 perror ("clock_gettime");
400 return;
401 }
402
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))
409 {
410 fprintf (stderr,
411 ("lzma large: "
412 "benchmark backtrace_uncompress_lzma failed\n"));
413 return;
414 }
415
416 if (clock_gettime (cid, &ts2) < 0)
417 {
418 perror ("clock_gettime");
419 return;
420 }
421
422 ctime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
423 ctime += ts2.tv_nsec - ts1.tv_nsec;
424 ctimes[i] = ctime;
425
426 stream = initial_stream;
427
428 r = lzma_auto_decoder (&stream, UINT64_MAX, 0);
429 if (r != LZMA_OK)
430 {
431 fprintf (stderr, "lzma_stream_decoder failed: %d\n", r);
432 goto fail;
433 }
434
435 stream.next_in = compressed_buf;
436 stream.avail_in = compressed_bufsize;
437 stream.next_out = spare_buf;
438 stream.avail_out = orig_bufsize;
439
440 if (clock_gettime (cid, &ts1) < 0)
441 {
442 perror("clock_gettime");
443 return;
444 }
445
446 do
447 {
448 r = lzma_code (&stream, LZMA_FINISH);
449 if (r != LZMA_OK && r != LZMA_STREAM_END)
450 {
451 fprintf (stderr, "lzma_code failed: %d\n", r);
452 goto fail;
453 }
454 }
455 while (r != LZMA_STREAM_END);
456
457 if (clock_gettime (cid, &ts2) < 0)
458 {
459 perror ("clock_gettime");
460 return;
461 }
462
463 ztime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
464 ztime += ts2.tv_nsec - ts1.tv_nsec;
465 ztimes[i] = ztime;
466 }
467
468 /* Toss the highest and lowest times and average the rest. */
469 ctime = average_time (ctimes, trials);
470 ztime = average_time (ztimes, trials);
471
472 printf ("backtrace: %zu ns\n", ctime);
473 printf ("liblzma : %zu ns\n", ztime);
474 printf ("ratio : %g\n", (double) ztime / (double) ctime);
475
476 return;
477
478 fail:
479 printf ("FAIL: lzma large\n");
480 ++failures;
481
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);
488
489#else /* !HAVE_LIBLZMA */
490
491 printf ("UNSUPPORTED: lzma large\n");
492
493#endif /* !HAVE_LIBLZMA */
494}
495
496int
497main (int argc ATTRIBUTE_UNUSED, char **argv)
498{
499 struct backtrace_state *state;
500
501 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
502 error_callback_create, NULL);
503
504 test_samples (state);
505 test_large (state);
506
507 exit (failures != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
508}