src/third-party/libpng/contrib/libtests/timepng.c (view raw)
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
38static 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
100static 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
111static 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
181static 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
222int 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}