Make LZFX Hash size dynamic.

Use smaller min rabin block when using fast compression algos.
Add missing check for algo init function return value.
This commit is contained in:
Moinak Ghosh 2012-07-23 21:43:12 +05:30
parent 8cfd54fe34
commit 53d4311534
7 changed files with 86 additions and 30 deletions

View file

@ -24,6 +24,8 @@
#ifndef __ALLOCATOR_H__ #ifndef __ALLOCATOR_H__
#define __ALLOCATOR_H__ #define __ALLOCATOR_H__
#include <sys/types.h>
void slab_init(); void slab_init();
void slab_cleanup(int quiet); void slab_cleanup(int quiet);
void *slab_alloc(void *p, size_t size); void *slab_alloc(void *p, size_t size);

View file

@ -56,8 +56,7 @@
*/ */
#include "lzfx.h" #include "lzfx.h"
#include <allocator.h>
#define LZFX_HSIZE (1 << (LZFX_HLOG))
/* We need this for memset */ /* We need this for memset */
#ifdef __cplusplus #ifdef __cplusplus
@ -74,13 +73,10 @@
# define fx_expect_true(expr) (expr) # define fx_expect_true(expr) (expr)
#endif #endif
typedef unsigned char u8;
typedef const u8 *LZSTATE[LZFX_HSIZE];
/* Define the hash function */ /* Define the hash function */
#define LZFX_FRST(p) (((p[0]) << 8) | p[1]) #define LZFX_FRST(p) (((p[0]) << 8) | p[1])
#define LZFX_NEXT(v,p) (((v) << 8) | p[2]) #define LZFX_NEXT(v,p) (((v) << 8) | p[2])
#define LZFX_IDX(h) ((( h >> (3*8 - LZFX_HLOG)) - h ) & (LZFX_HSIZE - 1)) #define LZFX_IDX(h, bits) ((( h >> (3*8 - bits)) - h ) & (LZFX_HTAB_SIZE(bits) - 1))
/* These cannot be changed, as they are related to the compressed format. */ /* These cannot be changed, as they are related to the compressed format. */
#define LZFX_MAX_LIT (1 << 5) #define LZFX_MAX_LIT (1 << 5)
@ -110,11 +106,12 @@ int lzfx_getsize(const void* ibuf, unsigned int ilen, unsigned int *olen);
*/ */
#include <stdio.h> #include <stdio.h>
int lzfx_compress(const void *const ibuf, const unsigned int ilen, int lzfx_compress(const void *const ibuf, const unsigned int ilen,
void *obuf, unsigned int *const olen){ void *obuf, unsigned int *const olen,
unsigned int htab_bits){
/* Hash table; an array of u8*'s which point /* Hash table; an array of u8*'s which point
to various locations in the input buffer */ to various locations in the input buffer */
const u8 *htab[LZFX_HSIZE]; const u8 **htab;
const u8 **hslot; /* Pointer to entry in hash table */ const u8 **hslot; /* Pointer to entry in hash table */
unsigned int hval; /* Hash value generated by macros above */ unsigned int hval; /* Hash value generated by macros above */
@ -145,7 +142,8 @@ int lzfx_compress(const void *const ibuf, const unsigned int ilen,
return lzfx_getsize(ibuf, ilen, olen); return lzfx_getsize(ibuf, ilen, olen);
} }
memset(htab, 0, sizeof(htab)); htab = (const u8 **)slab_calloc(NULL, LZFX_HTAB_SIZE(htab_bits), sizeof (u8*));
if (htab == NULL) return LZFX_ENOMEM;
/* Start a literal run. Whenever we do this the output pointer is /* Start a literal run. Whenever we do this the output pointer is
advanced because the current byte will hold the encoded length. */ advanced because the current byte will hold the encoded length. */
@ -156,7 +154,7 @@ int lzfx_compress(const void *const ibuf, const unsigned int ilen,
while(ip + 2 < in_end){ /* The NEXT macro reads 2 bytes ahead */ while(ip + 2 < in_end){ /* The NEXT macro reads 2 bytes ahead */
hval = LZFX_NEXT(hval, ip); hval = LZFX_NEXT(hval, ip);
hslot = htab + LZFX_IDX(hval); hslot = htab + LZFX_IDX(hval, htab_bits);
ref = *hslot; *hslot = ip; ref = *hslot; *hslot = ip;
@ -174,8 +172,10 @@ int lzfx_compress(const void *const ibuf, const unsigned int ilen,
/* lit == 0: op + 3 must be < out_end (because we undo the run) /* lit == 0: op + 3 must be < out_end (because we undo the run)
lit != 0: op + 3 + 1 must be < out_end */ lit != 0: op + 3 + 1 must be < out_end */
if(fx_expect_false(op - !lit + 3 + 1 >= out_end)) if(fx_expect_false(op - !lit + 3 + 1 >= out_end)) {
slab_free(NULL, htab);
return LZFX_ESIZE; return LZFX_ESIZE;
}
op [- lit - 1] = lit - 1; /* Terminate literal run */ op [- lit - 1] = lit - 1; /* Terminate literal run */
op -= !lit; /* Undo run if length is zero */ op -= !lit; /* Undo run if length is zero */
@ -209,14 +209,17 @@ int lzfx_compress(const void *const ibuf, const unsigned int ilen,
hval = LZFX_FRST (ip); hval = LZFX_FRST (ip);
hval = LZFX_NEXT (hval, ip); hval = LZFX_NEXT (hval, ip);
htab[LZFX_IDX (hval)] = ip; htab[LZFX_IDX (hval, htab_bits)] = ip;
ip++; /* ip = initial ip + #octets */ ip++; /* ip = initial ip + #octets */
} else { } else {
/* Keep copying literal bytes */ /* Keep copying literal bytes */
if (fx_expect_false (op >= out_end)) return LZFX_ESIZE; if (fx_expect_false (op >= out_end)) {
slab_free(NULL, htab);
return LZFX_ESIZE;
}
lit++; *op++ = *ip++; lit++; *op++ = *ip++;
@ -231,7 +234,10 @@ int lzfx_compress(const void *const ibuf, const unsigned int ilen,
/* At most 3 bytes remain in input. We therefore need 4 bytes available /* At most 3 bytes remain in input. We therefore need 4 bytes available
in the output buffer to store them (3 data + ctrl byte).*/ in the output buffer to store them (3 data + ctrl byte).*/
if (op + 3 > out_end) return LZFX_ESIZE; if (op + 3 > out_end) {
slab_free(NULL, htab);
return LZFX_ESIZE;
}
while (ip < in_end) { while (ip < in_end) {
@ -247,6 +253,7 @@ int lzfx_compress(const void *const ibuf, const unsigned int ilen,
op -= !lit; op -= !lit;
*olen = op - (u8 *)obuf; *olen = op - (u8 *)obuf;
slab_free(NULL, htab);
return 0; return 0;
} }

View file

@ -72,15 +72,15 @@ extern "C" {
#define LZFX_VERSION_MINOR 1 #define LZFX_VERSION_MINOR 1
#define LZFX_VERSION_STRING "0.1" #define LZFX_VERSION_STRING "0.1"
/* Hashtable size (2**LZFX_HLOG entries) */ #define LZFX_HTAB_SIZE(x) (1 << x)
#ifndef LZFX_HLOG
# define LZFX_HLOG 16
#endif
/* Predefined errors. */ /* Predefined errors. */
#define LZFX_ESIZE -1 /* Output buffer too small */ #define LZFX_ESIZE -1 /* Output buffer too small */
#define LZFX_ECORRUPT -2 /* Invalid data for decompression */ #define LZFX_ECORRUPT -2 /* Invalid data for decompression */
#define LZFX_EARGS -3 /* Arguments invalid (NULL) */ #define LZFX_EARGS -3 /* Arguments invalid (NULL) */
#define LZFX_ENOMEM -4 /* Out of memory when allocating hashtable */
typedef unsigned char u8;
/* Buffer-to buffer compression. /* Buffer-to buffer compression.
@ -92,7 +92,8 @@ extern "C" {
value is returned and olen is not modified. value is returned and olen is not modified.
*/ */
int lzfx_compress(const void* ibuf, unsigned int ilen, int lzfx_compress(const void* ibuf, unsigned int ilen,
void* obuf, unsigned int *olen); void* obuf, unsigned int *olen,
unsigned int htab_bits);
/* Buffer-to-buffer decompression. /* Buffer-to-buffer decompression.

View file

@ -28,6 +28,11 @@
#include <utils.h> #include <utils.h>
#include <pcompress.h> #include <pcompress.h>
#include <lzfx.h> #include <lzfx.h>
#include <allocator.h>
struct lzfx_params {
uint32_t htab_bits;
};
void void
lz_fx_stats(int show) lz_fx_stats(int show)
@ -37,11 +42,33 @@ lz_fx_stats(int show)
int int
lz_fx_init(void **data, int *level, ssize_t chunksize) lz_fx_init(void **data, int *level, ssize_t chunksize)
{ {
if (*level > 9) *level = 9; struct lzfx_params *lzdat;
int lev;
if (chunksize > UINT_MAX) { if (chunksize > UINT_MAX) {
fprintf(stderr, "Chunk size too big for LZFX.\n"); fprintf(stderr, "Chunk size too big for LZFX.\n");
return (1); return (1);
} }
lzdat = slab_alloc(NULL, sizeof (struct lzfx_params));
lev = *level;
if (lev > 5) lev = 5;
lzdat->htab_bits = 16 + (lev-1);
*data = lzdat;
if (*level > 9) *level = 9;
return (0);
}
int
lz_fx_deinit(void **data)
{
struct lzfx_params *lzdat = (struct lzfx_params *)(*data);
if (lzdat) {
slab_free(NULL, lzdat);
}
*data = NULL;
return (0); return (0);
} }
@ -58,6 +85,9 @@ lz_fx_err(int err)
case LZFX_EARGS: case LZFX_EARGS:
fprintf(stderr, "LZFX: Invalid arguments.\n"); fprintf(stderr, "LZFX: Invalid arguments.\n");
break; break;
case LZFX_ENOMEM:
fprintf(stderr, "LZFX: Out of memory when allocating hashtable.\n");
break;
default: default:
fprintf(stderr, "LZFX: Unknown error code: %d\n", err); fprintf(stderr, "LZFX: Unknown error code: %d\n", err);
} }
@ -68,10 +98,11 @@ lz_fx_compress(void *src, size_t srclen, void *dst, size_t *dstlen,
int level, uchar_t chdr, void *data) int level, uchar_t chdr, void *data)
{ {
int rv; int rv;
struct lzfx_params *lzdat = (struct lzfx_params *)data;
unsigned int _srclen = srclen; unsigned int _srclen = srclen;
unsigned int _dstlen = *dstlen; unsigned int _dstlen = *dstlen;
rv = lzfx_compress(src, _srclen, dst, &_dstlen); rv = lzfx_compress(src, _srclen, dst, &_dstlen, lzdat->htab_bits);
if (rv == -1) { if (rv == -1) {
lz_fx_err(rv); lz_fx_err(rv);
return (-1); return (-1);

16
main.c
View file

@ -442,8 +442,11 @@ start_decompress(const char *filename, const char *to_filename)
sem_init(&(tdat->start_sem), 0, 0); sem_init(&(tdat->start_sem), 0, 0);
sem_init(&(tdat->cmp_done_sem), 0, 0); sem_init(&(tdat->cmp_done_sem), 0, 0);
sem_init(&(tdat->write_done_sem), 0, 1); sem_init(&(tdat->write_done_sem), 0, 1);
if (_init_func) if (_init_func) {
_init_func(&(tdat->data), &(tdat->level), chunksize); if (_init_func(&(tdat->data), &(tdat->level), chunksize) != 0) {
UNCOMP_BAIL;
}
}
if (enable_rabin_scan) if (enable_rabin_scan)
tdat->rctx = create_rabin_context(chunksize, compressed_chunksize, tdat->rctx = create_rabin_context(chunksize, compressed_chunksize,
algo, enable_delta_encode); algo, enable_delta_encode);
@ -918,8 +921,11 @@ start_compress(const char *filename, uint64_t chunksize, int level)
sem_init(&(tdat->start_sem), 0, 0); sem_init(&(tdat->start_sem), 0, 0);
sem_init(&(tdat->cmp_done_sem), 0, 0); sem_init(&(tdat->cmp_done_sem), 0, 0);
sem_init(&(tdat->write_done_sem), 0, 1); sem_init(&(tdat->write_done_sem), 0, 1);
if (_init_func) if (_init_func) {
_init_func(&(tdat->data), &(tdat->level), chunksize); if (_init_func(&(tdat->data), &(tdat->level), chunksize) != 0) {
COMP_BAIL;
}
}
if (enable_rabin_scan) if (enable_rabin_scan)
tdat->rctx = create_rabin_context(chunksize, compressed_chunksize, tdat->rctx = create_rabin_context(chunksize, compressed_chunksize,
algo, enable_delta_encode); algo, enable_delta_encode);
@ -1189,7 +1195,7 @@ init_algo(const char *algo, int bail)
_compress_func = lz_fx_compress; _compress_func = lz_fx_compress;
_decompress_func = lz_fx_decompress; _decompress_func = lz_fx_decompress;
_init_func = lz_fx_init; _init_func = lz_fx_init;
_deinit_func = NULL; _deinit_func = lz_fx_deinit;
_stats_func = lz_fx_stats; _stats_func = lz_fx_stats;
rv = 0; rv = 0;

View file

@ -92,6 +92,7 @@ extern int lz_fx_init(void **data, int *level, ssize_t chunksize);
extern int adapt_deinit(void **data); extern int adapt_deinit(void **data);
extern int lzma_deinit(void **data); extern int lzma_deinit(void **data);
extern int ppmd_deinit(void **data); extern int ppmd_deinit(void **data);
extern int lz_fx_deinit(void **data);
extern void adapt_stats(int show); extern void adapt_stats(int show);
extern void ppmd_stats(int show); extern void ppmd_stats(int show);

View file

@ -111,12 +111,20 @@ create_rabin_context(uint64_t chunksize, uint64_t real_chunksize, const char *al
*/ */
ctx = (rabin_context_t *)slab_alloc(NULL, sizeof (rabin_context_t)); ctx = (rabin_context_t *)slab_alloc(NULL, sizeof (rabin_context_t));
ctx->rabin_poly_max_block_size = RAB_POLYNOMIAL_MAX_BLOCK_SIZE; ctx->rabin_poly_max_block_size = RAB_POLYNOMIAL_MAX_BLOCK_SIZE;
if (((memcmp(algo, "lzma", 4) == 0 || memcmp(algo, "adapt", 5) == 0) && if (((memcmp(algo, "lzma", 4) == 0 || memcmp(algo, "adapt", 5) == 0) &&
chunksize <= LZMA_WINDOW_MAX) || delta_flag) { chunksize <= LZMA_WINDOW_MAX) || delta_flag) {
if (memcmp(algo, "lzfx", 4) == 0 || memcmp(algo, "lz4", 3) == 0) {
ctx->rabin_poly_min_block_size = RAB_POLYNOMIAL_MIN_BLOCK_SIZE2;
ctx->rabin_avg_block_mask = RAB_POLYNOMIAL_AVG_BLOCK_MASK2;
ctx->rabin_poly_avg_block_size = RAB_POLYNOMIAL_AVG_BLOCK_SIZE2;
ctx->rabin_break_patt = 0;
} else {
ctx->rabin_poly_min_block_size = RAB_POLYNOMIAL_MIN_BLOCK_SIZE; ctx->rabin_poly_min_block_size = RAB_POLYNOMIAL_MIN_BLOCK_SIZE;
ctx->rabin_avg_block_mask = RAB_POLYNOMIAL_AVG_BLOCK_MASK; ctx->rabin_avg_block_mask = RAB_POLYNOMIAL_AVG_BLOCK_MASK;
ctx->rabin_poly_avg_block_size = RAB_POLYNOMIAL_AVG_BLOCK_SIZE; ctx->rabin_poly_avg_block_size = RAB_POLYNOMIAL_AVG_BLOCK_SIZE;
ctx->rabin_break_patt = RAB_POLYNOMIAL_CONST; ctx->rabin_break_patt = RAB_POLYNOMIAL_CONST;
}
} else { } else {
ctx->rabin_poly_min_block_size = RAB_POLYNOMIAL_MIN_BLOCK_SIZE2; ctx->rabin_poly_min_block_size = RAB_POLYNOMIAL_MIN_BLOCK_SIZE2;
ctx->rabin_avg_block_mask = RAB_POLYNOMIAL_AVG_BLOCK_MASK2; ctx->rabin_avg_block_mask = RAB_POLYNOMIAL_AVG_BLOCK_MASK2;