| /* |
| * 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 <config.h> |
| #include <cups/raster.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/time.h> |
| #include <signal.h> |
| #include <unistd.h> |
| #include <sys/wait.h> |
| |
| |
| /* |
| * 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); |
| } |