all repos — mgba @ 6882339f625b97f344c6464915c2038bc453ea3c

mGBA Game Boy Advance Emulator

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}