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