Skip to content

Instantly share code, notes, and snippets.

@dajhorn
Created May 11, 2015 21:30
Show Gist options
  • Save dajhorn/793c64d3fe77069fb1e0 to your computer and use it in GitHub Desktop.
Save dajhorn/793c64d3fe77069fb1e0 to your computer and use it in GitHub Desktop.
Tinc compression benchmark, updated for the liblz4 head.
/*
compression.c -- compression benchmark
Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org>
Compile: gcc -std=gnu99 compression_speed.c -lz -llzo2 -llz4 -lrt
Usage: compression_speed [packet size] < input
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <zlib.h>
#include <lzo/lzo1x.h>
#include <lz4.h>
#include <lz4hc.h>
struct timespec start;
struct timespec end;
static void clock_start() {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
}
static double clock_end() {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
return end.tv_sec + end.tv_nsec * 1e-9 - start.tv_sec - start.tv_nsec * 1e-9;
}
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
static void *lz4_wrkmem;
static ssize_t do_compress(int level, const void *in, size_t inlen, void *out, size_t maxlen) {
if(level <= 9) {
unsigned long outlen = maxlen;
if(compress2(out, &outlen, in, inlen, level) != Z_OK)
return -1;
return outlen;
} else if(level <= 11) {
lzo_uint outlen = maxlen;
int result;
if(level == 10)
result = lzo1x_1_compress(in, inlen, out, &outlen, lzo_wrkmem);
else
result = lzo1x_999_compress(in, inlen, out, &outlen, lzo_wrkmem);
if(result != LZO_E_OK)
return -1;
return outlen;
} else if(level <= 13) {
/* LZ4 release 1.7.0 legacy interface. */
int outlen;
if(level == 12)
outlen = LZ4_compress_limitedOutput(in, out, inlen, maxlen);
else
outlen = LZ4_compressHC_limitedOutput(in, out, inlen, maxlen);
return outlen;
} else if(level <= 15) {
/* LZ4 head r129 */
if(level == 14)
/* LZ4_compress_default() level. */
return LZ4_compress_fast_extState(lz4_wrkmem, in, out, inlen, maxlen, 1);
else if (level == 15)
/* New liblz4 default level. */
return LZ4_compress_fast_extState(lz4_wrkmem, in, out, inlen, maxlen, 0);
}
}
static ssize_t do_decompress(int level, const void *in, size_t inlen, void *out, size_t maxlen) {
if(level <= 9) {
unsigned long outlen = maxlen;
if(uncompress(out, &outlen, in, inlen) != Z_OK)
return -1;
return outlen;
} else if(level <= 11) {
lzo_uint outlen = maxlen;
int result;
result = lzo1x_decompress_safe(in, inlen, out, &outlen, lzo_wrkmem);
if(result != LZO_E_OK)
return -1;
return outlen;
} else if(level <= 15) {
return LZ4_decompress_safe(in, out, inlen, maxlen);
}
}
int main(int argc, char *argv[]) {
fprintf(stderr, "Reading input from stdin... ");
size_t datalen = 0;
size_t alloced = 1e6;
char *data = malloc(alloced);
lz4_wrkmem = malloc(LZ4_sizeofState());
if(!data)
abort();
ssize_t len;
while((len = read(0, data + datalen, alloced - datalen)) > 0) {
datalen += len;
if(datalen >= alloced) {
alloced += 1e6;
data = realloc(data, alloced);
if(!data)
abort();
}
}
if(!datalen)
return 1;
fprintf(stderr, "%zu bytes\n", datalen);
lzo_init();
const size_t psize = argc > 1 ? atoi(argv[1]) : 1451;
fprintf(stderr, "Packet size: %zu\n", psize);
char buf1[psize * 2 + 1024];
char buf2[psize * 2 + 1024];
for(int level = 1; level <= 15; level++) {
if(level <= 9)
fprintf(stderr, "zlib%d: ", level);
else if(level <= 11)
fprintf(stderr, "lzo1x_%s ", (level == 11) ? "999: " : "1: ");
else if(level <= 13)
// Old LZ4.
fprintf(stderr, "lz4_%s ", (level == 13) ? "hc: " : "lo: ");
else if(level <= 15)
// New LZ4.
fprintf(stderr, "lz4_%s ", (level == 15) ? "acc:" : "ext:");
// warmup, ignore any errors.
for(const char *p = data; p < data + datalen - psize; p += psize) {
ssize_t len1 = do_compress(level, p, psize, buf1, sizeof buf1);
if(len1 > 0)
do_decompress(level, buf1, len1, buf2, sizeof buf2);
}
// real run
size_t ulen = 0;
size_t clen = 0;
clock_start();
for(const char *p = data; p < data + datalen - psize; p += psize) {
ssize_t len1 = do_compress(level, p, psize, buf1, sizeof buf1);
if(len1 <= 0) {
fprintf(stderr, "compression failed\n");
return 2;
}
ssize_t len2 = do_decompress(level, buf1, len1, buf2, sizeof buf2);
if(len2 <= 0) {
fprintf(stderr, "decompression failed\n");
return 3;
}
if(len2 != psize) {
fprintf(stderr, "decompressed size does not match input\n");
return 4;
}
#if 0
if(memcmp(p, buf2, psize)) {
fprintf(stderr, "decompressed data does not match input\n");
return 5;
}
#endif
ulen += psize;
clen += len1;
}
double elapsed = clock_end();
fprintf(stderr, "%6.2lf MB/s, ratio %.2lf\n", ulen / elapsed * 1e-6, (double)clen / ulen);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment