Imported Upstream version 1.6.13
[platform/upstream/libpng.git] / contrib / libtests / timepng.c
1 /* timepng.c
2  *
3  * Copyright (c) 2013 John Cunningham Bowler
4  *
5  * Last changed in libpng 1.6.1 [March 28, 2013]
6  *
7  * This code is released under the libpng license.
8  * For conditions of distribution and use, see the disclaimer
9  * and license in png.h
10  *
11  * Load an arbitrary number of PNG files (from the command line, or, if there
12  * are no arguments on the command line, from stdin) then run a time test by
13  * reading each file by row.  The test does nothing with the read result and
14  * does no transforms.  The only output is a time as a floating point number of
15  * seconds with 9 decimal digits.
16  */
17 #define _POSIX_C_SOURCE 199309L /* for clock_gettime */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include <time.h>
24
25 #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
26 #  include <config.h>
27 #endif
28
29 /* Define the following to use this test against your installed libpng, rather
30  * than the one being built here:
31  */
32 #ifdef PNG_FREESTANDING_TESTS
33 #  include <png.h>
34 #else
35 #  include "../../png.h"
36 #endif
37
38 static int read_png(FILE *fp)
39 {
40    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
41    png_infop info_ptr = NULL;
42    png_bytep row = NULL, display = NULL;
43
44    if (png_ptr == NULL)
45       return 0;
46
47    if (setjmp(png_jmpbuf(png_ptr)))
48    {
49       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
50       if (row != NULL) free(row);
51       if (display != NULL) free(display);
52       return 0;
53    }
54
55    png_init_io(png_ptr, fp);
56
57    info_ptr = png_create_info_struct(png_ptr);
58    if (info_ptr == NULL)
59       png_error(png_ptr, "OOM allocating info structure");
60
61    png_read_info(png_ptr, info_ptr);
62
63    {
64       png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
65
66       row = malloc(rowbytes);
67       display = malloc(rowbytes);
68
69       if (row == NULL || display == NULL)
70          png_error(png_ptr, "OOM allocating row buffers");
71
72       {
73          png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
74          int passes = png_set_interlace_handling(png_ptr);
75          int pass;
76
77          png_start_read_image(png_ptr);
78
79          for (pass = 0; pass < passes; ++pass)
80          {
81             png_uint_32 y = height;
82
83             /* NOTE: this trashes the row each time; interlace handling won't
84              * work, but this avoids memory thrashing for speed testing.
85              */
86             while (y-- > 0)
87                png_read_row(png_ptr, row, display);
88          }
89       }
90    }
91
92    /* Make sure to read to the end of the file: */
93    png_read_end(png_ptr, info_ptr);
94    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
95    free(row);
96    free(display);
97    return 1;
98 }
99
100 static int mytime(struct timespec *t)
101 {
102    /* Do the timing using clock_gettime and the per-process timer. */
103    if (!clock_gettime(CLOCK_PROCESS_CPUTIME_ID, t))
104       return 1;
105
106    perror("CLOCK_PROCESS_CPUTIME_ID");
107    fprintf(stderr, "timepng: could not get the time\n");
108    return 0;
109 }
110
111 static int perform_one_test(FILE *fp, int nfiles)
112 {
113    int i;
114    struct timespec before, after;
115
116    /* Clear out all errors: */
117    rewind(fp);
118
119    if (mytime(&before))
120    {
121       for (i=0; i<nfiles; ++i)
122       {
123          if (read_png(fp))
124          {
125             if (ferror(fp))
126             {
127                perror("temporary file");
128                fprintf(stderr, "file %d: error reading PNG data\n", i);
129                return 0;
130             }
131          }
132
133          else
134          {
135             perror("temporary file");
136             fprintf(stderr, "file %d: error from libpng\n", i);
137             return 0;
138          }
139       }
140    }
141
142    else
143       return 0;
144
145    if (mytime(&after))
146    {
147       /* Work out the time difference and print it - this is the only output,
148        * so flush it immediately.
149        */
150       unsigned long s = after.tv_sec - before.tv_sec;
151       long ns = after.tv_nsec - before.tv_nsec;
152
153       if (ns < 0)
154       {
155          --s;
156          ns += 1000000000;
157
158          if (ns < 0)
159          {
160             fprintf(stderr, "timepng: bad clock from kernel\n");
161             return 0;
162          }
163       }
164
165       printf("%lu.%.9ld\n", s, ns);
166       fflush(stdout);
167       if (ferror(stdout))
168       {
169          fprintf(stderr, "timepng: error writing output\n");
170          return 0;
171       }
172
173       /* Successful return */
174       return 1;
175    }
176
177    else
178       return 0;
179 }
180
181 static int add_one_file(FILE *fp, char *name)
182 {
183    FILE *ip = fopen(name, "rb");
184
185    if (ip != NULL)
186    {
187       int ch;
188       for (;;)
189       {
190          ch = getc(ip);
191          if (ch == EOF) break;
192          putc(ch, fp);
193       }
194
195       if (ferror(ip))
196       {
197          perror(name);
198          fprintf(stderr, "%s: read error\n", name);
199          return 0;
200       }
201
202       (void)fclose(ip);
203
204       if (ferror(fp))
205       {
206          perror("temporary file");
207          fprintf(stderr, "temporary file write error\n");
208          return 0;
209       }
210    }
211
212    else
213    {
214       perror(name);
215       fprintf(stderr, "%s: open failed\n", name);
216       return 0;
217    }
218
219    return 1;
220 }
221
222 int main(int argc, char **argv)
223 {
224    int ok = 0;
225    FILE *fp = tmpfile();
226
227    if (fp != NULL)
228    {
229       int err = 0;
230       int nfiles = 0;
231
232       if (argc > 1)
233       {
234          int i;
235
236          for (i=1; i<argc; ++i)
237          {
238             if (add_one_file(fp, argv[i]))
239                ++nfiles;
240
241             else
242             {
243                err = 1;
244                break;
245             }
246          }
247       }
248
249       else
250       {
251          char filename[FILENAME_MAX+1];
252
253          while (fgets(filename, FILENAME_MAX+1, stdin))
254          {
255             size_t len = strlen(filename);
256
257             if (filename[len-1] == '\n')
258             {
259                filename[len-1] = 0;
260                if (add_one_file(fp, filename))
261                   ++nfiles;
262
263                else
264                {
265                   err = 1;
266                   break;
267                }
268             }
269
270             else
271             {
272                fprintf(stderr, "timepng: truncated file name ...%s\n",
273                   filename+len-32);
274                err = 1;
275                break;
276             }
277          }
278
279          if (ferror(stdin))
280          {
281             fprintf(stderr, "timepng: stdin: read error\n");
282             err = 1;
283          }
284       }
285
286       if (!err)
287       {
288          if (nfiles > 0)
289             ok = perform_one_test(fp, nfiles);
290
291          else
292             fprintf(stderr, "usage: timepng {files} or ls files | timepng\n");
293       }
294
295       (void)fclose(fp);
296    }
297
298    else
299       fprintf(stderr, "timepng: could not open temporary file\n");
300
301    /* Exit code 0 on success. */
302    return ok == 0;
303 }