igzip: Create stateless FULL_FLUSH mode

Add flush modes to isal_deflate_stateless. IGZIP_USE_GZIP_FORMAT is not
supported because of limitations imposed by the statelessness.

Signed-off-by: Roy Oursler <roy.j.oursler@intel.com>
Reviewed-by: Greg Tucker <greg.b.tucker@intel.com>
This commit is contained in:
Roy Oursler
2016-07-18 14:00:44 -07:00
committed by Greg Tucker
parent b25ef61a57
commit a1981da94e
3 changed files with 394 additions and 43 deletions

View File

@@ -154,6 +154,44 @@ void sync_flush(struct isal_zstream *stream)
}
}
static
void sync_flush_stateless(struct isal_zstream *stream)
{
struct isal_zstate *state = &stream->internal_state;
uint64_t bits_to_write = 0xFFFF0000, bits_len;
uint64_t code = 0, len = 0, bytes;
int flush_size;
if (stream->avail_out >= 8) {
set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
if (!state->has_eob)
get_lit_code(stream->hufftables, 256, &code, &len);
flush_size = (-(state->bitbuf.m_bit_count + len + 3)) % 8;
bits_to_write <<= flush_size + 3;
bits_len = 32 + len + flush_size + 3;
#ifdef USE_BITBUFB /* Write Bits Always */
state->state = ZSTATE_NEW_HDR;
#else /* Not Write Bits Always */
state->state = ZSTATE_FLUSH_WRITE_BUFFER;
#endif
state->has_eob = 0;
if (len > 0)
bits_to_write = (bits_to_write << len) | code;
write_bits(&state->bitbuf, bits_to_write, bits_len);
bytes = buffer_used(&state->bitbuf);
stream->next_out = buffer_ptr(&state->bitbuf);
stream->avail_out -= bytes;
stream->total_out += bytes;
}
}
static void flush_write_buffer(struct isal_zstream *stream)
{
struct isal_zstate *state = &stream->internal_state;
@@ -211,8 +249,10 @@ static uint32_t write_constant_compressed_stateless(struct isal_zstream *stream,
/* Assumes the repeated char is either 0 or 0xFF. */
memcpy(stream->next_out, repeated_char_header[repeated_char & 1], HEADER_LENGTH);
if (end_of_stream > 0)
if (end_of_stream > 0) {
stream->next_out[0] |= 1;
state->has_eob_hdr = 1;
}
memset(stream->next_out + HEADER_LENGTH, 0, rep_bytes);
stream->avail_out -= HEADER_LENGTH + rep_bytes;
@@ -261,6 +301,8 @@ static uint32_t write_constant_compressed_stateless(struct isal_zstream *stream,
write_bits(&state->bitbuf, END_OF_BLOCK, END_OF_BLOCK_LEN);
state->has_eob = 1;
stream->next_in += repeated_length;
stream->avail_in -= repeated_length;
stream->total_in += repeated_length;
@@ -313,22 +355,33 @@ static int isal_deflate_int_stateless(struct isal_zstream *stream, uint8_t * nex
if (stream->avail_in == repeated_char_length) {
if (write_constant_compressed_stateless(stream,
stream->next_in[0],
repeated_char_length, 1) != COMP_OK)
repeated_char_length,
stream->end_of_stream) != COMP_OK)
return STATELESS_OVERFLOW;
#ifndef DEFLATE
crc32 = crc32_gzip(0x0, next_in, avail_in);
#endif
/* write_trailer_stateless is required because if flushes out the last of the output */
if (stream->internal_state.has_eob_hdr) {
if (write_trailer_stateless(stream, avail_in, crc32) != COMP_OK)
return STATELESS_OVERFLOW;
} else if (stream->avail_out >= 8) {
sync_flush_stateless(stream);
#ifndef USE_BITBUFB
flush_write_buffer(stream);
if (stream->internal_state.bitbuf.m_bit_count != 0)
return STATELESS_OVERFLOW;
#endif
} else
return STATELESS_OVERFLOW;
return COMP_OK;
} else if (repeated_char_length >= MIN_REPEAT_LEN) {
if (write_constant_compressed_stateless
(stream, stream->next_in[0], repeated_char_length, 0) != COMP_OK)
return STATELESS_OVERFLOW;
stream->internal_state.has_eob = 0;
}
if (write_deflate_header_unaligned_stateless(stream) != COMP_OK)
@@ -336,6 +389,10 @@ static int isal_deflate_int_stateless(struct isal_zstream *stream, uint8_t * nex
if (stream->avail_out < 8)
return STATELESS_OVERFLOW;
stream->internal_state.file_start = (uint8_t *) & stream->internal_state.buffer;
stream->internal_state.b_bytes_processed = 0;
reset_match_history(stream);
isal_deflate_body_stateless(stream);
if (!stream->internal_state.has_eob)
@@ -345,8 +402,18 @@ static int isal_deflate_int_stateless(struct isal_zstream *stream, uint8_t * nex
crc32 = crc32_gzip(0x0, next_in, avail_in);
#endif
if (stream->internal_state.has_eob_hdr) {
if (write_trailer_stateless(stream, avail_in, crc32) != COMP_OK)
return STATELESS_OVERFLOW;
} else if (stream->avail_out >= 8) {
sync_flush_stateless(stream);
#ifndef USE_BITBUFB
flush_write_buffer(stream);
if (stream->internal_state.bitbuf.m_bit_count != 0)
return STATELESS_OVERFLOW;
#endif
} else
return STATELESS_OVERFLOW;
return COMP_OK;
}
@@ -388,9 +455,12 @@ static int write_stored_block_stateless(struct isal_zstream *stream,
avail_in -= copy_size;
/* Handle BFINAL bit */
if (avail_in == 0)
if (avail_in == 0) {
if (stream->flush == NO_FLUSH || stream->end_of_stream) {
stored_blk_hdr |= 0x1;
stream->internal_state.has_eob_hdr = 1;
}
}
memcpy(stream->next_out, &stored_blk_hdr, STORED_BLK_HDR_BZ);
stream->next_out += STORED_BLK_HDR_BZ;
@@ -401,11 +471,13 @@ static int write_stored_block_stateless(struct isal_zstream *stream,
} while (avail_in != 0);
#ifndef DEFLATE
if (stream->internal_state.has_eob_hdr) {
gzip_trl = stream->avail_in;
gzip_trl <<= 32;
gzip_trl |= crc32 & 0xFFFFFFFF;
memcpy(stream->next_out, &gzip_trl, gzip_trl_bytes);
stream->next_out += gzip_trl_bytes;
}
#endif
stream->avail_in = 0;
@@ -418,11 +490,12 @@ static inline void reset_match_history(struct isal_zstream *stream)
uint16_t *head = stream->internal_state.head;
int i = 0;
for (i = 0; i < sizeof(state->head) / 2; i++)
for (i = 0; i < sizeof(state->head) / 2; i++) {
head[i] =
(uint16_t) (state->b_bytes_processed + state->buffer - state->file_start -
(IGZIP_D + 1));
}
}
void isal_deflate_init_01(struct isal_zstream *stream)
{
@@ -458,13 +531,25 @@ void isal_deflate_init_01(struct isal_zstream *stream)
return;
}
void isal_deflate_stateless_init(struct isal_zstream *stream)
{
stream->total_in = 0;
stream->total_out = 0;
stream->hufftables = (struct isal_hufftables *)&hufftables_default;
stream->flush = NO_FLUSH;
stream->end_of_stream = 0;
return;
}
int isal_deflate_stateless(struct isal_zstream *stream)
{
uint8_t *next_in = stream->next_in;
const uint32_t avail_in = stream->avail_in;
const uint32_t total_in = stream->total_in;
uint8_t *next_out = stream->next_out;
const uint32_t avail_out = stream->avail_out;
const uint32_t total_out = stream->total_out;
uint32_t crc32 = 0;
uint32_t stored_len;
@@ -472,6 +557,15 @@ int isal_deflate_stateless(struct isal_zstream *stream)
uint32_t min_len;
uint32_t select_stored_blk = 0;
/* Final block has already been written */
stream->internal_state.has_eob_hdr = 0;
init(&stream->internal_state.bitbuf);
if (stream->flush == NO_FLUSH)
stream->end_of_stream = 1;
if (stream->flush != NO_FLUSH && stream->flush != FULL_FLUSH)
return INVALID_FLUSH;
if (avail_in == 0)
stored_len = STORED_BLK_HDR_BZ;
else
@@ -507,19 +601,26 @@ int isal_deflate_stateless(struct isal_zstream *stream)
if (!select_stored_blk) {
if (isal_deflate_int_stateless(stream, next_in, avail_in) == COMP_OK)
return COMP_OK;
else {
if (stream->flush == FULL_FLUSH) {
stream->internal_state.file_start =
(uint8_t *) & stream->internal_state.buffer;
reset_match_history(stream);
}
stream->internal_state.has_eob_hdr = 0;
}
}
if (avail_out < stored_len)
return STATELESS_OVERFLOW;
isal_deflate_init(stream);
stream->next_in = next_in;
stream->avail_in = avail_in;
stream->total_in = 0;
stream->total_in = total_in;
stream->next_out = next_out;
stream->avail_out = avail_out;
stream->total_out = 0;
stream->total_out = total_out;
#ifndef DEFLATE
crc32 = crc32_gzip(0x0, next_in, avail_in);
@@ -654,6 +755,11 @@ static int write_deflate_header_stateless(struct isal_zstream *stream)
memcpy(stream->next_out, hufftables->deflate_hdr, hufftables->deflate_hdr_count);
if (stream->end_of_stream == 0)
*stream->next_out -= 1;
else
state->has_eob_hdr = 1;
stream->avail_out -= hufftables->deflate_hdr_count;
stream->total_out += hufftables->deflate_hdr_count;
stream->next_out += hufftables->deflate_hdr_count;
@@ -692,6 +798,18 @@ static int write_deflate_header_unaligned_stateless(struct isal_zstream *stream)
header_next = (uint64_t *) hufftables->deflate_hdr;
header_end = header_next + hufftables->deflate_hdr_count / 8;
header_bits = *header_next;
if (stream->end_of_stream == 0)
header_bits--;
else
state->has_eob_hdr = 1;
write_bits(&state->bitbuf, header_bits, 32);
header_bits >>= 32;
write_bits(&state->bitbuf, header_bits, 32);
header_next++;
/* Write out Complete Header bits */
for (; header_next < header_end; header_next++) {
header_bits = *header_next;
@@ -759,7 +877,7 @@ void write_header(struct isal_zstream *stream)
if (state->count == 0 && count > 0) {
if (!stream->end_of_stream)
*stream->next_out &= 0xfe;
*stream->next_out -= 1;
else
state->has_eob_hdr = 1;
}

View File

@@ -404,8 +404,10 @@ int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size)
break;
}
if (gstream.avail_in != 0)
if (gstream.avail_in != 0) {
printf("leftover = %d\n", gstream.avail_in);
return INFLATE_LEFTOVER_INPUT;
}
if (gstream.total_out != in_size)
return INFLATE_INCORRECT_OUTPUT_SIZE;
@@ -699,23 +701,23 @@ int compress_single_pass(uint8_t * data, uint32_t data_size, uint8_t * compresse
/* Statelessly compress the input buffer into the output buffer */
int compress_stateless(uint8_t * data, uint32_t data_size, uint8_t * compressed_buf,
uint32_t * compressed_size)
uint32_t * compressed_size, uint32_t flush_type)
{
int ret = IGZIP_COMP_OK;
struct isal_zstream stream;
create_rand_repeat_data((uint8_t *) & stream, sizeof(stream));
isal_deflate_init(&stream);
isal_deflate_stateless_init(&stream);
if (hufftables != NULL)
stream.hufftables = hufftables;
stream.avail_in = data_size;
stream.end_of_stream = 1;
stream.next_in = data;
stream.flush = NO_FLUSH;
stream.flush = flush_type;
if (flush_type != NO_FLUSH)
stream.end_of_stream = 1;
stream.avail_out = *compressed_size;
stream.next_out = compressed_buf;
@@ -733,6 +735,8 @@ int compress_stateless(uint8_t * data, uint32_t data_size, uint8_t * compressed_
if (ret != IGZIP_COMP_OK) {
if (ret == STATELESS_OVERFLOW)
return COMPRESS_OUT_BUFFER_OVERFLOW;
else if (ret == INVALID_FLUSH)
return INVALID_FLUSH_ERROR;
else
return COMPRESS_GENERAL_ERROR;
}
@@ -750,6 +754,99 @@ int compress_stateless(uint8_t * data, uint32_t data_size, uint8_t * compressed_
}
/* Statelessly compress the input buffer into the output buffer */
int compress_stateless_full_flush(uint8_t * data, uint32_t data_size, uint8_t * compressed_buf,
uint32_t * compressed_size)
{
int ret = IGZIP_COMP_OK;
uint8_t *in_buf = NULL, *out_buf = compressed_buf;
uint32_t in_size = 0;
uint32_t in_processed = 00;
struct isal_zstream stream;
uint32_t loop_count = 0;
#ifdef VERBOSE
printf("Starting Stateless Compress Full Flush\n");
#endif
create_rand_repeat_data((uint8_t *) & stream, sizeof(stream));
isal_deflate_stateless_init(&stream);
if (hufftables != NULL)
stream.hufftables = hufftables;
stream.flush = FULL_FLUSH;
stream.end_of_stream = 0;
stream.avail_out = *compressed_size;
stream.next_out = compressed_buf;
while (1) {
loop_count++;
/* Randomly choose size of the next out buffer */
in_size = rand() % (data_size + 1);
/* Limit size of buffer to be smaller than maximum */
if (in_size >= data_size - in_processed) {
in_size = data_size - in_processed;
stream.end_of_stream = 1;
}
stream.avail_in = in_size;
if (in_size != 0) {
if (in_buf != NULL) {
free(in_buf);
in_buf = NULL;
}
in_buf = malloc(in_size);
if (in_buf == NULL) {
ret = MALLOC_FAILED;
break;
}
memcpy(in_buf, data + in_processed, in_size);
in_processed += in_size;
stream.next_in = in_buf;
}
out_buf = stream.next_out;
ret = isal_deflate_stateless(&stream);
assert(stream.internal_state.bitbuf.m_bit_count == 0);
assert(compressed_buf == stream.next_out - stream.total_out);
if (ret)
break;
/* Verify that blocks are independent */
ret = inflate_check(out_buf, stream.next_out - out_buf, in_buf, in_size);
if (ret == INFLATE_INVALID_LOOK_BACK_DISTANCE) {
break;
} else
ret = 0;
/* Check if the compression is completed */
if (in_processed == data_size) {
*compressed_size = stream.total_out;
break;
}
}
if (in_buf != NULL)
free(in_buf);
if (ret == STATELESS_OVERFLOW && loop_count >= MAX_LOOPS)
ret = COMPRESS_LOOP_COUNT_OVERFLOW;
return ret;
}
/* Compress the input data into the output buffer where the input buffer and
* is randomly segmented to test for independence of blocks in full flush
* compression*/
@@ -913,7 +1010,7 @@ int compress_swap_flush(uint8_t * data, uint32_t data_size, uint8_t * compressed
}
/* Test deflate_stateless */
int test_compress_stateless(uint8_t * in_data, uint32_t in_size)
int test_compress_stateless(uint8_t * in_data, uint32_t in_size, uint32_t flush_type)
{
int ret = IGZIP_COMP_OK;
uint32_t z_size, overflow;
@@ -939,7 +1036,26 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size)
create_rand_repeat_data(z_buf, z_size);
ret = compress_stateless(in_buf, in_size, z_buf, &z_size);
/* If flush type is invalid */
if (flush_type != NO_FLUSH && flush_type != FULL_FLUSH) {
ret = compress_stateless(in_buf, in_size, z_buf, &z_size, flush_type);
if (ret != INVALID_FLUSH_ERROR)
print_error(ret);
else
ret = 0;
if (z_buf != NULL)
free(z_buf);
if (in_buf != NULL)
free(in_buf);
return ret;
}
/* Else test valid flush type */
ret = compress_stateless(in_buf, in_size, z_buf, &z_size, flush_type);
if (!ret)
ret = inflate_check(z_buf, z_size, in_buf, in_size);
@@ -957,6 +1073,7 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size)
free(z_buf);
z_buf = NULL;
}
print_error(ret);
if (ret)
return ret;
@@ -979,7 +1096,7 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size)
create_rand_repeat_data(z_buf, z_size);
ret = compress_stateless(in_buf, in_size, z_buf, &z_size);
ret = compress_stateless(in_buf, in_size, z_buf, &z_size, flush_type);
if (!ret)
ret = inflate_check(z_buf, z_size, in_buf, in_size);
#ifdef VERBOSE
@@ -1009,7 +1126,7 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size)
return MALLOC_FAILED;
}
overflow = compress_stateless(in_buf, in_size, z_buf, &z_size);
overflow = compress_stateless(in_buf, in_size, z_buf, &z_size, flush_type);
if (overflow != COMPRESS_OUT_BUFFER_OVERFLOW) {
#ifdef VERBOSE
@@ -1026,12 +1143,51 @@ int test_compress_stateless(uint8_t * in_data, uint32_t in_size)
printf("Data: ");
print_uint8_t(in_buf, in_size);
#endif
ret = OVERFLOW_TEST_ERROR;
}
}
if (ret) {
if (z_buf != NULL) {
free(z_buf);
z_buf = NULL;
}
if (in_buf != NULL)
free(in_buf);
return ret;
}
if (flush_type == FULL_FLUSH) {
if (z_buf != NULL)
free(z_buf);
z_size = 2 * in_size + MAX_LOOPS * (hdr_bytes + trl_bytes + 5);
z_buf = malloc(z_size);
if (z_buf == NULL)
return MALLOC_FAILED;
create_rand_repeat_data(z_buf, z_size);
/* Else test valid flush type */
ret = compress_stateless_full_flush(in_buf, in_size, z_buf, &z_size);
if (!ret)
ret = inflate_check(z_buf, z_size, in_buf, in_size);
else if (ret == COMPRESS_LOOP_COUNT_OVERFLOW)
ret = 0;
print_error(ret);
#ifdef VERBOSE
if (ret) {
printf("Compressed array: ");
print_uint8_t(z_buf, z_size);
printf("\n");
printf("Data: ");
print_uint8_t(in_buf, in_size);
}
#endif
}
if (z_buf != NULL)
free(z_buf);
@@ -1315,7 +1471,11 @@ int test_compress_file(char *file_name)
fread(in_buf, 1, in_size, in_file);
}
ret |= test_compress_stateless(in_buf, in_size);
ret |= test_compress_stateless(in_buf, in_size, NO_FLUSH);
ret |= test_compress_stateless(in_buf, in_size, SYNC_FLUSH);
#ifndef IGZIP_USE_GZIP_FORMAT
ret |= test_compress_stateless(in_buf, in_size, FULL_FLUSH);
#endif
ret |= test_compress(in_buf, in_size, NO_FLUSH);
ret |= test_compress(in_buf, in_size, SYNC_FLUSH);
ret |= test_compress(in_buf, in_size, FULL_FLUSH);
@@ -1436,11 +1596,11 @@ int main(int argc, char *argv[])
printf("igzip_rand_test stateless: ");
ret = test_compress_stateless((uint8_t *) str1, sizeof(str1));
ret = test_compress_stateless((uint8_t *) str1, sizeof(str1), NO_FLUSH);
if (ret)
return ret;
ret |= test_compress_stateless((uint8_t *) str2, sizeof(str2));
ret |= test_compress_stateless((uint8_t *) str2, sizeof(str2), NO_FLUSH);
if (ret)
return ret;
@@ -1451,7 +1611,7 @@ int main(int argc, char *argv[])
create_rand_repeat_data(in_buf, in_size);
ret |= test_compress_stateless(in_buf, in_size);
ret |= test_compress_stateless(in_buf, in_size, NO_FLUSH);
in_buf -= offset;
@@ -1464,14 +1624,78 @@ int main(int argc, char *argv[])
for (i = 0; i < RANDOMS / 16; i++) {
create_rand_repeat_data(in_buf, PAGE_SIZE);
ret |= test_compress_stateless(in_buf, PAGE_SIZE); // good for efence
ret |= test_compress_stateless(in_buf, PAGE_SIZE, NO_FLUSH); // good for efence
}
fin_ret |= ret;
ret = test_compress_stateless((uint8_t *) str1, sizeof(str1), SYNC_FLUSH);
if (ret)
return ret;
ret |= test_compress_stateless((uint8_t *) str2, sizeof(str2), SYNC_FLUSH);
if (ret)
return ret;
for (i = 0; i < 16; i++) {
in_size = rand() % (IBUF_SIZE + 1);
offset = rand() % (IBUF_SIZE + 1 - in_size);
in_buf += offset;
create_rand_repeat_data(in_buf, in_size);
ret |= test_compress_stateless(in_buf, in_size, SYNC_FLUSH);
in_buf -= offset;
if (ret)
return ret;
}
fin_ret |= ret;
printf("%s\n", ret ? "Fail" : "Pass");
printf("igzip_rand_test NO_FLUSH: ");
#ifndef IGZIP_USE_GZIP_FORMAT
printf("igzip_rand_test stateless FULL_FLUSH: ");
ret = test_compress_stateless((uint8_t *) str1, sizeof(str1), FULL_FLUSH);
if (ret)
return ret;
ret |= test_compress_stateless((uint8_t *) str2, sizeof(str2), FULL_FLUSH);
if (ret)
return ret;
for (i = 0; i < RANDOMS; i++) {
in_size = rand() % (IBUF_SIZE + 1);
offset = rand() % (IBUF_SIZE + 1 - in_size);
in_buf += offset;
create_rand_repeat_data(in_buf, in_size);
ret |= test_compress_stateless(in_buf, in_size, FULL_FLUSH);
in_buf -= offset;
if (i % (RANDOMS / 16) == 0)
printf(".");
if (ret)
return ret;
}
for (i = 0; i < RANDOMS / 16; i++) {
create_rand_repeat_data(in_buf, PAGE_SIZE);
ret |= test_compress_stateless(in_buf, PAGE_SIZE, FULL_FLUSH); // good for efence
}
fin_ret |= ret;
printf("%s\n", ret ? "Fail" : "Pass");
#endif
printf("igzip_rand_test stateful NO_FLUSH: ");
ret = test_compress((uint8_t *) str1, sizeof(str1), NO_FLUSH);
if (ret)
@@ -1502,7 +1726,7 @@ int main(int argc, char *argv[])
printf("%s\n", ret ? "Fail" : "Pass");
printf("igzip_rand_test SYNC_FLUSH: ");
printf("igzip_rand_test stateful SYNC_FLUSH: ");
ret = test_compress((uint8_t *) str1, sizeof(str1), SYNC_FLUSH);
if (ret)
@@ -1533,7 +1757,7 @@ int main(int argc, char *argv[])
printf("%s\n", ret ? "Fail" : "Pass");
printf("igzip_rand_test FULL_FLUSH: ");
printf("igzip_rand_test stateful FULL_FLUSH: ");
ret = test_compress((uint8_t *) str1, sizeof(str1), FULL_FLUSH);
if (ret)
@@ -1581,7 +1805,7 @@ int main(int argc, char *argv[])
printf("%s\n", ret ? "Fail" : "Pass");
printf("igzip_rand_test Change Flush: ");
printf("igzip_rand_test stateful Change Flush: ");
ret = test_flush((uint8_t *) str1, sizeof(str1));
if (ret)

View File

@@ -317,6 +317,15 @@ int isal_create_hufftables_subset(struct isal_hufftables * hufftables,
void isal_deflate_init(struct isal_zstream *stream);
/**
* @brief Initialize compression stream data structure
*
* @param stream Structure holding state information on the compression streams.
* @returns none
*/
void isal_deflate_stateless_init(struct isal_zstream *stream);
/**
* @brief Fast data (deflate) compression for storage applications.
*