ovsdb: Correct specification inconsistency between "lock" and "assert".
[openvswitch] / utilities / ovs-benchmark.c
1 /*
2  * Copyright (c) 2010, 2011 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include <errno.h>
20 #include <getopt.h>
21 #include <limits.h>
22 #include <poll.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/time.h>
26 #include <stddef.h>
27 #include <unistd.h>
28
29 #include "command-line.h"
30 #include "poll-loop.h"
31 #include "socket-util.h"
32 #include "timeval.h"
33 #include "util.h"
34 #include "vlog.h"
35
36 #define DEFAULT_PORT 6630
37
38 #define MAX_SOCKETS 65535
39 static int n_batches = 1;
40 static int n_sockets = 100;
41
42 static struct in_addr local_addr;
43 static unsigned short int local_min_port, local_max_port;
44
45 static struct in_addr remote_addr;
46 static unsigned short int remote_min_port, remote_max_port;
47
48 static double max_rate;
49
50 static double timeout;
51
52 static const struct command all_commands[];
53
54 static void parse_options(int argc, char *argv[]);
55 static void usage(void);
56
57 static long long int
58 time_in_msec(void)
59 {
60     struct timeval tv;
61
62     if (gettimeofday(&tv, NULL) < 0) {
63         ovs_fatal(errno, "gettimeofday");
64     }
65
66     return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
67 }
68
69 int
70 main(int argc, char *argv[])
71 {
72     set_program_name(argv[0]);
73     vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_EMER);
74     parse_options(argc, argv);
75     run_command(argc - optind, argv + optind, all_commands);
76     return 0;
77 }
78
79 static void
80 parse_target(const char *s_, struct in_addr *addr,
81              unsigned short int *min, unsigned short int *max)
82 {
83     char *s = xstrdup(s_);
84     char *colon;
85     int error;
86
87     colon = strchr(s, ':');
88     if (colon) {
89         *colon = '\0';
90     }
91
92     if (*s != '\0') {
93         error = lookup_hostname(s, addr);
94         if (error) {
95             ovs_fatal(error, "failed to look up IP address for \"%s\"", s_);
96         }
97     } else {
98         addr->s_addr = htonl(INADDR_ANY);
99     }
100
101     *min = *max = 0;
102     if (colon && colon[1] != '\0') {
103         const char *ports = colon + 1;
104         if (sscanf(ports, "%hu-%hu", min, max) == 2) {
105             if (*min > *max) {
106                 ovs_fatal(0, "%s: minimum is greater than maximum", s_);
107             }
108         } else if (sscanf(ports, "%hu", min) == 1) {
109             *max = *min;
110         } else {
111             ovs_fatal(0, "%s: number or range expected", s_);
112         }
113     }
114
115     free(s);
116 }
117
118 static void
119 parse_options(int argc, char *argv[])
120 {
121     static struct option long_options[] = {
122         {"local", required_argument, NULL, 'l'},
123         {"remote", required_argument, NULL, 'r'},
124         {"batches", required_argument, NULL, 'b'},
125         {"sockets", required_argument, NULL, 's'},
126         {"max-rate", required_argument, NULL, 'c'},
127         {"timeout", required_argument, NULL, 'T'},
128         {"help", no_argument, NULL, 'h'},
129         {"version", no_argument, NULL, 'V'},
130         {NULL, 0, NULL, 0},
131     };
132     char *short_options = long_options_to_short_options(long_options);
133
134     local_addr.s_addr = htonl(INADDR_ANY);
135     local_min_port = local_max_port = 0;
136
137     remote_addr.s_addr = htonl(0);
138     remote_min_port = remote_max_port = 0;
139
140     for (;;) {
141         int c;
142
143         c = getopt_long(argc, argv, short_options, long_options, NULL);
144         if (c == -1) {
145             break;
146         }
147
148         switch (c) {
149         case 'l':
150             parse_target(optarg,
151                          &local_addr, &local_min_port, &local_max_port);
152             break;
153
154         case 'r':
155             parse_target(optarg,
156                          &remote_addr, &remote_min_port, &remote_max_port);
157             if (remote_addr.s_addr == htonl(INADDR_ANY)) {
158                 ovs_fatal(0, "remote IP address is required");
159             }
160             break;
161
162         case 'b':
163             n_batches = atoi(optarg);
164             if (n_batches < 0) {
165                 ovs_fatal(0, "--batches or -b argument must be at least 1");
166             }
167             break;
168
169         case 's':
170             n_sockets = atoi(optarg);
171             if (n_sockets < 1 || n_sockets > MAX_SOCKETS) {
172                 ovs_fatal(0, "--sockets or -s argument must be between 1 "
173                           "and %d (inclusive)", MAX_SOCKETS);
174             }
175             break;
176
177         case 'c':
178             max_rate = atof(optarg);
179             if (max_rate <= 0.0) {
180                 ovs_fatal(0, "--max-rate or -c argument must be positive");
181             }
182             break;
183
184         case 'T':
185             timeout = atoi(optarg);
186             if (!timeout) {
187                 ovs_fatal(0, "-T or --timeout argument must be positive");
188             }
189             break;
190
191         case 'h':
192             usage();
193
194         case 'V':
195             ovs_print_version(0, 0);
196             exit(EXIT_SUCCESS);
197
198         case '?':
199             exit(EXIT_FAILURE);
200
201         default:
202             abort();
203         }
204     }
205     free(short_options);
206 }
207
208 static void
209 usage(void)
210 {
211     printf("\
212 %s: Open vSwitch flow setup benchmark utility\n\
213 usage: %s [OPTIONS] COMMAND [ARG...]\n\
214   latency                     connect many times all at once\n\
215   rate                        measure sustained flow setup rate\n\
216   listen                      accept TCP connections\n\
217   help                        display this help message\n\
218 \n\
219 Command options:\n\
220   -l, --local [IP][:PORTS]    use local IP and range of PORTS\n\
221   -r, --remote IP[:PORTS]     connect to remote IP and PORTS\n\
222   -s, --sockets N             number of sockets for \"rate\" or \"latency\"\n\
223   -b, --batches N             number of connection batches for \"latency\"\n\
224   -c, --max-rate NPERSEC      connection rate limit for \"rate\"\n\
225   -T, --timeout MAXSECS       max number of seconds to run for \"rate\"\n\
226 \n\
227 Other options:\n\
228   -h, --help                  display this help message\n\
229   -V, --version               display version information\n",
230            program_name, program_name);
231     exit(EXIT_SUCCESS);
232 }
233
234 static void
235 cmd_listen(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
236 {
237     struct pollfd *fds;
238     int n_fds;
239     int port;
240     int i;
241
242     if (!local_min_port && !local_max_port) {
243         local_min_port = local_max_port = DEFAULT_PORT;
244     }
245     fds = xmalloc((1 + local_max_port - local_min_port) * sizeof *fds);
246     n_fds = 0;
247     for (port = local_min_port; port <= local_max_port; port++) {
248         struct sockaddr_in sin;
249         unsigned int yes = 1;
250         int error;
251         int fd;
252
253         /* Create socket, set SO_REUSEADDR. */
254         fd = socket(AF_INET, SOCK_STREAM, 0);
255         if (fd < 0) {
256             ovs_fatal(errno, "failed to create socket");
257         }
258         error = set_nonblocking(fd);
259         if (error) {
260             ovs_fatal(error, "failed to set non-blocking mode");
261         }
262         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
263             ovs_fatal(errno, "setsockopt(SO_REUSEADDR) failed");
264         }
265
266         /* Bind. */
267         sin.sin_family = AF_INET;
268         sin.sin_addr = remote_addr;
269         sin.sin_port = htons(port);
270         if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
271             ovs_fatal(errno, "bind failed");
272         }
273
274         /* Listen. */
275         if (listen(fd, 10000) < 0) {
276             ovs_fatal(errno, "listen failed");
277         }
278
279         fds[n_fds].fd = fd;
280         fds[n_fds].events = POLLIN;
281         n_fds++;
282     }
283
284     for (;;) {
285         int retval;
286
287         do {
288             retval = poll(fds, n_fds, -1);
289         } while (retval < 0 && errno == EINTR);
290         if (retval < 0) {
291             ovs_fatal(errno, "poll failed");
292         }
293
294         for (i = 0; i < n_fds; i++) {
295             if (fds[i].revents & POLLIN) {
296                 int newfd;
297
298                 do {
299                     newfd = accept(fds[i].fd, NULL, NULL);
300                 } while (newfd < 0 && errno == EINTR);
301
302                 if (newfd >= 0) {
303                     close(newfd);
304                 } else if (errno != EAGAIN) {
305                     ovs_fatal(errno, "accept failed");
306                 }
307             }
308         }
309     }
310 }
311
312 /* Increments '*value' within the range 'min...max' inclusive.  Returns true
313  * if '*value' wraps around to 'min', otherwise false. */
314 static bool
315 increment(unsigned short int *value,
316           unsigned short int min, unsigned short int max)
317 {
318     if (*value < max) {
319         ++*value;
320         return false;
321     } else {
322         *value = min;
323         return true;
324     }
325 }
326
327 static void
328 next_ports(unsigned short int *local_port, unsigned short int *remote_port)
329 {
330     if (increment(local_port, local_min_port, local_max_port)) {
331         increment(remote_port, remote_min_port, remote_max_port);
332     }
333 }
334
335 static void
336 bind_local_port(int fd, unsigned short int *local_port,
337                 unsigned short int *remote_port)
338 {
339     int error;
340
341     if (!local_min_port && !local_max_port) {
342         next_ports(local_port, remote_port);
343         return;
344     }
345
346     do {
347         struct sockaddr_in local;
348
349         memset(&local, 0, sizeof local);
350         local.sin_family = AF_INET;
351         local.sin_addr = local_addr;
352         local.sin_port = htons(*local_port);
353         error = (bind(fd, (struct sockaddr *) &local, sizeof local) < 0
354                  ? errno : 0);
355         next_ports(local_port, remote_port);
356     } while (error == EADDRINUSE || error == EINTR);
357     if (error) {
358         ovs_fatal(error, "bind failed");
359     }
360 }
361
362 static void
363 cmd_rate(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
364 {
365     unsigned short int local_port;
366     unsigned short int remote_port;
367     unsigned int completed = 0;
368     unsigned int failures = 0;
369     long long int start, prev;
370     struct pollfd *fds;
371     int n_fds;
372
373     if (!remote_addr.s_addr) {
374         ovs_fatal(0, "remote address must be specified with -r or --remote");
375     }
376     if (!remote_min_port && !remote_max_port) {
377         remote_min_port = remote_max_port = DEFAULT_PORT;
378     }
379
380     local_port = local_min_port;
381     remote_port = remote_min_port;
382     fds = xmalloc(n_sockets * sizeof *fds);
383     n_fds = 0;
384     start = prev = time_in_msec();
385     for (;;) {
386         long long int now;
387         long long int may_open;
388         int delay;
389         int error;
390         int j;
391
392         if (max_rate > 0) {
393             long long int cur_total = completed + n_fds;
394             long long int max_total = (time_in_msec() - start) * (max_rate / 1000.0);
395             if (max_total > cur_total) {
396                 may_open = MIN(n_sockets, max_total - cur_total);
397             } else {
398                 may_open = 0;
399             }
400             delay = 1000.0 / max_rate;
401         } else {
402             may_open = n_sockets;
403             delay = 1000;
404         }
405
406         while (may_open-- > 0 && n_fds < n_sockets) {
407             struct sockaddr_in remote;
408             int error;
409             int fd;
410
411             fd = socket(AF_INET, SOCK_STREAM, 0);
412             if (fd < 0) {
413                 ovs_fatal(errno, "socket failed");
414             }
415
416             error = set_nonblocking(fd);
417             if (error) {
418                 ovs_fatal(error, "set_nonblocking failed");
419             }
420
421             bind_local_port(fd, &local_port, &remote_port);
422
423             memset(&remote, 0, sizeof remote);
424             remote.sin_family = AF_INET;
425             remote.sin_addr = remote_addr;
426             remote.sin_port = htons(remote_port);
427             if (connect(fd, (struct sockaddr *) &remote, sizeof remote) < 0) {
428                 if (errno == EINPROGRESS) {
429                     fds[n_fds].fd = fd;
430                     fds[n_fds].events = POLLOUT;
431                     fds[n_fds].revents = 0;
432                     n_fds++;
433                 } else if (errno != ECONNREFUSED) {
434                     ovs_fatal(errno, "connect");
435                 }
436             } else {
437                 /* Success, I guess. */
438                 shutdown(fd, 2);
439                 close(fd);
440                 completed++;
441             }
442         }
443
444         if (n_fds == n_sockets) {
445             delay = 1000;
446         }
447
448         do {
449             error = poll(fds, n_fds, delay) < 0 ? errno : 0;
450         } while (error == EINTR);
451         if (error) {
452             ovs_fatal(errno, "poll");
453         }
454
455         for (j = 0; j < n_fds; ) {
456             if (fds[j].revents) {
457                 if (fds[j].revents & POLLERR) {
458                     failures++;
459                 }
460                 shutdown(fds[j].fd, 2);
461                 close(fds[j].fd);
462                 fds[j] = fds[--n_fds];
463                 completed++;
464             } else {
465                 j++;
466             }
467         }
468
469         now = time_in_msec();
470         if (now >= prev + 10) {
471             long long int elapsed = now - start;
472             printf("%.3f s elapsed, %u OK, %u failed, avg %.1f/s     \r",
473                    elapsed / 1000.0, completed - failures, failures,
474                    completed / (elapsed / 1000.0));
475             fflush(stdout);
476             prev = now;
477
478             if (timeout && elapsed > timeout * 1000LL) {
479                 break;
480             }
481         }
482     }
483 }
484
485 static void
486 timer_end(long long int start, bool error,
487           int *min, int *max, unsigned long long int *total)
488 {
489     int elapsed = time_in_msec() - start;
490     static int last_elapsed = INT_MIN;
491     char c = error ? '!' : '.';
492
493     if (last_elapsed != elapsed) {
494         if (last_elapsed != INT_MIN) {
495             putchar('\n');
496         }
497         printf("%5d %c", elapsed, c);
498         fflush(stdout);
499         last_elapsed = elapsed;
500     } else {
501         putchar(c);
502         fflush(stdout);
503     }
504
505     if (elapsed < *min) {
506         *min = elapsed;
507     }
508     if (elapsed > *max) {
509         *max = elapsed;
510     }
511     *total += elapsed;
512 }
513
514 static void
515 cmd_latency(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
516 {
517     unsigned short int local_port;
518     unsigned short int remote_port;
519     int min = INT_MAX;
520     int max = 0;
521     unsigned long long int total = 0;
522     int i;
523
524     if (!remote_addr.s_addr) {
525         ovs_fatal(0, "remote address must be specified with -r or --rate");
526     }
527     if (!remote_min_port && !remote_max_port) {
528         remote_min_port = remote_max_port = DEFAULT_PORT;
529     }
530
531     local_port = local_min_port;
532     remote_port = remote_min_port;
533     for (i = 0; i < n_batches; i++) {
534         struct pollfd fds[MAX_SOCKETS];
535         long long int start;
536         int n_fds;
537         int j;
538
539         start = time_in_msec();
540         n_fds = 0;
541         for (j = 0; j < n_sockets; j++) {
542             struct sockaddr_in remote;
543             int error;
544             int fd;
545
546             fd = socket(AF_INET, SOCK_STREAM, 0);
547             if (fd < 0) {
548                 ovs_fatal(errno, "socket failed");
549             }
550
551             error = set_nonblocking(fd);
552             if (error) {
553                 ovs_fatal(error, "set_nonblocking failed");
554             }
555
556             bind_local_port(fd, &local_port, &remote_port);
557
558             memset(&remote, 0, sizeof remote);
559             remote.sin_family = AF_INET;
560             remote.sin_addr = remote_addr;
561             remote.sin_port = htons(remote_port);
562             if (connect(fd, (struct sockaddr *) &remote, sizeof remote) < 0) {
563                 if (errno == EINPROGRESS) {
564                     fds[n_fds].fd = fd;
565                     fds[n_fds].events = POLLOUT;
566                     fds[n_fds].revents = 0;
567                     n_fds++;
568                 } else if (errno != ECONNREFUSED) {
569                     ovs_fatal(errno, "connect");
570                 }
571             } else {
572                 /* Success, I guess. */
573                 close(fd);
574                 timer_end(start, 0, &min, &max, &total);
575             }
576         }
577
578         while (n_fds > 0) {
579             int error;
580
581             do {
582                 error = poll(fds, n_fds, -1) < 0 ? errno : 0;
583             } while (error == EINTR);
584             if (error) {
585                 ovs_fatal(errno, "poll");
586             }
587
588             for (j = 0; j < n_fds; ) {
589                 if (fds[j].revents) {
590                     timer_end(start,
591                               fds[j].revents & (POLLERR|POLLHUP) ? 1 : 0,
592                               &min, &max, &total);
593                     close(fds[j].fd);
594                     fds[j] = fds[--n_fds];
595                 } else {
596                     j++;
597                 }
598             }
599         }
600         putchar('\n');
601     }
602
603     printf("min %d ms, max %d ms, avg %llu ms\n",
604            min, max, total / (1ULL * n_sockets * n_batches));
605 }
606
607 static void
608 cmd_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
609 {
610     usage();
611 }
612
613 static const struct command all_commands[] = {
614     { "listen", 0, 0, cmd_listen },
615     { "rate", 0, 0, cmd_rate },
616     { "latency", 0, 0, cmd_latency },
617     { "help", 0, 0, cmd_help },
618     { NULL, 0, 0, NULL },
619 };