|
| 1 | +/* |
| 2 | + * Copyright (c) Meta Platforms, Inc. and affiliates. |
| 3 | + * All rights reserved. |
| 4 | + * |
| 5 | + * This source code is licensed under both the BSD-style license (found in the |
| 6 | + * LICENSE file in the root directory of this source tree) and the GPLv2 (found |
| 7 | + * in the COPYING file in the root directory of this source tree). |
| 8 | + */ |
| 9 | + |
| 10 | +/* seqBench: roundtrip benchmark using sequence-level compression API. |
| 11 | + * |
| 12 | + * Usage: seqBench <file> |
| 13 | + * |
| 14 | + * Generates sequences from the input file, then recompresses them |
| 15 | + * using ZSTD_compressSequences() with explicit block delimiters, |
| 16 | + * finally validates the output by decompressing and comparing. |
| 17 | + */ |
| 18 | + |
1 | 19 | #define ZSTD_STATIC_LINKING_ONLY |
2 | | -#include <zstd.h> |
| 20 | +#include <assert.h> |
3 | 21 | #include <stdio.h> |
4 | 22 | #include <stdlib.h> |
5 | | -#include <assert.h> |
6 | 23 | #include <string.h> |
| 24 | +#include <zstd.h> |
7 | 25 |
|
8 | 26 | int main(int argc, char *argv[]) { |
9 | | - ZSTD_CCtx* zc = ZSTD_createCCtx(); |
| 27 | + int ret = 0; |
10 | 28 |
|
11 | | - if (argc != 2) { |
12 | | - printf("Usage: seqBench <file>\n"); // TODO provide the block delim option here |
13 | | - return 1; |
14 | | - } |
| 29 | + if (argc != 2) { |
| 30 | + fprintf(stderr, "Usage: seqBench <file>\n"); |
| 31 | + fprintf(stderr, |
| 32 | + "\nRoundtrip benchmark using sequence-level compression.\n"); |
| 33 | + fprintf(stderr, "Generates sequences with ZSTD_generateSequences(),\n"); |
| 34 | + fprintf(stderr, "recompresses with ZSTD_compressSequences() using\n"); |
| 35 | + fprintf(stderr, |
| 36 | + "explicit block delimiters, and validates by decompression.\n"); |
| 37 | + return 1; |
| 38 | + } |
| 39 | + |
| 40 | + ZSTD_CCtx *zc = ZSTD_createCCtx(); |
| 41 | + if (zc == NULL) { |
| 42 | + fprintf(stderr, "ERROR: ZSTD_createCCtx() failed\n"); |
| 43 | + return 1; |
| 44 | + } |
15 | 45 |
|
16 | | - FILE *f = fopen(argv[1], "rb"); |
17 | | - fseek(f, 0, SEEK_END); |
18 | | - long inBufSize = ftell(f); |
19 | | - fseek(f, 0, SEEK_SET); |
| 46 | + FILE *f = fopen(argv[1], "rb"); |
| 47 | + if (f == NULL) { |
| 48 | + fprintf(stderr, "ERROR: could not open file '%s'\n", argv[1]); |
| 49 | + ZSTD_freeCCtx(zc); |
| 50 | + return 1; |
| 51 | + } |
20 | 52 |
|
21 | | - char *inBuf = malloc(inBufSize + 1); |
22 | | - fread(inBuf, inBufSize, 1, f); |
| 53 | + fseek(f, 0, SEEK_END); |
| 54 | + long inBufSize = ftell(f); |
| 55 | + fseek(f, 0, SEEK_SET); |
| 56 | + |
| 57 | + if (inBufSize <= 0) { |
| 58 | + fprintf(stderr, "ERROR: file '%s' is empty or unreadable\n", argv[1]); |
| 59 | + fclose(f); |
| 60 | + ZSTD_freeCCtx(zc); |
| 61 | + return 1; |
| 62 | + } |
| 63 | + |
| 64 | + char *inBuf = (char *)malloc((size_t)inBufSize + 1); |
| 65 | + if (inBuf == NULL) { |
| 66 | + fprintf(stderr, "ERROR: could not allocate %ld bytes for input\n", |
| 67 | + inBufSize); |
23 | 68 | fclose(f); |
| 69 | + ZSTD_freeCCtx(zc); |
| 70 | + return 1; |
| 71 | + } |
24 | 72 |
|
25 | | - size_t seqsSize = ZSTD_sequenceBound(inBufSize); |
26 | | - ZSTD_Sequence *seqs = (ZSTD_Sequence*)malloc(seqsSize * sizeof(ZSTD_Sequence)); |
27 | | - char *outBuf = malloc(ZSTD_compressBound(inBufSize)); |
| 73 | + size_t const bytesRead = fread(inBuf, 1, (size_t)inBufSize, f); |
| 74 | + fclose(f); |
| 75 | + if ((long)bytesRead != inBufSize) { |
| 76 | + fprintf(stderr, "ERROR: read only %zu of %ld bytes\n", bytesRead, |
| 77 | + inBufSize); |
| 78 | + free(inBuf); |
| 79 | + ZSTD_freeCCtx(zc); |
| 80 | + return 1; |
| 81 | + } |
28 | 82 |
|
29 | | - ZSTD_generateSequences(zc, seqs, seqsSize, inBuf, inBufSize); |
30 | | - ZSTD_CCtx_setParameter(zc, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters); |
31 | | - size_t outBufSize = ZSTD_compressSequences(zc, outBuf, inBufSize, seqs, seqsSize, inBuf, inBufSize); |
32 | | - if (ZSTD_isError(outBufSize)) { |
33 | | - printf("ERROR: %lu\n", outBufSize); |
34 | | - return 1; |
35 | | - } |
| 83 | + size_t seqsSize = ZSTD_sequenceBound((size_t)inBufSize); |
| 84 | + ZSTD_Sequence *seqs = |
| 85 | + (ZSTD_Sequence *)malloc(seqsSize * sizeof(ZSTD_Sequence)); |
| 86 | + size_t const outBufCapacity = ZSTD_compressBound((size_t)inBufSize); |
| 87 | + char *outBuf = (char *)malloc(outBufCapacity); |
| 88 | + char *validationBuf = (char *)malloc((size_t)inBufSize); |
| 89 | + |
| 90 | + if (seqs == NULL || outBuf == NULL || validationBuf == NULL) { |
| 91 | + fprintf(stderr, "ERROR: memory allocation failed\n"); |
| 92 | + ret = 1; |
| 93 | + goto cleanup; |
| 94 | + } |
| 95 | + |
| 96 | + ZSTD_generateSequences(zc, seqs, seqsSize, inBuf, (size_t)inBufSize); |
| 97 | + ZSTD_CCtx_setParameter(zc, ZSTD_c_blockDelimiters, |
| 98 | + ZSTD_sf_explicitBlockDelimiters); |
| 99 | + size_t outBufSize = ZSTD_compressSequences( |
| 100 | + zc, outBuf, outBufCapacity, seqs, seqsSize, inBuf, (size_t)inBufSize); |
| 101 | + if (ZSTD_isError(outBufSize)) { |
| 102 | + fprintf(stderr, "ERROR: ZSTD_compressSequences failed: %s\n", |
| 103 | + ZSTD_getErrorName(outBufSize)); |
| 104 | + ret = 1; |
| 105 | + goto cleanup; |
| 106 | + } |
| 107 | + |
| 108 | + size_t const decSize = |
| 109 | + ZSTD_decompress(validationBuf, (size_t)inBufSize, outBuf, outBufSize); |
| 110 | + if (ZSTD_isError(decSize)) { |
| 111 | + fprintf(stderr, "ERROR: ZSTD_decompress failed: %s\n", |
| 112 | + ZSTD_getErrorName(decSize)); |
| 113 | + ret = 1; |
| 114 | + goto cleanup; |
| 115 | + } |
| 116 | + |
| 117 | + if ((long)decSize != inBufSize) { |
| 118 | + fprintf(stderr, "ERROR: decompressed size (%zu) != original size (%ld)\n", |
| 119 | + decSize, inBufSize); |
| 120 | + ret = 1; |
| 121 | + goto cleanup; |
| 122 | + } |
36 | 123 |
|
37 | | - char *validationBuf = malloc(inBufSize); |
38 | | - ZSTD_decompress(validationBuf, inBufSize, outBuf, outBufSize); |
39 | | - |
40 | | - if (memcmp(inBuf, validationBuf, inBufSize) == 0) { |
41 | | - printf("Compression and decompression were successful!\n"); |
42 | | - } else { |
43 | | - printf("ERROR: input and validation buffers don't match!\n"); |
44 | | - for (int i = 0; i < inBufSize; i++) { |
45 | | - if (inBuf[i] != validationBuf[i]) { |
46 | | - printf("First bad index: %d\n", i); |
47 | | - break; |
48 | | - } |
49 | | - } |
| 124 | + if (memcmp(inBuf, validationBuf, (size_t)inBufSize) == 0) { |
| 125 | + printf("Compression and decompression were successful!\n"); |
| 126 | + printf(" Original size: %ld bytes\n", inBufSize); |
| 127 | + printf(" Compressed size: %zu bytes\n", outBufSize); |
| 128 | + printf(" Ratio: %.2f\n", (double)inBufSize / (double)outBufSize); |
| 129 | + } else { |
| 130 | + fprintf(stderr, "ERROR: input and validation buffers don't match!\n"); |
| 131 | + for (long i = 0; i < inBufSize; i++) { |
| 132 | + if (inBuf[i] != validationBuf[i]) { |
| 133 | + fprintf(stderr, "First bad index: %ld\n", i); |
| 134 | + break; |
| 135 | + } |
50 | 136 | } |
| 137 | + ret = 1; |
| 138 | + } |
51 | 139 |
|
52 | | - return 0; |
| 140 | +cleanup: |
| 141 | + free(validationBuf); |
| 142 | + free(outBuf); |
| 143 | + free(seqs); |
| 144 | + free(inBuf); |
| 145 | + ZSTD_freeCCtx(zc); |
| 146 | + return ret; |
53 | 147 | } |
0 commit comments