Blame scheduler/testspeed.c

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