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