• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
def(FILE * source,FILE * dest,int level)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 
inf(FILE * source)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 
usage(void)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
get_time_usec(void)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 
main(int argc,char ** argv)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