1/* 2 * "$Id: testspeed.c 11560 2014-02-06 20:10:19Z msweet $" 3 * 4 * Scheduler speed test for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2005 by Easy Software Products. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 */ 15 16/* 17 * Include necessary headers... 18 */ 19 20#include <cups/string-private.h> 21#include <cups/cups.h> 22#include <cups/language.h> 23#include <cups/debug-private.h> 24#include <sys/types.h> 25#include <sys/time.h> 26#include <sys/wait.h> 27 28 29/* 30 * Local functions... 31 */ 32 33static int do_test(const char *server, int port, 34 http_encryption_t encryption, int requests, 35 const char *opstring, int verbose); 36static void usage(void) __attribute__((noreturn)); 37 38 39/* 40 * 'main()' - Send multiple IPP requests and report on the average response 41 * time. 42 */ 43 44int 45main(int argc, /* I - Number of command-line arguments */ 46 char *argv[]) /* I - Command-line arguments */ 47{ 48 int i; /* Looping var */ 49 char *server, /* Server to use */ 50 *ptr; /* Pointer to port in server */ 51 int port; /* Port to use */ 52 http_encryption_t encryption; /* Encryption to use */ 53 int requests; /* Number of requests to send */ 54 int children; /* Number of children to fork */ 55 int good_children; /* Number of children that exited normally */ 56 int pid; /* Child PID */ 57 int status; /* Child status */ 58 time_t start, /* Start time */ 59 end; /* End time */ 60 double elapsed; /* Elapsed time */ 61 int verbose; /* Verbosity */ 62 const char *opstring; /* Operation name */ 63 64 65 /* 66 * Parse command-line options... 67 */ 68 69 requests = 100; 70 children = 5; 71 server = (char *)cupsServer(); 72 port = ippPort(); 73 encryption = HTTP_ENCRYPT_IF_REQUESTED; 74 verbose = 0; 75 opstring = NULL; 76 77 for (i = 1; i < argc; i ++) 78 if (argv[i][0] == '-') 79 { 80 for (ptr = argv[i] + 1; *ptr; ptr ++) 81 switch (*ptr) 82 { 83 case 'E' : /* Enable encryption */ 84 encryption = HTTP_ENCRYPT_REQUIRED; 85 break; 86 87 case 'c' : /* Number of children */ 88 i ++; 89 if (i >= argc) 90 usage(); 91 92 children = atoi(argv[i]); 93 break; 94 95 case 'o' : /* Operation */ 96 i ++; 97 if (i >= argc) 98 usage(); 99 100 opstring = argv[i]; 101 break; 102 103 case 'r' : /* Number of requests */ 104 i ++; 105 if (i >= argc) 106 usage(); 107 108 requests = atoi(argv[i]); 109 break; 110 111 case 'v' : /* Verbose logging */ 112 verbose ++; 113 break; 114 115 default : 116 usage(); 117 break; 118 } 119 } 120 else 121 { 122 server = argv[i]; 123 124 if (server[0] != '/' && (ptr = strrchr(server, ':')) != NULL) 125 { 126 *ptr++ = '\0'; 127 port = atoi(ptr); 128 } 129 } 130 131 /* 132 * Then create child processes to act as clients... 133 */ 134 135 if (children > 0) 136 { 137 printf("testspeed: Simulating %d clients with %d requests to %s with " 138 "%sencryption...\n", children, requests, server, 139 encryption == HTTP_ENCRYPT_IF_REQUESTED ? "no " : ""); 140 } 141 142 start = time(NULL); 143 144 if (children < 1) 145 return (do_test(server, port, encryption, requests, opstring, verbose)); 146 else if (children == 1) 147 good_children = do_test(server, port, encryption, requests, opstring, 148 verbose) ? 0 : 1; 149 else 150 { 151 char options[255], /* Command-line options for child */ 152 reqstr[255], /* Requests string for child */ 153 serverstr[255]; /* Server:port string for child */ 154 155 156 snprintf(reqstr, sizeof(reqstr), "%d", requests); 157 158 if (port == 631 || server[0] == '/') 159 strlcpy(serverstr, server, sizeof(serverstr)); 160 else 161 snprintf(serverstr, sizeof(serverstr), "%s:%d", server, port); 162 163 strlcpy(options, "-cr", sizeof(options)); 164 165 if (encryption == HTTP_ENCRYPT_REQUIRED) 166 strlcat(options, "E", sizeof(options)); 167 168 if (verbose) 169 strlcat(options, "v", sizeof(options)); 170 171 for (i = 0; i < children; i ++) 172 { 173 fflush(stdout); 174 175 if ((pid = fork()) == 0) 176 { 177 /* 178 * Child goes here... 179 */ 180 181 if (opstring) 182 execlp(argv[0], argv[0], options, "0", reqstr, "-o", opstring, 183 serverstr, (char *)NULL); 184 else 185 execlp(argv[0], argv[0], options, "0", reqstr, serverstr, (char *)NULL); 186 187 exit(errno); 188 } 189 else if (pid < 0) 190 { 191 printf("testspeed: Fork failed: %s\n", strerror(errno)); 192 break; 193 } 194 else 195 printf("testspeed: Started child %d...\n", pid); 196 } 197 198 /* 199 * Wait for children to finish... 200 */ 201 202 puts("testspeed: Waiting for children to finish..."); 203 204 for (good_children = 0;;) 205 { 206 pid = wait(&status); 207 208 if (pid < 0 && errno != EINTR) 209 break; 210 211 printf("testspeed: Ended child %d (%d)...\n", pid, status / 256); 212 213 if (!status) 214 good_children ++; 215 } 216 } 217 218 /* 219 * Compute the total run time... 220 */ 221 222 if (good_children > 0) 223 { 224 end = time(NULL); 225 elapsed = end - start; 226 i = good_children * requests; 227 228 printf("testspeed: %dx%d=%d requests in %.1fs (%.3fs/r, %.1fr/s)\n", 229 good_children, requests, i, elapsed, elapsed / i, i / elapsed); 230 } 231 232 /* 233 * Exit with no errors... 234 */ 235 236 return (0); 237} 238 239 240/* 241 * 'do_test()' - Run a test on a specific host... 242 */ 243 244static int /* O - Exit status */ 245do_test(const char *server, /* I - Server to use */ 246 int port, /* I - Port number to use */ 247 http_encryption_t encryption, /* I - Encryption to use */ 248 int requests, /* I - Number of requests to send */ 249 const char *opstring, /* I - Operation string */ 250 int verbose) /* I - Verbose output? */ 251{ 252 int i; /* Looping var */ 253 http_t *http; /* Connection to server */ 254 ipp_t *request; /* IPP Request */ 255 struct timeval start, /* Start time */ 256 end; /* End time */ 257 double reqtime, /* Time for this request */ 258 elapsed; /* Elapsed time */ 259 int op; /* Current operation */ 260 static ipp_op_t ops[5] = /* Operations to test... */ 261 { 262 IPP_PRINT_JOB, 263 CUPS_GET_DEFAULT, 264 CUPS_GET_PRINTERS, 265 CUPS_GET_CLASSES, 266 IPP_GET_JOBS 267 }; 268 269 270 /* 271 * Connect to the server... 272 */ 273 274 if ((http = httpConnectEncrypt(server, port, encryption)) == NULL) 275 { 276 printf("testspeed(%d): unable to connect to server - %s\n", (int)getpid(), 277 strerror(errno)); 278 return (1); 279 } 280 281 /* 282 * Do multiple requests... 283 */ 284 285 for (elapsed = 0.0, i = 0; i < requests; i ++) 286 { 287 /* 288 * Build a request which requires the following attributes: 289 * 290 * attributes-charset 291 * attributes-natural-language 292 * 293 * In addition, IPP_GET_JOBS needs a printer-uri attribute. 294 */ 295 296 if (opstring) 297 op = ippOpValue(opstring); 298 else 299 op = ops[i % (int)(sizeof(ops) / sizeof(ops[0]))]; 300 301 request = ippNewRequest(op); 302 303 gettimeofday(&start, NULL); 304 305 if (verbose) 306 printf("testspeed(%d): %.6f %s ", (int)getpid(), elapsed, 307 ippOpString(op)); 308 309 switch (op) 310 { 311 case IPP_GET_JOBS : 312 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 313 NULL, "ipp://localhost/printers/"); 314 315 default : 316 ippDelete(cupsDoRequest(http, request, "/")); 317 break; 318 319 case IPP_PRINT_JOB : 320 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 321 NULL, "ipp://localhost/printers/test"); 322 ippDelete(cupsDoFileRequest(http, request, "/printers/test", 323 "../data/testprint.ps")); 324 break; 325 } 326 327 gettimeofday(&end, NULL); 328 329 reqtime = (end.tv_sec - start.tv_sec) + 330 0.000001 * (end.tv_usec - start.tv_usec); 331 elapsed += reqtime; 332 333 switch (cupsLastError()) 334 { 335 case IPP_OK : 336 case IPP_NOT_FOUND : 337 if (verbose) 338 { 339 printf("succeeded: %s (%.6f)\n", cupsLastErrorString(), reqtime); 340 fflush(stdout); 341 } 342 break; 343 344 default : 345 if (!verbose) 346 printf("testspeed(%d): %s ", (int)getpid(), 347 ippOpString(ops[i & 3])); 348 349 printf("failed: %s\n", cupsLastErrorString()); 350 httpClose(http); 351 return (1); 352 } 353 } 354 355 httpClose(http); 356 357 printf("testspeed(%d): %d requests in %.1fs (%.3fs/r, %.1fr/s)\n", 358 (int)getpid(), i, elapsed, elapsed / i, i / elapsed); 359 360 return (0); 361} 362 363 364/* 365 * 'usage()' - Show program usage... 366 */ 367 368static void 369usage(void) 370{ 371 puts("Usage: testspeed [-c children] [-h] [-o operation] [-r requests] [-v] " 372 "[-E] hostname[:port]"); 373 exit(0); 374} 375 376 377 378/* 379 * End of "$Id: testspeed.c 11560 2014-02-06 20:10:19Z msweet $". 380 */ 381