]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
23ef1cac | 2 | * "$Id$" |
ef416fc2 | 3 | * |
7e86f2f6 | 4 | * Scheduler speed test for CUPS. |
ef416fc2 | 5 | * |
7e86f2f6 MS |
6 | * Copyright 2007-2014 by Apple Inc. |
7 | * Copyright 1997-2005 by Easy Software Products. | |
ef416fc2 | 8 | * |
7e86f2f6 MS |
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/". | |
ef416fc2 | 14 | */ |
15 | ||
16 | /* | |
17 | * Include necessary headers... | |
18 | */ | |
19 | ||
71e16022 | 20 | #include <cups/string-private.h> |
ef416fc2 | 21 | #include <cups/cups.h> |
22 | #include <cups/language.h> | |
71e16022 | 23 | #include <cups/debug-private.h> |
75bd9771 MS |
24 | #include <sys/types.h> |
25 | #include <sys/time.h> | |
26 | #include <sys/wait.h> | |
ef416fc2 | 27 | |
28 | ||
29 | /* | |
30 | * Local functions... | |
31 | */ | |
32 | ||
dd1abb6b MS |
33 | static int do_test(const char *server, int port, |
34 | http_encryption_t encryption, int requests, | |
23ef1cac | 35 | const char *opstring, int verbose); |
85dda01c | 36 | static void usage(void) __attribute__((noreturn)); |
ef416fc2 | 37 | |
38 | ||
39 | /* | |
40 | * 'main()' - Send multiple IPP requests and report on the average response | |
41 | * time. | |
42 | */ | |
43 | ||
44 | int | |
45 | main(int argc, /* I - Number of command-line arguments */ | |
46 | char *argv[]) /* I - Command-line arguments */ | |
47 | { | |
48 | int i; /* Looping var */ | |
dd1abb6b MS |
49 | char *server, /* Server to use */ |
50 | *ptr; /* Pointer to port in server */ | |
51 | int port; /* Port to use */ | |
ef416fc2 | 52 | http_encryption_t encryption; /* Encryption to use */ |
53 | int requests; /* Number of requests to send */ | |
54 | int children; /* Number of children to fork */ | |
dd1abb6b | 55 | int good_children; /* Number of children that exited normally */ |
ef416fc2 | 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 */ | |
23ef1cac | 62 | const char *opstring; /* Operation name */ |
ef416fc2 | 63 | |
64 | ||
65 | /* | |
66 | * Parse command-line options... | |
67 | */ | |
68 | ||
69 | requests = 100; | |
70 | children = 5; | |
dd1abb6b MS |
71 | server = (char *)cupsServer(); |
72 | port = ippPort(); | |
ef416fc2 | 73 | encryption = HTTP_ENCRYPT_IF_REQUESTED; |
74 | verbose = 0; | |
23ef1cac | 75 | opstring = NULL; |
ef416fc2 | 76 | |
77 | for (i = 1; i < argc; i ++) | |
dd1abb6b | 78 | if (argv[i][0] == '-') |
ef416fc2 | 79 | { |
dd1abb6b MS |
80 | for (ptr = argv[i] + 1; *ptr; ptr ++) |
81 | switch (*ptr) | |
82 | { | |
23ef1cac MS |
83 | case 'E' : /* Enable encryption */ |
84 | encryption = HTTP_ENCRYPT_REQUIRED; | |
85 | break; | |
86 | ||
dd1abb6b MS |
87 | case 'c' : /* Number of children */ |
88 | i ++; | |
89 | if (i >= argc) | |
90 | usage(); | |
91 | ||
92 | children = atoi(argv[i]); | |
93 | break; | |
94 | ||
23ef1cac | 95 | case 'o' : /* Operation */ |
dd1abb6b MS |
96 | i ++; |
97 | if (i >= argc) | |
98 | usage(); | |
99 | ||
23ef1cac | 100 | opstring = argv[i]; |
dd1abb6b MS |
101 | break; |
102 | ||
23ef1cac MS |
103 | case 'r' : /* Number of requests */ |
104 | i ++; | |
105 | if (i >= argc) | |
106 | usage(); | |
107 | ||
108 | requests = atoi(argv[i]); | |
dd1abb6b MS |
109 | break; |
110 | ||
111 | case 'v' : /* Verbose logging */ | |
112 | verbose ++; | |
113 | break; | |
114 | ||
115 | default : | |
116 | usage(); | |
117 | break; | |
118 | } | |
ef416fc2 | 119 | } |
dd1abb6b | 120 | else |
ef416fc2 | 121 | { |
dd1abb6b | 122 | server = argv[i]; |
ef416fc2 | 123 | |
dd1abb6b MS |
124 | if (server[0] != '/' && (ptr = strrchr(server, ':')) != NULL) |
125 | { | |
126 | *ptr++ = '\0'; | |
127 | port = atoi(ptr); | |
128 | } | |
ef416fc2 | 129 | } |
ef416fc2 | 130 | |
131 | /* | |
132 | * Then create child processes to act as clients... | |
133 | */ | |
134 | ||
dd1abb6b MS |
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 | } | |
ef416fc2 | 141 | |
142 | start = time(NULL); | |
143 | ||
dd1abb6b | 144 | if (children < 1) |
23ef1cac | 145 | return (do_test(server, port, encryption, requests, opstring, verbose)); |
dd1abb6b | 146 | else if (children == 1) |
23ef1cac MS |
147 | good_children = do_test(server, port, encryption, requests, opstring, |
148 | verbose) ? 0 : 1; | |
ef416fc2 | 149 | else |
150 | { | |
dd1abb6b MS |
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 | ||
ef416fc2 | 171 | for (i = 0; i < children; i ++) |
dd1abb6b MS |
172 | { |
173 | fflush(stdout); | |
174 | ||
ef416fc2 | 175 | if ((pid = fork()) == 0) |
176 | { | |
177 | /* | |
178 | * Child goes here... | |
179 | */ | |
180 | ||
23ef1cac MS |
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 | ||
dd1abb6b | 187 | exit(errno); |
ef416fc2 | 188 | } |
189 | else if (pid < 0) | |
190 | { | |
dd1abb6b | 191 | printf("testspeed: Fork failed: %s\n", strerror(errno)); |
ef416fc2 | 192 | break; |
193 | } | |
194 | else | |
dd1abb6b MS |
195 | printf("testspeed: Started child %d...\n", pid); |
196 | } | |
ef416fc2 | 197 | |
198 | /* | |
199 | * Wait for children to finish... | |
200 | */ | |
201 | ||
dd1abb6b MS |
202 | puts("testspeed: Waiting for children to finish..."); |
203 | ||
204 | for (good_children = 0;;) | |
ef416fc2 | 205 | { |
206 | pid = wait(&status); | |
207 | ||
208 | if (pid < 0 && errno != EINTR) | |
209 | break; | |
210 | ||
dd1abb6b MS |
211 | printf("testspeed: Ended child %d (%d)...\n", pid, status / 256); |
212 | ||
213 | if (!status) | |
214 | good_children ++; | |
ef416fc2 | 215 | } |
216 | } | |
217 | ||
218 | /* | |
219 | * Compute the total run time... | |
220 | */ | |
221 | ||
dd1abb6b MS |
222 | if (good_children > 0) |
223 | { | |
224 | end = time(NULL); | |
225 | elapsed = end - start; | |
226 | i = good_children * requests; | |
ef416fc2 | 227 | |
dd1abb6b MS |
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 | } | |
ef416fc2 | 231 | |
232 | /* | |
233 | * Exit with no errors... | |
234 | */ | |
235 | ||
91c84a35 | 236 | return (0); |
ef416fc2 | 237 | } |
238 | ||
239 | ||
240 | /* | |
241 | * 'do_test()' - Run a test on a specific host... | |
242 | */ | |
243 | ||
e1d6a774 | 244 | static int /* O - Exit status */ |
ef416fc2 | 245 | do_test(const char *server, /* I - Server to use */ |
dd1abb6b | 246 | int port, /* I - Port number to use */ |
ef416fc2 | 247 | http_encryption_t encryption, /* I - Encryption to use */ |
248 | int requests, /* I - Number of requests to send */ | |
23ef1cac | 249 | const char *opstring, /* I - Operation string */ |
ef416fc2 | 250 | int verbose) /* I - Verbose output? */ |
251 | { | |
252 | int i; /* Looping var */ | |
253 | http_t *http; /* Connection to server */ | |
dd1abb6b | 254 | ipp_t *request; /* IPP Request */ |
ef416fc2 | 255 | struct timeval start, /* Start time */ |
256 | end; /* End time */ | |
dd1abb6b MS |
257 | double reqtime, /* Time for this request */ |
258 | elapsed; /* Elapsed time */ | |
259 | int op; /* Current operation */ | |
23ef1cac | 260 | static ipp_op_t ops[5] = /* Operations to test... */ |
ef416fc2 | 261 | { |
262 | IPP_PRINT_JOB, | |
23ef1cac | 263 | CUPS_GET_DEFAULT, |
ef416fc2 | 264 | CUPS_GET_PRINTERS, |
265 | CUPS_GET_CLASSES, | |
266 | IPP_GET_JOBS | |
267 | }; | |
268 | ||
269 | ||
270 | /* | |
271 | * Connect to the server... | |
272 | */ | |
273 | ||
dd1abb6b | 274 | if ((http = httpConnectEncrypt(server, port, encryption)) == NULL) |
ef416fc2 | 275 | { |
dd1abb6b MS |
276 | printf("testspeed(%d): unable to connect to server - %s\n", (int)getpid(), |
277 | strerror(errno)); | |
ef416fc2 | 278 | return (1); |
279 | } | |
280 | ||
ef416fc2 | 281 | /* |
282 | * Do multiple requests... | |
283 | */ | |
284 | ||
285 | for (elapsed = 0.0, i = 0; i < requests; i ++) | |
286 | { | |
ef416fc2 | 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 | ||
23ef1cac MS |
296 | if (opstring) |
297 | op = ippOpValue(opstring); | |
298 | else | |
7e86f2f6 | 299 | op = ops[i % (int)(sizeof(ops) / sizeof(ops[0]))]; |
23ef1cac | 300 | |
dd1abb6b | 301 | request = ippNewRequest(op); |
ef416fc2 | 302 | |
303 | gettimeofday(&start, NULL); | |
304 | ||
dd1abb6b MS |
305 | if (verbose) |
306 | printf("testspeed(%d): %.6f %s ", (int)getpid(), elapsed, | |
307 | ippOpString(op)); | |
308 | ||
309 | switch (op) | |
ef416fc2 | 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 : | |
dd1abb6b | 316 | ippDelete(cupsDoRequest(http, request, "/")); |
ef416fc2 | 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"); | |
dd1abb6b MS |
322 | ippDelete(cupsDoFileRequest(http, request, "/printers/test", |
323 | "../data/testprint.ps")); | |
ef416fc2 | 324 | break; |
325 | } | |
326 | ||
327 | gettimeofday(&end, NULL); | |
328 | ||
dd1abb6b MS |
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; | |
ef416fc2 | 343 | |
dd1abb6b MS |
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 | } | |
ef416fc2 | 353 | } |
354 | ||
ef416fc2 | 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 | ||
e1d6a774 | 368 | static void |
ef416fc2 | 369 | usage(void) |
370 | { | |
23ef1cac MS |
371 | puts("Usage: testspeed [-c children] [-h] [-o operation] [-r requests] [-v] " |
372 | "[-E] hostname[:port]"); | |
ef416fc2 | 373 | exit(0); |
374 | } | |
375 | ||
376 | ||
377 | ||
378 | /* | |
23ef1cac | 379 | * End of "$Id$". |
ef416fc2 | 380 | */ |