diff --git a/igzip/Makefile.am b/igzip/Makefile.am index a060b0a..85d0c05 100644 --- a/igzip/Makefile.am +++ b/igzip/Makefile.am @@ -59,7 +59,8 @@ lsrc_x86_64 += \ igzip/igzip_inflate_multibinary.asm \ igzip/encode_df_04.asm \ igzip/encode_df_06.asm \ - igzip/proc_heap.asm + igzip/proc_heap.asm \ + igzip/igzip_deflate_hash.asm src_include += -I $(srcdir)/igzip extern_hdrs += include/igzip_lib.h diff --git a/igzip/data_struct2.asm b/igzip/data_struct2.asm index 06ef8f5..56d304f 100644 --- a/igzip/data_struct2.asm +++ b/igzip/data_struct2.asm @@ -222,4 +222,10 @@ _STORED_BLK equ 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +IGZIP_NO_HIST equ 0 +IGZIP_HIST equ 1 +IGZIP_DICT_HIST equ 2 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/igzip/igzip.c b/igzip/igzip.c index 4ba52e7..189955c 100644 --- a/igzip/igzip.c +++ b/igzip/igzip.c @@ -66,6 +66,7 @@ # define to_be32(x) _byteswap_ulong(x) #endif +extern void isal_deflate_hash_lvl0(struct isal_zstream *stream, uint8_t * dict, int dict_len); extern const uint8_t gzip_hdr[]; extern const uint32_t gzip_hdr_bytes; extern const uint32_t gzip_trl_bytes; @@ -125,6 +126,9 @@ struct slver isal_deflate_stateless_slver = { 0x0083, 0x01, 0x01 }; struct slver isal_deflate_set_hufftables_slver_00_01_008b; struct slver isal_deflate_set_hufftables_slver = { 0x008b, 0x01, 0x00 }; +struct slver isal_deflate_set_dict_slver_00_01_008c; +struct slver isal_deflate_set_dict_slver = { 0x008c, 0x01, 0x00 }; + /*****************************************************************/ // isal_adler32_bam1 - adler with (B | A minus 1) storage @@ -188,7 +192,7 @@ void sync_flush(struct isal_zstream *stream) if (stream->flush == FULL_FLUSH) { /* Clear match history so there are no cross * block length distance pairs */ - reset_match_history(stream); + state->has_hist = IGZIP_NO_HIST; } } } @@ -757,7 +761,7 @@ static inline void reset_match_history(struct isal_zstream *stream) uint16_t *head = stream->internal_state.head; int i = 0; - state->has_hist = 0; + state->has_hist = IGZIP_NO_HIST; if ((stream->total_in & 0xFFFF) == 0) memset(stream->internal_state.head, 0, sizeof(stream->internal_state.head)); @@ -786,21 +790,17 @@ void isal_deflate_init(struct isal_zstream *stream) state->b_bytes_processed = 0; state->has_eob = 0; state->has_eob_hdr = 0; - state->has_hist = 0; + state->has_hist = IGZIP_NO_HIST; state->state = ZSTATE_NEW_HDR; state->count = 0; state->tmp_out_start = 0; state->tmp_out_end = 0; - state->file_start = stream->next_in; - init(&state->bitbuf); state->crc = 0; - memset(state->head, 0, sizeof(state->head)); - return; } @@ -844,6 +844,40 @@ void isal_deflate_stateless_init(struct isal_zstream *stream) return; } +void isal_deflate_hash(struct isal_zstream *stream, uint8_t * dict, uint32_t dict_len) +{ + isal_deflate_hash_lvl0(stream, dict, dict_len); + stream->internal_state.has_hist = IGZIP_HIST; +} + +int isal_deflate_set_dict(struct isal_zstream *stream, uint8_t * dict, uint32_t dict_len) +{ + struct isal_zstate *state = &stream->internal_state; + + if (state->state != ZSTATE_NEW_HDR || state->b_bytes_processed != state->b_bytes_valid) + return ISAL_INVALID_STATE; + + if (dict_len <= 0) + return COMP_OK; + + if (dict_len > IGZIP_HIST_SIZE) { + dict = dict + dict_len - IGZIP_HIST_SIZE; + dict_len = IGZIP_HIST_SIZE; + } + + memcpy(state->buffer, dict, dict_len); + state->b_bytes_processed = dict_len; + state->b_bytes_valid = dict_len; + + /* Reset history to prevent out of bounds matches this works because + * dictionary must set at least 1 element in the history */ + memset(stream->internal_state.head, -1, sizeof(stream->internal_state.head)); + + state->has_hist = IGZIP_DICT_HIST; + + return COMP_OK; +} + int isal_deflate_stateless(struct isal_zstream *stream) { uint8_t *next_in = stream->next_in; @@ -963,6 +997,11 @@ int isal_deflate(struct isal_zstream *stream) avail_in = stream->avail_in; stream->total_in -= state->b_bytes_valid - state->b_bytes_processed; + if (state->has_hist == IGZIP_NO_HIST) + reset_match_history(stream); + else if (state->has_hist == IGZIP_DICT_HIST) + isal_deflate_hash(stream, state->buffer, state->b_bytes_processed); + do { size = avail_in; if (size > sizeof(state->buffer) - state->b_bytes_valid) { diff --git a/igzip/igzip_base.c b/igzip/igzip_base.c index 0e2b705..d5720eb 100644 --- a/igzip/igzip_base.c +++ b/igzip/igzip_base.c @@ -208,3 +208,22 @@ void isal_deflate_finish_base(struct isal_zstream *stream) return; } + +void isal_deflate_hash_lvl0_base(struct isal_zstream *stream, uint8_t * dict, + uint32_t dict_len) +{ + uint8_t *next_in = dict; + uint8_t *end_in = dict + dict_len - SHORTEST_MATCH; + uint32_t literal; + uint32_t hash; + uint16_t lookup_val = stream->total_in - dict_len; + uint16_t *last_seen = stream->internal_state.head; + + while (next_in <= end_in) { + literal = *(uint32_t *) next_in; + hash = compute_hash(literal) & HASH_MASK; + last_seen[hash] = lookup_val; + lookup_val++; + next_in++; + } +} diff --git a/igzip/igzip_base_aliases.c b/igzip/igzip_base_aliases.c index 92b550f..ad2a406 100644 --- a/igzip/igzip_base_aliases.c +++ b/igzip/igzip_base_aliases.c @@ -43,6 +43,8 @@ struct deflate_icf *encode_deflate_icf_base(struct deflate_icf *next_in, uint32_t crc32_gzip_base(uint32_t init_crc, const unsigned char *buf, uint64_t len); uint32_t adler32_base(uint32_t init, const unsigned char *buf, uint64_t len); int decode_huffman_code_block_stateless_base(struct inflate_state *s); +void isal_deflate_hash_lvl0_base(struct isal_zstream *stream, uint8_t * dict, + uint32_t dict_len); void isal_deflate_body(struct isal_zstream *stream) { @@ -91,3 +93,8 @@ int decode_huffman_code_block_stateless(struct inflate_state *s) { return decode_huffman_code_block_stateless_base(s); } + +void isal_deflate_hash_lvl0(struct isal_zstream *stream, uint8_t * dict, uint32_t dict_len) +{ + return isal_deflate_hash_lvl0_base(stream, dict, dict_len); +} diff --git a/igzip/igzip_body.asm b/igzip/igzip_body.asm index e588af6..3a84d02 100644 --- a/igzip/igzip_body.asm +++ b/igzip/igzip_body.asm @@ -212,7 +212,7 @@ MARK __body_compute_hash_ %+ ARCH and hash, HASH_MASK and hash2, HASH_MASK - cmp dword [stream + _internal_state_has_hist], 0 + cmp dword [stream + _internal_state_has_hist], IGZIP_NO_HIST je write_first_byte jmp loop2 @@ -545,7 +545,7 @@ write_first_byte: cmp m_out_buf, [stream + _internal_state_bitbuf_m_out_end] ja output_end - mov dword [stream + _internal_state_has_hist], 1 + mov dword [stream + _internal_state_has_hist], IGZIP_HIST mov [stream + _internal_state_head + 2 * hash], f_i %+ w diff --git a/igzip/igzip_decode_block_stateless.asm b/igzip/igzip_decode_block_stateless.asm index b048223..7f92c63 100644 --- a/igzip/igzip_decode_block_stateless.asm +++ b/igzip/igzip_decode_block_stateless.asm @@ -363,6 +363,7 @@ decode_huffman_code_block_stateless_ %+ ARCH %+ : mov dword [state + _copy_overflow_dist], 0 mov tmp3 %+ d, dword [state + _total_out] + add tmp3 %+ d, dword [state + _dict_length] sub tmp3, next_out neg tmp3 @@ -658,6 +659,7 @@ end: sub end_out, next_out mov dword [state + _avail_out], end_out %+ d sub next_out, [rsp + start_out_mem_offset] + sub next_out %+ d, [state + _dict_length] mov [state + _total_out], next_out %+ d mov [state + _next_in], next_in sub end_in, next_in diff --git a/igzip/igzip_deflate_hash.asm b/igzip/igzip_deflate_hash.asm new file mode 100644 index 0000000..162014e --- /dev/null +++ b/igzip/igzip_deflate_hash.asm @@ -0,0 +1,61 @@ +%include "options.asm" +%include "lz0a_const.asm" +%include "data_struct2.asm" +%include "huffman.asm" +%include "reg_sizes.asm" + +%define DICT_SLOP 4 + +%ifidn __OUTPUT_FORMAT__, win64 +%define arg1 rcx +%define arg2 rdx +%define arg3 r8 +%else +%define arg1 rdi +%define arg2 rsi +%define arg3 rdx +%endif + +%define stream arg1 + +%define dict_offset arg2 + +%define dict_len arg3 +%define f_i arg3 + +%define data r9 + +%define hash r10 + +%define f_i_end r11 + +global isal_deflate_hash_lvl0_01 +isal_deflate_hash_lvl0_01: +%ifnidn (arg1, stream) + mov stream, arg1 +%endif +%ifnidn (arg2, dict_next) + mov dict_offset, arg2 +%endif + + mov f_i_end %+ d, dword [stream + _total_in] + neg f_i + add f_i, f_i_end + + sub dict_offset, f_i + + sub f_i_end, DICT_SLOP + cmp f_i, f_i_end + jg end + +main_loop: + mov data %+ d, [f_i + dict_offset] + compute_hash hash, data + and hash, HASH_MASK + mov [stream + _internal_state_head + 2 * hash], f_i %+ w + + add f_i, 1 + cmp f_i, f_i_end + jle main_loop +end: + ret diff --git a/igzip/igzip_file_perf.c b/igzip/igzip_file_perf.c index 828fe80..08a0540 100644 --- a/igzip/igzip_file_perf.c +++ b/igzip/igzip_file_perf.c @@ -52,26 +52,31 @@ int usage(void) " -X use compression level X with 0 <= X <= 1\n" " -b input buffer size, 0 buffers all the input\n" " -i number of iterations (at least 1)\n" - " -o output file for compresed data\n"); + " -o output file for compresed data\n" + " -d dictionary file used by compression\n"); + exit(0); } int main(int argc, char *argv[]) { - FILE *in = NULL, *out = NULL; - unsigned char *inbuf, *outbuf, *level_buf = NULL; + FILE *in = NULL, *out = NULL, *dict = NULL; + unsigned char *inbuf, *outbuf, *level_buf = NULL, *dictbuf = NULL; int i, c, iterations = 0, inbuf_size = 0; - uint64_t infile_size, outbuf_size; + uint64_t infile_size, outbuf_size, dictfile_size; struct isal_huff_histogram histogram; struct isal_hufftables hufftables_custom; int level = 0, level_size = 0, avail_in; - char *in_file_name = NULL, *out_file_name = NULL; + char *in_file_name = NULL, *out_file_name = NULL, *dict_file_name = NULL; - while ((c = getopt(argc, argv, "h01i:b:o:")) != -1) { + while ((c = getopt(argc, argv, "h01i:b:o:d:")) != -1) { switch (c) { case 'o': out_file_name = optarg; break; + case 'd': + dict_file_name = optarg; + break; case 'i': iterations = atoi(optarg); if (iterations < 1) @@ -112,6 +117,15 @@ int main(int argc, char *argv[]) printf("outfile=%s\n", out_file_name); } + if (dict_file_name != NULL) { + dict = fopen(dict_file_name, "rb"); + if (!dict) { + fprintf(stderr, "Can't open %s for reading\n", dict_file_name); + exit(0); + } + printf("outfile=%s\n", dict_file_name); + } + printf("Window Size: %d K\n", IGZIP_HIST_SIZE / 1024); printf("igzip_file_perf: \n"); fflush(0); @@ -123,6 +137,10 @@ int main(int argc, char *argv[]) outbuf_size = 2 * infile_size + BUF_SIZE; + dictfile_size = 0; + if (dict_file_name != NULL) + dictfile_size = get_filesize(dict); + if (iterations == 0) { iterations = infile_size ? RUN_MEM_SIZE / infile_size : MIN_TEST_LOOPS; if (iterations < MIN_TEST_LOOPS) @@ -140,6 +158,14 @@ int main(int argc, char *argv[]) exit(0); } + if (dictfile_size != 0) { + dictbuf = malloc(dictfile_size); + if (dictbuf == NULL) { + fprintf(stderr, "Can't allocate dictionary buffer memory\n"); + exit(0); + } + } + if (level_size != 0) { level_buf = malloc(level_size); if (level_buf == NULL) { @@ -158,11 +184,18 @@ int main(int argc, char *argv[]) exit(0); } + if (dictfile_size != (uint32_t) fread(dictbuf, 1, dictfile_size, dict)) { + fprintf(stderr, "Couldn't fit all of dictionary file into buffer\n"); + exit(0); + } + struct perf start, stop; perf_start(&start); for (i = 0; i < iterations; i++) { isal_deflate_init(&stream); + if (dict_file_name != NULL) + isal_deflate_set_dict(&stream, dictbuf, dictfile_size); stream.end_of_stream = 0; stream.flush = NO_FLUSH; stream.level = level; diff --git a/igzip/igzip_finish.asm b/igzip/igzip_finish.asm index e8d5e36..dbbe0d9 100644 --- a/igzip/igzip_finish.asm +++ b/igzip/igzip_finish.asm @@ -126,7 +126,7 @@ skip_SLOP: mov curr_data %+ d, [file_start + f_i] - cmp dword [stream + _internal_state_has_hist], 0 + cmp dword [stream + _internal_state_has_hist], IGZIP_NO_HIST jne skip_write_first_byte cmp m_out_buf, [stream + _internal_state_bitbuf_m_out_end] @@ -135,7 +135,7 @@ skip_SLOP: compute_hash hash, curr_data and hash %+ d, HASH_MASK mov [stream + _internal_state_head + 2 * hash], f_i %+ w - mov dword [stream + _internal_state_has_hist], 1 + mov dword [stream + _internal_state_has_hist], IGZIP_HIST jmp encode_literal skip_write_first_byte: diff --git a/igzip/igzip_icf_body.asm b/igzip/igzip_icf_body.asm index bc76114..abfc814 100644 --- a/igzip/igzip_icf_body.asm +++ b/igzip/igzip_icf_body.asm @@ -193,7 +193,7 @@ MARK __body_compute_hash_ %+ ARCH and hash, HASH_MASK and hash2, HASH_MASK - cmp dword [stream + _internal_state_has_hist], 0 + cmp dword [stream + _internal_state_has_hist], IGZIP_NO_HIST je write_first_byte jmp loop2 @@ -482,7 +482,7 @@ write_first_byte: cmp m_out_buf, [rsp + m_out_end] ja output_end - mov dword [stream + _internal_state_has_hist], 1 + mov dword [stream + _internal_state_has_hist], IGZIP_HIST mov [stream + _internal_state_head + 2 * hash], f_i %+ w diff --git a/igzip/igzip_icf_finish.asm b/igzip/igzip_icf_finish.asm index 2d65a61..15be09c 100644 --- a/igzip/igzip_icf_finish.asm +++ b/igzip/igzip_icf_finish.asm @@ -122,7 +122,7 @@ isal_deflate_icf_finish_01: mov curr_data %+ d, [file_start + f_i] - cmp dword [stream + _internal_state_has_hist], 0 + cmp dword [stream + _internal_state_has_hist], IGZIP_NO_HIST jne skip_write_first_byte cmp m_out_buf, [rsp + m_out_end] @@ -131,7 +131,7 @@ isal_deflate_icf_finish_01: compute_hash hash, curr_data and hash %+ d, HASH_MASK mov [stream + _internal_state_head + 2 * hash], f_i %+ w - mov dword [stream + _internal_state_has_hist], 1 + mov dword [stream + _internal_state_has_hist], IGZIP_HIST jmp encode_literal skip_write_first_byte: diff --git a/igzip/igzip_inflate.c b/igzip/igzip_inflate.c index fe3b984..1fcf654 100644 --- a/igzip/igzip_inflate.c +++ b/igzip/igzip_inflate.c @@ -87,6 +87,9 @@ struct slver isal_inflate_stateless_slver = { 0x0089, 0x01, 0x00 }; struct slver isal_inflate_slver_0001008a; struct slver isal_inflate_slver = { 0x008a, 0x01, 0x00 }; +struct slver isal_inflate_set_dict_slver_0001008d; +struct slver isal_inflate_set_dict_slver = { 0x008d, 0x01, 0x00 }; + /*Performs a copy of length repeat_length data starting at dest - * lookback_distance into dest. This copy copies data previously copied when the * src buffer and the dest buffer overlap. */ @@ -1064,7 +1067,7 @@ int decode_huffman_code_block_stateless_base(struct inflate_state *state) return ISAL_END_INPUT; } - if (look_back_dist > state->total_out) + if (look_back_dist > state->total_out + state->dict_length) return ISAL_INVALID_LOOKBACK; if (state->avail_out < repeat_length) { @@ -1103,6 +1106,7 @@ void isal_inflate_init(struct inflate_state *state) state->next_out = NULL; state->avail_out = 0; state->total_out = 0; + state->dict_length = 0; state->block_state = ISAL_BLOCK_NEW_HDR; state->bfinal = 0; state->crc_flag = 0; @@ -1115,6 +1119,26 @@ void isal_inflate_init(struct inflate_state *state) state->tmp_out_valid = 0; } +int isal_inflate_set_dict(struct inflate_state *state, uint8_t * dict, uint32_t dict_len) +{ + + if (state->block_state != ISAL_BLOCK_NEW_HDR + || state->tmp_out_processed != state->tmp_out_valid) + return ISAL_INVALID_STATE; + + if (dict_len > IGZIP_HIST_SIZE) { + dict = dict + dict_len - IGZIP_HIST_SIZE; + dict_len = IGZIP_HIST_SIZE; + } + + memcpy(state->tmp_out_buffer, dict, dict_len); + state->tmp_out_processed = dict_len; + state->tmp_out_valid = dict_len; + state->dict_length = dict_len; + + return COMP_OK; +} + int isal_inflate_stateless(struct inflate_state *state) { uint32_t ret = 0; @@ -1123,6 +1147,7 @@ int isal_inflate_stateless(struct inflate_state *state) state->read_in = 0; state->read_in_length = 0; state->block_state = ISAL_BLOCK_NEW_HDR; + state->dict_length = 0; state->bfinal = 0; state->crc = 0; state->total_out = 0; diff --git a/igzip/igzip_multibinary.asm b/igzip/igzip_multibinary.asm index 516be0e..52df6d3 100644 --- a/igzip/igzip_multibinary.asm +++ b/igzip/igzip_multibinary.asm @@ -71,6 +71,9 @@ extern adler32_base extern adler32_avx2_4 extern adler32_sse +extern isal_deflate_hash_lvl0_base +extern isal_deflate_hash_lvl0_01 + section .text %include "multibinary.asm" @@ -101,3 +104,6 @@ mbin_dispatch_init5 crc32_gzip, crc32_gzip_base, crc32_gzip_base, crc32_gzip_01, mbin_interface isal_adler32 mbin_dispatch_init5 isal_adler32, adler32_base, adler32_sse, adler32_sse, adler32_avx2_4 + +mbin_interface isal_deflate_hash_lvl0 +mbin_dispatch_init5 isal_deflate_hash_lvl0, isal_deflate_hash_lvl0_base, isal_deflate_hash_lvl0_01, isal_deflate_hash_lvl0_01, isal_deflate_hash_lvl0_01 diff --git a/igzip/igzip_rand_test.c b/igzip/igzip_rand_test.c index 8e196f4..5f713ec 100644 --- a/igzip/igzip_rand_test.c +++ b/igzip/igzip_rand_test.c @@ -210,6 +210,29 @@ void create_rand_repeat_data(uint8_t * data, int size) } } +void create_rand_dict(uint8_t * dict, uint32_t dict_len, uint8_t * buf, uint32_t buf_len) +{ + uint32_t dict_chunk_size, buf_chunk_size; + while (dict_len > 0) { + dict_chunk_size = rand() % IGZIP_K; + dict_chunk_size = (dict_len >= dict_chunk_size) ? dict_chunk_size : dict_len; + + buf_chunk_size = rand() % IGZIP_K; + buf_chunk_size = (buf_len >= buf_chunk_size) ? buf_chunk_size : buf_len; + + if (rand() % 3 == 0 && buf_len >= dict_len) + memcpy(dict, buf, dict_chunk_size); + else + create_rand_repeat_data(dict, dict_chunk_size); + + dict_len -= dict_chunk_size; + dict += dict_chunk_size; + buf_len -= buf_chunk_size; + buf += buf_chunk_size; + } + +} + int get_rand_data_length(void) { int max_mask = @@ -435,7 +458,8 @@ int inflate_stateless_pass(uint8_t * compress_buf, uint64_t compress_len, } int inflate_multi_pass(uint8_t * compress_buf, uint64_t compress_len, - uint8_t * uncompress_buf, uint32_t * uncompress_len, uint32_t gzip_flag) + uint8_t * uncompress_buf, uint32_t * uncompress_len, uint32_t gzip_flag, + uint8_t * dict, uint32_t dict_len) { struct inflate_state *state = NULL; int ret = 0; @@ -452,6 +476,9 @@ int inflate_multi_pass(uint8_t * compress_buf, uint64_t compress_len, isal_inflate_init(state); + if (dict != NULL) + isal_inflate_set_dict(state, dict, dict_len); + state->next_in = NULL; state->next_out = NULL; state->avail_in = 0; @@ -583,7 +610,7 @@ int inflate_multi_pass(uint8_t * compress_buf, uint64_t compress_len, /* Inflate the compressed data and check that the decompressed data agrees with the input data */ int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size, - uint32_t gzip_flag) + uint32_t gzip_flag, uint8_t * dict, uint32_t dict_len) { /* Test inflate with reference inflate */ @@ -613,11 +640,13 @@ int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size, z_size -= zlib_hdr_bytes; } - if (inflate_type == 0) { + if (inflate_type == 0 && dict == NULL) { ret = inflate_stateless_pass(z_buf, z_size, test_buf, &test_size, gzip_flag); inflate_type = 1; } else { - ret = inflate_multi_pass(z_buf, z_size, test_buf, &test_size, gzip_flag); + ret = + inflate_multi_pass(z_buf, z_size, test_buf, &test_size, gzip_flag, dict, + dict_len); inflate_type = 0; } @@ -796,7 +825,7 @@ void set_random_hufftable(struct isal_zstream *stream) * compression*/ int compress_multi_pass(uint8_t * data, uint32_t data_size, uint8_t * compressed_buf, uint32_t * compressed_size, uint32_t flush_type, uint32_t gzip_flag, - uint32_t level) + uint32_t level, uint8_t * dict, uint32_t dict_len) { int ret = IGZIP_COMP_OK; uint8_t *in_buf = NULL, *out_buf = NULL; @@ -946,7 +975,7 @@ int compress_multi_pass(uint8_t * data, uint32_t data_size, uint8_t * compressed /* Compress the input data into the outbuffer in one call to isal_deflate */ int compress_single_pass(uint8_t * data, uint32_t data_size, uint8_t * compressed_buf, uint32_t * compressed_size, uint32_t flush_type, uint32_t gzip_flag, - uint32_t level) + uint32_t level, uint8_t * dict, uint32_t dict_len) { int ret = IGZIP_COMP_OK; struct isal_zstream stream; @@ -967,6 +996,9 @@ int compress_single_pass(uint8_t * data, uint32_t data_size, uint8_t * compresse if (state->state != ZSTATE_NEW_HDR) return COMPRESS_INCORRECT_STATE; + if (dict != NULL) + isal_deflate_set_dict(&stream, dict, dict_len); + stream.flush = flush_type; stream.avail_in = data_size; stream.next_in = data; @@ -1153,7 +1185,9 @@ int compress_stateless_full_flush(uint8_t * data, uint32_t data_size, uint8_t * break; /* Verify that blocks are independent */ - ret = inflate_check(out_buf, stream.next_out - out_buf, in_buf, in_size, 0); + ret = + inflate_check(out_buf, stream.next_out - out_buf, in_buf, in_size, 0, NULL, + 0); if (ret == INFLATE_INVALID_LOOK_BACK_DISTANCE) { break; @@ -1272,7 +1306,7 @@ int compress_full_flush(uint8_t * data, uint32_t data_size, uint8_t * compressed if (state->state == ZSTATE_NEW_HDR || state->state == ZSTATE_END) { ret = inflate_check(out_buf, stream.next_out - out_buf, in_buf, in_size, - 0); + 0, NULL, 0); if (ret == INFLATE_INVALID_LOOK_BACK_DISTANCE) break; @@ -1425,7 +1459,7 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size, uint32_t flush_ compress_stateless(in_buf, in_size, z_buf, &z_size, flush_type, gzip_flag, level); if (!ret) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, NULL, 0); #ifdef VERBOSE if (ret) { @@ -1473,7 +1507,7 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size, uint32_t flush_ ret = compress_stateless(in_buf, in_size, z_buf, &z_size, flush_type, gzip_flag, level); if (!ret) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, NULL, 0); #ifdef VERBOSE if (ret) { printf("Compressed array at level %d with gzip flag %d: ", level, gzip_flag); @@ -1511,7 +1545,8 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size, uint32_t flush_ print_error(overflow); if (overflow == 0) { overflow = - inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, + NULL, 0); printf("inflate ret = %d\n", overflow); print_error(overflow); } @@ -1553,7 +1588,7 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size, uint32_t flush_ ret = compress_stateless_full_flush(in_buf, in_size, z_buf, &z_size, level); if (!ret) - ret = inflate_check(z_buf, z_size, in_buf, in_size, 0); + ret = inflate_check(z_buf, z_size, in_buf, in_size, 0, NULL, 0); else if (ret == COMPRESS_LOOP_COUNT_OVERFLOW) ret = 0; @@ -1583,8 +1618,8 @@ int test_compress(uint8_t * in_buf, uint32_t in_size, uint32_t flush_type) { int ret = IGZIP_COMP_OK, fin_ret = IGZIP_COMP_OK; uint32_t overflow = 0, gzip_flag, level; - uint32_t z_size = 0, z_size_max = 0, z_compressed_size; - uint8_t *z_buf = NULL; + uint32_t z_size = 0, z_size_max = 0, z_compressed_size, dict_len = 0; + uint8_t *z_buf = NULL, *dict = NULL; /* Test a non overflow case */ if (flush_type == NO_FLUSH) @@ -1617,17 +1652,32 @@ int test_compress(uint8_t * in_buf, uint32_t in_size, uint32_t flush_type) } create_rand_repeat_data(z_buf, z_size); + if (rand() % 8 == 0) { + dict_len = (rand() % IGZIP_HIST_SIZE) + 1; + dict = malloc(dict_len); + if (dict == NULL) { + print_error(MALLOC_FAILED); + return MALLOC_FAILED; + } + create_rand_dict(dict, dict_len, z_buf, z_size); + } + ret = compress_single_pass(in_buf, in_size, z_buf, &z_size, flush_type, - gzip_flag, level); + gzip_flag, level, dict, dict_len); if (!ret) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, dict, dict_len); if (ret) { #ifdef VERBOSE printf("Compressed array at level %d with gzip flag %d: ", level, gzip_flag); print_uint8_t(z_buf, z_size); printf("\n"); + if (dict != NULL) { + printf("Using Dictionary: "); + print_uint8_t(dict, dict_len); + printf("\n"); + } printf("Data: "); print_uint8_t(in_buf, in_size); #endif @@ -1635,23 +1685,45 @@ int test_compress(uint8_t * in_buf, uint32_t in_size, uint32_t flush_type) print_error(ret); } + if (dict != NULL) { + free(dict); + dict = NULL; + dict_len = 0; + } + fin_ret |= ret; z_compressed_size = z_size; z_size = z_size_max; create_rand_repeat_data(z_buf, z_size_max); + if (rand() % 8 == 0) { + dict_len = (rand() % IGZIP_HIST_SIZE) + 1; + dict = malloc(dict_len); + if (dict == NULL) { + print_error(MALLOC_FAILED); + return MALLOC_FAILED; + } + create_rand_dict(dict, dict_len, z_buf, z_size); + } + ret = - compress_multi_pass(in_buf, in_size, z_buf, &z_size, flush_type, gzip_flag, level); + compress_multi_pass(in_buf, in_size, z_buf, &z_size, flush_type, gzip_flag, level, + dict, dict_len); if (!ret) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, dict, dict_len); if (ret) { #ifdef VERBOSE printf("Compressed array at level %d with gzip flag %d: ", level, gzip_flag); print_uint8_t(z_buf, z_size); printf("\n"); + if (dict != NULL) { + printf("Using Dictionary: "); + print_uint8_t(dict, dict_len); + printf("\n"); + } printf("Data: "); print_uint8_t(in_buf, in_size); #endif @@ -1659,6 +1731,12 @@ int test_compress(uint8_t * in_buf, uint32_t in_size, uint32_t flush_type) print_error(ret); } + if (dict != NULL) { + free(dict); + dict = NULL; + dict_len = 0; + } + fin_ret |= ret; ret = 0; @@ -1671,11 +1749,13 @@ int test_compress(uint8_t * in_buf, uint32_t in_size, uint32_t flush_type) create_rand_repeat_data(z_buf, z_size_max); overflow = compress_single_pass(in_buf, in_size, z_buf, &z_size, flush_type, - gzip_flag, level); + gzip_flag, level, dict, dict_len); if (overflow != COMPRESS_OUT_BUFFER_OVERFLOW) { if (overflow == 0) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = + inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, dict, + dict_len); /* Rarely single pass overflow will compresses data * better than the initial run. This is to stop that @@ -1707,11 +1787,13 @@ int test_compress(uint8_t * in_buf, uint32_t in_size, uint32_t flush_type) overflow = compress_multi_pass(in_buf, in_size, z_buf, &z_size, flush_type, - gzip_flag, level); + gzip_flag, level, dict, dict_len); if (overflow != COMPRESS_OUT_BUFFER_OVERFLOW) { if (overflow == 0) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = + inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, + dict, dict_len); /* Rarely multi pass overflow will compresses data * better than the initial run. This is to stop that @@ -1775,7 +1857,7 @@ int test_flush(uint8_t * in_buf, uint32_t in_size) /* Test invalid flush */ ret = compress_single_pass(in_buf, in_size, z_buf, &z_size, flush_type, - gzip_flag, level); + gzip_flag, level, NULL, 0); if (ret == COMPRESS_GENERAL_ERROR) ret = 0; @@ -1793,7 +1875,7 @@ int test_flush(uint8_t * in_buf, uint32_t in_size) ret = compress_swap_flush(in_buf, in_size, z_buf, &z_size, rand() % 3, gzip_flag); if (!ret) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, NULL, 0); if (ret) { #ifdef VERBOSE @@ -1844,7 +1926,7 @@ int test_full_flush(uint8_t * in_buf, uint32_t in_size) ret = compress_full_flush(in_buf, in_size, z_buf, &z_size, gzip_flag, level); if (!ret) - ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag); + ret = inflate_check(z_buf, z_size, in_buf, in_size, gzip_flag, NULL, 0); if (ret) { #ifdef VERBOSE @@ -1887,7 +1969,8 @@ int test_inflate(struct vect_result *in_vector) ret = IGZIP_COMP_OK; if (!ret) { - ret = inflate_multi_pass(compress_buf, compress_len, out_buf, &out_size, 0); + ret = inflate_multi_pass(compress_buf, compress_len, out_buf, &out_size, + 0, NULL, 0); if (ret == INFLATE_LEFTOVER_INPUT) ret = ISAL_DECOMP_OK; diff --git a/igzip/inflate_data_structs.asm b/igzip/inflate_data_structs.asm index 3d4d24d..8742a31 100644 --- a/igzip/inflate_data_structs.asm +++ b/igzip/inflate_data_structs.asm @@ -89,6 +89,7 @@ FIELD _read_in_length,4, 4 FIELD _lit_huff_code, _inflate_huff_code_large_size, _inflate_huff_code_large_align FIELD _dist_huff_code,_inflate_huff_code_small_size, _inflate_huff_code_small_align FIELD _block_state, 4, 4 +FIELD _dict_length, 4, 4 FIELD _bfinal, 4, 4 FIELD _crc_flag, 4, 4 FIELD _crc, 4, 4 diff --git a/include/igzip_lib.h b/include/igzip_lib.h index f116810..a7098db 100644 --- a/include/igzip_lib.h +++ b/include/igzip_lib.h @@ -156,7 +156,7 @@ enum {IGZIP_LIT_TABLE_SIZE = ISAL_DEF_LIT_SYMBOLS}; #define STATELESS_OVERFLOW -1 #define ISAL_INVALID_OPERATION -9 #define ISAL_INVALID_LEVEL -4 /* Invalid Compression level set */ - +#define ISAL_INVALID_STATE -3 /** * @enum isal_zstate_state * @brief Compression State please note ZSTATE_TRL only applies for GZIP compression @@ -264,6 +264,10 @@ struct isal_mod_hist { #define ISAL_DEF_LVL1_EXTRA_LARGE (ISAL_DEF_LVL1_REQ + ISAL_DEF_LVL1_TOKEN_SIZE * 128 * IGZIP_K) #define ISAL_DEF_LVL1_DEFAULT ISAL_DEF_LVL1_LARGE +#define IGZIP_NO_HIST 0 +#define IGZIP_HIST 1 +#define IGZIP_DICT_HIST 2 + /** @brief Holds Bit Buffer information*/ struct BitBuf2 { uint64_t m_bits; //!< bits in the bit buffer @@ -410,6 +414,7 @@ struct inflate_state { struct inflate_huff_code_large lit_huff_code; //!< Structure for decoding lit/len symbols struct inflate_huff_code_small dist_huff_code; //!< Structure for decoding dist symbols enum isal_block_state block_state; //!< Current decompression state + uint32_t dict_length; //!< Length of dictionary used uint32_t bfinal; //!< Flag identifying final block uint32_t crc_flag; //!< Flag identifying whether to track of crc uint32_t crc; //!< Contains crc of output if crc_flag is set @@ -506,6 +511,22 @@ int isal_deflate_set_hufftables(struct isal_zstream *stream, void isal_deflate_stateless_init(struct isal_zstream *stream); +/** + * @brief Set compression dictionary to use + * + * This function is to be called after isal_deflate_init, or after completing a + * SYNC_FLUSH or FULL_FLUSH and before the next call do isal_deflate. If the + * dictionary is longer than IGZIP_HIST_SIZE, only the last IGZIP_HIST_SIZE + * bytes will be used. + * + * @param stream Structure holding state information on the compression streams. + * @param dict: Array containing dictionary to use. + * @param dict_len: Lenth of dict. + * @returns COMP_OK, + * ISAL_INVALID_STATE (dictionary could not be set) + */ +int isal_deflate_set_dict(struct isal_zstream *stream, uint8_t *dict, uint32_t dict_len); + /** * @brief Fast data (deflate) compression for storage applications. * @@ -546,6 +567,9 @@ void isal_deflate_stateless_init(struct isal_zstream *stream); * not include previous blocks so new blocks are fully independent. Switching * between flush types is supported. * + * If a compression dictionary is required, the dictionary can be set calling + * isal_deflate_set_dictionary before calling isal_deflate. + * * If the gzip_flag is set to IGZIP_GZIP, a generic gzip header and the gzip * trailer are written around the deflate compressed data. If gzip_flag is set * to IGZIP_GZIP_NO_HDR, then only the gzip trailer is written. @@ -598,6 +622,21 @@ int isal_deflate_stateless(struct isal_zstream *stream); */ void isal_inflate_init(struct inflate_state *state); +/** + * @brief Set decompression dictionary to use + * + * This function is to be called after isal_inflate_init. If the dictionary is + * longer than IGZIP_HIST_SIZE, only the last IGZIP_HIST_SIZE bytes will be + * used. + * + * @param state: Structure holding state information on the decompression stream. + * @param dict: Array containing dictionary to use. + * @param dict_len: Lenth of dict. + * @returns COMP_OK, + * ISAL_INVALID_STATE (dictionary could not be set) + */ +int isal_inflate_set_dict(struct inflate_state *state, uint8_t *dict, uint32_t dict_len); + /** * @brief Fast data (deflate) decompression for storage applications. * @@ -617,6 +656,9 @@ void isal_inflate_init(struct inflate_state *state); * in state->crc. Alternatively, if the crc_flag is set to ISAL_ZLIB_NO_HDR the * adler32 of the output is stored in state->crc. * + * If a dictionary is required, a call to isal_inflate_set_dict will set the + * dictionary. + * * @param state Structure holding state information on the compression streams. * @return ISAL_DECOMP_OK (if everything is ok), * ISAL_END_INPUT (if all input was decompressed), @@ -625,6 +667,7 @@ void isal_inflate_init(struct inflate_state *state); * ISAL_INVALID_SYMBOL, * ISAL_INVALID_LOOKBACK. */ + int isal_inflate(struct inflate_state *state); /**