xref: /aosp_15_r20/external/libcups/scheduler/testspeed.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
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  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
8  */
9 
10 /*
11  * Include necessary headers...
12  */
13 
14 #include <cups/string-private.h>
15 #include <cups/cups.h>
16 #include <cups/language.h>
17 #include <cups/debug-private.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/wait.h>
21 
22 
23 /*
24  * Local functions...
25  */
26 
27 static int	do_test(const char *server, int port,
28 		        http_encryption_t encryption, int requests,
29 			const char *opstring, int verbose);
30 static void	usage(void) _CUPS_NORETURN;
31 
32 
33 /*
34  * 'main()' - Send multiple IPP requests and report on the average response
35  *            time.
36  */
37 
38 int
main(int argc,char * argv[])39 main(int  argc,				/* I - Number of command-line arguments */
40      char *argv[])			/* I - Command-line arguments */
41 {
42   int		i;			/* Looping var */
43   char		*server,		/* Server to use */
44 		*ptr;			/* Pointer to port in server */
45   int		port;			/* Port to use */
46   http_encryption_t encryption;		/* Encryption to use */
47   int		requests;		/* Number of requests to send */
48   int		children;		/* Number of children to fork */
49   int		good_children;		/* Number of children that exited normally */
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 */
56   const char	*opstring;		/* Operation name */
57 
58 
59  /*
60   * Parse command-line options...
61   */
62 
63   requests   = 100;
64   children   = 5;
65   server     = (char *)cupsServer();
66   port       = ippPort();
67   encryption = HTTP_ENCRYPT_IF_REQUESTED;
68   verbose    = 0;
69   opstring   = NULL;
70 
71   for (i = 1; i < argc; i ++)
72     if (argv[i][0] == '-')
73     {
74       for (ptr = argv[i] + 1; *ptr; ptr ++)
75         switch (*ptr)
76 	{
77 	  case 'E' : /* Enable encryption */
78 	      encryption = HTTP_ENCRYPT_REQUIRED;
79 	      break;
80 
81 	  case 'c' : /* Number of children */
82 	      i ++;
83 	      if (i >= argc)
84 		usage();
85 
86 	      children = atoi(argv[i]);
87 	      break;
88 
89           case 'o' : /* Operation */
90 	      i ++;
91 	      if (i >= argc)
92 		usage();
93 
94 	      opstring = argv[i];
95 	      break;
96 
97           case 'r' : /* Number of requests */
98 	      i ++;
99 	      if (i >= argc)
100 		usage();
101 
102 	      requests = atoi(argv[i]);
103 	      break;
104 
105           case 'v' : /* Verbose logging */
106               verbose ++;
107 	      break;
108 
109           default :
110               usage();
111 	      break;
112         }
113     }
114     else
115     {
116       server = argv[i];
117 
118       if (server[0] != '/' && (ptr = strrchr(server, ':')) != NULL)
119       {
120         *ptr++ = '\0';
121 	port   = atoi(ptr);
122       }
123     }
124 
125  /*
126   * Then create child processes to act as clients...
127   */
128 
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   }
135 
136   start = time(NULL);
137 
138   if (children < 1)
139     return (do_test(server, port, encryption, requests, opstring, verbose));
140   else if (children == 1)
141     good_children = do_test(server, port, encryption, requests, opstring,
142                             verbose) ? 0 : 1;
143   else
144   {
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 
165     for (i = 0; i < children; i ++)
166     {
167       fflush(stdout);
168 
169       if ((pid = fork()) == 0)
170       {
171        /*
172 	* Child goes here...
173 	*/
174 
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 
181 	exit(errno);
182       }
183       else if (pid < 0)
184       {
185 	printf("testspeed: Fork failed: %s\n", strerror(errno));
186 	break;
187       }
188       else
189 	printf("testspeed: Started child %d...\n", pid);
190     }
191 
192    /*
193     * Wait for children to finish...
194     */
195 
196     puts("testspeed: Waiting for children to finish...");
197 
198     for (good_children = 0;;)
199     {
200       pid = wait(&status);
201 
202       if (pid < 0 && errno != EINTR)
203 	break;
204 
205       printf("testspeed: Ended child %d (%d)...\n", pid, status / 256);
206 
207       if (!status)
208         good_children ++;
209     }
210   }
211 
212  /*
213   * Compute the total run time...
214   */
215 
216   if (good_children > 0)
217   {
218     end     = time(NULL);
219     elapsed = end - start;
220     i       = good_children * requests;
221 
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   }
225 
226  /*
227   * Exit with no errors...
228   */
229 
230   return (0);
231 }
232 
233 
234 /*
235  * 'do_test()' - Run a test on a specific host...
236  */
237 
238 static int				/* O - Exit status */
do_test(const char * server,int port,http_encryption_t encryption,int requests,const char * opstring,int verbose)239 do_test(const char        *server,	/* I - Server to use */
240         int               port,		/* I - Port number to use */
241         http_encryption_t encryption,	/* I - Encryption to use */
242 	int               requests,	/* I - Number of requests to send */
243 	const char        *opstring,	/* I - Operation string */
244 	int               verbose)	/* I - Verbose output? */
245 {
246   int		i;			/* Looping var */
247   http_t	*http;			/* Connection to server */
248   ipp_t		*request;		/* IPP Request */
249   struct timeval start,			/* Start time */
250 		end;			/* End time */
251   double	reqtime,		/* Time for this request */
252 		elapsed;		/* Elapsed time */
253   int		op;			/* Current operation */
254   static ipp_op_t ops[5] =		/* Operations to test... */
255 		{
256 		  IPP_PRINT_JOB,
257 		  CUPS_GET_DEFAULT,
258 		  CUPS_GET_PRINTERS,
259 		  CUPS_GET_CLASSES,
260 		  IPP_GET_JOBS
261 		};
262 
263 
264  /*
265   * Connect to the server...
266   */
267 
268   if ((http = httpConnectEncrypt(server, port, encryption)) == NULL)
269   {
270     printf("testspeed(%d): unable to connect to server - %s\n", (int)getpid(),
271            strerror(errno));
272     return (1);
273   }
274 
275  /*
276   * Do multiple requests...
277   */
278 
279   for (elapsed = 0.0, i = 0; i < requests; i ++)
280   {
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 
290     if (opstring)
291       op = ippOpValue(opstring);
292     else
293       op = ops[i % (int)(sizeof(ops) / sizeof(ops[0]))];
294 
295     request = ippNewRequest(op);
296 
297     gettimeofday(&start, NULL);
298 
299     if (verbose)
300       printf("testspeed(%d): %.6f %s ", (int)getpid(), elapsed,
301 	     ippOpString(op));
302 
303     switch (op)
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 :
310 	  ippDelete(cupsDoRequest(http, request, "/"));
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");
316 	  ippDelete(cupsDoFileRequest(http, request, "/printers/test",
317 	                              "../data/testprint.ps"));
318           break;
319     }
320 
321     gettimeofday(&end, NULL);
322 
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;
337 
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     }
347   }
348 
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 
362 static void
usage(void)363 usage(void)
364 {
365   puts("Usage: testspeed [-c children] [-h] [-o operation] [-r requests] [-v] "
366        "[-E] hostname[:port]");
367   exit(0);
368 }
369