Home | History | Annotate | Download | only in other
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 /* this small program is used to measure the performance of zlib's inflate
     29  * algorithm...
     30  */
     31 
     32 /* most code lifted from the public-domain http://www.zlib.net/zpipe.c */
     33 
     34 #include <zlib.h>
     35 #include <time.h>
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #include <errno.h>
     40 #include <unistd.h>
     41 #include <sys/time.h>
     42 
     43 #define  CHUNK    32768
     44 
     45 int def(FILE *source, FILE *dest, int level)
     46 {
     47     int ret, flush;
     48     unsigned have;
     49     z_stream strm;
     50     unsigned char in[CHUNK];
     51     unsigned char out[CHUNK];
     52 
     53     /* allocate deflate state */
     54     strm.zalloc = Z_NULL;
     55     strm.zfree = Z_NULL;
     56     strm.opaque = Z_NULL;
     57     ret = deflateInit(&strm, level);
     58     if (ret != Z_OK)
     59         return ret;
     60 
     61     /* compress until end of file */
     62     do {
     63         strm.avail_in = fread(in, 1, CHUNK, source);
     64         if (ferror(source)) {
     65             (void)deflateEnd(&strm);
     66             return Z_ERRNO;
     67         }
     68         flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
     69         strm.next_in = in;
     70 
     71         /* run deflate() on input until output buffer not full, finish
     72         compression if all of source has been read in */
     73         do {
     74             strm.avail_out = CHUNK;
     75             strm.next_out = out;
     76             ret = deflate(&strm, flush);    /* no bad return value */
     77             have = CHUNK - strm.avail_out;
     78             if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
     79                 (void)deflateEnd(&strm);
     80                 return Z_ERRNO;
     81             }
     82         } while (strm.avail_out == 0);
     83 
     84         /* done when last data in file processed */
     85     } while (flush != Z_FINISH);
     86 
     87     /* clean up and return */
     88     (void)deflateEnd(&strm);
     89     return Z_OK;
     90 }
     91 
     92 
     93 int inf(FILE *source)
     94 {
     95     int ret;
     96     unsigned have;
     97     z_stream strm;
     98     static unsigned char in[CHUNK];
     99     static unsigned char out[CHUNK];
    100 
    101     /* allocate inflate state */
    102     strm.zalloc   = Z_NULL;
    103     strm.zfree    = Z_NULL;
    104     strm.opaque   = Z_NULL;
    105     strm.avail_in = 0;
    106     strm.next_in  = Z_NULL;
    107     ret = inflateInit(&strm);
    108     if (ret != Z_OK)
    109         return ret;
    110 
    111     /* decompress until deflate stream ends or end of file */
    112     do {
    113         strm.avail_in = fread(in, 1, CHUNK, source);
    114         if (ferror(source)) {
    115             (void)inflateEnd(&strm);
    116             return Z_ERRNO;
    117         }
    118         if (strm.avail_in == 0)
    119             break;
    120         strm.next_in = in;
    121 
    122         /* run inflate() on input until output buffer not full */
    123         do {
    124             strm.avail_out = CHUNK;
    125             strm.next_out  = out;
    126             ret = inflate(&strm, Z_NO_FLUSH);
    127             switch (ret) {
    128                 case Z_NEED_DICT:
    129                     ret = Z_DATA_ERROR;     /* and fall through */
    130                 case Z_DATA_ERROR:
    131                 case Z_MEM_ERROR:
    132                     (void)inflateEnd(&strm);
    133                     return ret;
    134             }
    135         } while (strm.avail_out == 0);
    136 
    137         /* done when inflate() says it's done */
    138     } while (ret != Z_STREAM_END);
    139 
    140     /* clean up and return */
    141     (void)inflateEnd(&strm);
    142     return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
    143 }
    144 
    145 #define  DEFAULT_REPEAT  10
    146 #define  DEFAULT_LEVEL   9
    147 
    148 static void usage(void)
    149 {
    150     fprintf(stderr, "usage: test_zlib [options] filename [filename2 ...]\n" );
    151     fprintf(stderr, "options:  -r NN   repeat count  (default %d)\n", DEFAULT_REPEAT );
    152     fprintf(stderr, "          -N      set compression level (default %d)\n", DEFAULT_LEVEL );
    153     exit(1);
    154 }
    155 
    156 static double
    157 get_time_usec( void )
    158 {
    159 #ifdef HAVE_ANDROID_OS
    160     struct timespec  ts;
    161 
    162     if ( clock_gettime( CLOCK_MONOTONIC, &ts ) < 0 )
    163         fprintf(stderr, "clock_gettime: %s\n", strerror(errno) );
    164 
    165     return ts.tv_sec*1e6 + ts.tv_nsec*1e-3;
    166 #else
    167     struct timeval  tv;
    168     if (gettimeofday( &tv, NULL ) < 0)
    169         fprintf(stderr, "gettimeofday: %s\n", strerror(errno) );
    170 
    171     return tv.tv_sec*1000000. + tv.tv_usec*1.0;
    172 #endif
    173 }
    174 
    175 int  main( int  argc, char**  argv )
    176 {
    177     FILE*  f;
    178     char   tempfile[256];
    179     int    repeat_count      = DEFAULT_REPEAT;
    180     int    compression_level = DEFAULT_LEVEL;
    181     double  usec0, usec1;
    182 
    183     if (argc < 2)
    184         usage();
    185 
    186     for ( ; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
    187         const char*  arg = &argv[1][1];
    188         switch (arg[0]) {
    189             case 'r':
    190                 if (arg[1] == 0) {
    191                     if (argc < 3)
    192                         usage();
    193                     arg = argv[2];
    194                     argc--;
    195                     argv++;
    196                 } else
    197                     arg += 1;
    198 
    199                 repeat_count = strtol(arg, NULL, 10);
    200 
    201                 if (repeat_count <= 0)
    202                     repeat_count = 1;
    203                 break;
    204 
    205             case '0': case '1': case '2': case '3': case '4':
    206             case '5': case '6': case '7': case '8': case '9':
    207                 compression_level = arg[0] - '0';
    208                 break;
    209 
    210             default:
    211                 usage();
    212         }
    213     }
    214 
    215     sprintf(tempfile, "/tmp/ztest.%d", getpid() );
    216 
    217     for ( ; argc > 1; argc--, argv++ )
    218     {
    219         /* first, compress the file into a temporary storage */
    220         FILE*  f   = fopen(argv[1], "rb");
    221         FILE*  out = NULL;
    222         long   fsize;
    223         int    ret, rr;
    224 
    225         if (f == NULL) {
    226             fprintf(stderr, "could not open '%s': %s\n", argv[1], strerror(errno) );
    227             continue;
    228         }
    229 
    230         printf( "testing %s\n", argv[1] );
    231         fseek( f, 0, SEEK_END );
    232         fsize = ftell(f);
    233         fseek( f, 0, SEEK_SET );
    234 
    235         out = fopen( tempfile, "wb" );
    236         if (out == NULL) {
    237             fprintf(stderr, "could not create '%s': %s\n", tempfile, strerror(errno));
    238             fclose(f);
    239             continue;
    240         }
    241 
    242         usec0 = get_time_usec();
    243 
    244         ret = def( f, out, compression_level );
    245 
    246         usec1 = get_time_usec() - usec0;
    247         printf( "compression took:   %10.3f ms  (%.2f KB/s)\n", usec1/1e3, fsize*(1e6/1024)/usec1 );
    248 
    249         fclose( out );
    250         fclose(f);
    251 
    252         usec0 = get_time_usec();
    253         f    = fopen( tempfile, "rb" );
    254 
    255         for ( rr = repeat_count; rr > 0; rr -- )
    256         {
    257             fseek( f, 0, SEEK_SET );
    258             inf(f);
    259         }
    260         fclose( f );
    261         usec1 = get_time_usec() - usec0;
    262         printf( "decompression took: %10.3f ms (%.2f KB/s, %d passes)\n", usec1/1e3, fsize*(1e6/1024)*repeat_count/usec1, repeat_count );
    263     }
    264 
    265     unlink(tempfile);
    266     return 0;
    267 }
    268