Home | History | Annotate | Download | only in filter
      1 /*
      2  * Raster benchmark program for CUPS.
      3  *
      4  * Copyright 2007-2016 by Apple Inc.
      5  * Copyright 1997-2006 by Easy Software Products.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /*
     17  * Include necessary headers...
     18  */
     19 
     20 #include <config.h>
     21 #include <cups/raster.h>
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <sys/time.h>
     25 #include <signal.h>
     26 #include <unistd.h>
     27 #include <sys/wait.h>
     28 
     29 
     30 /*
     31  * Constants...
     32  */
     33 
     34 #define TEST_WIDTH	1024
     35 #define TEST_HEIGHT	1024
     36 #define TEST_PAGES	16
     37 #define TEST_PASSES	20
     38 
     39 
     40 /*
     41  * Local functions...
     42  */
     43 
     44 static double	compute_median(double *secs);
     45 static double	get_time(void);
     46 static void	read_test(int fd);
     47 static int	run_read_test(void);
     48 static void	write_test(int fd, cups_mode_t mode);
     49 
     50 
     51 /*
     52  * 'main()' - Benchmark the raster read/write functions.
     53  */
     54 
     55 int					/* O - Exit status */
     56 main(int  argc,				/* I - Number of command-line args */
     57      char *argv[])			/* I - Command-line arguments */
     58 {
     59   int		i;			/* Looping var */
     60   int		ras_fd,			/* File descriptor for read process */
     61 		status;			/* Exit status of read process */
     62   double	start_secs,		/* Start time */
     63 		write_secs,		/* Write time */
     64 		read_secs,		/* Read time */
     65 		pass_secs[TEST_PASSES];	/* Total test times */
     66   cups_mode_t	mode;			/* Write mode */
     67 
     68 
     69  /*
     70   * See if we have anything on the command-line...
     71   */
     72 
     73   if (argc > 2 || (argc == 2 && strcmp(argv[1], "-z")))
     74   {
     75     puts("Usage: rasterbench [-z]");
     76     return (1);
     77   }
     78 
     79   mode = argc > 1 ? CUPS_RASTER_WRITE_COMPRESSED : CUPS_RASTER_WRITE;
     80 
     81  /*
     82   * Ignore SIGPIPE...
     83   */
     84 
     85   signal(SIGPIPE, SIG_IGN);
     86 
     87  /*
     88   * Run the tests several times to get a good average...
     89   */
     90 
     91   printf("Test read/write speed of %d pages, %dx%d pixels...\n\n",
     92          TEST_PAGES, TEST_WIDTH, TEST_HEIGHT);
     93   for (i = 0; i < TEST_PASSES; i ++)
     94   {
     95     printf("PASS %2d: ", i + 1);
     96     fflush(stdout);
     97 
     98     ras_fd     = run_read_test();
     99     start_secs = get_time();
    100 
    101     write_test(ras_fd, mode);
    102 
    103     write_secs = get_time();
    104     printf(" %.3f write,", write_secs - start_secs);
    105     fflush(stdout);
    106 
    107     close(ras_fd);
    108     wait(&status);
    109 
    110     read_secs    = get_time();
    111     pass_secs[i] = read_secs - start_secs;
    112     printf(" %.3f read, %.3f total\n", read_secs - write_secs, pass_secs[i]);
    113   }
    114 
    115   printf("\nMedian Total Time: %.3f seconds per document\n",
    116          compute_median(pass_secs));
    117 
    118   return (0);
    119 }
    120 
    121 
    122 /*
    123  * 'compute_median()' - Compute the median time for a test.
    124  */
    125 
    126 static double				/* O - Median time in seconds */
    127 compute_median(double *secs)		/* I - Array of time samples */
    128 {
    129   int		i, j;			/* Looping vars */
    130   double	temp;			/* Swap variable */
    131 
    132 
    133  /*
    134   * Sort the array into ascending order using a quicky bubble sort...
    135   */
    136 
    137   for (i = 0; i < (TEST_PASSES - 1); i ++)
    138     for (j = i + 1; j < TEST_PASSES; j ++)
    139       if (secs[i] > secs[j])
    140       {
    141         temp    = secs[i];
    142 	secs[i] = secs[j];
    143 	secs[j] = temp;
    144       }
    145 
    146  /*
    147   * Return the average of the middle two samples...
    148   */
    149 
    150   return (0.5 * (secs[TEST_PASSES / 2 - 1] + secs[TEST_PASSES / 2]));
    151 }
    152 
    153 
    154 /*
    155  * 'get_time()' - Get the current time in seconds.
    156  */
    157 
    158 static double				/* O - Time in seconds */
    159 get_time(void)
    160 {
    161   struct timeval	curtime;	/* Current time */
    162 
    163 
    164   gettimeofday(&curtime, NULL);
    165   return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
    166 }
    167 
    168 
    169 /*
    170  * 'read_test()' - Benchmark the raster read functions.
    171  */
    172 
    173 static void
    174 read_test(int fd)			/* I - File descriptor to read from */
    175 {
    176   unsigned		y;		/* Looping var */
    177   cups_raster_t		*r;		/* Raster stream */
    178   cups_page_header2_t	header;		/* Page header */
    179   unsigned char		buffer[8 * TEST_WIDTH];
    180 					/* Read buffer */
    181 
    182 
    183  /*
    184   * Test read speed...
    185   */
    186 
    187   if ((r = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL)
    188   {
    189     perror("Unable to create raster input stream");
    190     return;
    191   }
    192 
    193   while (cupsRasterReadHeader2(r, &header))
    194   {
    195     for (y = 0; y < header.cupsHeight; y ++)
    196       cupsRasterReadPixels(r, buffer, header.cupsBytesPerLine);
    197   }
    198 
    199   cupsRasterClose(r);
    200 }
    201 
    202 
    203 /*
    204  * 'run_read_test()' - Run the read test as a child process via pipes.
    205  */
    206 
    207 static int				/* O - Standard input of child */
    208 run_read_test(void)
    209 {
    210   int	ras_pipes[2];			/* Raster data pipes */
    211   int	pid;				/* Child process ID */
    212 
    213 
    214   if (pipe(ras_pipes))
    215     return (-1);
    216 
    217   if ((pid = fork()) < 0)
    218   {
    219    /*
    220     * Fork error - return -1 on error...
    221     */
    222 
    223     close(ras_pipes[0]);
    224     close(ras_pipes[1]);
    225 
    226     return (-1);
    227   }
    228   else if (pid == 0)
    229   {
    230    /*
    231     * Child comes here - read data from the input pipe...
    232     */
    233 
    234     close(ras_pipes[1]);
    235     read_test(ras_pipes[0]);
    236     exit(0);
    237   }
    238   else
    239   {
    240    /*
    241     * Parent comes here - return the output pipe...
    242     */
    243 
    244     close(ras_pipes[0]);
    245     return (ras_pipes[1]);
    246   }
    247 }
    248 
    249 
    250 /*
    251  * 'write_test()' - Benchmark the raster write functions.
    252  */
    253 
    254 static void
    255 write_test(int         fd,		/* I - File descriptor to write to */
    256            cups_mode_t mode)		/* I - Write mode */
    257 {
    258   unsigned		page, x, y;	/* Looping vars */
    259   unsigned		count;		/* Number of bytes to set */
    260   cups_raster_t		*r;		/* Raster stream */
    261   cups_page_header2_t	header;		/* Page header */
    262   unsigned char		data[32][8 * TEST_WIDTH];
    263 					/* Raster data to write */
    264 
    265 
    266  /*
    267   * Create a combination of random data and repeated data to simulate
    268   * text with some whitespace.
    269   */
    270 
    271   CUPS_SRAND(time(NULL));
    272 
    273   memset(data, 0, sizeof(data));
    274 
    275   for (y = 0; y < 28; y ++)
    276   {
    277     for (x = CUPS_RAND() & 127, count = (CUPS_RAND() & 15) + 1;
    278          x < sizeof(data[0]);
    279          x ++, count --)
    280     {
    281       if (count <= 0)
    282       {
    283 	x     += (CUPS_RAND() & 15) + 1;
    284 	count = (CUPS_RAND() & 15) + 1;
    285 
    286         if (x >= sizeof(data[0]))
    287 	  break;
    288       }
    289 
    290       data[y][x] = (unsigned char)CUPS_RAND();
    291     }
    292   }
    293 
    294  /*
    295   * Test write speed...
    296   */
    297 
    298   if ((r = cupsRasterOpen(fd, mode)) == NULL)
    299   {
    300     perror("Unable to create raster output stream");
    301     return;
    302   }
    303 
    304   for (page = 0; page < TEST_PAGES; page ++)
    305   {
    306     memset(&header, 0, sizeof(header));
    307     header.cupsWidth        = TEST_WIDTH;
    308     header.cupsHeight       = TEST_HEIGHT;
    309     header.cupsBytesPerLine = TEST_WIDTH;
    310 
    311     if (page & 1)
    312     {
    313       header.cupsBytesPerLine *= 4;
    314       header.cupsColorSpace = CUPS_CSPACE_CMYK;
    315       header.cupsColorOrder = CUPS_ORDER_CHUNKED;
    316     }
    317     else
    318     {
    319       header.cupsColorSpace = CUPS_CSPACE_K;
    320       header.cupsColorOrder = CUPS_ORDER_BANDED;
    321     }
    322 
    323     if (page & 2)
    324     {
    325       header.cupsBytesPerLine *= 2;
    326       header.cupsBitsPerColor = 16;
    327       header.cupsBitsPerPixel = (page & 1) ? 64 : 16;
    328     }
    329     else
    330     {
    331       header.cupsBitsPerColor = 8;
    332       header.cupsBitsPerPixel = (page & 1) ? 32 : 8;
    333     }
    334 
    335     cupsRasterWriteHeader2(r, &header);
    336 
    337     for (y = 0; y < TEST_HEIGHT; y ++)
    338       cupsRasterWritePixels(r, data[y & 31], header.cupsBytesPerLine);
    339   }
    340 
    341   cupsRasterClose(r);
    342 }
    343