xref: /isa-l/igzip/igzip_perf.c (revision 55fbfabfc60f1002bc8133b730a59f6abd22cfce)
1 /**********************************************************************
2   Copyright(c) 2011-2018 Intel Corporation All rights reserved.
3 
4   Redistribution and use in source and binary forms, with or without
5   modification, are permitted provided that the following conditions
6   are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in
11       the documentation and/or other materials provided with the
12       distribution.
13     * Neither the name of Intel Corporation nor the names of its
14       contributors may be used to endorse or promote products derived
15       from this software without specific prior written permission.
16 
17   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 **********************************************************************/
29 
30 #define _FILE_OFFSET_BITS 64
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <assert.h>
34 #include <getopt.h>
35 #include "huff_codes.h"
36 #include "igzip_lib.h"
37 #include "test.h"
38 
39 #include <zlib.h>
40 
41 #define BUF_SIZE 1024
42 
43 #define OPTARGS "hl:f:z:i:d:stub:y:w:o:D:"
44 
45 #define COMPRESSION_QUEUE_LIMIT 32
46 #define UNSET                   -1
47 
48 #define xstr(a) str(a)
49 #define str(a)  #a
50 
51 /* Limit output buffer size to 2 Gigabytes. Since stream->avail_out is a
52  * uint32_t and there is no logic for handling an overflowed output buffer in
53  * the perf test, this define must be less then 4 Gigabytes */
54 #define MAX_COMPRESS_BUF_SIZE (1U << 31)
55 
56 int level_size_buf[10] = {
57 #ifdef ISAL_DEF_LVL0_DEFAULT
58         ISAL_DEF_LVL0_DEFAULT,
59 #else
60         0,
61 #endif
62 #ifdef ISAL_DEF_LVL1_DEFAULT
63         ISAL_DEF_LVL1_DEFAULT,
64 #else
65         0,
66 #endif
67 #ifdef ISAL_DEF_LVL2_DEFAULT
68         ISAL_DEF_LVL2_DEFAULT,
69 #else
70         0,
71 #endif
72 #ifdef ISAL_DEF_LVL3_DEFAULT
73         ISAL_DEF_LVL3_DEFAULT,
74 #else
75         0,
76 #endif
77 #ifdef ISAL_DEF_LVL4_DEFAULT
78         ISAL_DEF_LVL4_DEFAULT,
79 #else
80         0,
81 #endif
82 #ifdef ISAL_DEF_LVL5_DEFAULT
83         ISAL_DEF_LVL5_DEFAULT,
84 #else
85         0,
86 #endif
87 #ifdef ISAL_DEF_LVL6_DEFAULT
88         ISAL_DEF_LVL6_DEFAULT,
89 #else
90         0,
91 #endif
92 #ifdef ISAL_DEF_LVL7_DEFAULT
93         ISAL_DEF_LVL7_DEFAULT,
94 #else
95         0,
96 #endif
97 #ifdef ISAL_DEF_LVL8_DEFAULT
98         ISAL_DEF_LVL8_DEFAULT,
99 #else
100         0,
101 #endif
102 #ifdef ISAL_DEF_LVL9_DEFAULT
103         ISAL_DEF_LVL9_DEFAULT,
104 #else
105         0,
106 #endif
107 };
108 
109 enum { ISAL_STATELESS, ISAL_STATEFUL, ISAL_WITH_DICTIONARY, ZLIB };
110 
111 struct compress_strategy {
112         int32_t mode;
113         int32_t level;
114 };
115 
116 struct inflate_modes {
117         int32_t stateless;
118         int32_t stateful;
119         int32_t zlib;
120 };
121 
122 struct perf_info {
123         char *file_name;
124         size_t file_size;
125         size_t deflate_size;
126         uint32_t inblock_size;
127         uint32_t flush_type;
128         int32_t hist_bits;
129         int32_t deflate_time;
130         int32_t inflate_time;
131         struct compress_strategy strategy;
132         uint32_t inflate_mode;
133         struct perf start;
134 };
135 
136 void
init_perf_info(struct perf_info * info)137 init_perf_info(struct perf_info *info)
138 {
139         memset(info, 0, sizeof(*info));
140         info->deflate_time = BENCHMARK_TIME;
141         info->inflate_time = BENCHMARK_TIME;
142 }
143 
144 int
usage(void)145 usage(void)
146 {
147         fprintf(stderr,
148                 "Usage: igzip_perf [options] <infile>\n"
149                 "  -h          help, print this message\n"
150                 "  The options -l, -f, -z may be used up to " xstr(
151                         COMPRESSION_QUEUE_LIMIT) " times\n"
152                                                  "  -l <level>  isa-l stateless deflate level to "
153                                                  "test (" xstr(ISAL_DEF_MIN_LEVEL) "-" xstr(
154                                                          ISAL_DEF_MAX_LEVEL) ")\n"
155                                                                              "  -f <level>  isa-l "
156                                                                              "stateful deflate "
157                                                                              "level to test (" xstr(ISAL_DEF_MIN_LEVEL) "-" xstr(
158                                                                                      ISAL_DEF_MAX_LEVEL) ")\n"
159                                                                                                          "  -z <level>  zlib  deflate level to test\n"
160                                                                                                          "  -d <time>   approx time in seconds for deflate (at least 0)\n"
161                                                                                                          "  -i <time>   approx time in seconds for inflate (at least 0)\n"
162                                                                                                          "  -s          performance test isa-l stateful inflate\n"
163                                                                                                          "  -t          performance test isa-l stateless inflate\n"
164                                                                                                          "  -u          performance test zlib inflate\n"
165                                                                                                          "  -D <file>   use dictionary file\n"
166                                                                                                          "  -o <file>   output file to store compressed data (last one if multiple)\n"
167                                                                                                          "  -b <size>   input buffer size, applies to stateful options (-f,-z,-s)\n"
168                                                                                                          "  -y <type>   flush type: 0 (default: no flush), 1 (sync flush), 2 (full flush)\n"
169                                                                                                          "  -w <size>   log base 2 size of history window, between 9 and 15\n");
170         exit(0);
171 }
172 
173 void
print_perf_info_line(struct perf_info * info)174 print_perf_info_line(struct perf_info *info)
175 {
176         printf("igzip_perf-> compress level: %d flush_type: %d block_size: %d\n",
177                info->strategy.level, info->flush_type, info->inblock_size);
178 }
179 
180 void
print_file_line(struct perf_info * info)181 print_file_line(struct perf_info *info)
182 {
183         printf("  file info-> name: %s file_size: %lu compress_size: %lu ratio: %2.02f%%\n",
184                info->file_name, info->file_size, info->deflate_size,
185                100.0 * info->deflate_size / info->file_size);
186 }
187 
188 void
print_deflate_perf_line(struct perf_info * info)189 print_deflate_perf_line(struct perf_info *info)
190 {
191         if (info->strategy.mode == ISAL_STATELESS)
192                 printf("    isal_stateless_deflate-> ");
193         else if (info->strategy.mode == ISAL_STATEFUL)
194                 printf("    isal_stateful_deflate->  ");
195         else if (info->strategy.mode == ISAL_WITH_DICTIONARY)
196                 printf("    isal_dictionary_deflate-> ");
197         else if (info->strategy.mode == ZLIB)
198                 printf("    zlib_deflate->           ");
199 
200         perf_print(info->start, info->file_size);
201 }
202 
203 void
print_inflate_perf_line(struct perf_info * info)204 print_inflate_perf_line(struct perf_info *info)
205 {
206         if (info->inflate_mode == ISAL_STATELESS)
207                 printf("    isal_stateless_inflate-> ");
208         else if (info->inflate_mode == ISAL_STATEFUL)
209                 printf("    isal_stateful_inflate->  ");
210         else if (info->inflate_mode == ISAL_WITH_DICTIONARY)
211                 printf("    isal_dictionary_inflate-> ");
212         else if (info->inflate_mode == ZLIB)
213                 printf("    zlib_inflate->           ");
214 
215         perf_print(info->start, info->file_size);
216 }
217 
218 int
isal_deflate_round(struct isal_zstream * stream,uint8_t * outbuf,uint32_t outbuf_size,uint8_t * inbuf,uint32_t inbuf_size,uint32_t level,uint8_t * level_buf,uint32_t level_buf_size,int flush_type,int hist_bits)219 isal_deflate_round(struct isal_zstream *stream, uint8_t *outbuf, uint32_t outbuf_size,
220                    uint8_t *inbuf, uint32_t inbuf_size, uint32_t level, uint8_t *level_buf,
221                    uint32_t level_buf_size, int flush_type, int hist_bits)
222 {
223         int check;
224 
225         /* Setup stream for stateless compression */
226         isal_deflate_init(stream);
227         stream->end_of_stream = 1; /* Do the entire file at once */
228         stream->flush = flush_type;
229         stream->next_in = inbuf;
230         stream->avail_in = inbuf_size;
231         stream->next_out = outbuf;
232         stream->avail_out = outbuf_size;
233         stream->level = level;
234         stream->level_buf = level_buf;
235         stream->level_buf_size = level_buf_size;
236         stream->hist_bits = hist_bits;
237 
238         /* Compress stream */
239         check = isal_deflate_stateless(stream);
240 
241         /* Verify compression success */
242         if (check || stream->avail_in)
243                 return 1;
244 
245         return 0;
246 }
247 
248 int
isal_deflate_dict_round(struct isal_zstream * stream,uint8_t * outbuf,uint32_t outbuf_size,uint8_t * inbuf,uint32_t inbuf_size,uint32_t level,uint8_t * level_buf,uint32_t level_buf_size,int flush_type,int hist_bits,struct isal_dict * dict_str)249 isal_deflate_dict_round(struct isal_zstream *stream, uint8_t *outbuf, uint32_t outbuf_size,
250                         uint8_t *inbuf, uint32_t inbuf_size, uint32_t level, uint8_t *level_buf,
251                         uint32_t level_buf_size, int flush_type, int hist_bits,
252                         struct isal_dict *dict_str)
253 {
254         int check;
255 
256         /* Setup stream for compression with dictionary */
257         isal_deflate_init(stream);
258         stream->level = level;
259         stream->level_buf = level_buf;
260         stream->level_buf_size = level_buf_size;
261 
262         if (COMP_OK != isal_deflate_reset_dict(stream, dict_str))
263                 return 1;
264 
265         stream->end_of_stream = 1;
266         stream->flush = flush_type;
267         stream->next_in = inbuf;
268         stream->avail_in = inbuf_size;
269         stream->next_out = outbuf;
270         stream->avail_out = outbuf_size;
271         stream->hist_bits = hist_bits;
272 
273         check = isal_deflate(stream);
274 
275         /* Verify Compression Success */
276         if (COMP_OK != check || stream->avail_in > 0)
277                 return 1;
278 
279         return 0;
280 }
281 
282 int
isal_inflate_round(struct inflate_state * state,uint8_t * inbuf,uint32_t inbuf_size,uint8_t * outbuf,uint32_t outbuf_size,int hist_bits)283 isal_inflate_round(struct inflate_state *state, uint8_t *inbuf, uint32_t inbuf_size,
284                    uint8_t *outbuf, uint32_t outbuf_size, int hist_bits)
285 {
286         int check = 0;
287 
288         /* Setup for stateless inflate */
289         state->next_in = inbuf;
290         state->avail_in = inbuf_size;
291         state->next_out = outbuf;
292         state->avail_out = outbuf_size;
293         state->crc_flag = ISAL_DEFLATE;
294         state->hist_bits = hist_bits;
295 
296         /* Inflate data */
297         check = isal_inflate_stateless(state);
298 
299         /* Verify inflate was successful */
300         if (check)
301                 return 1;
302 
303         return 0;
304 }
305 
306 int
isal_deflate_stateful_round(struct isal_zstream * stream,uint8_t * outbuf,uint32_t outbuf_size,uint8_t * inbuf,uint32_t inbuf_size,uint32_t in_block_size,uint32_t level,uint8_t * level_buf,uint32_t level_buf_size,int flush_type,int hist_bits)307 isal_deflate_stateful_round(struct isal_zstream *stream, uint8_t *outbuf, uint32_t outbuf_size,
308                             uint8_t *inbuf, uint32_t inbuf_size, uint32_t in_block_size,
309                             uint32_t level, uint8_t *level_buf, uint32_t level_buf_size,
310                             int flush_type, int hist_bits)
311 {
312         uint64_t inbuf_remaining;
313         int check = COMP_OK;
314 
315         /* Setup stream for stateful compression */
316         inbuf_remaining = inbuf_size;
317         isal_deflate_init(stream);
318         stream->flush = flush_type;
319         stream->next_in = inbuf;
320         stream->next_out = outbuf;
321         stream->avail_out = outbuf_size;
322         stream->level = level;
323         stream->level_buf = level_buf;
324         stream->level_buf_size = level_buf_size;
325         stream->hist_bits = hist_bits;
326 
327         /* Keep compressing so long as more data is available and no error has
328          * been hit */
329         while (COMP_OK == check && inbuf_remaining > in_block_size) {
330                 /* Setup next in buffer, assumes out buffer is sufficiently
331                  * large */
332                 stream->avail_in = in_block_size;
333                 inbuf_remaining -= in_block_size;
334 
335                 /* Compress stream */
336                 check = isal_deflate(stream);
337         }
338 
339         /* Finish compressing all remaining input */
340         if (COMP_OK == check) {
341                 stream->avail_in = inbuf_remaining;
342                 stream->end_of_stream = 1;
343                 check = isal_deflate(stream);
344         }
345 
346         /* Verify Compression Success */
347         if (COMP_OK != check || stream->avail_in > 0)
348                 return 1;
349 
350         return 0;
351 }
352 
353 int
isal_inflate_stateful_round(struct inflate_state * state,uint8_t * inbuf,uint32_t inbuf_size,uint32_t in_block_size,uint8_t * outbuf,uint32_t outbuf_size,int hist_bits,uint8_t * dict_buf,int dict_file_size)354 isal_inflate_stateful_round(struct inflate_state *state, uint8_t *inbuf, uint32_t inbuf_size,
355                             uint32_t in_block_size, uint8_t *outbuf, uint32_t outbuf_size,
356                             int hist_bits, uint8_t *dict_buf, int dict_file_size)
357 {
358         int check = ISAL_DECOMP_OK;
359         uint64_t inbuf_remaining;
360 
361         isal_inflate_init(state);
362         state->next_in = inbuf;
363         state->next_out = outbuf;
364         state->avail_out = outbuf_size;
365         state->hist_bits = hist_bits;
366         if (dict_file_size != 0)
367                 isal_inflate_set_dict(state, dict_buf, dict_file_size);
368 
369         inbuf_remaining = inbuf_size;
370 
371         while (ISAL_DECOMP_OK == check && inbuf_remaining >= in_block_size) {
372                 state->avail_in = in_block_size;
373                 inbuf_remaining -= in_block_size;
374                 check = isal_inflate(state);
375         }
376         if (ISAL_DECOMP_OK == check && inbuf_remaining > 0) {
377                 state->avail_in = inbuf_remaining;
378                 check = isal_inflate(state);
379         }
380 
381         if (ISAL_DECOMP_OK != check || state->avail_in > 0)
382                 return 1;
383 
384         return 0;
385 }
386 
387 int
zlib_deflate_round(z_stream * gstream,uint8_t * outbuf,uInt outbuf_size,uint8_t * inbuf,uLong inbuf_size,uLong in_block_size,int level,int flush_type)388 zlib_deflate_round(z_stream *gstream, uint8_t *outbuf, uInt outbuf_size, uint8_t *inbuf,
389                    uLong inbuf_size, uLong in_block_size, int level, int flush_type)
390 {
391         uLong inbuf_remaining;
392         int check = Z_OK;
393 
394         inbuf_remaining = inbuf_size;
395 
396         /* Setup stream for stateful compression */
397         if (0 != deflateReset(gstream))
398                 return 1;
399 
400         gstream->next_in = inbuf;
401         gstream->next_out = outbuf;
402         gstream->avail_out = outbuf_size;
403 
404         /* Keep compressing so long as more data is available and no error has
405          * been hit */
406         while (Z_OK == check && inbuf_remaining > in_block_size) {
407                 gstream->avail_in = in_block_size;
408                 inbuf_remaining -= in_block_size;
409                 check = deflate(gstream, flush_type);
410         }
411 
412         /* Finish compressing all remaining input */
413         if (Z_OK == check) {
414                 gstream->avail_in = inbuf_remaining;
415                 check = deflate(gstream, Z_FINISH);
416         }
417 
418         /* Verify Compression Success */
419         if (Z_STREAM_END != check)
420                 return 1;
421 
422         return 0;
423 }
424 
425 int
zlib_inflate_round(z_stream * gstream,uint8_t * inbuf,uLong inbuf_size,uint8_t * outbuf,uInt outbuf_size)426 zlib_inflate_round(z_stream *gstream, uint8_t *inbuf, uLong inbuf_size, uint8_t *outbuf,
427                    uInt outbuf_size)
428 {
429         int check = 0;
430 
431         if (0 != inflateReset(gstream))
432                 return 1;
433 
434         gstream->next_in = inbuf;
435         gstream->avail_in = inbuf_size;
436         gstream->next_out = outbuf;
437         gstream->avail_out = outbuf_size;
438         check = inflate(gstream, Z_FINISH);
439         if (check != Z_STREAM_END)
440                 return 1;
441 
442         return 0;
443 }
444 
445 int
isal_deflate_perf(uint8_t * outbuf,uint64_t * outbuf_size,uint8_t * inbuf,uint64_t inbuf_size,int level,int flush_type,int hist_bits,int time,struct perf * start)446 isal_deflate_perf(uint8_t *outbuf, uint64_t *outbuf_size, uint8_t *inbuf, uint64_t inbuf_size,
447                   int level, int flush_type, int hist_bits, int time, struct perf *start)
448 {
449         struct isal_zstream stream;
450         uint8_t *level_buf = NULL;
451         int check;
452 
453         if (level_size_buf[level] > 0) {
454                 level_buf = malloc(level_size_buf[level]);
455                 if (level_buf == NULL)
456                         return 1;
457         }
458 
459         BENCHMARK(start, time,
460                   check = isal_deflate_round(&stream, outbuf, *outbuf_size, inbuf, inbuf_size,
461                                              level, level_buf, level_size_buf[level], flush_type,
462                                              hist_bits));
463         *outbuf_size = stream.total_out;
464         return check;
465 }
466 
467 int
isal_deflate_dict_perf(uint8_t * outbuf,uint64_t * outbuf_size,uint8_t * inbuf,uint64_t inbuf_size,int level,int flush_type,int hist_bits,int time,struct perf * start,uint8_t * dict_buf,int dict_file_size)468 isal_deflate_dict_perf(uint8_t *outbuf, uint64_t *outbuf_size, uint8_t *inbuf, uint64_t inbuf_size,
469                        int level, int flush_type, int hist_bits, int time, struct perf *start,
470                        uint8_t *dict_buf, int dict_file_size)
471 {
472         struct isal_zstream stream;
473         struct isal_dict dict_str;
474         uint8_t *level_buf = NULL;
475         int check;
476 
477         if (level_size_buf[level] > 0) {
478                 level_buf = malloc(level_size_buf[level]);
479                 if (level_buf == NULL)
480                         return 1;
481         }
482 
483         stream.level = level;
484         if (isal_deflate_process_dict(&stream, &dict_str, dict_buf, dict_file_size) != COMP_OK) {
485                 if (level_buf != NULL)
486                         free(level_buf);
487                 return 1;
488         }
489 
490         BENCHMARK(start, time,
491                   check = isal_deflate_dict_round(&stream, outbuf, *outbuf_size, inbuf, inbuf_size,
492                                                   level, level_buf, level_size_buf[level],
493                                                   flush_type, hist_bits, &dict_str));
494         if (level_buf != NULL)
495                 free(level_buf);
496         *outbuf_size = stream.total_out;
497         return check;
498 }
499 
500 int
isal_deflate_stateful_perf(uint8_t * outbuf,uint64_t * outbuf_size,uint8_t * inbuf,uint64_t inbuf_size,int level,int flush_type,uint64_t in_block_size,int hist_bits,int time,struct perf * start)501 isal_deflate_stateful_perf(uint8_t *outbuf, uint64_t *outbuf_size, uint8_t *inbuf,
502                            uint64_t inbuf_size, int level, int flush_type, uint64_t in_block_size,
503                            int hist_bits, int time, struct perf *start)
504 {
505         struct isal_zstream stream;
506         uint8_t *level_buf = NULL;
507         int check;
508 
509         if (in_block_size == 0)
510                 in_block_size = inbuf_size;
511 
512         if (level_size_buf[level] > 0) {
513                 level_buf = malloc(level_size_buf[level]);
514                 if (level_buf == NULL)
515                         return 1;
516         }
517 
518         BENCHMARK(start, time,
519                   check = isal_deflate_stateful_round(
520                           &stream, outbuf, *outbuf_size, inbuf, inbuf_size, in_block_size, level,
521                           level_buf, level_size_buf[level], flush_type, hist_bits));
522         *outbuf_size = stream.total_out;
523         return check;
524 }
525 
526 int
zlib_deflate_perf(uint8_t * outbuf,uint64_t * outbuf_size,uint8_t * inbuf,uint64_t inbuf_size,int level,int flush_type,uint64_t in_block_size,int hist_bits,int time,struct perf * start)527 zlib_deflate_perf(uint8_t *outbuf, uint64_t *outbuf_size, uint8_t *inbuf, uint64_t inbuf_size,
528                   int level, int flush_type, uint64_t in_block_size, int hist_bits, int time,
529                   struct perf *start)
530 {
531         int check;
532         z_stream gstream;
533         int flush_translator[] = { Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH };
534 
535         if (in_block_size == 0)
536                 in_block_size = inbuf_size;
537 
538         flush_type = flush_translator[flush_type];
539 
540         /* Initialize the gstream buffer */
541         gstream.next_in = inbuf;
542         gstream.avail_in = inbuf_size;
543         gstream.zalloc = Z_NULL;
544         gstream.zfree = Z_NULL;
545         gstream.opaque = Z_NULL;
546 
547         if (hist_bits == 0)
548                 hist_bits = -15;
549         else
550                 hist_bits = -hist_bits;
551 
552         if (0 != deflateInit2(&gstream, level, Z_DEFLATED, hist_bits, 9, Z_DEFAULT_STRATEGY))
553                 return 1;
554 
555         BENCHMARK(start, time,
556                   check = zlib_deflate_round(&gstream, outbuf, *outbuf_size, inbuf, inbuf_size,
557                                              in_block_size, level, flush_type));
558 
559         *outbuf_size = gstream.total_out;
560         deflateEnd(&gstream);
561 
562         return check;
563 }
564 
565 int
isal_inflate_perf(uint8_t * inbuf,uint64_t inbuf_size,uint8_t * outbuf,uint64_t outbuf_size,uint8_t * filebuf,uint64_t file_size,int hist_bits,int time,struct perf * start)566 isal_inflate_perf(uint8_t *inbuf, uint64_t inbuf_size, uint8_t *outbuf, uint64_t outbuf_size,
567                   uint8_t *filebuf, uint64_t file_size, int hist_bits, int time, struct perf *start)
568 {
569         struct inflate_state state;
570         int check;
571 
572         /* Check that data decompresses */
573         check = isal_inflate_round(&state, inbuf, inbuf_size, outbuf, outbuf_size, hist_bits);
574         if (check || state.total_out != file_size || memcmp(outbuf, filebuf, file_size))
575                 return 1;
576 
577         BENCHMARK(start, time,
578                   isal_inflate_round(&state, inbuf, inbuf_size, outbuf, outbuf_size, hist_bits));
579 
580         return check;
581 }
582 
583 int
isal_inflate_stateful_perf(uint8_t * inbuf,uint64_t inbuf_size,uint8_t * outbuf,uint64_t outbuf_size,uint8_t * filebuf,uint64_t file_size,uint64_t in_block_size,int hist_bits,int time,struct perf * start,uint8_t * dict_buf,int dict_file_size)584 isal_inflate_stateful_perf(uint8_t *inbuf, uint64_t inbuf_size, uint8_t *outbuf,
585                            uint64_t outbuf_size, uint8_t *filebuf, uint64_t file_size,
586                            uint64_t in_block_size, int hist_bits, int time, struct perf *start,
587                            uint8_t *dict_buf, int dict_file_size)
588 {
589         struct inflate_state state;
590         int check;
591 
592         if (in_block_size == 0)
593                 in_block_size = inbuf_size;
594 
595         check = isal_inflate_stateful_round(&state, inbuf, inbuf_size, in_block_size, outbuf,
596                                             outbuf_size, hist_bits, dict_buf, dict_file_size);
597         if (check || state.total_out != file_size || memcmp(outbuf, filebuf, file_size))
598                 return 1;
599 
600         BENCHMARK(start, time,
601                   isal_inflate_stateful_round(&state, inbuf, inbuf_size, in_block_size, outbuf,
602                                               outbuf_size, hist_bits, dict_buf, dict_file_size));
603 
604         return 0;
605 }
606 
607 int
zlib_inflate_perf(uint8_t * inbuf,uint64_t inbuf_size,uint8_t * outbuf,uint64_t outbuf_size,uint8_t * filebuf,uint64_t file_size,int hist_bits,int time,struct perf * start)608 zlib_inflate_perf(uint8_t *inbuf, uint64_t inbuf_size, uint8_t *outbuf, uint64_t outbuf_size,
609                   uint8_t *filebuf, uint64_t file_size, int hist_bits, int time, struct perf *start)
610 {
611         int check;
612         z_stream gstream;
613 
614         gstream.next_in = inbuf;
615         gstream.avail_in = inbuf_size;
616         gstream.zalloc = Z_NULL;
617         gstream.zfree = Z_NULL;
618         gstream.opaque = Z_NULL;
619 
620         if (hist_bits == 0)
621                 hist_bits = -15;
622         else
623                 hist_bits = -hist_bits;
624 
625         if (0 != inflateInit2(&gstream, hist_bits))
626                 return 1;
627 
628         check = zlib_inflate_round(&gstream, inbuf, inbuf_size, outbuf, outbuf_size);
629         if (check || gstream.total_out != file_size || memcmp(outbuf, filebuf, file_size))
630                 return 1;
631 
632         BENCHMARK(start, time,
633                   zlib_inflate_round(&gstream, inbuf, inbuf_size, outbuf, outbuf_size));
634 
635         inflateEnd(&gstream);
636         return 0;
637 }
638 
639 int
main(int argc,char * argv[])640 main(int argc, char *argv[])
641 {
642         FILE *in = NULL;
643         FILE *dict_fn = NULL;
644         unsigned char *compressbuf, *decompbuf, *filebuf;
645         char *outfile = NULL;
646         int i, c, ret = 0;
647         int dict_file_size = 0;
648         uint8_t *dict_buf = NULL;
649         uint64_t decompbuf_size, compressbuf_size;
650         uint64_t block_count;
651 
652         struct compress_strategy compression_queue[COMPRESSION_QUEUE_LIMIT];
653 
654         int compression_queue_size = 0;
655         struct compress_strategy compress_strat;
656         struct inflate_modes inflate_strat = { 0 };
657         struct perf_info info;
658         init_perf_info(&info);
659 
660         while ((c = getopt(argc, argv, OPTARGS)) != -1) {
661                 switch (c) {
662                 case 'l':
663                         if (compression_queue_size >= COMPRESSION_QUEUE_LIMIT) {
664                                 printf("Too many levels specified");
665                                 exit(0);
666                         }
667 
668                         compress_strat.mode = ISAL_STATELESS;
669                         compress_strat.level = atoi(optarg);
670                         if (compress_strat.level > ISAL_DEF_MAX_LEVEL) {
671                                 printf("Unsupported isa-l compression level\n");
672                                 exit(0);
673                         }
674 
675                         compression_queue[compression_queue_size] = compress_strat;
676                         compression_queue_size++;
677                         break;
678                 case 'f':
679                         if (compression_queue_size >= COMPRESSION_QUEUE_LIMIT) {
680                                 printf("Too many levels specified");
681                                 exit(0);
682                         }
683 
684                         compress_strat.mode = ISAL_STATEFUL;
685                         compress_strat.level = atoi(optarg);
686                         if (compress_strat.level > ISAL_DEF_MAX_LEVEL) {
687                                 printf("Unsupported isa-l compression level\n");
688                                 exit(0);
689                         }
690 
691                         compression_queue[compression_queue_size] = compress_strat;
692                         compression_queue_size++;
693                         break;
694                 case 'z':
695                         if (compression_queue_size >= COMPRESSION_QUEUE_LIMIT) {
696                                 printf("Too many levels specified");
697                                 exit(0);
698                         }
699 
700                         compress_strat.mode = ZLIB;
701                         compress_strat.level = atoi(optarg);
702                         if (compress_strat.level > Z_BEST_COMPRESSION) {
703                                 printf("Unsupported zlib compression level\n");
704                                 exit(0);
705                         }
706                         compression_queue[compression_queue_size] = compress_strat;
707                         compression_queue_size++;
708                         break;
709                 case 'i':
710                         info.inflate_time = atoi(optarg);
711                         if (info.inflate_time < 0)
712                                 usage();
713                         break;
714                 case 'd':
715                         info.deflate_time = atoi(optarg);
716                         if (info.deflate_time < 0)
717                                 usage();
718                         break;
719                 case 'D':
720                         dict_fn = fopen(optarg, "rb");
721                         if (!dict_fn) {
722                                 printf("Can't open dictionary for reading\n");
723                                 exit(0);
724                         }
725                         dict_file_size = get_filesize(dict_fn);
726                         dict_buf = malloc(dict_file_size);
727                         if (dict_buf == NULL || dict_file_size == 0) {
728                                 printf("Can't allocate mem for dictionary buffer\n");
729                                 exit(0);
730                         }
731                         if (dict_file_size != fread(dict_buf, 1, dict_file_size, dict_fn)) {
732                                 printf("Couldn't read all of dictionary file\n");
733                                 exit(0);
734                         }
735                         fclose(dict_fn);
736                         break;
737                 case 's':
738                         inflate_strat.stateful = 1;
739                         break;
740                 case 't':
741                         inflate_strat.stateless = 1;
742                         break;
743                 case 'u':
744                         inflate_strat.zlib = 1;
745                         break;
746                 case 'b':
747                         inflate_strat.stateful = 1;
748                         info.inblock_size = atoi(optarg);
749                         break;
750                 case 'y':
751                         info.flush_type = atoi(optarg);
752                         if (info.flush_type != NO_FLUSH && info.flush_type != SYNC_FLUSH &&
753                             info.flush_type != FULL_FLUSH) {
754                                 printf("Unsupported flush type\n");
755                                 exit(0);
756                         }
757                         break;
758 
759                 case 'w':
760                         info.hist_bits = atoi(optarg);
761                         if (info.hist_bits > 15 || info.hist_bits < 9)
762                                 usage();
763                         break;
764                 case 'o':
765                         outfile = optarg;
766                         break;
767                 case 'h':
768                 default:
769                         usage();
770                         break;
771                 }
772         }
773 
774         if (optind >= argc)
775                 usage();
776 
777         if (!inflate_strat.stateless && !inflate_strat.stateful && !inflate_strat.zlib) {
778                 if (info.inblock_size == 0)
779                         inflate_strat.stateless = 1;
780                 else
781                         inflate_strat.stateful = 1;
782         }
783 
784         /* Allocate space for entire input file and output
785          * (assuming some possible expansion on output size)
786          */
787         info.file_name = argv[optind];
788         in = fopen(info.file_name, "rb");
789         if (NULL == in) {
790                 printf("Error: Can not find file %s\n", info.file_name);
791                 exit(0);
792         }
793 
794         info.file_size = get_filesize(in);
795         if (info.file_size == 0) {
796                 printf("Error: input file has 0 size\n");
797                 exit(0);
798         }
799 
800         decompbuf_size = info.file_size;
801 
802         if (compression_queue_size == 0) {
803                 if (info.inblock_size == 0)
804                         compression_queue[0].mode = ISAL_STATELESS;
805                 else
806                         compression_queue[0].mode = ISAL_STATEFUL;
807                 compression_queue[0].level = 1;
808                 compression_queue_size = 1;
809         }
810 
811         filebuf = malloc(info.file_size);
812         if (filebuf == NULL) {
813                 fprintf(stderr, "Can't allocate temp buffer memory\n");
814                 exit(0);
815         }
816 
817         block_count = 1;
818         if (info.flush_type > 0)
819                 block_count = (info.file_size + info.inblock_size - 1) / info.inblock_size;
820 
821         /* Way overestimate likely compressed size to handle bad type 0 and
822          * small block_size case */
823         compressbuf_size = block_count * ISAL_DEF_MAX_HDR_SIZE + 2 * info.file_size;
824         if (compressbuf_size >= MAX_COMPRESS_BUF_SIZE)
825                 compressbuf_size = MAX_COMPRESS_BUF_SIZE;
826 
827         compressbuf = malloc(compressbuf_size);
828         if (compressbuf == NULL) {
829                 fprintf(stderr, "Can't allocate input buffer memory\n");
830                 exit(0);
831         }
832 
833         decompbuf = malloc(decompbuf_size);
834         if (decompbuf == NULL) {
835                 fprintf(stderr, "Can't allocate output buffer memory\n");
836                 exit(0);
837         }
838 
839         if (info.file_size != fread(filebuf, 1, info.file_size, in)) {
840                 fprintf(stderr, "Could not read in all input\n");
841                 exit(0);
842         }
843         fclose(in);
844 
845         for (i = 0; i < compression_queue_size; i++) {
846                 if (i > 0)
847                         printf("\n\n");
848 
849                 info.strategy = compression_queue[i];
850                 print_perf_info_line(&info);
851 
852                 info.deflate_size = compressbuf_size;
853 
854                 if (dict_file_size != 0) {
855                         info.strategy.mode = ISAL_WITH_DICTIONARY;
856                         ret = isal_deflate_dict_perf(
857                                 compressbuf, &info.deflate_size, filebuf, info.file_size,
858                                 compression_queue[i].level, info.flush_type, info.hist_bits,
859                                 info.deflate_time, &info.start, dict_buf, dict_file_size);
860                 } else if (info.strategy.mode == ISAL_STATELESS)
861                         ret = isal_deflate_perf(compressbuf, &info.deflate_size, filebuf,
862                                                 info.file_size, compression_queue[i].level,
863                                                 info.flush_type, info.hist_bits, info.deflate_time,
864                                                 &info.start);
865 
866                 else if (info.strategy.mode == ISAL_STATEFUL)
867                         ret = isal_deflate_stateful_perf(
868                                 compressbuf, &info.deflate_size, filebuf, info.file_size,
869                                 compression_queue[i].level, info.flush_type, info.inblock_size,
870                                 info.hist_bits, info.deflate_time, &info.start);
871                 else if (info.strategy.mode == ZLIB)
872                         ret = zlib_deflate_perf(compressbuf, &info.deflate_size, filebuf,
873                                                 info.file_size, compression_queue[i].level,
874                                                 info.flush_type, info.inblock_size, info.hist_bits,
875                                                 info.deflate_time, &info.start);
876                 if (ret) {
877                         printf("  Error in compression\n");
878                         continue;
879                 }
880 
881                 print_file_line(&info);
882                 printf("\n");
883                 print_deflate_perf_line(&info);
884                 printf("\n");
885 
886                 if (outfile != NULL && i + 1 == compression_queue_size) {
887                         FILE *out = fopen(outfile, "wb");
888 
889                         if (out == NULL) {
890                                 fprintf(stderr, "Could not write to the output file \"%s\"\n",
891                                         outfile);
892                                 exit(0);
893                         }
894                         fwrite(compressbuf, 1, info.deflate_size, out);
895                         fclose(out);
896                 }
897 
898                 if (info.inflate_time == 0)
899                         continue;
900 
901                 if (inflate_strat.stateless) {
902                         if (dict_file_size != 0)
903                                 continue;
904 
905                         info.inflate_mode = ISAL_STATELESS;
906                         ret = isal_inflate_perf(compressbuf, info.deflate_size, decompbuf,
907                                                 decompbuf_size, filebuf, info.file_size,
908                                                 info.hist_bits, info.inflate_time, &info.start);
909                         if (ret)
910                                 printf("    Error in isal stateless inflate\n");
911                         else
912                                 print_inflate_perf_line(&info);
913                 }
914 
915                 if (inflate_strat.stateful) {
916                         info.inflate_mode =
917                                 (dict_file_size == 0) ? ISAL_STATEFUL : ISAL_WITH_DICTIONARY;
918 
919                         ret = isal_inflate_stateful_perf(
920                                 compressbuf, info.deflate_size, decompbuf, decompbuf_size, filebuf,
921                                 info.file_size, info.inblock_size, info.hist_bits,
922                                 info.inflate_time, &info.start, dict_buf, dict_file_size);
923 
924                         if (ret)
925                                 printf("    Error in isal stateful inflate\n");
926                         else
927                                 print_inflate_perf_line(&info);
928                 }
929 
930                 if (inflate_strat.zlib) {
931                         info.inflate_mode = ZLIB;
932                         ret = zlib_inflate_perf(compressbuf, info.deflate_size, decompbuf,
933                                                 decompbuf_size, filebuf, info.file_size,
934                                                 info.hist_bits, info.inflate_time, &info.start);
935                         if (ret)
936                                 printf("    Error in zlib inflate\n");
937                         else
938                                 print_inflate_perf_line(&info);
939                 }
940         }
941 
942         free(compressbuf);
943         free(decompbuf);
944         free(filebuf);
945         if (dict_buf != NULL)
946                 free(dict_buf);
947         return 0;
948 }
949