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