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 45int 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 93int 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 148static 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 156static double 157get_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 175int 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