/* * Raster benchmark program for CUPS. * * Copyright 2007-2016 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include #include #include #include #include #include #include #include /* * Constants... */ #define TEST_WIDTH 1024 #define TEST_HEIGHT 1024 #define TEST_PAGES 16 #define TEST_PASSES 20 /* * Local functions... */ static double compute_median(double *secs); static double get_time(void); static void read_test(int fd); static int run_read_test(void); static void write_test(int fd, cups_mode_t mode); /* * 'main()' - Benchmark the raster read/write functions. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ int ras_fd, /* File descriptor for read process */ status; /* Exit status of read process */ double start_secs, /* Start time */ write_secs, /* Write time */ read_secs, /* Read time */ pass_secs[TEST_PASSES]; /* Total test times */ cups_mode_t mode; /* Write mode */ /* * See if we have anything on the command-line... */ if (argc > 2 || (argc == 2 && strcmp(argv[1], "-z"))) { puts("Usage: rasterbench [-z]"); return (1); } mode = argc > 1 ? CUPS_RASTER_WRITE_COMPRESSED : CUPS_RASTER_WRITE; /* * Ignore SIGPIPE... */ signal(SIGPIPE, SIG_IGN); /* * Run the tests several times to get a good average... */ printf("Test read/write speed of %d pages, %dx%d pixels...\n\n", TEST_PAGES, TEST_WIDTH, TEST_HEIGHT); for (i = 0; i < TEST_PASSES; i ++) { printf("PASS %2d: ", i + 1); fflush(stdout); ras_fd = run_read_test(); start_secs = get_time(); write_test(ras_fd, mode); write_secs = get_time(); printf(" %.3f write,", write_secs - start_secs); fflush(stdout); close(ras_fd); wait(&status); read_secs = get_time(); pass_secs[i] = read_secs - start_secs; printf(" %.3f read, %.3f total\n", read_secs - write_secs, pass_secs[i]); } printf("\nMedian Total Time: %.3f seconds per document\n", compute_median(pass_secs)); return (0); } /* * 'compute_median()' - Compute the median time for a test. */ static double /* O - Median time in seconds */ compute_median(double *secs) /* I - Array of time samples */ { int i, j; /* Looping vars */ double temp; /* Swap variable */ /* * Sort the array into ascending order using a quicky bubble sort... */ for (i = 0; i < (TEST_PASSES - 1); i ++) for (j = i + 1; j < TEST_PASSES; j ++) if (secs[i] > secs[j]) { temp = secs[i]; secs[i] = secs[j]; secs[j] = temp; } /* * Return the average of the middle two samples... */ return (0.5 * (secs[TEST_PASSES / 2 - 1] + secs[TEST_PASSES / 2])); } /* * 'get_time()' - Get the current time in seconds. */ static double /* O - Time in seconds */ get_time(void) { struct timeval curtime; /* Current time */ gettimeofday(&curtime, NULL); return (curtime.tv_sec + 0.000001 * curtime.tv_usec); } /* * 'read_test()' - Benchmark the raster read functions. */ static void read_test(int fd) /* I - File descriptor to read from */ { unsigned y; /* Looping var */ cups_raster_t *r; /* Raster stream */ cups_page_header2_t header; /* Page header */ unsigned char buffer[8 * TEST_WIDTH]; /* Read buffer */ /* * Test read speed... */ if ((r = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL) { perror("Unable to create raster input stream"); return; } while (cupsRasterReadHeader2(r, &header)) { for (y = 0; y < header.cupsHeight; y ++) cupsRasterReadPixels(r, buffer, header.cupsBytesPerLine); } cupsRasterClose(r); } /* * 'run_read_test()' - Run the read test as a child process via pipes. */ static int /* O - Standard input of child */ run_read_test(void) { int ras_pipes[2]; /* Raster data pipes */ int pid; /* Child process ID */ if (pipe(ras_pipes)) return (-1); if ((pid = fork()) < 0) { /* * Fork error - return -1 on error... */ close(ras_pipes[0]); close(ras_pipes[1]); return (-1); } else if (pid == 0) { /* * Child comes here - read data from the input pipe... */ close(ras_pipes[1]); read_test(ras_pipes[0]); exit(0); } else { /* * Parent comes here - return the output pipe... */ close(ras_pipes[0]); return (ras_pipes[1]); } } /* * 'write_test()' - Benchmark the raster write functions. */ static void write_test(int fd, /* I - File descriptor to write to */ cups_mode_t mode) /* I - Write mode */ { unsigned page, x, y; /* Looping vars */ unsigned count; /* Number of bytes to set */ cups_raster_t *r; /* Raster stream */ cups_page_header2_t header; /* Page header */ unsigned char data[32][8 * TEST_WIDTH]; /* Raster data to write */ /* * Create a combination of random data and repeated data to simulate * text with some whitespace. */ CUPS_SRAND(time(NULL)); memset(data, 0, sizeof(data)); for (y = 0; y < 28; y ++) { for (x = CUPS_RAND() & 127, count = (CUPS_RAND() & 15) + 1; x < sizeof(data[0]); x ++, count --) { if (count <= 0) { x += (CUPS_RAND() & 15) + 1; count = (CUPS_RAND() & 15) + 1; if (x >= sizeof(data[0])) break; } data[y][x] = (unsigned char)CUPS_RAND(); } } /* * Test write speed... */ if ((r = cupsRasterOpen(fd, mode)) == NULL) { perror("Unable to create raster output stream"); return; } for (page = 0; page < TEST_PAGES; page ++) { memset(&header, 0, sizeof(header)); header.cupsWidth = TEST_WIDTH; header.cupsHeight = TEST_HEIGHT; header.cupsBytesPerLine = TEST_WIDTH; if (page & 1) { header.cupsBytesPerLine *= 4; header.cupsColorSpace = CUPS_CSPACE_CMYK; header.cupsColorOrder = CUPS_ORDER_CHUNKED; } else { header.cupsColorSpace = CUPS_CSPACE_K; header.cupsColorOrder = CUPS_ORDER_BANDED; } if (page & 2) { header.cupsBytesPerLine *= 2; header.cupsBitsPerColor = 16; header.cupsBitsPerPixel = (page & 1) ? 64 : 16; } else { header.cupsBitsPerColor = 8; header.cupsBitsPerPixel = (page & 1) ? 32 : 8; } cupsRasterWriteHeader2(r, &header); for (y = 0; y < TEST_HEIGHT; y ++) cupsRasterWritePixels(r, data[y & 31], header.cupsBytesPerLine); } cupsRasterClose(r); }