]>
git.proxmox.com Git - mirror_ovs.git/blob - utilities/ovs-benchmark.c
2 * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <sys/socket.h>
29 #include "command-line.h"
30 #include "poll-loop.h"
31 #include "socket-util.h"
34 #include "openvswitch/vlog.h"
36 #define DEFAULT_PORT 6630
38 #define MAX_SOCKETS 65535
39 static int n_batches
= 1;
40 static int n_sockets
= 100;
42 static struct in_addr local_addr
;
43 static unsigned short int local_min_port
, local_max_port
;
45 static struct in_addr remote_addr
;
46 static unsigned short int remote_min_port
, remote_max_port
;
48 static double max_rate
;
50 static double timeout
;
52 static const struct command
*get_all_commands(void);
54 static void parse_options(int argc
, char *argv
[]);
55 static void usage(void);
58 do_poll(struct pollfd
*fds
, int nfds
, int timeout
)
63 retval
= poll(fds
, nfds
, timeout
);
64 } while (retval
< 0 && errno
== EINTR
);
66 retval
= WSAPoll(fds
, nfds
, timeout
);
78 return tv
.tv_sec
* 1000LL + tv
.tv_usec
/ 1000;
82 main(int argc
, char *argv
[])
84 set_program_name(argv
[0]);
85 vlog_set_levels(NULL
, VLF_ANY_DESTINATION
, VLL_EMER
);
86 parse_options(argc
, argv
);
87 run_command(argc
- optind
, argv
+ optind
, get_all_commands());
92 parse_target(const char *s_
, struct in_addr
*addr
,
93 unsigned short int *min
, unsigned short int *max
)
95 char *s
= xstrdup(s_
);
99 colon
= strchr(s
, ':');
105 error
= lookup_hostname(s
, addr
);
107 ovs_fatal(error
, "failed to look up IP address for \"%s\"", s_
);
110 addr
->s_addr
= htonl(INADDR_ANY
);
114 if (colon
&& colon
[1] != '\0') {
115 const char *ports
= colon
+ 1;
116 if (ovs_scan(ports
, "%hu-%hu", min
, max
)) {
118 ovs_fatal(0, "%s: minimum is greater than maximum", s_
);
120 } else if (ovs_scan(ports
, "%hu", min
)) {
123 ovs_fatal(0, "%s: number or range expected", s_
);
131 parse_options(int argc
, char *argv
[])
133 static const struct option long_options
[] = {
134 {"local", required_argument
, NULL
, 'l'},
135 {"remote", required_argument
, NULL
, 'r'},
136 {"batches", required_argument
, NULL
, 'b'},
137 {"sockets", required_argument
, NULL
, 's'},
138 {"max-rate", required_argument
, NULL
, 'c'},
139 {"timeout", required_argument
, NULL
, 'T'},
140 {"help", no_argument
, NULL
, 'h'},
141 {"version", no_argument
, NULL
, 'V'},
144 char *short_options
= long_options_to_short_options(long_options
);
146 local_addr
.s_addr
= htonl(INADDR_ANY
);
147 local_min_port
= local_max_port
= 0;
149 remote_addr
.s_addr
= htonl(0);
150 remote_min_port
= remote_max_port
= 0;
155 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
163 &local_addr
, &local_min_port
, &local_max_port
);
168 &remote_addr
, &remote_min_port
, &remote_max_port
);
169 if (remote_addr
.s_addr
== htonl(INADDR_ANY
)) {
170 ovs_fatal(0, "remote IP address is required");
175 n_batches
= atoi(optarg
);
177 ovs_fatal(0, "--batches or -b argument must be at least 1");
182 n_sockets
= atoi(optarg
);
183 if (n_sockets
< 1 || n_sockets
> MAX_SOCKETS
) {
184 ovs_fatal(0, "--sockets or -s argument must be between 1 "
185 "and %d (inclusive)", MAX_SOCKETS
);
190 max_rate
= atof(optarg
);
191 if (max_rate
<= 0.0) {
192 ovs_fatal(0, "--max-rate or -c argument must be positive");
197 timeout
= atoi(optarg
);
199 ovs_fatal(0, "-T or --timeout argument must be positive");
207 ovs_print_version(0, 0);
224 %s: Open vSwitch flow setup benchmark utility\n\
225 usage: %s [OPTIONS] COMMAND [ARG...]\n\
226 latency connect many times all at once\n\
227 rate measure sustained flow setup rate\n\
228 listen accept TCP connections\n\
229 help display this help message\n\
232 -l, --local [IP][:PORTS] use local IP and range of PORTS\n\
233 -r, --remote IP[:PORTS] connect to remote IP and PORTS\n\
234 -s, --sockets N number of sockets for \"rate\" or \"latency\"\n\
235 -b, --batches N number of connection batches for \"latency\"\n\
236 -c, --max-rate NPERSEC connection rate limit for \"rate\"\n\
237 -T, --timeout MAXSECS max number of seconds to run for \"rate\"\n\
240 -h, --help display this help message\n\
241 -V, --version display version information\n",
242 program_name
, program_name
);
247 cmd_listen(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
254 if (!local_min_port
&& !local_max_port
) {
255 local_min_port
= local_max_port
= DEFAULT_PORT
;
257 fds
= xmalloc((1 + local_max_port
- local_min_port
) * sizeof *fds
);
259 for (port
= local_min_port
; port
<= local_max_port
; port
++) {
260 struct sockaddr_in sin
;
261 unsigned int yes
= 1;
265 /* Create socket, set SO_REUSEADDR. */
266 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
268 ovs_fatal(errno
, "failed to create socket");
270 error
= set_nonblocking(fd
);
272 ovs_fatal(error
, "failed to set non-blocking mode");
274 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof yes
) < 0) {
275 ovs_fatal(errno
, "setsockopt(SO_REUSEADDR) failed");
279 sin
.sin_family
= AF_INET
;
280 sin
.sin_addr
= remote_addr
;
281 sin
.sin_port
= htons(port
);
282 if (bind(fd
, (struct sockaddr
*) &sin
, sizeof sin
) < 0) {
283 ovs_fatal(errno
, "bind failed");
287 if (listen(fd
, 10000) < 0) {
288 ovs_fatal(errno
, "listen failed");
292 fds
[n_fds
].events
= POLLIN
;
299 retval
= do_poll(fds
, n_fds
, -1);
301 ovs_fatal(errno
, "poll failed");
304 for (i
= 0; i
< n_fds
; i
++) {
305 if (fds
[i
].revents
& POLLIN
) {
309 newfd
= accept(fds
[i
].fd
, NULL
, NULL
);
310 } while (newfd
< 0 && errno
== EINTR
);
314 } else if (errno
!= EAGAIN
) {
315 ovs_fatal(errno
, "accept failed");
322 /* Increments '*value' within the range 'min...max' inclusive. Returns true
323 * if '*value' wraps around to 'min', otherwise false. */
325 increment(unsigned short int *value
,
326 unsigned short int min
, unsigned short int max
)
338 next_ports(unsigned short int *local_port
, unsigned short int *remote_port
)
340 if (increment(local_port
, local_min_port
, local_max_port
)) {
341 increment(remote_port
, remote_min_port
, remote_max_port
);
346 bind_local_port(int fd
, unsigned short int *local_port
,
347 unsigned short int *remote_port
)
351 if (!local_min_port
&& !local_max_port
) {
352 next_ports(local_port
, remote_port
);
357 struct sockaddr_in local
;
359 memset(&local
, 0, sizeof local
);
360 local
.sin_family
= AF_INET
;
361 local
.sin_addr
= local_addr
;
362 local
.sin_port
= htons(*local_port
);
363 error
= (bind(fd
, (struct sockaddr
*) &local
, sizeof local
) < 0
365 next_ports(local_port
, remote_port
);
366 } while (error
== EADDRINUSE
|| error
== EINTR
);
368 ovs_fatal(error
, "bind failed");
373 cmd_rate(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
375 unsigned short int local_port
;
376 unsigned short int remote_port
;
377 unsigned int completed
= 0;
378 unsigned int failures
= 0;
379 long long int start
, prev
;
383 if (!remote_addr
.s_addr
) {
384 ovs_fatal(0, "remote address must be specified with -r or --remote");
386 if (!remote_min_port
&& !remote_max_port
) {
387 remote_min_port
= remote_max_port
= DEFAULT_PORT
;
390 local_port
= local_min_port
;
391 remote_port
= remote_min_port
;
392 fds
= xmalloc(n_sockets
* sizeof *fds
);
394 start
= prev
= time_in_msec();
397 long long int may_open
;
403 long long int cur_total
= completed
+ n_fds
;
404 long long int max_total
= (time_in_msec() - start
) * (max_rate
/ 1000.0);
405 if (max_total
> cur_total
) {
406 may_open
= MIN(n_sockets
, max_total
- cur_total
);
410 delay
= 1000.0 / max_rate
;
412 may_open
= n_sockets
;
416 while (may_open
-- > 0 && n_fds
< n_sockets
) {
417 struct sockaddr_in remote
;
421 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
423 ovs_fatal(errno
, "socket failed");
426 error
= set_nonblocking(fd
);
428 ovs_fatal(error
, "set_nonblocking failed");
431 bind_local_port(fd
, &local_port
, &remote_port
);
433 memset(&remote
, 0, sizeof remote
);
434 remote
.sin_family
= AF_INET
;
435 remote
.sin_addr
= remote_addr
;
436 remote
.sin_port
= htons(remote_port
);
437 if (connect(fd
, (struct sockaddr
*) &remote
, sizeof remote
) < 0) {
438 if (errno
== EINPROGRESS
) {
440 fds
[n_fds
].events
= POLLOUT
;
441 fds
[n_fds
].revents
= 0;
443 } else if (errno
!= ECONNREFUSED
) {
444 ovs_fatal(errno
, "connect");
447 /* Success, I guess. */
454 if (n_fds
== n_sockets
) {
458 error
= do_poll(fds
, n_fds
, delay
);
460 ovs_fatal(errno
, "poll");
463 for (j
= 0; j
< n_fds
; ) {
464 if (fds
[j
].revents
) {
465 if (fds
[j
].revents
& POLLERR
) {
468 shutdown(fds
[j
].fd
, 2);
470 fds
[j
] = fds
[--n_fds
];
477 now
= time_in_msec();
478 if (now
>= prev
+ 1000) {
479 long long int elapsed
= now
- start
;
480 printf("%.3f s elapsed, %u OK, %u failed, avg %.1f/s\n",
481 elapsed
/ 1000.0, completed
- failures
, failures
,
482 completed
/ (elapsed
/ 1000.0));
486 if (timeout
&& elapsed
> timeout
* 1000LL) {
494 timer_end(long long int start
, bool error
,
495 int *min
, int *max
, unsigned long long int *total
)
497 int elapsed
= time_in_msec() - start
;
498 static int last_elapsed
= INT_MIN
;
499 char c
= error
? '!' : '.';
501 if (last_elapsed
!= elapsed
) {
502 if (last_elapsed
!= INT_MIN
) {
505 printf("%5d %c", elapsed
, c
);
507 last_elapsed
= elapsed
;
513 if (elapsed
< *min
) {
516 if (elapsed
> *max
) {
523 cmd_latency(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
525 unsigned short int local_port
;
526 unsigned short int remote_port
;
529 unsigned long long int total
= 0;
532 if (!remote_addr
.s_addr
) {
533 ovs_fatal(0, "remote address must be specified with -r or --rate");
535 if (!remote_min_port
&& !remote_max_port
) {
536 remote_min_port
= remote_max_port
= DEFAULT_PORT
;
539 local_port
= local_min_port
;
540 remote_port
= remote_min_port
;
541 for (i
= 0; i
< n_batches
; i
++) {
542 struct pollfd fds
[MAX_SOCKETS
];
547 start
= time_in_msec();
549 for (j
= 0; j
< n_sockets
; j
++) {
550 struct sockaddr_in remote
;
554 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
556 ovs_fatal(errno
, "socket failed");
559 error
= set_nonblocking(fd
);
561 ovs_fatal(error
, "set_nonblocking failed");
564 bind_local_port(fd
, &local_port
, &remote_port
);
566 memset(&remote
, 0, sizeof remote
);
567 remote
.sin_family
= AF_INET
;
568 remote
.sin_addr
= remote_addr
;
569 remote
.sin_port
= htons(remote_port
);
570 if (connect(fd
, (struct sockaddr
*) &remote
, sizeof remote
) < 0) {
571 if (errno
== EINPROGRESS
) {
573 fds
[n_fds
].events
= POLLOUT
;
574 fds
[n_fds
].revents
= 0;
576 } else if (errno
!= ECONNREFUSED
) {
577 ovs_fatal(errno
, "connect");
580 /* Success, I guess. */
582 timer_end(start
, 0, &min
, &max
, &total
);
589 error
= do_poll(fds
, n_fds
, -1);
591 ovs_fatal(errno
, "poll");
594 for (j
= 0; j
< n_fds
; ) {
595 if (fds
[j
].revents
) {
597 fds
[j
].revents
& (POLLERR
|POLLHUP
) ? 1 : 0,
600 fds
[j
] = fds
[--n_fds
];
609 printf("min %d ms, max %d ms, avg %llu ms\n",
610 min
, max
, total
/ (1ULL * n_sockets
* n_batches
));
614 cmd_help(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
619 static const struct command all_commands
[] = {
620 { "listen", NULL
, 0, 0, cmd_listen
},
621 { "rate", NULL
, 0, 0, cmd_rate
},
622 { "latency", NULL
, 0, 0, cmd_latency
},
623 { "help", NULL
, 0, 0, cmd_help
},
624 { NULL
, NULL
, 0, 0, NULL
},
627 static const struct command
*get_all_commands(void)