You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
337 lines
6.7 KiB
337 lines
6.7 KiB
/*
|
|
* 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);
|
|
}
|