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
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
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. */
40 #include <sys/types.h>
47 #include "backtrace.h"
48 #include "backtrace-supported.h"
53 #ifndef HAVE_CLOCK_GETTIME
55 typedef int xclockid_t
;
58 xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED
,
59 struct timespec
*ts ATTRIBUTE_UNUSED
)
65 #define clockid_t xclockid_t
66 #define clock_gettime xclock_gettime
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
75 #define ZSTD_CLOCK_GETTIME_ARG CLOCK_REALTIME
78 /* Some tests for the local zstd inflation code. */
83 const char *uncompressed
;
84 size_t uncompressed_len
;
85 const char *compressed
;
86 size_t compressed_len
;
92 error_callback_compress (void *vdata ATTRIBUTE_UNUSED
, const char *msg
,
95 fprintf (stderr
, "%s", msg
);
97 fprintf (stderr
, ": %s", strerror (errnum
));
98 fprintf (stderr
, "\n");
102 static const struct zstd_test tests
[] =
108 "\x28\xb5\x2f\xfd\x24\x00\x01\x00\x00\x99\xe9\xd8\x51",
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"),
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"),
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"),
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"
188 /* Test the hand coded samples. */
191 test_samples (struct backtrace_state
*state
)
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
)
208 fprintf (stderr
, "test %s: uncompress failed\n", tests
[i
].name
);
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
);
225 if (memcmp (tests
[i
].uncompressed
, uncompressed
, uncompressed_len
)
230 fprintf (stderr
, "test %s: uncompressed data mismatch\n",
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
]);
239 printf ("PASS: uncompress %s\n", tests
[i
].name
);
248 /* Given a set of TRIALS timings, discard the lowest and highest
249 values and return the mean average of the rest. */
252 average_time (const size_t *times
, size_t trials
)
265 for (i
= 1; i
< trials
; ++i
)
280 for (i
= 0; i
< trials
; ++i
)
282 if (i
!= imax
&& i
!= imin
)
285 return sum
/ (trials
- 2);
290 /* Test a larger text, if available. */
293 test_large (struct backtrace_state
*state ATTRIBUTE_UNUSED
)
296 unsigned char *orig_buf
;
299 char *compressed_buf
;
300 size_t compressed_bufsize
;
301 size_t compressed_size
;
302 unsigned char *uncompressed_buf
;
309 const size_t trials
= 16;
312 static const char * const names
[] = {
313 "Isaac.Newton-Opticks.txt",
314 "../libgo/go/testdata/Isaac.Newton-Opticks.txt",
319 uncompressed_buf
= NULL
;
320 compressed_buf
= NULL
;
322 for (i
= 0; i
< sizeof names
/ sizeof names
[0]; ++i
)
331 len
= strlen (SRCDIR
) + strlen (names
[i
]) + 2;
332 namebuf
= malloc (len
);
338 snprintf (namebuf
, len
, "%s/%s", SRCDIR
, names
[i
]);
339 e
= fopen (namebuf
, "r");
343 if (fstat (fileno (e
), &st
) < 0)
349 rbuf
= malloc (st
.st_size
);
355 got
= fread (rbuf
, 1, st
.st_size
, e
);
359 orig_buf
= (unsigned char *) rbuf
;
366 if (orig_buf
== NULL
)
368 /* We couldn't find an input file. */
369 printf ("UNSUPPORTED: zstd large\n");
373 compressed_bufsize
= ZSTD_compressBound (orig_bufsize
);
374 compressed_buf
= malloc (compressed_bufsize
);
375 if (compressed_buf
== NULL
)
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
));
391 uncompressed_buf
= malloc (orig_bufsize
);
392 if (uncompressed_buf
== NULL
)
398 if (!backtrace_uncompress_zstd (state
, (unsigned char *) compressed_buf
,
400 error_callback_compress
, NULL
,
401 uncompressed_buf
, orig_bufsize
))
403 fprintf (stderr
, "zstd large: backtrace_uncompress_zstd failed\n");
407 if (memcmp (uncompressed_buf
, orig_buf
, orig_bufsize
) != 0)
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
]);
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)
428 perror ("clock_gettime");
432 if (!backtrace_uncompress_zstd (state
,
433 (unsigned char *) compressed_buf
,
435 error_callback_compress
, NULL
,
441 "benchmark backtrace_uncompress_zstd failed\n"));
445 if (clock_gettime (cid
, &ts2
) < 0)
447 perror ("clock_gettime");
451 ctime
= (ts2
.tv_sec
- ts1
.tv_sec
) * 1000000000;
452 ctime
+= ts2
.tv_nsec
- ts1
.tv_nsec
;
455 if (clock_gettime (cid
, &ts1
) < 0)
457 perror("clock_gettime");
461 r
= ZSTD_decompress (uncompressed_buf
, orig_bufsize
,
462 compressed_buf
, compressed_size
);
464 if (clock_gettime (cid
, &ts2
) < 0)
466 perror ("clock_gettime");
470 if (ZSTD_isError (r
))
473 "zstd large: benchmark zlib uncompress failed: %s\n",
474 ZSTD_getErrorName (r
));
478 ztime
= (ts2
.tv_sec
- ts1
.tv_sec
) * 1000000000;
479 ztime
+= ts2
.tv_nsec
- ts1
.tv_nsec
;
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
);
494 printf ("FAIL: zstd large\n");
497 if (orig_buf
!= NULL
)
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
);
522 exit (failures
!= 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);