Add very numerous bug fixes and features, from Norse Corp.ahc_fix_select
@@ -34,57 +34,92 @@ | |||||
#include "config.h" | #include "config.h" | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <fcntl.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | |||||
#include <sys/mman.h> | |||||
#include <sys/stat.h> | |||||
#include <generic_types.h> | #include <generic_types.h> | ||||
#include <object.h> | #include <object.h> | ||||
#include <timer.h> | #include <timer.h> | ||||
#include <httperf.h> | #include <httperf.h> | ||||
#include <call.h> | |||||
#include <conn.h> | #include <conn.h> | ||||
#include <core.h> | |||||
static char *srvbase, *srvend, *srvcurrent; | |||||
void | |||||
conn_add_servers (void) | |||||
{ | |||||
struct stat st; | |||||
int fd, len; | |||||
fd = open(param.server, O_RDONLY, 0); | |||||
if (fd == -1) | |||||
panic("%s: can't open %s\n", prog_name, param.server); | |||||
fstat(fd, &st); | |||||
if (st.st_size == 0) | |||||
panic("%s: file %s is empty\n", prog_name, param.server); | |||||
srvbase = (char *)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | |||||
if (srvbase == (char *)-1) | |||||
panic("%s: can't mmap the file: %s\n", prog_name, strerror(errno)); | |||||
close (fd); | |||||
srvend = srvbase + st.st_size; | |||||
for (srvcurrent = srvbase; srvcurrent < srvend; srvcurrent += len + 1) { | |||||
len = strlen(srvcurrent); | |||||
core_addr_intern(srvcurrent, len, param.port); | |||||
} | |||||
srvcurrent = srvbase; | |||||
} | |||||
void | void | ||||
conn_init (Conn *conn) | conn_init (Conn *conn) | ||||
{ | { | ||||
conn->hostname = param.server; | |||||
conn->hostname_len = strlen (param.server); | |||||
conn->port = param.port; | |||||
conn->sd = -1; | |||||
conn->myport = -1; | |||||
conn->line.iov_base = conn->line_buf; | |||||
if (param.server_name) | |||||
{ | |||||
conn->fqdname = param.server_name; | |||||
conn->fqdname_len = strlen (param.server_name); | |||||
} | |||||
else | |||||
{ | |||||
conn->fqdname = conn->hostname; | |||||
conn->fqdname_len = conn->hostname_len; | |||||
} | |||||
int len; | |||||
len = strlen(srvcurrent); | |||||
conn->hostname = srvcurrent; | |||||
conn->hostname_len = len; | |||||
srvcurrent += len + 1; | |||||
if (srvcurrent >= srvend) | |||||
srvcurrent = srvbase; | |||||
conn->port = param.port; | |||||
conn->sd = -1; | |||||
conn->myport = -1; | |||||
conn->line.iov_base = conn->line_buf; | |||||
conn->fqdname = conn->hostname; | |||||
conn->fqdname_len = conn->hostname_len; | |||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
if (param.use_ssl) | |||||
{ | |||||
conn->ssl = SSL_new (ssl_ctx); | |||||
if (!conn->ssl) | |||||
{ | |||||
ERR_print_errors_fp (stderr); | |||||
exit (-1); | |||||
} | |||||
if (param.use_ssl) { | |||||
conn->ssl = SSL_new(ssl_ctx); | |||||
if (!conn->ssl) { | |||||
ERR_print_errors_fp(stderr); | |||||
exit(-1); | |||||
} | |||||
if (param.ssl_cipher_list) | |||||
{ | |||||
/* set order of ciphers */ | |||||
int ssl_err = SSL_set_cipher_list (conn->ssl, param.ssl_cipher_list); | |||||
if (param.ssl_cipher_list) { | |||||
/* set order of ciphers */ | |||||
int ssl_err = SSL_set_cipher_list(conn->ssl, param.ssl_cipher_list); | |||||
if (DBG > 2) | |||||
fprintf (stderr, "core_ssl_connect: set_cipher_list returned %d\n", | |||||
ssl_err); | |||||
if (DBG > 2) | |||||
fprintf(stderr, | |||||
"core_ssl_connect: set_cipher_list returned %d\n", | |||||
ssl_err); | |||||
} | |||||
} | } | ||||
} | |||||
#endif | #endif | ||||
} | } | ||||
@@ -66,6 +66,8 @@ typedef enum Conn_State | |||||
} | } | ||||
Conn_State; | Conn_State; | ||||
struct local_addr; | |||||
typedef struct Conn | typedef struct Conn | ||||
{ | { | ||||
Object obj; | Object obj; | ||||
@@ -92,6 +94,7 @@ typedef struct Conn | |||||
int port; /* server's port (or -1 for default) */ | int port; /* server's port (or -1 for default) */ | ||||
int sd; /* socket descriptor */ | int sd; /* socket descriptor */ | ||||
int myport; /* local port number or -1 */ | int myport; /* local port number or -1 */ | ||||
struct local_addr *myaddr; | |||||
/* Since replies are read off the socket sequentially, much of the | /* Since replies are read off the socket sequentially, much of the | ||||
reply-processing related state can be kept here instead of in | reply-processing related state can be kept here instead of in | ||||
the reply structure: */ | the reply structure: */ | ||||
@@ -99,6 +102,8 @@ typedef struct Conn | |||||
size_t content_length; /* content length (or INF if unknown) */ | size_t content_length; /* content length (or INF if unknown) */ | ||||
u_int has_body : 1; /* does reply have a body? */ | u_int has_body : 1; /* does reply have a body? */ | ||||
u_int is_chunked : 1; /* is the reply chunked? */ | u_int is_chunked : 1; /* is the reply chunked? */ | ||||
u_int reading : 1; | |||||
u_int writing : 1; | |||||
char line_buf[MAX_HDR_LINE_LEN]; /* default line buffer */ | char line_buf[MAX_HDR_LINE_LEN]; /* default line buffer */ | ||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
@@ -110,6 +115,9 @@ Conn; | |||||
extern int max_num_conn; | extern int max_num_conn; | ||||
extern Conn *conn; | extern Conn *conn; | ||||
/* Store the servers to connect to in memory. */ | |||||
extern void conn_add_servers (void); | |||||
/* Initialize the new connection object C. */ | /* Initialize the new connection object C. */ | ||||
extern void conn_init (Conn *c); | extern void conn_init (Conn *c); | ||||
@@ -30,6 +30,10 @@ | |||||
#include "config.h" | #include "config.h" | ||||
#ifdef __FreeBSD__ | |||||
#define HAVE_KEVENT | |||||
#endif | |||||
#include <assert.h> | #include <assert.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
@@ -47,7 +51,21 @@ | |||||
#ifdef HAVE_SYS_SELECT_H | #ifdef HAVE_SYS_SELECT_H | ||||
#include <sys/select.h> | #include <sys/select.h> | ||||
#endif | #endif | ||||
#ifdef HAVE_KEVENT | |||||
#include <sys/event.h> | |||||
/* | |||||
* Older systems using kevent() always specify the time in | |||||
* milliseconds and do not have a flag to select a different scale. | |||||
*/ | |||||
#ifndef NOTE_MSECONDS | |||||
#define NOTE_MSECONDS 0 | |||||
#endif | |||||
#endif | |||||
#ifdef __FreeBSD__ | |||||
#include <ifaddrs.h> | |||||
#endif | |||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||||
@@ -69,16 +87,35 @@ | |||||
#define MAX_IP_PORT 65535 | #define MAX_IP_PORT 65535 | ||||
#define BITSPERLONG (8*sizeof (u_long)) | #define BITSPERLONG (8*sizeof (u_long)) | ||||
static int running = 1; | |||||
struct local_addr { | |||||
struct in_addr ip; | |||||
u_long port_free_map[((MAX_IP_PORT - MIN_IP_PORT + BITSPERLONG) | |||||
/ BITSPERLONG)]; | |||||
u_long mask; | |||||
int previous; | |||||
}; | |||||
struct address_pool { | |||||
struct local_addr *addresses; | |||||
int count; | |||||
int last; | |||||
}; | |||||
static volatile int running = 1; | |||||
static int iteration; | static int iteration; | ||||
static u_long max_burst_len; | static u_long max_burst_len; | ||||
#ifdef HAVE_KEVENT | |||||
static int kq, max_sd = 0; | |||||
#else | |||||
static fd_set rdfds, wrfds; | static fd_set rdfds, wrfds; | ||||
static int min_sd = 0x7fffffff, max_sd = 0, alloced_sd_to_conn = 0; | static int min_sd = 0x7fffffff, max_sd = 0, alloced_sd_to_conn = 0; | ||||
static struct timeval select_timeout; | static struct timeval select_timeout; | ||||
#endif | |||||
static struct sockaddr_in myaddr; | static struct sockaddr_in myaddr; | ||||
static struct address_pool myaddrs; | |||||
#ifndef HAVE_KEVENT | |||||
Conn **sd_to_conn; | Conn **sd_to_conn; | ||||
static u_long port_free_map[((MAX_IP_PORT - MIN_IP_PORT + BITSPERLONG) | |||||
/ BITSPERLONG)]; | |||||
#endif | |||||
static char http10req[] = | static char http10req[] = | ||||
" HTTP/1.0\r\nUser-Agent: httperf/" VERSION | " HTTP/1.0\r\nUser-Agent: httperf/" VERSION | ||||
"\r\nConnection: keep-alive\r\nHost: "; | "\r\nConnection: keep-alive\r\nHost: "; | ||||
@@ -113,13 +150,13 @@ static char http11req_nohost[] = | |||||
enum Syscalls { | enum Syscalls { | ||||
SC_BIND, SC_CONNECT, SC_READ, SC_SELECT, SC_SOCKET, SC_WRITEV, | SC_BIND, SC_CONNECT, SC_READ, SC_SELECT, SC_SOCKET, SC_WRITEV, | ||||
SC_SSL_READ, SC_SSL_WRITEV, | |||||
SC_SSL_READ, SC_SSL_WRITEV, SC_KEVENT, | |||||
SC_NUM_SYSCALLS | SC_NUM_SYSCALLS | ||||
}; | }; | ||||
static const char *const syscall_name[SC_NUM_SYSCALLS] = { | static const char *const syscall_name[SC_NUM_SYSCALLS] = { | ||||
"bind", "connct", "read", "select", "socket", "writev", | "bind", "connct", "read", "select", "socket", "writev", | ||||
"ssl_read", "ssl_writev" | |||||
"ssl_read", "ssl_writev", "kevent" | |||||
}; | }; | ||||
static Time syscall_time[SC_NUM_SYSCALLS]; | static Time syscall_time[SC_NUM_SYSCALLS]; | ||||
static u_int syscall_count[SC_NUM_SYSCALLS]; | static u_int syscall_count[SC_NUM_SYSCALLS]; | ||||
@@ -208,6 +245,9 @@ hash_lookup(const char *server, size_t server_len, int port) | |||||
static int | static int | ||||
lffs(long w) | lffs(long w) | ||||
{ | { | ||||
#ifdef __FreeBSD__ | |||||
return ffsl(w); | |||||
#else | |||||
int r; | int r; | ||||
if (sizeof(w) == sizeof(int)) | if (sizeof(w) == sizeof(int)) | ||||
@@ -223,33 +263,32 @@ lffs(long w) | |||||
#endif | #endif | ||||
} | } | ||||
return r; | return r; | ||||
#endif | |||||
} | } | ||||
static void | static void | ||||
port_put(int port) | |||||
port_put(struct local_addr *addr, int port) | |||||
{ | { | ||||
int i, bit; | int i, bit; | ||||
port -= MIN_IP_PORT; | port -= MIN_IP_PORT; | ||||
i = port / BITSPERLONG; | i = port / BITSPERLONG; | ||||
bit = port % BITSPERLONG; | bit = port % BITSPERLONG; | ||||
port_free_map[i] |= (1UL << bit); | |||||
addr->port_free_map[i] |= (1UL << bit); | |||||
} | } | ||||
static int | static int | ||||
port_get(void) | |||||
port_get(struct local_addr *addr) | |||||
{ | { | ||||
static u_long mask = ~0UL; | |||||
static int previous = 0; | |||||
int port, bit, i; | int port, bit, i; | ||||
i = previous; | |||||
if ((port_free_map[i] & mask) == 0) { | |||||
i = addr->previous; | |||||
if ((addr->port_free_map[i] & addr->mask) == 0) { | |||||
do { | do { | ||||
++i; | ++i; | ||||
if (i >= NELEMS(port_free_map)) | |||||
if (i >= NELEMS(addr->port_free_map)) | |||||
i = 0; | i = 0; | ||||
if (i == previous) { | |||||
if (i == addr->previous) { | |||||
if (DBG > 0) | if (DBG > 0) | ||||
fprintf(stderr, | fprintf(stderr, | ||||
"%s.port_get: Yikes! I'm out of port numbers!\n", | "%s.port_get: Yikes! I'm out of port numbers!\n", | ||||
@@ -257,17 +296,17 @@ port_get(void) | |||||
return -1; | return -1; | ||||
} | } | ||||
} | } | ||||
while (port_free_map[i] == 0); | |||||
mask = ~0UL; | |||||
while (addr->port_free_map[i] == 0); | |||||
addr->mask = ~0UL; | |||||
} | } | ||||
previous = i; | |||||
addr->previous = i; | |||||
bit = lffs(port_free_map[i] & mask) - 1; | |||||
bit = lffs(addr->port_free_map[i] & addr->mask) - 1; | |||||
if (bit >= BITSPERLONG - 1) | if (bit >= BITSPERLONG - 1) | ||||
mask = 0; | |||||
addr->mask = 0; | |||||
else | else | ||||
mask = ~((1UL << (bit + 1)) - 1); | |||||
port_free_map[i] &= ~(1UL << bit); | |||||
addr->mask = ~((1UL << (bit + 1)) - 1); | |||||
addr->port_free_map[i] &= ~(1UL << bit); | |||||
port = bit + i * BITSPERLONG + MIN_IP_PORT; | port = bit + i * BITSPERLONG + MIN_IP_PORT; | ||||
return port; | return port; | ||||
} | } | ||||
@@ -297,10 +336,10 @@ conn_timeout(struct Timer *t, Any_Type arg) | |||||
c = 0; | c = 0; | ||||
if (s->sd >= 0) { | if (s->sd >= 0) { | ||||
now = timer_now(); | now = timer_now(); | ||||
if (FD_ISSET(s->sd, &rdfds) | |||||
if (s->reading | |||||
&& s->recvq && now >= s->recvq->timeout) | && s->recvq && now >= s->recvq->timeout) | ||||
c = s->recvq; | c = s->recvq; | ||||
else if (FD_ISSET(s->sd, &wrfds) | |||||
else if (s->writing | |||||
&& s->sendq && now >= s->sendq->timeout) | && s->sendq && now >= s->sendq->timeout) | ||||
c = s->sendq; | c = s->sendq; | ||||
} | } | ||||
@@ -318,18 +357,70 @@ conn_timeout(struct Timer *t, Any_Type arg) | |||||
core_close(s); | core_close(s); | ||||
} | } | ||||
enum IO_DIR { READ, WRITE }; | |||||
static void | static void | ||||
set_active(Conn * s, fd_set * fdset) | |||||
clear_active(Conn * s, enum IO_DIR dir) | |||||
{ | |||||
int sd = s->sd; | |||||
#ifdef HAVE_KEVENT | |||||
struct kevent ev; | |||||
EV_SET(&ev, sd, dir == WRITE ? EVFILT_WRITE : EVFILT_READ, EV_DELETE, | |||||
0, 0, s); | |||||
if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0) { | |||||
fprintf(stderr, "failed to add %s filter\n", write ? | |||||
"write" : "read"); | |||||
exit(1); | |||||
} | |||||
#else | |||||
fd_set * fdset; | |||||
if (dir == WRITE) | |||||
fdset = &wrfds; | |||||
else | |||||
fdset = &rdfds; | |||||
FD_CLR(sd, fdset); | |||||
#endif | |||||
if (dir == WRITE) | |||||
s->writing = 0; | |||||
else | |||||
s->reading = 0; | |||||
} | |||||
static void | |||||
set_active(Conn * s, enum IO_DIR dir) | |||||
{ | { | ||||
int sd = s->sd; | int sd = s->sd; | ||||
Any_Type arg; | Any_Type arg; | ||||
Time timeout; | Time timeout; | ||||
#ifdef HAVE_KEVENT | |||||
struct kevent ev; | |||||
EV_SET(&ev, sd, dir == WRITE ? EVFILT_WRITE : EVFILT_READ, EV_ADD, | |||||
0, 0, s); | |||||
if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0) { | |||||
fprintf(stderr, "failed to add %s filter\n", write ? | |||||
"write" : "read"); | |||||
exit(1); | |||||
} | |||||
#else | |||||
fd_set * fdset; | |||||
if (dir == WRITE) | |||||
fdset = &wrfds; | |||||
else | |||||
fdset = &rdfds; | |||||
FD_SET(sd, fdset); | FD_SET(sd, fdset); | ||||
if (sd < min_sd) | if (sd < min_sd) | ||||
min_sd = sd; | min_sd = sd; | ||||
#endif | |||||
if (sd >= max_sd) | if (sd >= max_sd) | ||||
max_sd = sd; | max_sd = sd; | ||||
if (dir == WRITE) | |||||
s->writing = 1; | |||||
else | |||||
s->reading = 1; | |||||
if (s->watchdog) | if (s->watchdog) | ||||
return; | return; | ||||
@@ -434,7 +525,7 @@ do_send(Conn * conn) | |||||
*/ | */ | ||||
call->timeout = | call->timeout = | ||||
param.timeout ? timer_now() + param.timeout : 0.0; | param.timeout ? timer_now() + param.timeout : 0.0; | ||||
set_active(conn, &wrfds); | |||||
set_active(conn, WRITE); | |||||
return; | return; | ||||
} | } | ||||
@@ -444,7 +535,7 @@ do_send(Conn * conn) | |||||
conn->sendq = call->sendq_next; | conn->sendq = call->sendq_next; | ||||
if (!conn->sendq) { | if (!conn->sendq) { | ||||
conn->sendq_tail = 0; | conn->sendq_tail = 0; | ||||
FD_CLR(sd, &wrfds); | |||||
clear_active(conn, WRITE); | |||||
} | } | ||||
arg.l = 0; | arg.l = 0; | ||||
event_signal(EV_CALL_SEND_STOP, (Object *) call, arg); | event_signal(EV_CALL_SEND_STOP, (Object *) call, arg); | ||||
@@ -468,7 +559,7 @@ do_send(Conn * conn) | |||||
call->timeout = param.timeout + param.think_timeout; | call->timeout = param.timeout + param.think_timeout; | ||||
if (call->timeout > 0.0) | if (call->timeout > 0.0) | ||||
call->timeout += timer_now(); | call->timeout += timer_now(); | ||||
set_active(conn, &rdfds); | |||||
set_active(conn, READ); | |||||
if (conn->state < S_REPLY_STATUS) | if (conn->state < S_REPLY_STATUS) | ||||
conn->state = S_REPLY_STATUS; /* expecting reply | conn->state = S_REPLY_STATUS; /* expecting reply | ||||
* status */ | * status */ | ||||
@@ -491,7 +582,7 @@ recv_done(Call * call) | |||||
conn->recvq = call->recvq_next; | conn->recvq = call->recvq_next; | ||||
if (!conn->recvq) { | if (!conn->recvq) { | ||||
FD_CLR(conn->sd, &rdfds); | |||||
clear_active(conn, READ); | |||||
conn->recvq_tail = 0; | conn->recvq_tail = 0; | ||||
} | } | ||||
/* | /* | ||||
@@ -602,7 +693,7 @@ do_recv(Conn * s) | |||||
while (buf_len > 0); | while (buf_len > 0); | ||||
if (s->recvq) | if (s->recvq) | ||||
set_active(c->conn, &rdfds); | |||||
set_active(c->conn, READ); | |||||
} | } | ||||
struct sockaddr_in * | struct sockaddr_in * | ||||
@@ -645,22 +736,192 @@ core_addr_intern(const char *server, size_t server_len, int port) | |||||
return &h->sin; | return &h->sin; | ||||
} | } | ||||
static void | |||||
core_add_address(struct in_addr ip) | |||||
{ | |||||
struct local_addr *addr; | |||||
myaddrs.addresses = realloc(myaddrs.addresses, | |||||
sizeof(struct local_addr) * (myaddrs.count + 1)); | |||||
if (myaddrs.addresses == NULL) { | |||||
fprintf(stderr, | |||||
"%s: out of memory parsing address list\n", | |||||
prog_name); | |||||
exit(1); | |||||
} | |||||
addr = &myaddrs.addresses[myaddrs.count]; | |||||
addr->ip = ip; | |||||
memset(&addr->port_free_map, 0xff, sizeof(addr->port_free_map)); | |||||
addr->mask = ~0UL; | |||||
addr->previous = 0; | |||||
myaddrs.count++; | |||||
} | |||||
/* | |||||
* Parses the value provided to --myaddr. A value can either be a | |||||
* hostname or IP, or an IP range. Multiple values can be specified | |||||
* in which case all matches are added to a pool which new connections | |||||
* use in a round-robin fashion. An interface name may also be | |||||
* specified in which case all IP addresses assigned to that interface | |||||
* are used. | |||||
*/ | |||||
void | |||||
core_add_addresses(const char *spec) | |||||
{ | |||||
struct hostent *he; | |||||
struct in_addr ip; | |||||
#ifdef __FreeBSD__ | |||||
struct ifaddrs *iflist, *ifa; | |||||
#endif | |||||
char *cp; | |||||
/* First try to resolve the argument as a hostname. */ | |||||
he = gethostbyname(spec); | |||||
if (he) { | |||||
if (he->h_addrtype != AF_INET || | |||||
he->h_length != sizeof(struct in_addr)) { | |||||
fprintf(stderr, | |||||
"%s: can't deal with addr family %d or size %d\n", | |||||
prog_name, he->h_addrtype, he->h_length); | |||||
exit(1); | |||||
} | |||||
core_add_address(*(struct in_addr *)he->h_addr_list[0]); | |||||
return; | |||||
} | |||||
/* If there seems to be an IP range, try that next. */ | |||||
cp = strchr(spec, '-'); | |||||
if (cp != NULL) { | |||||
char *start_s; | |||||
struct in_addr end_ip; | |||||
start_s = strndup(spec, cp - spec); | |||||
if (!inet_aton(start_s, &ip)) { | |||||
fprintf(stderr, "%s: invalid starting address %s\n", | |||||
prog_name, start_s); | |||||
exit(1); | |||||
} | |||||
if (!inet_aton(cp + 1, &end_ip)) { | |||||
fprintf(stderr, "%s: invalid ending address %s\n", | |||||
prog_name, cp + 1); | |||||
exit(1); | |||||
} | |||||
while (ip.s_addr != end_ip.s_addr) { | |||||
core_add_address(ip); | |||||
ip.s_addr += htonl(1); | |||||
} | |||||
core_add_address(end_ip); | |||||
return; | |||||
} | |||||
/* Check for a single IP. */ | |||||
if (inet_aton(spec, &ip)) { | |||||
core_add_address(ip); | |||||
return; | |||||
} | |||||
#ifdef __FreeBSD__ | |||||
/* Check for an interface name. */ | |||||
if (getifaddrs(&iflist) == 0) { | |||||
int found; | |||||
found = 0; | |||||
for (ifa = iflist; ifa != NULL; ifa = ifa->ifa_next) { | |||||
if (strcmp(ifa->ifa_name, spec) != 0) | |||||
continue; | |||||
if (found == 0) | |||||
found = 1; | |||||
if (ifa->ifa_addr->sa_family != AF_INET) | |||||
continue; | |||||
found = 2; | |||||
core_add_address( | |||||
((struct sockaddr_in *)ifa->ifa_addr)->sin_addr); | |||||
} | |||||
freeifaddrs(iflist); | |||||
if (found == 2) | |||||
return; | |||||
if (found == 1) { | |||||
fprintf(stderr, | |||||
"%s: no valid addresses found on interface %s\n", | |||||
prog_name, spec); | |||||
exit(1); | |||||
} | |||||
} | |||||
#endif | |||||
fprintf(stderr, "%s: invalid address list %s\n", | |||||
prog_name, spec); | |||||
exit(1); | |||||
} | |||||
static struct local_addr * | |||||
core_get_next_myaddr(void) | |||||
{ | |||||
struct local_addr *addr; | |||||
assert(myaddrs.last >= 0 && myaddrs.last < myaddrs.count); | |||||
addr = &myaddrs.addresses[myaddrs.last]; | |||||
myaddrs.last++; | |||||
if (myaddrs.last == myaddrs.count) | |||||
myaddrs.last = 0; | |||||
return (addr); | |||||
} | |||||
static void | |||||
core_runtime_timer(struct Timer *t, Any_Type arg) | |||||
{ | |||||
core_exit(); | |||||
} | |||||
void | void | ||||
core_init(void) | core_init(void) | ||||
{ | { | ||||
struct rlimit rlimit; | struct rlimit rlimit; | ||||
Any_Type arg; | |||||
memset(&hash_table, 0, sizeof(hash_table)); | memset(&hash_table, 0, sizeof(hash_table)); | ||||
#ifndef HAVE_KEVENT | |||||
memset(&rdfds, 0, sizeof(rdfds)); | memset(&rdfds, 0, sizeof(rdfds)); | ||||
memset(&wrfds, 0, sizeof(wrfds)); | memset(&wrfds, 0, sizeof(wrfds)); | ||||
#endif | |||||
memset(&myaddr, 0, sizeof(myaddr)); | memset(&myaddr, 0, sizeof(myaddr)); | ||||
memset(&port_free_map, 0xff, sizeof(port_free_map)); | |||||
#ifdef __FreeBSD__ | |||||
myaddr.sin_len = sizeof(myaddr); | |||||
#endif | |||||
myaddr.sin_family = AF_INET; | |||||
myaddr.sin_addr.s_addr = htonl(INADDR_ANY); | |||||
if (myaddrs.count == 0) | |||||
core_add_address(myaddr.sin_addr); | |||||
/* | /* | ||||
* Don't disturb just because a TCP connection closed on us... | * Don't disturb just because a TCP connection closed on us... | ||||
*/ | */ | ||||
signal(SIGPIPE, SIG_IGN); | signal(SIGPIPE, SIG_IGN); | ||||
#ifdef HAVE_KEVENT | |||||
kq = kqueue(); | |||||
if (kq < 0) { | |||||
fprintf(stderr, | |||||
"%s: failed to create kqueue: %s", prog_name, | |||||
strerror(errno)); | |||||
exit(1); | |||||
} | |||||
/* | |||||
* TIMER_INTERVAL doesn't exist anymore, so just take a wild | |||||
* guess. | |||||
*/ | |||||
struct kevent ev; | |||||
EV_SET(&ev, 0, EVFILT_TIMER, EV_ADD, NOTE_MSECONDS, 1, NULL); | |||||
if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0) { | |||||
fprintf(stderr, | |||||
"%s: failed to add timer event: %s", prog_name, | |||||
strerror(errno)); | |||||
} | |||||
#else | |||||
#ifdef DONT_POLL | #ifdef DONT_POLL | ||||
/* | /* | ||||
* This causes select() to take several milliseconds on both Linux/x86 | * This causes select() to take several milliseconds on both Linux/x86 | ||||
@@ -677,6 +938,7 @@ core_init(void) | |||||
*/ | */ | ||||
select_timeout.tv_sec = 0; | select_timeout.tv_sec = 0; | ||||
select_timeout.tv_usec = 0; | select_timeout.tv_usec = 0; | ||||
#endif | |||||
#endif | #endif | ||||
/* | /* | ||||
@@ -702,8 +964,11 @@ core_init(void) | |||||
prog_name, rlimit.rlim_max); | prog_name, rlimit.rlim_max); | ||||
if (param.server) | if (param.server) | ||||
core_addr_intern(param.server, strlen(param.server), | |||||
param.port); | |||||
conn_add_servers(); | |||||
if (param.runtime) { | |||||
arg.l = 0; | |||||
timer_schedule(core_runtime_timer, arg, param.runtime); | |||||
} | |||||
} | } | ||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
@@ -735,13 +1000,13 @@ core_ssl_connect(Conn * s) | |||||
SSL_ERROR_WANT_READ) ? "read" : | SSL_ERROR_WANT_READ) ? "read" : | ||||
"write"); | "write"); | ||||
if (reason == SSL_ERROR_WANT_READ | if (reason == SSL_ERROR_WANT_READ | ||||
&& !FD_ISSET(s->sd, &rdfds)) { | |||||
FD_CLR(s->sd, &wrfds); | |||||
set_active(s, &rdfds); | |||||
&& !s->reading) { | |||||
clear_active(s, WRITE); | |||||
set_active(s, READ); | |||||
} else if (reason == SSL_ERROR_WANT_WRITE | } else if (reason == SSL_ERROR_WANT_WRITE | ||||
&& !FD_ISSET(s->sd, &wrfds)) { | |||||
FD_CLR(s->sd, &rdfds); | |||||
set_active(s, &wrfds); | |||||
&& !s->writing) { | |||||
clear_active(s, READ); | |||||
set_active(s, WRITE); | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
@@ -758,7 +1023,7 @@ core_ssl_connect(Conn * s) | |||||
fprintf(stderr, "core_ssl_connect: SSL is connected!\n"); | fprintf(stderr, "core_ssl_connect: SSL is connected!\n"); | ||||
if (DBG > 1) { | if (DBG > 1) { | ||||
SSL_CIPHER *ssl_cipher; | |||||
const SSL_CIPHER *ssl_cipher; | |||||
ssl_cipher = SSL_get_current_cipher(s->ssl); | ssl_cipher = SSL_get_current_cipher(s->ssl); | ||||
if (!ssl_cipher) | if (!ssl_cipher) | ||||
@@ -852,6 +1117,7 @@ core_connect(Conn * s) | |||||
} | } | ||||
s->sd = sd; | s->sd = sd; | ||||
#ifndef HAVE_KEVENT | |||||
if (sd >= alloced_sd_to_conn) { | if (sd >= alloced_sd_to_conn) { | ||||
size_t size, old_size; | size_t size, old_size; | ||||
@@ -873,6 +1139,7 @@ core_connect(Conn * s) | |||||
} | } | ||||
assert(!sd_to_conn[sd]); | assert(!sd_to_conn[sd]); | ||||
sd_to_conn[sd] = s; | sd_to_conn[sd] = s; | ||||
#endif | |||||
sin = hash_lookup(s->hostname, s->hostname_len, s->port); | sin = hash_lookup(s->hostname, s->hostname_len, s->port); | ||||
if (!sin) { | if (!sin) { | ||||
@@ -888,9 +1155,11 @@ core_connect(Conn * s) | |||||
if (s->state >= S_CLOSING) | if (s->state >= S_CLOSING) | ||||
goto failure; | goto failure; | ||||
s->myaddr = core_get_next_myaddr(); | |||||
myaddr.sin_addr = s->myaddr->ip; | |||||
if (param.hog) { | if (param.hog) { | ||||
while (1) { | while (1) { | ||||
myport = port_get(); | |||||
myport = port_get(s->myaddr); | |||||
if (myport < 0) | if (myport < 0) | ||||
goto failure; | goto failure; | ||||
@@ -910,6 +1179,12 @@ core_connect(Conn * s) | |||||
} | } | ||||
} | } | ||||
s->myport = myport; | s->myport = myport; | ||||
} else if (myaddr.sin_addr.s_addr != htonl(INADDR_ANY)) { | |||||
SYSCALL(BIND, | |||||
result = bind(sd, (struct sockaddr *) &myaddr, | |||||
sizeof(myaddr))); | |||||
if (result != 0) | |||||
goto failure; | |||||
} | } | ||||
SYSCALL(CONNECT, | SYSCALL(CONNECT, | ||||
@@ -932,7 +1207,7 @@ core_connect(Conn * s) | |||||
* connection establishment. | * connection establishment. | ||||
*/ | */ | ||||
s->state = S_CONNECTING; | s->state = S_CONNECTING; | ||||
set_active(s, &wrfds); | |||||
set_active(s, WRITE); | |||||
if (param.timeout > 0.0) { | if (param.timeout > 0.0) { | ||||
arg.vp = s; | arg.vp = s; | ||||
assert(!s->watchdog); | assert(!s->watchdog); | ||||
@@ -949,6 +1224,8 @@ core_connect(Conn * s) | |||||
fprintf(stderr, | fprintf(stderr, | ||||
"%s.core_connect.connect: %s (max_sd=%d)\n", | "%s.core_connect.connect: %s (max_sd=%d)\n", | ||||
prog_name, strerror(errno), max_sd); | prog_name, strerror(errno), max_sd); | ||||
if (s->myport > 0) | |||||
port_put(s->myaddr, s->myport); | |||||
goto failure; | goto failure; | ||||
} | } | ||||
return 0; | return 0; | ||||
@@ -1033,7 +1310,7 @@ core_send(Conn * conn, Call * call) | |||||
return -1; | return -1; | ||||
call->timeout = | call->timeout = | ||||
param.timeout ? timer_now() + param.timeout : 0.0; | param.timeout ? timer_now() + param.timeout : 0.0; | ||||
set_active(conn, &wrfds); | |||||
set_active(conn, WRITE); | |||||
} else { | } else { | ||||
conn->sendq_tail->sendq_next = call; | conn->sendq_tail->sendq_next = call; | ||||
conn->sendq_tail = call; | conn->sendq_tail = call; | ||||
@@ -1089,12 +1366,16 @@ core_close(Conn * conn) | |||||
if (sd >= 0) { | if (sd >= 0) { | ||||
close(sd); | close(sd); | ||||
#ifndef HAVE_KEVENT | |||||
sd_to_conn[sd] = 0; | sd_to_conn[sd] = 0; | ||||
FD_CLR(sd, &wrfds); | FD_CLR(sd, &wrfds); | ||||
FD_CLR(sd, &rdfds); | FD_CLR(sd, &rdfds); | ||||
#endif | |||||
conn->reading = 0; | |||||
conn->writing = 0; | |||||
} | } | ||||
if (conn->myport > 0) | if (conn->myport > 0) | ||||
port_put(conn->myport); | |||||
port_put(conn->myaddr, conn->myport); | |||||
/* | /* | ||||
* A connection that has been closed is not useful anymore, so we give | * A connection that has been closed is not useful anymore, so we give | ||||
@@ -1104,6 +1385,63 @@ core_close(Conn * conn) | |||||
conn_dec_ref(conn); | conn_dec_ref(conn); | ||||
} | } | ||||
#ifdef HAVE_KEVENT | |||||
void | |||||
core_loop(void) | |||||
{ | |||||
struct kevent ev; | |||||
int n; | |||||
Any_Type arg; | |||||
Conn *conn; | |||||
while (running) { | |||||
++iteration; | |||||
n = kevent(kq, NULL, 0, &ev, 1, NULL); | |||||
if (n < 0 && errno != EINTR) { | |||||
fprintf(stderr, "failed to fetch event: %s", | |||||
strerror(errno)); | |||||
exit(1); | |||||
} | |||||
switch (ev.filter) { | |||||
case EVFILT_TIMER: | |||||
timer_tick(); | |||||
break; | |||||
case EVFILT_READ: | |||||
case EVFILT_WRITE: | |||||
conn = ev.udata; | |||||
conn_inc_ref(conn); | |||||
if (conn->watchdog) { | |||||
timer_cancel(conn->watchdog); | |||||
conn->watchdog = 0; | |||||
} | |||||
if (conn->state == S_CONNECTING) { | |||||
#ifdef HAVE_SSL | |||||
if (param.use_ssl) | |||||
core_ssl_connect(conn); | |||||
else | |||||
#endif | |||||
if (ev.filter == EVFILT_WRITE) { | |||||
clear_active(conn, WRITE); | |||||
conn->state = S_CONNECTED; | |||||
arg.l = 0; | |||||
event_signal(EV_CONN_CONNECTED, (Object*)conn, arg); | |||||
} | |||||
} else { | |||||
if (ev.filter == EVFILT_WRITE && conn->sendq) | |||||
do_send(conn); | |||||
if (ev.filter == EVFILT_READ && conn->recvq) | |||||
do_recv(conn); | |||||
} | |||||
conn_dec_ref(conn); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
#else | |||||
void | void | ||||
core_loop(void) | core_loop(void) | ||||
{ | { | ||||
@@ -1175,7 +1513,7 @@ core_loop(void) | |||||
else | else | ||||
#endif | #endif | ||||
if (is_writable) { | if (is_writable) { | ||||
FD_CLR(sd, &wrfds); | |||||
clear_active(conn, WRITE); | |||||
conn->state = S_CONNECTED; | conn->state = S_CONNECTED; | ||||
arg.l = 0; | arg.l = 0; | ||||
event_signal(EV_CONN_CONNECTED, (Object*)conn, arg); | event_signal(EV_CONN_CONNECTED, (Object*)conn, arg); | ||||
@@ -1199,11 +1537,13 @@ core_loop(void) | |||||
} | } | ||||
} | } | ||||
} | } | ||||
#endif | |||||
void | void | ||||
core_exit(void) | core_exit(void) | ||||
{ | { | ||||
running = 0; | running = 0; | ||||
param.num_conns = 0; | |||||
printf("Maximum connect burst length: %lu\n", max_burst_len); | printf("Maximum connect burst length: %lu\n", max_burst_len); | ||||
@@ -36,7 +36,8 @@ | |||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
extern void core_init (void); | extern void core_init (void); | ||||
extern struct sockaddr_in *core_intern_addr (const char *hostname, | |||||
extern void core_add_addresses (const char *spec); | |||||
extern struct sockaddr_in *core_addr_intern (const char *hostname, | |||||
size_t hostname_len, int port); | size_t hostname_len, int port); | ||||
extern int core_connect (Conn *conn); | extern int core_connect (Conn *conn); | ||||
extern int core_send (Conn *conn, Call *call); | extern int core_send (Conn *conn, Call *call); | ||||
@@ -52,29 +52,46 @@ | |||||
static int num_conns_generated; | static int num_conns_generated; | ||||
static int num_conns_destroyed; | static int num_conns_destroyed; | ||||
static int num_conns_open; | |||||
static Rate_Generator rg; | static Rate_Generator rg; | ||||
static bool paused; | |||||
static int | static int | ||||
make_conn (Any_Type arg) | make_conn (Any_Type arg) | ||||
{ | { | ||||
Conn *s; | Conn *s; | ||||
if (paused) | |||||
return 0; | |||||
if (num_conns_generated++ >= param.num_conns) | if (num_conns_generated++ >= param.num_conns) | ||||
return -1; | return -1; | ||||
if (param.max_conns != 0 && num_conns_open >= param.max_conns) | |||||
return 0; | |||||
s = conn_new (); | s = conn_new (); | ||||
if (!s) | if (!s) | ||||
return -1; | return -1; | ||||
core_connect (s); | |||||
num_conns_open++; | |||||
if (core_connect (s) == -1) { | |||||
num_conns_generated--; | |||||
num_conns_destroyed--; | |||||
paused = true; | |||||
} | |||||
return 0; | return 0; | ||||
} | } | ||||
static void | static void | ||||
destroyed (void) | destroyed (void) | ||||
{ | { | ||||
Any_Type arg; | |||||
if (++num_conns_destroyed >= param.num_conns) | if (++num_conns_destroyed >= param.num_conns) | ||||
core_exit (); | core_exit (); | ||||
num_conns_open--; | |||||
paused = false; | |||||
} | } | ||||
static void | static void | ||||
@@ -42,12 +42,17 @@ | |||||
#include "config.h" | #include "config.h" | ||||
#include <sys/types.h> | |||||
#include <sys/mman.h> | |||||
#include <sys/stat.h> | |||||
#include <assert.h> | #include <assert.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | |||||
#include <generic_types.h> | #include <generic_types.h> | ||||
#include <object.h> | #include <object.h> | ||||
@@ -55,10 +60,10 @@ | |||||
#include <call.h> | #include <call.h> | ||||
#include <localevent.h> | #include <localevent.h> | ||||
static const char *extra; | |||||
static const char *extra, *extra_file; | |||||
static size_t extra_len; | static size_t extra_len; | ||||
static size_t method_len; | |||||
static size_t method_len, file_len; | |||||
/* A simple module that collects cookies from the server responses and | /* A simple module that collects cookies from the server responses and | ||||
includes them in future calls to the server. */ | includes them in future calls to the server. */ | ||||
@@ -125,6 +130,9 @@ call_created (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type arg) | |||||
if (extra_len > 0) | if (extra_len > 0) | ||||
call_append_request_header (c, extra, extra_len); | call_append_request_header (c, extra, extra_len); | ||||
if (file_len > 0) | |||||
call_append_request_header (c, extra_file, file_len); | |||||
} | } | ||||
@@ -132,10 +140,31 @@ static void | |||||
init (void) | init (void) | ||||
{ | { | ||||
Any_Type arg; | Any_Type arg; | ||||
struct stat st; | |||||
int fd; | |||||
if (param.additional_header) | if (param.additional_header) | ||||
extra = unescape (param.additional_header, &extra_len); | extra = unescape (param.additional_header, &extra_len); | ||||
if (param.additional_header_file) { | |||||
fd = open (param.additional_header_file, O_RDONLY); | |||||
if (fd < 0) | |||||
fprintf (stderr, "%s: failed to open header file\n", prog_name); | |||||
else { | |||||
if (fstat(fd, &st) < 0) | |||||
fprintf (stderr, "%s: failed to stat header file\n", prog_name); | |||||
else { | |||||
extra_file = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); | |||||
if (extra_file == (char *)MAP_FAILED) { | |||||
fprintf (stderr, "%s: failed to map header file\n", prog_name); | |||||
extra_file = NULL; | |||||
} else | |||||
file_len = st.st_size; | |||||
} | |||||
close(fd); | |||||
} | |||||
} | |||||
if (param.method) | if (param.method) | ||||
method_len = strlen (param.method); | method_len = strlen (param.method); | ||||
@@ -91,6 +91,7 @@ | |||||
const char *prog_name; | const char *prog_name; | ||||
int verbose; | int verbose; | ||||
int periodic_stats; | |||||
Cmdline_Params param; | Cmdline_Params param; | ||||
Time test_time_start; | Time test_time_start; | ||||
Time test_time_stop; | Time test_time_stop; | ||||
@@ -110,7 +111,8 @@ static Time perf_sample_start; | |||||
static struct option longopts[] = { | static struct option longopts[] = { | ||||
{"add-header", required_argument, (int *) ¶m.additional_header, 0}, | {"add-header", required_argument, (int *) ¶m.additional_header, 0}, | ||||
{"burst-length", required_argument, ¶m.burst_len, 0}, | |||||
{"add-header-file", required_argument, (int *) ¶m.additional_header_file, 0 }, | |||||
{"burst-length", required_argument, (int *) ¶m.burst_len, 0}, | |||||
{"client", required_argument, (int *) ¶m.client, 0}, | {"client", required_argument, (int *) ¶m.client, 0}, | ||||
{"close-with-reset", no_argument, ¶m.close_with_reset, 1}, | {"close-with-reset", no_argument, ¶m.close_with_reset, 1}, | ||||
{"debug", required_argument, 0, 'd'}, | {"debug", required_argument, 0, 'd'}, | ||||
@@ -118,9 +120,10 @@ static struct option longopts[] = { | |||||
{"help", no_argument, 0, 'h'}, | {"help", no_argument, 0, 'h'}, | ||||
{"hog", no_argument, ¶m.hog, 1}, | {"hog", no_argument, ¶m.hog, 1}, | ||||
{"http-version", required_argument, (int *) ¶m.http_version, 0}, | {"http-version", required_argument, (int *) ¶m.http_version, 0}, | ||||
{"max-connections", required_argument, ¶m.max_conns, 0}, | |||||
{"max-piped-calls", required_argument, ¶m.max_piped, 0}, | |||||
{"max-connections", required_argument, (int *) ¶m.max_conns, 0}, | |||||
{"max-piped-calls", required_argument, (int *) ¶m.max_piped, 0}, | |||||
{"method", required_argument, (int *) ¶m.method, 0}, | {"method", required_argument, (int *) ¶m.method, 0}, | ||||
{"myaddr", required_argument, (int *) ¶m.myaddr, 0}, | |||||
{"no-host-hdr", no_argument, ¶m.no_host_hdr, 1}, | {"no-host-hdr", no_argument, ¶m.no_host_hdr, 1}, | ||||
{"num-calls", required_argument, (int *) ¶m.num_calls, 0}, | {"num-calls", required_argument, (int *) ¶m.num_calls, 0}, | ||||
{"num-conns", required_argument, (int *) ¶m.num_conns, 0}, | {"num-conns", required_argument, (int *) ¶m.num_conns, 0}, | ||||
@@ -131,9 +134,9 @@ static struct option longopts[] = { | |||||
{"rate", required_argument, (int *) ¶m.rate, 0}, | {"rate", required_argument, (int *) ¶m.rate, 0}, | ||||
{"recv-buffer", required_argument, (int *) ¶m.recv_buffer_size, 0}, | {"recv-buffer", required_argument, (int *) ¶m.recv_buffer_size, 0}, | ||||
{"retry-on-failure", no_argument, ¶m.retry_on_failure, 1}, | {"retry-on-failure", no_argument, ¶m.retry_on_failure, 1}, | ||||
{"runtime", required_argument, (int *) ¶m.runtime, 0}, | |||||
{"send-buffer", required_argument, (int *) ¶m.send_buffer_size, 0}, | {"send-buffer", required_argument, (int *) ¶m.send_buffer_size, 0}, | ||||
{"server", required_argument, (int *) ¶m.server, 0}, | {"server", required_argument, (int *) ¶m.server, 0}, | ||||
{"server-name", required_argument, (int *) ¶m.server_name, 0}, | |||||
{"uri", required_argument, (int *) ¶m.uri, 0}, | {"uri", required_argument, (int *) ¶m.uri, 0}, | ||||
{"session-cookies", no_argument, (int *) ¶m.session_cookies, 1}, | {"session-cookies", no_argument, (int *) ¶m.session_cookies, 1}, | ||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
@@ -146,6 +149,7 @@ static struct option longopts[] = { | |||||
{"use-timer-cache", no_argument, ¶m.use_timer_cache, 1}, | {"use-timer-cache", no_argument, ¶m.use_timer_cache, 1}, | ||||
{"verbose", no_argument, 0, 'v'}, | {"verbose", no_argument, 0, 'v'}, | ||||
{"version", no_argument, 0, 'V'}, | {"version", no_argument, 0, 'V'}, | ||||
{"periodic-stats", no_argument, 0, 'n'}, | |||||
{"wlog", required_argument, (int *) ¶m.wlog, 0}, | {"wlog", required_argument, (int *) ¶m.wlog, 0}, | ||||
{"wsess", required_argument, (int *) ¶m.wsess, 0}, | {"wsess", required_argument, (int *) ¶m.wsess, 0}, | ||||
{"wsesslog", required_argument, (int *) ¶m.wsesslog, 0}, | {"wsesslog", required_argument, (int *) ¶m.wsesslog, 0}, | ||||
@@ -167,14 +171,16 @@ usage(void) | |||||
"\t[--print-reply [header|body]] [--print-request [header|body]]\n" | "\t[--print-reply [header|body]] [--print-request [header|body]]\n" | ||||
"\t[--rate X] [--recv-buffer N] [--retry-on-failure] " | "\t[--rate X] [--recv-buffer N] [--retry-on-failure] " | ||||
"[--send-buffer N]\n" | "[--send-buffer N]\n" | ||||
"\t[--server S] [--server-name S] [--port N] [--uri S] \n" | |||||
"\t<--server file> [--port N] [--uri S] [--myaddr S]\n" | |||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
"\t[--ssl] [--ssl-ciphers L] [--ssl-no-reuse]\n" | "\t[--ssl] [--ssl-ciphers L] [--ssl-no-reuse]\n" | ||||
#endif | #endif | ||||
"\t[--think-timeout X] [--timeout X] [--verbose] [--version]\n" | "\t[--think-timeout X] [--timeout X] [--verbose] [--version]\n" | ||||
"\t[--wlog y|n,file] [--wsess N,N,X] [--wsesslog N,X,file]\n" | "\t[--wlog y|n,file] [--wsess N,N,X] [--wsesslog N,X,file]\n" | ||||
"\t[--wset N,X]\n" | "\t[--wset N,X]\n" | ||||
"\t[--use-timer-cache]\n", prog_name); | |||||
"\t[--runtime X]\n" | |||||
"\t[--use-timer-cache]\n" | |||||
"\t[--periodic-stats]\n", prog_name); | |||||
} | } | ||||
void | void | ||||
@@ -254,7 +260,6 @@ main(int argc, char **argv) | |||||
param.http_version = 0x10001; /* default to HTTP/1.1 */ | param.http_version = 0x10001; /* default to HTTP/1.1 */ | ||||
param.client.id = 0; | param.client.id = 0; | ||||
param.client.num_clients = 1; | param.client.num_clients = 1; | ||||
param.server = "localhost"; | |||||
param.port = -1; | param.port = -1; | ||||
param.uri = "/"; | param.uri = "/"; | ||||
param.num_calls = 1; | param.num_calls = 1; | ||||
@@ -284,7 +289,7 @@ main(int argc, char **argv) | |||||
* process command line options: | * process command line options: | ||||
*/ | */ | ||||
while ((ch = | while ((ch = | ||||
getopt_long(argc, argv, "d:hvV", longopts, &longindex)) >= 0) { | |||||
getopt_long(argc, argv, "d:hvVn", longopts, &longindex)) >= 0) { | |||||
switch (ch) { | switch (ch) { | ||||
case 0: | case 0: | ||||
flag = longopts[longindex].flag; | flag = longopts[longindex].flag; | ||||
@@ -293,6 +298,8 @@ main(int argc, char **argv) | |||||
param.method = optarg; | param.method = optarg; | ||||
else if (flag == ¶m.additional_header) | else if (flag == ¶m.additional_header) | ||||
param.additional_header = optarg; | param.additional_header = optarg; | ||||
else if (flag == ¶m.additional_header_file) | |||||
param.additional_header_file = optarg; | |||||
else if (flag == ¶m.num_calls) { | else if (flag == ¶m.num_calls) { | ||||
errno = 0; | errno = 0; | ||||
param.num_calls = strtoul(optarg, &end, 10); | param.num_calls = strtoul(optarg, &end, 10); | ||||
@@ -312,6 +319,8 @@ main(int argc, char **argv) | |||||
} | } | ||||
param.http_version = | param.http_version = | ||||
(major << 16) | (minor & 0xffff); | (major << 16) | (minor & 0xffff); | ||||
} else if (flag == ¶m.myaddr) { | |||||
core_add_addresses(optarg); | |||||
} else if (flag == ¶m.burst_len) { | } else if (flag == ¶m.burst_len) { | ||||
errno = 0; | errno = 0; | ||||
param.burst_len = strtoul(optarg, &end, 10); | param.burst_len = strtoul(optarg, &end, 10); | ||||
@@ -345,8 +354,7 @@ main(int argc, char **argv) | |||||
} else if (flag == ¶m.max_conns) { | } else if (flag == ¶m.max_conns) { | ||||
errno = 0; | errno = 0; | ||||
param.max_conns = strtoul(optarg, &end, 10); | param.max_conns = strtoul(optarg, &end, 10); | ||||
if (errno == ERANGE || end == optarg || *end | |||||
|| param.max_conns < 0) { | |||||
if (errno == ERANGE || end == optarg || *end) { | |||||
fprintf(stderr, | fprintf(stderr, | ||||
"%s: illegal max. # of connection %s\n", | "%s: illegal max. # of connection %s\n", | ||||
prog_name, optarg); | prog_name, optarg); | ||||
@@ -355,8 +363,7 @@ main(int argc, char **argv) | |||||
} else if (flag == ¶m.max_piped) { | } else if (flag == ¶m.max_piped) { | ||||
errno = 0; | errno = 0; | ||||
param.max_piped = strtoul(optarg, &end, 10); | param.max_piped = strtoul(optarg, &end, 10); | ||||
if (errno == ERANGE || end == optarg || *end | |||||
|| param.max_piped < 0) { | |||||
if (errno == ERANGE || end == optarg || *end) { | |||||
fprintf(stderr, | fprintf(stderr, | ||||
"%s: illegal max. # of piped calls %s\n", | "%s: illegal max. # of piped calls %s\n", | ||||
prog_name, optarg); | prog_name, optarg); | ||||
@@ -619,8 +626,6 @@ main(int argc, char **argv) | |||||
} | } | ||||
} else if (flag == ¶m.server) | } else if (flag == ¶m.server) | ||||
param.server = optarg; | param.server = optarg; | ||||
else if (flag == ¶m.server_name) | |||||
param.server_name = optarg; | |||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
else if (flag == ¶m.ssl_cipher_list) | else if (flag == ¶m.ssl_cipher_list) | ||||
param.ssl_cipher_list = optarg; | param.ssl_cipher_list = optarg; | ||||
@@ -645,6 +650,16 @@ main(int argc, char **argv) | |||||
prog_name, optarg); | prog_name, optarg); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
} else if (flag == ¶m.runtime) { | |||||
errno = 0; | |||||
param.runtime = strtod(optarg, &end); | |||||
if (errno == ERANGE || end == optarg || *end || | |||||
param.runtime <= 0.0) { | |||||
fprintf(stderr, | |||||
"%s: illegal runtime value %s\n", | |||||
prog_name, optarg); | |||||
exit(1); | |||||
} | |||||
} else if (flag == ¶m.wlog) { | } else if (flag == ¶m.wlog) { | ||||
gen[1] = &uri_wlog; /* XXX fix | gen[1] = &uri_wlog; /* XXX fix | ||||
* me---somehow */ | * me---somehow */ | ||||
@@ -880,6 +895,10 @@ main(int argc, char **argv) | |||||
" TIME_SYSCALLS.\n", prog_name); | " TIME_SYSCALLS.\n", prog_name); | ||||
exit(0); | exit(0); | ||||
case 'n': | |||||
++periodic_stats; | |||||
break; | |||||
case 'h': | case 'h': | ||||
usage(); | usage(); | ||||
exit(0); | exit(0); | ||||
@@ -907,6 +926,13 @@ main(int argc, char **argv) | |||||
} | } | ||||
} | } | ||||
if (param.server == NULL) { | |||||
fprintf(stderr, | |||||
"%s: must specify --server\n", | |||||
prog_name); | |||||
exit(-1); | |||||
} | |||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
if (param.use_ssl) { | if (param.use_ssl) { | ||||
char buf[1024]; | char buf[1024]; | ||||
@@ -947,7 +973,8 @@ main(int argc, char **argv) | |||||
gen[num_gen++] = &sess_cookie; | gen[num_gen++] = &sess_cookie; | ||||
} | } | ||||
if (param.additional_header || param.method) | |||||
if (param.additional_header || param.additional_header_file || | |||||
param.method) | |||||
gen[num_gen++] = &misc; | gen[num_gen++] = &misc; | ||||
/* | /* | ||||
@@ -990,11 +1017,11 @@ main(int argc, char **argv) | |||||
printf(" --think-timeout=%g", param.think_timeout); | printf(" --think-timeout=%g", param.think_timeout); | ||||
if (param.timeout > 0) | if (param.timeout > 0) | ||||
printf(" --timeout=%g", param.timeout); | printf(" --timeout=%g", param.timeout); | ||||
if (param.runtime > 0) | |||||
printf(" --runtime=%g", param.runtime); | |||||
printf(" --client=%u/%u", param.client.id, param.client.num_clients); | printf(" --client=%u/%u", param.client.id, param.client.num_clients); | ||||
if (param.server) | if (param.server) | ||||
printf(" --server=%s", param.server); | printf(" --server=%s", param.server); | ||||
if (param.server_name) | |||||
printf(" --server_name=%s", param.server_name); | |||||
if (param.port) | if (param.port) | ||||
printf(" --port=%d", param.port); | printf(" --port=%d", param.port); | ||||
if (param.uri) | if (param.uri) | ||||
@@ -1005,9 +1032,9 @@ main(int argc, char **argv) | |||||
printf(" --http-version=%u.%u", param.http_version >> 16, | printf(" --http-version=%u.%u", param.http_version >> 16, | ||||
param.http_version & 0xffff); | param.http_version & 0xffff); | ||||
if (param.max_conns) | if (param.max_conns) | ||||
printf(" --max-connections=%u", param.max_conns); | |||||
printf(" --max-connections=%lu", param.max_conns); | |||||
if (param.max_piped) | if (param.max_piped) | ||||
printf(" --max-piped-calls=%u", param.max_piped); | |||||
printf(" --max-piped-calls=%lu", param.max_piped); | |||||
if (param.rate.rate_param > 0.0) { | if (param.rate.rate_param > 0.0) { | ||||
switch (param.rate.dist) { | switch (param.rate.dist) { | ||||
case DETERMINISTIC: | case DETERMINISTIC: | ||||
@@ -1045,10 +1072,10 @@ main(int argc, char **argv) | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
printf(" --send-buffer=%d", param.send_buffer_size); | |||||
printf(" --send-buffer=%lu", param.send_buffer_size); | |||||
if (param.retry_on_failure) | if (param.retry_on_failure) | ||||
printf(" --retry-on-failure"); | printf(" --retry-on-failure"); | ||||
printf(" --recv-buffer=%d", param.recv_buffer_size); | |||||
printf(" --recv-buffer=%lu", param.recv_buffer_size); | |||||
if (param.session_cookies) | if (param.session_cookies) | ||||
printf(" --session-cookies"); | printf(" --session-cookies"); | ||||
#ifdef HAVE_SSL | #ifdef HAVE_SSL | ||||
@@ -1061,6 +1088,8 @@ main(int argc, char **argv) | |||||
#endif | #endif | ||||
if (param.additional_header) | if (param.additional_header) | ||||
printf(" --add-header='%s'", param.additional_header); | printf(" --add-header='%s'", param.additional_header); | ||||
if (param.additional_header_file) | |||||
printf(" --add-header-file='%s'", param.additional_header_file); | |||||
if (param.method) | if (param.method) | ||||
printf(" --method=%s", param.method); | printf(" --method=%s", param.method); | ||||
if (param.use_timer_cache) | if (param.use_timer_cache) | ||||
@@ -1081,17 +1110,19 @@ main(int argc, char **argv) | |||||
param.wsess.num_calls, param.wsess.think_time); | param.wsess.num_calls, param.wsess.think_time); | ||||
else { | else { | ||||
if (param.num_conns) | if (param.num_conns) | ||||
printf(" --num-conns=%d", param.num_conns); | |||||
printf(" --num-conns=%lu", param.num_conns); | |||||
if (param.num_calls) | if (param.num_calls) | ||||
printf(" --num-calls=%d", param.num_calls); | |||||
printf(" --num-calls=%lu", param.num_calls); | |||||
} | } | ||||
if (param.burst_len != 1) | if (param.burst_len != 1) | ||||
printf(" --burst-length=%d", param.burst_len); | |||||
printf(" --burst-length=%lu", param.burst_len); | |||||
if (param.wset.num_files) | if (param.wset.num_files) | ||||
printf(" --wset=%u,%.3f", | printf(" --wset=%u,%.3f", | ||||
param.wset.num_files, | param.wset.num_files, | ||||
param.wset.target_miss_rate); | param.wset.target_miss_rate); | ||||
} | } | ||||
if (periodic_stats) | |||||
printf(" --periodic-stats"); | |||||
printf("\n"); | printf("\n"); | ||||
if (timer_init() == false) { | if (timer_init() == false) { | ||||
@@ -91,21 +91,22 @@ Rate_Info; | |||||
typedef struct Cmdline_Params | typedef struct Cmdline_Params | ||||
{ | { | ||||
int http_version; /* (default) HTTP protocol version */ | int http_version; /* (default) HTTP protocol version */ | ||||
const char *server; /* (default) hostname */ | |||||
const char *server_name; /* fully qualified server name */ | |||||
const char *server; | |||||
int port; /* (default) server port */ | int port; /* (default) server port */ | ||||
const char *uri; /* (default) uri */ | const char *uri; /* (default) uri */ | ||||
const char *myaddr; | |||||
Rate_Info rate; | Rate_Info rate; | ||||
Time timeout; /* watchdog timeout */ | Time timeout; /* watchdog timeout */ | ||||
Time think_timeout; /* timeout for server think time */ | Time think_timeout; /* timeout for server think time */ | ||||
int num_conns; /* # of connections to generate */ | |||||
int num_calls; /* # of calls to generate per connection */ | |||||
int burst_len; /* # of calls to burst back-to-back */ | |||||
int max_piped; /* max # of piped calls per connection */ | |||||
int max_conns; /* max # of connections per session */ | |||||
Time runtime; /* how long to run the test */ | |||||
u_long num_conns; /* # of connections to generate */ | |||||
u_long num_calls; /* # of calls to generate per connection */ | |||||
u_long burst_len; /* # of calls to burst back-to-back */ | |||||
u_long max_piped; /* max # of piped calls per connection */ | |||||
u_long max_conns; /* max # of connections per session */ | |||||
int hog; /* client may hog as much resources as possible */ | int hog; /* client may hog as much resources as possible */ | ||||
int send_buffer_size; | |||||
int recv_buffer_size; | |||||
u_long send_buffer_size; | |||||
u_long recv_buffer_size; | |||||
int failure_status; /* status code that should be considered failure */ | int failure_status; /* status code that should be considered failure */ | ||||
int retry_on_failure; /* when a call fails, should we retry? */ | int retry_on_failure; /* when a call fails, should we retry? */ | ||||
int close_with_reset; /* close connections with TCP RESET? */ | int close_with_reset; /* close connections with TCP RESET? */ | ||||
@@ -120,6 +121,7 @@ typedef struct Cmdline_Params | |||||
#endif | #endif | ||||
int use_timer_cache; | int use_timer_cache; | ||||
const char *additional_header; /* additional request header(s) */ | const char *additional_header; /* additional request header(s) */ | ||||
const char *additional_header_file; | |||||
const char *method; /* default call method */ | const char *method; /* default call method */ | ||||
struct | struct | ||||
{ | { | ||||
@@ -146,7 +148,7 @@ typedef struct Cmdline_Params | |||||
u_int num_reqs; /* # of user requests per session */ | u_int num_reqs; /* # of user requests per session */ | ||||
Time think_time; /* user think time between requests */ | Time think_time; /* user think time between requests */ | ||||
} | } | ||||
wsesspage; | |||||
wsesspage; /* XXX Currently broken */ | |||||
struct | struct | ||||
{ | { | ||||
u_int num_sessions; /* # of user-sessions */ | u_int num_sessions; /* # of user-sessions */ | ||||
@@ -165,6 +167,7 @@ Cmdline_Params; | |||||
extern const char *prog_name; | extern const char *prog_name; | ||||
extern int verbose; | extern int verbose; | ||||
extern int periodic_stats; | |||||
extern Cmdline_Params param; | extern Cmdline_Params param; | ||||
extern Time test_time_start; | extern Time test_time_start; | ||||
extern Time test_time_stop; | extern Time test_time_stop; | ||||
@@ -59,44 +59,46 @@ | |||||
#define NUM_BINS ((u_int) (MAX_LIFETIME / BIN_WIDTH)) | #define NUM_BINS ((u_int) (MAX_LIFETIME / BIN_WIDTH)) | ||||
static struct { | static struct { | ||||
u_int num_conns_issued; /* total # of connections * issued */ | |||||
u_int num_replies[6]; /* completion count per status class */ | |||||
u_int num_client_timeouts; /* # of client timeouts */ | |||||
u_int num_sock_fdunavail; /* # of times out of * | |||||
u_long num_conns_issued; /* total # of connections * issued */ | |||||
u_long num_replies[6]; /* completion count per status class */ | |||||
u_long num_200; /* total # of 200 responses */ | |||||
u_long num_302; /* total # of 302 responses */ | |||||
u_long num_client_timeouts; /* # of client timeouts */ | |||||
u_long num_sock_fdunavail; /* # of times out of * | |||||
* filedescriptors */ | * filedescriptors */ | ||||
u_int num_sock_ftabfull; /* # of times file table was full */ | |||||
u_int num_sock_refused; /* # of ECONNREFUSED */ | |||||
u_int num_sock_reset; /* # of ECONNRESET */ | |||||
u_int num_sock_timeouts; /* # of ETIMEDOUT */ | |||||
u_int num_sock_addrunavail; /* # of EADDRNOTAVAIL */ | |||||
u_int num_other_errors; /* # of other errors */ | |||||
u_int max_conns; /* max # of concurrent connections */ | |||||
u_int num_lifetimes; | |||||
u_long num_sock_ftabfull; /* # of times file table was full */ | |||||
u_long num_sock_refused; /* # of ECONNREFUSED */ | |||||
u_long num_sock_reset; /* # of ECONNRESET */ | |||||
u_long num_sock_timeouts; /* # of ETIMEDOUT */ | |||||
u_long num_sock_addrunavail; /* # of EADDRNOTAVAIL */ | |||||
u_long num_other_errors; /* # of other errors */ | |||||
u_long max_conns; /* max # of concurrent connections */ | |||||
u_long num_lifetimes; | |||||
Time conn_lifetime_sum; /* sum of connection lifetimes */ | Time conn_lifetime_sum; /* sum of connection lifetimes */ | ||||
Time conn_lifetime_sum2; /* sum of connection lifetimes | Time conn_lifetime_sum2; /* sum of connection lifetimes | ||||
* squared */ | * squared */ | ||||
Time conn_lifetime_min; /* minimum connection lifetime */ | Time conn_lifetime_min; /* minimum connection lifetime */ | ||||
Time conn_lifetime_max; /* maximum connection lifetime */ | Time conn_lifetime_max; /* maximum connection lifetime */ | ||||
u_int num_reply_rates; | |||||
u_long num_reply_rates; | |||||
Time reply_rate_sum; | Time reply_rate_sum; | ||||
Time reply_rate_sum2; | Time reply_rate_sum2; | ||||
Time reply_rate_min; | Time reply_rate_min; | ||||
Time reply_rate_max; | Time reply_rate_max; | ||||
u_int num_connects; /* # of completed connect()s */ | |||||
u_long num_connects; /* # of completed connect()s */ | |||||
Time conn_connect_sum; /* sum of connect times */ | Time conn_connect_sum; /* sum of connect times */ | ||||
u_int num_responses; | |||||
u_long num_responses; | |||||
Time call_response_sum; /* sum of response times */ | Time call_response_sum; /* sum of response times */ | ||||
Time call_xfer_sum; /* sum of response times */ | Time call_xfer_sum; /* sum of response times */ | ||||
u_int num_sent; /* # of requests sent */ | |||||
u_long num_sent; /* # of requests sent */ | |||||
size_t req_bytes_sent; | size_t req_bytes_sent; | ||||
u_int num_received; /* # of replies received */ | |||||
u_long num_received; /* # of replies received */ | |||||
u_wide hdr_bytes_received; /* sum of all header bytes */ | u_wide hdr_bytes_received; /* sum of all header bytes */ | ||||
u_wide reply_bytes_received; /* sum of all data bytes */ | u_wide reply_bytes_received; /* sum of all data bytes */ | ||||
u_wide footer_bytes_received; /* sum of all footer bytes */ | u_wide footer_bytes_received; /* sum of all footer bytes */ | ||||
@@ -105,8 +107,8 @@ static struct { | |||||
* connection lifetimes */ | * connection lifetimes */ | ||||
} basic; | } basic; | ||||
static u_int num_active_conns; | |||||
static u_int num_replies; /* # of replies received in this interval */ | |||||
static u_long num_active_conns; | |||||
static u_long num_replies; /* # of replies received in this interval */ | |||||
static void | static void | ||||
perf_sample(Event_Type et, Object * obj, Any_Type reg_arg, Any_Type call_arg) | perf_sample(Event_Type et, Object * obj, Any_Type reg_arg, Any_Type call_arg) | ||||
@@ -278,6 +280,14 @@ recv_start(Event_Type et, Object * obj, Any_Type reg_arg, Any_Type call_arg) | |||||
basic.call_response_sum += now - c->basic.time_send_start; | basic.call_response_sum += now - c->basic.time_send_start; | ||||
c->basic.time_recv_start = now; | c->basic.time_recv_start = now; | ||||
++basic.num_responses; | ++basic.num_responses; | ||||
if (periodic_stats) { | |||||
if (c->reply.status == 200) | |||||
++basic.num_200; | |||||
if (c->reply.status == 302) | |||||
++basic.num_302; | |||||
} | |||||
} | } | ||||
static void | static void | ||||
@@ -303,6 +313,23 @@ recv_stop(Event_Type et, Object * obj, Any_Type reg_arg, Any_Type call_arg) | |||||
++c->conn->basic.num_calls_completed; | ++c->conn->basic.num_calls_completed; | ||||
} | } | ||||
static void | |||||
one_second_timer(struct Timer *t, Any_Type arg) | |||||
{ | |||||
static u_long prev200 = 0; | |||||
static u_long prev302 = 0; | |||||
printf("[%.6f s] 200=%lu, 302=%lu\n", | |||||
timer_now() - test_time_start, | |||||
basic.num_200 - prev200, | |||||
basic.num_302 - prev302); | |||||
prev200 = basic.num_200; | |||||
prev302 = basic.num_302; | |||||
timer_schedule(one_second_timer, arg, 1); | |||||
} | |||||
static void | static void | ||||
init(void) | init(void) | ||||
{ | { | ||||
@@ -323,6 +350,9 @@ init(void) | |||||
event_register_handler(EV_CALL_SEND_STOP, send_stop, arg); | event_register_handler(EV_CALL_SEND_STOP, send_stop, arg); | ||||
event_register_handler(EV_CALL_RECV_START, recv_start, arg); | event_register_handler(EV_CALL_RECV_START, recv_start, arg); | ||||
event_register_handler(EV_CALL_RECV_STOP, recv_stop, arg); | event_register_handler(EV_CALL_RECV_STOP, recv_stop, arg); | ||||
if (periodic_stats) | |||||
timer_schedule(one_second_timer, arg, 1); | |||||
} | } | ||||
static void | static void | ||||
@@ -335,7 +365,8 @@ dump(void) | |||||
Time lifetime_avg = 0.0, lifetime_stddev = | Time lifetime_avg = 0.0, lifetime_stddev = | ||||
0.0, lifetime_median = 0.0; | 0.0, lifetime_median = 0.0; | ||||
double reply_rate_avg = 0.0, reply_rate_stddev = 0.0; | double reply_rate_avg = 0.0, reply_rate_stddev = 0.0; | ||||
int i, total_replies = 0; | |||||
int i; | |||||
u_long total_replies = 0; | |||||
Time delta, user, sys; | Time delta, user, sys; | ||||
u_wide total_size; | u_wide total_size; | ||||
Time time; | Time time; | ||||
@@ -358,7 +389,7 @@ dump(void) | |||||
} | } | ||||
} | } | ||||
printf("\nTotal: connections %u requests %u replies %u " | |||||
printf("\nTotal: connections %lu requests %lu replies %lu " | |||||
"test-duration %.3f s\n", | "test-duration %.3f s\n", | ||||
basic.num_conns_issued, basic.num_sent, total_replies, delta); | basic.num_conns_issued, basic.num_sent, total_replies, delta); | ||||
@@ -367,7 +398,7 @@ dump(void) | |||||
if (basic.num_conns_issued) | if (basic.num_conns_issued) | ||||
conn_period = delta / basic.num_conns_issued; | conn_period = delta / basic.num_conns_issued; | ||||
printf("Connection rate: %.1f conn/s (%.1f ms/conn, " | printf("Connection rate: %.1f conn/s (%.1f ms/conn, " | ||||
"<=%u concurrent connections)\n", | |||||
"<=%lu concurrent connections)\n", | |||||
basic.num_conns_issued / delta, 1e3 * conn_period, | basic.num_conns_issued / delta, 1e3 * conn_period, | ||||
basic.max_conns); | basic.max_conns); | ||||
@@ -420,7 +451,7 @@ dump(void) | |||||
} | } | ||||
printf | printf | ||||
("Reply rate [replies/s]: min %.1f avg %.1f max %.1f stddev %.1f " | ("Reply rate [replies/s]: min %.1f avg %.1f max %.1f stddev %.1f " | ||||
"(%u samples)\n", | |||||
"(%lu samples)\n", | |||||
basic.num_reply_rates > 0 ? basic.reply_rate_min : 0.0, | basic.num_reply_rates > 0 ? basic.reply_rate_min : 0.0, | ||||
reply_rate_avg, basic.reply_rate_max, reply_rate_stddev, | reply_rate_avg, basic.reply_rate_max, reply_rate_stddev, | ||||
basic.num_reply_rates); | basic.num_reply_rates); | ||||
@@ -441,12 +472,17 @@ dump(void) | |||||
"(total %.1f)\n", hdr_size, reply_size, footer_size, | "(total %.1f)\n", hdr_size, reply_size, footer_size, | ||||
hdr_size + reply_size + footer_size); | hdr_size + reply_size + footer_size); | ||||
printf("Reply status: 1xx=%u 2xx=%u 3xx=%u 4xx=%u 5xx=%u\n", | |||||
printf("Reply status: 1xx=%lu 2xx=%lu 3xx=%lu 4xx=%lu 5xx=%lu\n", | |||||
basic.num_replies[1], basic.num_replies[2], | basic.num_replies[1], basic.num_replies[2], | ||||
basic.num_replies[3], basic.num_replies[4], basic.num_replies[5]); | basic.num_replies[3], basic.num_replies[4], basic.num_replies[5]); | ||||
putchar('\n'); | putchar('\n'); | ||||
if (periodic_stats) { | |||||
printf("Periodic stats: 200=%lu 302=%lu\n", basic.num_200, basic.num_302); | |||||
putchar('\n'); | |||||
} | |||||
user = (TV_TO_SEC(test_rusage_stop.ru_utime) | user = (TV_TO_SEC(test_rusage_stop.ru_utime) | ||||
- TV_TO_SEC(test_rusage_start.ru_utime)); | - TV_TO_SEC(test_rusage_start.ru_utime)); | ||||
sys = (TV_TO_SEC(test_rusage_stop.ru_stime) | sys = (TV_TO_SEC(test_rusage_stop.ru_stime) | ||||
@@ -463,9 +499,9 @@ dump(void) | |||||
putchar('\n'); | putchar('\n'); | ||||
printf("Errors: total %u client-timo %u socket-timo %u " | |||||
"connrefused %u connreset %u\n" | |||||
"Errors: fd-unavail %u addrunavail %u ftab-full %u other %u\n", | |||||
printf("Errors: total %lu client-timo %lu socket-timo %lu " | |||||
"connrefused %lu connreset %lu\n" | |||||
"Errors: fd-unavail %lu addrunavail %lu ftab-full %lu other %lu\n", | |||||
(basic.num_client_timeouts + basic.num_sock_timeouts | (basic.num_client_timeouts + basic.num_sock_timeouts | ||||
+ basic.num_sock_fdunavail + basic.num_sock_ftabfull | + basic.num_sock_fdunavail + basic.num_sock_ftabfull | ||||
+ basic.num_sock_refused + basic.num_sock_reset | + basic.num_sock_refused + basic.num_sock_reset | ||||
@@ -240,7 +240,7 @@ timer_schedule(void (*timeout) (struct Timer * t, Any_Type arg), | |||||
t->time_started = timer_now(); | t->time_started = timer_now(); | ||||
t->timeout_delay = delay; | t->timeout_delay = delay; | ||||
if (delay > 0) | |||||
if (delay > 0 || true) | |||||
{ | { | ||||
Any_Type temp; | Any_Type temp; | ||||
temp.vp = (void *)t; | temp.vp = (void *)t; | ||||