/* * ztest by Davide Libenzi (zlib bench test) * Copyright (C) 2007 Davide Libenzi * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * * * Done by partially reusing the example.c code of the zlib tarbal. * To build linking to the stock zlib: * * $ gcc -o ztest ztest.c -lz * * To build using your own zlib build (inside the $ZLIB directory): * * $ gcc -I $ZLIB -o ztest ztest.c $ZLIB/libz.a * */ #include #include #include #include #include #include #include #include #include #include "zlib.h" #define MIN_TESTIME (2 * 1000000) #define INNER_CYCLES 32 #define CHECK_ERR(err, msg) do { \ if (err != Z_OK) { \ fprintf(stderr, "%s error: %d\n", msg, err); \ exit(1); \ } \ } while (0) static unsigned long long mintt = MIN_TESTIME; static uLong incycles = INNER_CYCLES; static unsigned long long getustime(void) { struct timeval tm; gettimeofday(&tm, NULL); return tm.tv_sec * 1000000ULL + tm.tv_usec; } static void do_defl(Byte *cdata, uLong *clen, Byte *udata, uLong uclen) { z_stream c_stream; /* compression stream */ int err; c_stream.zalloc = (alloc_func) NULL; c_stream.zfree = (free_func) NULL; c_stream.opaque = (voidpf) NULL; err = deflateInit(&c_stream, Z_BEST_SPEED); CHECK_ERR(err, "deflateInit"); c_stream.next_out = cdata; c_stream.avail_out = (uInt) *clen; /* At this point, udata is still mostly zeroes, so it should compress * very well: */ c_stream.next_in = udata; c_stream.avail_in = (uInt) uclen; err = deflate(&c_stream, Z_FINISH); if (err != Z_STREAM_END) { fprintf(stderr, "whoops, got %d instead of Z_STREAM_END\n", err); exit(1); } err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); *clen = c_stream.next_out - cdata; } static void do_infl(Byte *cdata, uLong clen, Byte *udata, uLong *uclen) { int err; z_stream d_stream; /* decompression stream */ d_stream.zalloc = (alloc_func) NULL; d_stream.zfree = (free_func) NULL; d_stream.opaque = (voidpf) NULL; d_stream.next_in = cdata; d_stream.avail_in = (uInt) clen; err = inflateInit(&d_stream); CHECK_ERR(err, "inflateInit"); d_stream.next_out = udata; /* discard the output */ d_stream.avail_out = (uInt) *uclen; err = inflate(&d_stream, Z_FULL_FLUSH); if (err != Z_STREAM_END) { fprintf(stderr, "deflate should report Z_STREAM_END\n"); exit(1); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); *uclen = d_stream.next_out - udata; } static int do_filebench(char const *fpath) { int fd, err = -1; uLong i, n, clen, ulen, size; Byte *ubuf, *cbuf, *tbuf; unsigned long long ts, te; void *addr; struct stat stb; if ((fd = open(fpath, O_RDONLY)) == -1 || fstat(fd, &stb)) { perror(fpath); close(fd); return -1; } size = stb.st_size; addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); if (addr == (void *) -1L) { perror("mmap"); return -1; } ulen = size; clen = size + 4096; ubuf = addr; if ((tbuf = malloc(ulen + clen)) == NULL) { perror("malloc"); goto err_exit; } cbuf = tbuf + ulen; /* Warming up ... */ do_defl(cbuf, &clen, ubuf, ulen); do_infl(cbuf, clen, tbuf, &ulen); if (ulen != size) { fprintf(stderr, "size mismatch %lu instead of %lu\n", (unsigned long) ulen, (unsigned long) size); goto err_exit; } if (memcmp(tbuf, ubuf, size)) { fprintf(stderr, "whoops! we did not get back the same data\n"); goto err_exit; } /* Test ... */ fprintf(stdout, "testing: %s\n", fpath); ts = getustime(); n = 0; do { for (i = 0; i < incycles; i++) { ulen = size; do_infl(cbuf, clen, tbuf, &ulen); } n += i; te = getustime(); } while (te - ts < mintt); fprintf(stdout, "\tus time / cycle = %llu\n", (te - ts) / n); err = 0; err_exit: free(tbuf); munmap(addr, size); return err; } int main(int ac, char **av) { int i; for (i = 1; i < ac; i++) do_filebench(av[i]); return 0; }