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