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