/* * 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 #include #include #include #include #include #include /* * 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); }