]>
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"
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);
62 if (gettimeofday(&tv
, NULL
) < 0) {
63 ovs_fatal(errno
, "gettimeofday");
66 return tv
.tv_sec
* 1000LL + tv
.tv_usec
/ 1000;
70 main(int argc
, char *argv
[])
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
, get_all_commands());
80 parse_target(const char *s_
, struct in_addr
*addr
,
81 unsigned short int *min
, unsigned short int *max
)
83 char *s
= xstrdup(s_
);
87 colon
= strchr(s
, ':');
93 error
= lookup_hostname(s
, addr
);
95 ovs_fatal(error
, "failed to look up IP address for \"%s\"", s_
);
98 addr
->s_addr
= htonl(INADDR_ANY
);
102 if (colon
&& colon
[1] != '\0') {
103 const char *ports
= colon
+ 1;
104 if (ovs_scan(ports
, "%hu-%hu", min
, max
)) {
106 ovs_fatal(0, "%s: minimum is greater than maximum", s_
);
108 } else if (ovs_scan(ports
, "%hu", min
)) {
111 ovs_fatal(0, "%s: number or range expected", s_
);
119 parse_options(int argc
, char *argv
[])
121 static const 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'},
132 char *short_options
= long_options_to_short_options(long_options
);
134 local_addr
.s_addr
= htonl(INADDR_ANY
);
135 local_min_port
= local_max_port
= 0;
137 remote_addr
.s_addr
= htonl(0);
138 remote_min_port
= remote_max_port
= 0;
143 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
151 &local_addr
, &local_min_port
, &local_max_port
);
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");
163 n_batches
= atoi(optarg
);
165 ovs_fatal(0, "--batches or -b argument must be at least 1");
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
);
178 max_rate
= atof(optarg
);
179 if (max_rate
<= 0.0) {
180 ovs_fatal(0, "--max-rate or -c argument must be positive");
185 timeout
= atoi(optarg
);
187 ovs_fatal(0, "-T or --timeout argument must be positive");
195 ovs_print_version(0, 0);
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\
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\
228 -h, --help display this help message\n\
229 -V, --version display version information\n",
230 program_name
, program_name
);
235 cmd_listen(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
242 if (!local_min_port
&& !local_max_port
) {
243 local_min_port
= local_max_port
= DEFAULT_PORT
;
245 fds
= xmalloc((1 + local_max_port
- local_min_port
) * sizeof *fds
);
247 for (port
= local_min_port
; port
<= local_max_port
; port
++) {
248 struct sockaddr_in sin
;
249 unsigned int yes
= 1;
253 /* Create socket, set SO_REUSEADDR. */
254 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
256 ovs_fatal(errno
, "failed to create socket");
258 error
= set_nonblocking(fd
);
260 ovs_fatal(error
, "failed to set non-blocking mode");
262 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof yes
) < 0) {
263 ovs_fatal(errno
, "setsockopt(SO_REUSEADDR) failed");
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");
275 if (listen(fd
, 10000) < 0) {
276 ovs_fatal(errno
, "listen failed");
280 fds
[n_fds
].events
= POLLIN
;
288 retval
= poll(fds
, n_fds
, -1);
289 } while (retval
< 0 && errno
== EINTR
);
291 ovs_fatal(errno
, "poll failed");
294 for (i
= 0; i
< n_fds
; i
++) {
295 if (fds
[i
].revents
& POLLIN
) {
299 newfd
= accept(fds
[i
].fd
, NULL
, NULL
);
300 } while (newfd
< 0 && errno
== EINTR
);
304 } else if (errno
!= EAGAIN
) {
305 ovs_fatal(errno
, "accept failed");
312 /* Increments '*value' within the range 'min...max' inclusive. Returns true
313 * if '*value' wraps around to 'min', otherwise false. */
315 increment(unsigned short int *value
,
316 unsigned short int min
, unsigned short int max
)
328 next_ports(unsigned short int *local_port
, unsigned short int *remote_port
)
330 if (increment(local_port
, local_min_port
, local_max_port
)) {
331 increment(remote_port
, remote_min_port
, remote_max_port
);
336 bind_local_port(int fd
, unsigned short int *local_port
,
337 unsigned short int *remote_port
)
341 if (!local_min_port
&& !local_max_port
) {
342 next_ports(local_port
, remote_port
);
347 struct sockaddr_in local
;
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
355 next_ports(local_port
, remote_port
);
356 } while (error
== EADDRINUSE
|| error
== EINTR
);
358 ovs_fatal(error
, "bind failed");
363 cmd_rate(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
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
;
373 if (!remote_addr
.s_addr
) {
374 ovs_fatal(0, "remote address must be specified with -r or --remote");
376 if (!remote_min_port
&& !remote_max_port
) {
377 remote_min_port
= remote_max_port
= DEFAULT_PORT
;
380 local_port
= local_min_port
;
381 remote_port
= remote_min_port
;
382 fds
= xmalloc(n_sockets
* sizeof *fds
);
384 start
= prev
= time_in_msec();
387 long long int may_open
;
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
);
400 delay
= 1000.0 / max_rate
;
402 may_open
= n_sockets
;
406 while (may_open
-- > 0 && n_fds
< n_sockets
) {
407 struct sockaddr_in remote
;
411 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
413 ovs_fatal(errno
, "socket failed");
416 error
= set_nonblocking(fd
);
418 ovs_fatal(error
, "set_nonblocking failed");
421 bind_local_port(fd
, &local_port
, &remote_port
);
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
) {
430 fds
[n_fds
].events
= POLLOUT
;
431 fds
[n_fds
].revents
= 0;
433 } else if (errno
!= ECONNREFUSED
) {
434 ovs_fatal(errno
, "connect");
437 /* Success, I guess. */
444 if (n_fds
== n_sockets
) {
449 error
= poll(fds
, n_fds
, delay
) < 0 ? errno
: 0;
450 } while (error
== EINTR
);
452 ovs_fatal(errno
, "poll");
455 for (j
= 0; j
< n_fds
; ) {
456 if (fds
[j
].revents
) {
457 if (fds
[j
].revents
& POLLERR
) {
460 shutdown(fds
[j
].fd
, 2);
462 fds
[j
] = fds
[--n_fds
];
469 now
= time_in_msec();
470 if (now
>= prev
+ 1000) {
471 long long int elapsed
= now
- start
;
472 printf("%.3f s elapsed, %u OK, %u failed, avg %.1f/s\n",
473 elapsed
/ 1000.0, completed
- failures
, failures
,
474 completed
/ (elapsed
/ 1000.0));
478 if (timeout
&& elapsed
> timeout
* 1000LL) {
486 timer_end(long long int start
, bool error
,
487 int *min
, int *max
, unsigned long long int *total
)
489 int elapsed
= time_in_msec() - start
;
490 static int last_elapsed
= INT_MIN
;
491 char c
= error
? '!' : '.';
493 if (last_elapsed
!= elapsed
) {
494 if (last_elapsed
!= INT_MIN
) {
497 printf("%5d %c", elapsed
, c
);
499 last_elapsed
= elapsed
;
505 if (elapsed
< *min
) {
508 if (elapsed
> *max
) {
515 cmd_latency(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
517 unsigned short int local_port
;
518 unsigned short int remote_port
;
521 unsigned long long int total
= 0;
524 if (!remote_addr
.s_addr
) {
525 ovs_fatal(0, "remote address must be specified with -r or --rate");
527 if (!remote_min_port
&& !remote_max_port
) {
528 remote_min_port
= remote_max_port
= DEFAULT_PORT
;
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
];
539 start
= time_in_msec();
541 for (j
= 0; j
< n_sockets
; j
++) {
542 struct sockaddr_in remote
;
546 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
548 ovs_fatal(errno
, "socket failed");
551 error
= set_nonblocking(fd
);
553 ovs_fatal(error
, "set_nonblocking failed");
556 bind_local_port(fd
, &local_port
, &remote_port
);
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
) {
565 fds
[n_fds
].events
= POLLOUT
;
566 fds
[n_fds
].revents
= 0;
568 } else if (errno
!= ECONNREFUSED
) {
569 ovs_fatal(errno
, "connect");
572 /* Success, I guess. */
574 timer_end(start
, 0, &min
, &max
, &total
);
582 error
= poll(fds
, n_fds
, -1) < 0 ? errno
: 0;
583 } while (error
== EINTR
);
585 ovs_fatal(errno
, "poll");
588 for (j
= 0; j
< n_fds
; ) {
589 if (fds
[j
].revents
) {
591 fds
[j
].revents
& (POLLERR
|POLLHUP
) ? 1 : 0,
594 fds
[j
] = fds
[--n_fds
];
603 printf("min %d ms, max %d ms, avg %llu ms\n",
604 min
, max
, total
/ (1ULL * n_sockets
* n_batches
));
608 cmd_help(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
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
},
621 static const struct command
*get_all_commands(void)