blob: 7cd875c972577f7ca3dca94f499ddcd36577eee8 [file] [log] [blame]
/*
* Scheduler speed test for CUPS.
*
* Copyright 2007-2014 by Apple Inc.
* Copyright 1997-2005 by Easy Software Products.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more information.
*/
/*
* Include necessary headers...
*/
#include <cups/string-private.h>
#include <cups/cups.h>
#include <cups/language.h>
#include <cups/debug-private.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
/*
* Local functions...
*/
static int do_test(const char *server, int port,
http_encryption_t encryption, int requests,
const char *opstring, int verbose);
static void usage(void) _CUPS_NORETURN;
/*
* 'main()' - Send multiple IPP requests and report on the average response
* time.
*/
int
main(int argc, /* I - Number of command-line arguments */
char *argv[]) /* I - Command-line arguments */
{
int i; /* Looping var */
char *server, /* Server to use */
*ptr; /* Pointer to port in server */
int port; /* Port to use */
http_encryption_t encryption; /* Encryption to use */
int requests; /* Number of requests to send */
int children; /* Number of children to fork */
int good_children; /* Number of children that exited normally */
int pid; /* Child PID */
int status; /* Child status */
time_t start, /* Start time */
end; /* End time */
double elapsed; /* Elapsed time */
int verbose; /* Verbosity */
const char *opstring; /* Operation name */
/*
* Parse command-line options...
*/
requests = 100;
children = 5;
server = (char *)cupsServer();
port = ippPort();
encryption = HTTP_ENCRYPT_IF_REQUESTED;
verbose = 0;
opstring = NULL;
for (i = 1; i < argc; i ++)
if (argv[i][0] == '-')
{
for (ptr = argv[i] + 1; *ptr; ptr ++)
switch (*ptr)
{
case 'E' : /* Enable encryption */
encryption = HTTP_ENCRYPT_REQUIRED;
break;
case 'c' : /* Number of children */
i ++;
if (i >= argc)
usage();
children = atoi(argv[i]);
break;
case 'o' : /* Operation */
i ++;
if (i >= argc)
usage();
opstring = argv[i];
break;
case 'r' : /* Number of requests */
i ++;
if (i >= argc)
usage();
requests = atoi(argv[i]);
break;
case 'v' : /* Verbose logging */
verbose ++;
break;
default :
usage();
break;
}
}
else
{
server = argv[i];
if (server[0] != '/' && (ptr = strrchr(server, ':')) != NULL)
{
*ptr++ = '\0';
port = atoi(ptr);
}
}
/*
* Then create child processes to act as clients...
*/
if (children > 0)
{
printf("testspeed: Simulating %d clients with %d requests to %s with "
"%sencryption...\n", children, requests, server,
encryption == HTTP_ENCRYPT_IF_REQUESTED ? "no " : "");
}
start = time(NULL);
if (children < 1)
return (do_test(server, port, encryption, requests, opstring, verbose));
else if (children == 1)
good_children = do_test(server, port, encryption, requests, opstring,
verbose) ? 0 : 1;
else
{
char options[255], /* Command-line options for child */
reqstr[255], /* Requests string for child */
serverstr[255]; /* Server:port string for child */
snprintf(reqstr, sizeof(reqstr), "%d", requests);
if (port == 631 || server[0] == '/')
strlcpy(serverstr, server, sizeof(serverstr));
else
snprintf(serverstr, sizeof(serverstr), "%s:%d", server, port);
strlcpy(options, "-cr", sizeof(options));
if (encryption == HTTP_ENCRYPT_REQUIRED)
strlcat(options, "E", sizeof(options));
if (verbose)
strlcat(options, "v", sizeof(options));
for (i = 0; i < children; i ++)
{
fflush(stdout);
if ((pid = fork()) == 0)
{
/*
* Child goes here...
*/
if (opstring)
execlp(argv[0], argv[0], options, "0", reqstr, "-o", opstring,
serverstr, (char *)NULL);
else
execlp(argv[0], argv[0], options, "0", reqstr, serverstr, (char *)NULL);
exit(errno);
}
else if (pid < 0)
{
printf("testspeed: Fork failed: %s\n", strerror(errno));
break;
}
else
printf("testspeed: Started child %d...\n", pid);
}
/*
* Wait for children to finish...
*/
puts("testspeed: Waiting for children to finish...");
for (good_children = 0;;)
{
pid = wait(&status);
if (pid < 0 && errno != EINTR)
break;
printf("testspeed: Ended child %d (%d)...\n", pid, status / 256);
if (!status)
good_children ++;
}
}
/*
* Compute the total run time...
*/
if (good_children > 0)
{
end = time(NULL);
elapsed = end - start;
i = good_children * requests;
printf("testspeed: %dx%d=%d requests in %.1fs (%.3fs/r, %.1fr/s)\n",
good_children, requests, i, elapsed, elapsed / i, i / elapsed);
}
/*
* Exit with no errors...
*/
return (0);
}
/*
* 'do_test()' - Run a test on a specific host...
*/
static int /* O - Exit status */
do_test(const char *server, /* I - Server to use */
int port, /* I - Port number to use */
http_encryption_t encryption, /* I - Encryption to use */
int requests, /* I - Number of requests to send */
const char *opstring, /* I - Operation string */
int verbose) /* I - Verbose output? */
{
int i; /* Looping var */
http_t *http; /* Connection to server */
ipp_t *request; /* IPP Request */
struct timeval start, /* Start time */
end; /* End time */
double reqtime, /* Time for this request */
elapsed; /* Elapsed time */
int op; /* Current operation */
static ipp_op_t ops[5] = /* Operations to test... */
{
IPP_PRINT_JOB,
CUPS_GET_DEFAULT,
CUPS_GET_PRINTERS,
CUPS_GET_CLASSES,
IPP_GET_JOBS
};
/*
* Connect to the server...
*/
if ((http = httpConnectEncrypt(server, port, encryption)) == NULL)
{
printf("testspeed(%d): unable to connect to server - %s\n", (int)getpid(),
strerror(errno));
return (1);
}
/*
* Do multiple requests...
*/
for (elapsed = 0.0, i = 0; i < requests; i ++)
{
/*
* Build a request which requires the following attributes:
*
* attributes-charset
* attributes-natural-language
*
* In addition, IPP_GET_JOBS needs a printer-uri attribute.
*/
if (opstring)
op = ippOpValue(opstring);
else
op = ops[i % (int)(sizeof(ops) / sizeof(ops[0]))];
request = ippNewRequest(op);
gettimeofday(&start, NULL);
if (verbose)
printf("testspeed(%d): %.6f %s ", (int)getpid(), elapsed,
ippOpString(op));
switch (op)
{
case IPP_GET_JOBS :
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
NULL, "ipp://localhost/printers/");
default :
ippDelete(cupsDoRequest(http, request, "/"));
break;
case IPP_PRINT_JOB :
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
NULL, "ipp://localhost/printers/test");
ippDelete(cupsDoFileRequest(http, request, "/printers/test",
"../data/testprint.ps"));
break;
}
gettimeofday(&end, NULL);
reqtime = (end.tv_sec - start.tv_sec) +
0.000001 * (end.tv_usec - start.tv_usec);
elapsed += reqtime;
switch (cupsLastError())
{
case IPP_OK :
case IPP_NOT_FOUND :
if (verbose)
{
printf("succeeded: %s (%.6f)\n", cupsLastErrorString(), reqtime);
fflush(stdout);
}
break;
default :
if (!verbose)
printf("testspeed(%d): %s ", (int)getpid(),
ippOpString(ops[i & 3]));
printf("failed: %s\n", cupsLastErrorString());
httpClose(http);
return (1);
}
}
httpClose(http);
printf("testspeed(%d): %d requests in %.1fs (%.3fs/r, %.1fr/s)\n",
(int)getpid(), i, elapsed, elapsed / i, i / elapsed);
return (0);
}
/*
* 'usage()' - Show program usage...
*/
static void
usage(void)
{
puts("Usage: testspeed [-c children] [-h] [-o operation] [-r requests] [-v] "
"[-E] hostname[:port]");
exit(0);
}