Merge pull request #21 from erikarn/20150330_norse_fixes
Add very numerous bug fixes and features, from Norse Corp.
This commit is contained in:
commit
ab2b96b0f5
77
src/conn.c
77
src/conn.c
@ -34,54 +34,89 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <generic_types.h>
|
||||
|
||||
#include <object.h>
|
||||
#include <timer.h>
|
||||
#include <httperf.h>
|
||||
#include <call.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
|
||||
conn_init (Conn *conn)
|
||||
{
|
||||
conn->hostname = param.server;
|
||||
conn->hostname_len = strlen (param.server);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
if (param.ssl_cipher_list) {
|
||||
/* set order of ciphers */
|
||||
int ssl_err = SSL_set_cipher_list (conn->ssl, param.ssl_cipher_list);
|
||||
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",
|
||||
fprintf(stderr,
|
||||
"core_ssl_connect: set_cipher_list returned %d\n",
|
||||
ssl_err);
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ typedef enum Conn_State
|
||||
}
|
||||
Conn_State;
|
||||
|
||||
struct local_addr;
|
||||
|
||||
typedef struct Conn
|
||||
{
|
||||
Object obj;
|
||||
@ -92,6 +94,7 @@ typedef struct Conn
|
||||
int port; /* server's port (or -1 for default) */
|
||||
int sd; /* socket descriptor */
|
||||
int myport; /* local port number or -1 */
|
||||
struct local_addr *myaddr;
|
||||
/* Since replies are read off the socket sequentially, much of the
|
||||
reply-processing related state can be kept here instead of in
|
||||
the reply structure: */
|
||||
@ -99,6 +102,8 @@ typedef struct Conn
|
||||
size_t content_length; /* content length (or INF if unknown) */
|
||||
u_int has_body : 1; /* does reply have a body? */
|
||||
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 */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
@ -110,6 +115,9 @@ Conn;
|
||||
extern int max_num_conn;
|
||||
extern Conn *conn;
|
||||
|
||||
/* Store the servers to connect to in memory. */
|
||||
extern void conn_add_servers (void);
|
||||
|
||||
/* Initialize the new connection object C. */
|
||||
extern void conn_init (Conn *c);
|
||||
|
||||
|
428
src/core.c
428
src/core.c
@ -30,6 +30,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#define HAVE_KEVENT
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
@ -47,7 +51,21 @@
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#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/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
@ -69,16 +87,35 @@
|
||||
#define MAX_IP_PORT 65535
|
||||
#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 u_long max_burst_len;
|
||||
#ifdef HAVE_KEVENT
|
||||
static int kq, max_sd = 0;
|
||||
#else
|
||||
static fd_set rdfds, wrfds;
|
||||
static int min_sd = 0x7fffffff, max_sd = 0, alloced_sd_to_conn = 0;
|
||||
static struct timeval select_timeout;
|
||||
#endif
|
||||
static struct sockaddr_in myaddr;
|
||||
static struct address_pool myaddrs;
|
||||
#ifndef HAVE_KEVENT
|
||||
Conn **sd_to_conn;
|
||||
static u_long port_free_map[((MAX_IP_PORT - MIN_IP_PORT + BITSPERLONG)
|
||||
/ BITSPERLONG)];
|
||||
#endif
|
||||
static char http10req[] =
|
||||
" HTTP/1.0\r\nUser-Agent: httperf/" VERSION
|
||||
"\r\nConnection: keep-alive\r\nHost: ";
|
||||
@ -113,13 +150,13 @@ static char http11req_nohost[] =
|
||||
|
||||
enum Syscalls {
|
||||
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
|
||||
};
|
||||
|
||||
static const char *const syscall_name[SC_NUM_SYSCALLS] = {
|
||||
"bind", "connct", "read", "select", "socket", "writev",
|
||||
"ssl_read", "ssl_writev"
|
||||
"ssl_read", "ssl_writev", "kevent"
|
||||
};
|
||||
static Time syscall_time[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
|
||||
lffs(long w)
|
||||
{
|
||||
#ifdef __FreeBSD__
|
||||
return ffsl(w);
|
||||
#else
|
||||
int r;
|
||||
|
||||
if (sizeof(w) == sizeof(int))
|
||||
@ -223,33 +263,32 @@ lffs(long w)
|
||||
#endif
|
||||
}
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
port_put(int port)
|
||||
port_put(struct local_addr *addr, int port)
|
||||
{
|
||||
int i, bit;
|
||||
|
||||
port -= MIN_IP_PORT;
|
||||
i = port / BITSPERLONG;
|
||||
bit = port % BITSPERLONG;
|
||||
port_free_map[i] |= (1UL << bit);
|
||||
addr->port_free_map[i] |= (1UL << bit);
|
||||
}
|
||||
|
||||
static int
|
||||
port_get(void)
|
||||
port_get(struct local_addr *addr)
|
||||
{
|
||||
static u_long mask = ~0UL;
|
||||
static int previous = 0;
|
||||
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 {
|
||||
++i;
|
||||
if (i >= NELEMS(port_free_map))
|
||||
if (i >= NELEMS(addr->port_free_map))
|
||||
i = 0;
|
||||
if (i == previous) {
|
||||
if (i == addr->previous) {
|
||||
if (DBG > 0)
|
||||
fprintf(stderr,
|
||||
"%s.port_get: Yikes! I'm out of port numbers!\n",
|
||||
@ -257,17 +296,17 @@ port_get(void)
|
||||
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)
|
||||
mask = 0;
|
||||
addr->mask = 0;
|
||||
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;
|
||||
return port;
|
||||
}
|
||||
@ -297,10 +336,10 @@ conn_timeout(struct Timer *t, Any_Type arg)
|
||||
c = 0;
|
||||
if (s->sd >= 0) {
|
||||
now = timer_now();
|
||||
if (FD_ISSET(s->sd, &rdfds)
|
||||
if (s->reading
|
||||
&& s->recvq && now >= s->recvq->timeout)
|
||||
c = s->recvq;
|
||||
else if (FD_ISSET(s->sd, &wrfds)
|
||||
else if (s->writing
|
||||
&& s->sendq && now >= s->sendq->timeout)
|
||||
c = s->sendq;
|
||||
}
|
||||
@ -318,18 +357,70 @@ conn_timeout(struct Timer *t, Any_Type arg)
|
||||
core_close(s);
|
||||
}
|
||||
|
||||
enum IO_DIR { READ, WRITE };
|
||||
|
||||
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;
|
||||
Any_Type arg;
|
||||
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);
|
||||
if (sd < min_sd)
|
||||
min_sd = sd;
|
||||
#endif
|
||||
if (sd >= max_sd)
|
||||
max_sd = sd;
|
||||
if (dir == WRITE)
|
||||
s->writing = 1;
|
||||
else
|
||||
s->reading = 1;
|
||||
|
||||
if (s->watchdog)
|
||||
return;
|
||||
@ -434,7 +525,7 @@ do_send(Conn * conn)
|
||||
*/
|
||||
call->timeout =
|
||||
param.timeout ? timer_now() + param.timeout : 0.0;
|
||||
set_active(conn, &wrfds);
|
||||
set_active(conn, WRITE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -444,7 +535,7 @@ do_send(Conn * conn)
|
||||
conn->sendq = call->sendq_next;
|
||||
if (!conn->sendq) {
|
||||
conn->sendq_tail = 0;
|
||||
FD_CLR(sd, &wrfds);
|
||||
clear_active(conn, WRITE);
|
||||
}
|
||||
arg.l = 0;
|
||||
event_signal(EV_CALL_SEND_STOP, (Object *) call, arg);
|
||||
@ -468,7 +559,7 @@ do_send(Conn * conn)
|
||||
call->timeout = param.timeout + param.think_timeout;
|
||||
if (call->timeout > 0.0)
|
||||
call->timeout += timer_now();
|
||||
set_active(conn, &rdfds);
|
||||
set_active(conn, READ);
|
||||
if (conn->state < S_REPLY_STATUS)
|
||||
conn->state = S_REPLY_STATUS; /* expecting reply
|
||||
* status */
|
||||
@ -491,7 +582,7 @@ recv_done(Call * call)
|
||||
|
||||
conn->recvq = call->recvq_next;
|
||||
if (!conn->recvq) {
|
||||
FD_CLR(conn->sd, &rdfds);
|
||||
clear_active(conn, READ);
|
||||
conn->recvq_tail = 0;
|
||||
}
|
||||
/*
|
||||
@ -602,7 +693,7 @@ do_recv(Conn * s)
|
||||
while (buf_len > 0);
|
||||
|
||||
if (s->recvq)
|
||||
set_active(c->conn, &rdfds);
|
||||
set_active(c->conn, READ);
|
||||
}
|
||||
|
||||
struct sockaddr_in *
|
||||
@ -645,22 +736,192 @@ core_addr_intern(const char *server, size_t server_len, int port)
|
||||
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
|
||||
core_init(void)
|
||||
{
|
||||
struct rlimit rlimit;
|
||||
Any_Type arg;
|
||||
|
||||
memset(&hash_table, 0, sizeof(hash_table));
|
||||
#ifndef HAVE_KEVENT
|
||||
memset(&rdfds, 0, sizeof(rdfds));
|
||||
memset(&wrfds, 0, sizeof(wrfds));
|
||||
#endif
|
||||
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...
|
||||
*/
|
||||
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
|
||||
/*
|
||||
* 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_usec = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -702,8 +964,11 @@ core_init(void)
|
||||
prog_name, rlimit.rlim_max);
|
||||
|
||||
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
|
||||
@ -735,13 +1000,13 @@ core_ssl_connect(Conn * s)
|
||||
SSL_ERROR_WANT_READ) ? "read" :
|
||||
"write");
|
||||
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
|
||||
&& !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;
|
||||
}
|
||||
@ -758,7 +1023,7 @@ core_ssl_connect(Conn * s)
|
||||
fprintf(stderr, "core_ssl_connect: SSL is connected!\n");
|
||||
|
||||
if (DBG > 1) {
|
||||
SSL_CIPHER *ssl_cipher;
|
||||
const SSL_CIPHER *ssl_cipher;
|
||||
|
||||
ssl_cipher = SSL_get_current_cipher(s->ssl);
|
||||
if (!ssl_cipher)
|
||||
@ -852,6 +1117,7 @@ core_connect(Conn * s)
|
||||
}
|
||||
|
||||
s->sd = sd;
|
||||
#ifndef HAVE_KEVENT
|
||||
if (sd >= alloced_sd_to_conn) {
|
||||
size_t size, old_size;
|
||||
|
||||
@ -873,6 +1139,7 @@ core_connect(Conn * s)
|
||||
}
|
||||
assert(!sd_to_conn[sd]);
|
||||
sd_to_conn[sd] = s;
|
||||
#endif
|
||||
|
||||
sin = hash_lookup(s->hostname, s->hostname_len, s->port);
|
||||
if (!sin) {
|
||||
@ -888,9 +1155,11 @@ core_connect(Conn * s)
|
||||
if (s->state >= S_CLOSING)
|
||||
goto failure;
|
||||
|
||||
s->myaddr = core_get_next_myaddr();
|
||||
myaddr.sin_addr = s->myaddr->ip;
|
||||
if (param.hog) {
|
||||
while (1) {
|
||||
myport = port_get();
|
||||
myport = port_get(s->myaddr);
|
||||
if (myport < 0)
|
||||
goto failure;
|
||||
|
||||
@ -910,6 +1179,12 @@ core_connect(Conn * s)
|
||||
}
|
||||
}
|
||||
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,
|
||||
@ -932,7 +1207,7 @@ core_connect(Conn * s)
|
||||
* connection establishment.
|
||||
*/
|
||||
s->state = S_CONNECTING;
|
||||
set_active(s, &wrfds);
|
||||
set_active(s, WRITE);
|
||||
if (param.timeout > 0.0) {
|
||||
arg.vp = s;
|
||||
assert(!s->watchdog);
|
||||
@ -949,6 +1224,8 @@ core_connect(Conn * s)
|
||||
fprintf(stderr,
|
||||
"%s.core_connect.connect: %s (max_sd=%d)\n",
|
||||
prog_name, strerror(errno), max_sd);
|
||||
if (s->myport > 0)
|
||||
port_put(s->myaddr, s->myport);
|
||||
goto failure;
|
||||
}
|
||||
return 0;
|
||||
@ -1033,7 +1310,7 @@ core_send(Conn * conn, Call * call)
|
||||
return -1;
|
||||
call->timeout =
|
||||
param.timeout ? timer_now() + param.timeout : 0.0;
|
||||
set_active(conn, &wrfds);
|
||||
set_active(conn, WRITE);
|
||||
} else {
|
||||
conn->sendq_tail->sendq_next = call;
|
||||
conn->sendq_tail = call;
|
||||
@ -1089,12 +1366,16 @@ core_close(Conn * conn)
|
||||
|
||||
if (sd >= 0) {
|
||||
close(sd);
|
||||
#ifndef HAVE_KEVENT
|
||||
sd_to_conn[sd] = 0;
|
||||
FD_CLR(sd, &wrfds);
|
||||
FD_CLR(sd, &rdfds);
|
||||
#endif
|
||||
conn->reading = 0;
|
||||
conn->writing = 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
|
||||
@ -1104,6 +1385,63 @@ core_close(Conn * 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
|
||||
core_loop(void)
|
||||
{
|
||||
@ -1175,7 +1513,7 @@ core_loop(void)
|
||||
else
|
||||
#endif
|
||||
if (is_writable) {
|
||||
FD_CLR(sd, &wrfds);
|
||||
clear_active(conn, WRITE);
|
||||
conn->state = S_CONNECTED;
|
||||
arg.l = 0;
|
||||
event_signal(EV_CONN_CONNECTED, (Object*)conn, arg);
|
||||
@ -1199,11 +1537,13 @@ core_loop(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
core_exit(void)
|
||||
{
|
||||
running = 0;
|
||||
param.num_conns = 0;
|
||||
|
||||
printf("Maximum connect burst length: %lu\n", max_burst_len);
|
||||
|
||||
|
@ -36,7 +36,8 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
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);
|
||||
extern int core_connect (Conn *conn);
|
||||
extern int core_send (Conn *conn, Call *call);
|
||||
|
@ -52,29 +52,46 @@
|
||||
|
||||
static int num_conns_generated;
|
||||
static int num_conns_destroyed;
|
||||
static int num_conns_open;
|
||||
static Rate_Generator rg;
|
||||
static bool paused;
|
||||
|
||||
static int
|
||||
make_conn (Any_Type arg)
|
||||
{
|
||||
Conn *s;
|
||||
|
||||
if (paused)
|
||||
return 0;
|
||||
|
||||
if (num_conns_generated++ >= param.num_conns)
|
||||
return -1;
|
||||
|
||||
if (param.max_conns != 0 && num_conns_open >= param.max_conns)
|
||||
return 0;
|
||||
|
||||
s = conn_new ();
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
core_connect (s);
|
||||
num_conns_open++;
|
||||
if (core_connect (s) == -1) {
|
||||
num_conns_generated--;
|
||||
num_conns_destroyed--;
|
||||
paused = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
destroyed (void)
|
||||
{
|
||||
Any_Type arg;
|
||||
|
||||
if (++num_conns_destroyed >= param.num_conns)
|
||||
core_exit ();
|
||||
num_conns_open--;
|
||||
paused = false;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -42,12 +42,17 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <generic_types.h>
|
||||
#include <object.h>
|
||||
@ -55,10 +60,10 @@
|
||||
#include <call.h>
|
||||
#include <localevent.h>
|
||||
|
||||
static const char *extra;
|
||||
static const char *extra, *extra_file;
|
||||
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
|
||||
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)
|
||||
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)
|
||||
{
|
||||
Any_Type arg;
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
if (param.additional_header)
|
||||
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)
|
||||
method_len = strlen (param.method);
|
||||
|
||||
|
@ -91,6 +91,7 @@
|
||||
|
||||
const char *prog_name;
|
||||
int verbose;
|
||||
int periodic_stats;
|
||||
Cmdline_Params param;
|
||||
Time test_time_start;
|
||||
Time test_time_stop;
|
||||
@ -110,7 +111,8 @@ static Time perf_sample_start;
|
||||
|
||||
static struct option longopts[] = {
|
||||
{"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},
|
||||
{"close-with-reset", no_argument, ¶m.close_with_reset, 1},
|
||||
{"debug", required_argument, 0, 'd'},
|
||||
@ -118,9 +120,10 @@ static struct option longopts[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"hog", no_argument, ¶m.hog, 1},
|
||||
{"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},
|
||||
{"myaddr", required_argument, (int *) ¶m.myaddr, 0},
|
||||
{"no-host-hdr", no_argument, ¶m.no_host_hdr, 1},
|
||||
{"num-calls", required_argument, (int *) ¶m.num_calls, 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},
|
||||
{"recv-buffer", required_argument, (int *) ¶m.recv_buffer_size, 0},
|
||||
{"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},
|
||||
{"server", required_argument, (int *) ¶m.server, 0},
|
||||
{"server-name", required_argument, (int *) ¶m.server_name, 0},
|
||||
{"uri", required_argument, (int *) ¶m.uri, 0},
|
||||
{"session-cookies", no_argument, (int *) ¶m.session_cookies, 1},
|
||||
#ifdef HAVE_SSL
|
||||
@ -146,6 +149,7 @@ static struct option longopts[] = {
|
||||
{"use-timer-cache", no_argument, ¶m.use_timer_cache, 1},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{"periodic-stats", no_argument, 0, 'n'},
|
||||
{"wlog", required_argument, (int *) ¶m.wlog, 0},
|
||||
{"wsess", required_argument, (int *) ¶m.wsess, 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[--rate X] [--recv-buffer N] [--retry-on-failure] "
|
||||
"[--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
|
||||
"\t[--ssl] [--ssl-ciphers L] [--ssl-no-reuse]\n"
|
||||
#endif
|
||||
"\t[--think-timeout X] [--timeout X] [--verbose] [--version]\n"
|
||||
"\t[--wlog y|n,file] [--wsess N,N,X] [--wsesslog N,X,file]\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
|
||||
@ -254,7 +260,6 @@ main(int argc, char **argv)
|
||||
param.http_version = 0x10001; /* default to HTTP/1.1 */
|
||||
param.client.id = 0;
|
||||
param.client.num_clients = 1;
|
||||
param.server = "localhost";
|
||||
param.port = -1;
|
||||
param.uri = "/";
|
||||
param.num_calls = 1;
|
||||
@ -284,7 +289,7 @@ main(int argc, char **argv)
|
||||
* process command line options:
|
||||
*/
|
||||
while ((ch =
|
||||
getopt_long(argc, argv, "d:hvV", longopts, &longindex)) >= 0) {
|
||||
getopt_long(argc, argv, "d:hvVn", longopts, &longindex)) >= 0) {
|
||||
switch (ch) {
|
||||
case 0:
|
||||
flag = longopts[longindex].flag;
|
||||
@ -293,6 +298,8 @@ main(int argc, char **argv)
|
||||
param.method = optarg;
|
||||
else if (flag == ¶m.additional_header)
|
||||
param.additional_header = optarg;
|
||||
else if (flag == ¶m.additional_header_file)
|
||||
param.additional_header_file = optarg;
|
||||
else if (flag == ¶m.num_calls) {
|
||||
errno = 0;
|
||||
param.num_calls = strtoul(optarg, &end, 10);
|
||||
@ -312,6 +319,8 @@ main(int argc, char **argv)
|
||||
}
|
||||
param.http_version =
|
||||
(major << 16) | (minor & 0xffff);
|
||||
} else if (flag == ¶m.myaddr) {
|
||||
core_add_addresses(optarg);
|
||||
} else if (flag == ¶m.burst_len) {
|
||||
errno = 0;
|
||||
param.burst_len = strtoul(optarg, &end, 10);
|
||||
@ -345,8 +354,7 @@ main(int argc, char **argv)
|
||||
} else if (flag == ¶m.max_conns) {
|
||||
errno = 0;
|
||||
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,
|
||||
"%s: illegal max. # of connection %s\n",
|
||||
prog_name, optarg);
|
||||
@ -355,8 +363,7 @@ main(int argc, char **argv)
|
||||
} else if (flag == ¶m.max_piped) {
|
||||
errno = 0;
|
||||
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,
|
||||
"%s: illegal max. # of piped calls %s\n",
|
||||
prog_name, optarg);
|
||||
@ -619,8 +626,6 @@ main(int argc, char **argv)
|
||||
}
|
||||
} else if (flag == ¶m.server)
|
||||
param.server = optarg;
|
||||
else if (flag == ¶m.server_name)
|
||||
param.server_name = optarg;
|
||||
#ifdef HAVE_SSL
|
||||
else if (flag == ¶m.ssl_cipher_list)
|
||||
param.ssl_cipher_list = optarg;
|
||||
@ -645,6 +650,16 @@ main(int argc, char **argv)
|
||||
prog_name, optarg);
|
||||
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) {
|
||||
gen[1] = &uri_wlog; /* XXX fix
|
||||
* me---somehow */
|
||||
@ -880,6 +895,10 @@ main(int argc, char **argv)
|
||||
" TIME_SYSCALLS.\n", prog_name);
|
||||
exit(0);
|
||||
|
||||
case 'n':
|
||||
++periodic_stats;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
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
|
||||
if (param.use_ssl) {
|
||||
char buf[1024];
|
||||
@ -947,7 +973,8 @@ main(int argc, char **argv)
|
||||
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;
|
||||
|
||||
/*
|
||||
@ -990,11 +1017,11 @@ main(int argc, char **argv)
|
||||
printf(" --think-timeout=%g", param.think_timeout);
|
||||
if (param.timeout > 0)
|
||||
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);
|
||||
if (param.server)
|
||||
printf(" --server=%s", param.server);
|
||||
if (param.server_name)
|
||||
printf(" --server_name=%s", param.server_name);
|
||||
if (param.port)
|
||||
printf(" --port=%d", param.port);
|
||||
if (param.uri)
|
||||
@ -1005,9 +1032,9 @@ main(int argc, char **argv)
|
||||
printf(" --http-version=%u.%u", param.http_version >> 16,
|
||||
param.http_version & 0xffff);
|
||||
if (param.max_conns)
|
||||
printf(" --max-connections=%u", param.max_conns);
|
||||
printf(" --max-connections=%lu", param.max_conns);
|
||||
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) {
|
||||
switch (param.rate.dist) {
|
||||
case DETERMINISTIC:
|
||||
@ -1045,10 +1072,10 @@ main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf(" --send-buffer=%d", param.send_buffer_size);
|
||||
printf(" --send-buffer=%lu", param.send_buffer_size);
|
||||
if (param.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)
|
||||
printf(" --session-cookies");
|
||||
#ifdef HAVE_SSL
|
||||
@ -1061,6 +1088,8 @@ main(int argc, char **argv)
|
||||
#endif
|
||||
if (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)
|
||||
printf(" --method=%s", param.method);
|
||||
if (param.use_timer_cache)
|
||||
@ -1081,17 +1110,19 @@ main(int argc, char **argv)
|
||||
param.wsess.num_calls, param.wsess.think_time);
|
||||
else {
|
||||
if (param.num_conns)
|
||||
printf(" --num-conns=%d", param.num_conns);
|
||||
printf(" --num-conns=%lu", param.num_conns);
|
||||
if (param.num_calls)
|
||||
printf(" --num-calls=%d", param.num_calls);
|
||||
printf(" --num-calls=%lu", param.num_calls);
|
||||
}
|
||||
if (param.burst_len != 1)
|
||||
printf(" --burst-length=%d", param.burst_len);
|
||||
printf(" --burst-length=%lu", param.burst_len);
|
||||
if (param.wset.num_files)
|
||||
printf(" --wset=%u,%.3f",
|
||||
param.wset.num_files,
|
||||
param.wset.target_miss_rate);
|
||||
}
|
||||
if (periodic_stats)
|
||||
printf(" --periodic-stats");
|
||||
printf("\n");
|
||||
|
||||
if (timer_init() == false) {
|
||||
|
@ -91,21 +91,22 @@ Rate_Info;
|
||||
typedef struct Cmdline_Params
|
||||
{
|
||||
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 */
|
||||
const char *uri; /* (default) uri */
|
||||
const char *myaddr;
|
||||
Rate_Info rate;
|
||||
Time timeout; /* watchdog timeout */
|
||||
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 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 retry_on_failure; /* when a call fails, should we retry? */
|
||||
int close_with_reset; /* close connections with TCP RESET? */
|
||||
@ -120,6 +121,7 @@ typedef struct Cmdline_Params
|
||||
#endif
|
||||
int use_timer_cache;
|
||||
const char *additional_header; /* additional request header(s) */
|
||||
const char *additional_header_file;
|
||||
const char *method; /* default call method */
|
||||
struct
|
||||
{
|
||||
@ -146,7 +148,7 @@ typedef struct Cmdline_Params
|
||||
u_int num_reqs; /* # of user requests per session */
|
||||
Time think_time; /* user think time between requests */
|
||||
}
|
||||
wsesspage;
|
||||
wsesspage; /* XXX Currently broken */
|
||||
struct
|
||||
{
|
||||
u_int num_sessions; /* # of user-sessions */
|
||||
@ -165,6 +167,7 @@ Cmdline_Params;
|
||||
|
||||
extern const char *prog_name;
|
||||
extern int verbose;
|
||||
extern int periodic_stats;
|
||||
extern Cmdline_Params param;
|
||||
extern Time test_time_start;
|
||||
extern Time test_time_stop;
|
||||
|
@ -59,44 +59,46 @@
|
||||
#define NUM_BINS ((u_int) (MAX_LIFETIME / BIN_WIDTH))
|
||||
|
||||
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 */
|
||||
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_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_int num_lifetimes;
|
||||
u_long num_lifetimes;
|
||||
Time conn_lifetime_sum; /* sum of connection lifetimes */
|
||||
Time conn_lifetime_sum2; /* sum of connection lifetimes
|
||||
* squared */
|
||||
Time conn_lifetime_min; /* minimum 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_sum2;
|
||||
Time reply_rate_min;
|
||||
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 */
|
||||
|
||||
u_int num_responses;
|
||||
u_long num_responses;
|
||||
Time call_response_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;
|
||||
|
||||
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 reply_bytes_received; /* sum of all data bytes */
|
||||
u_wide footer_bytes_received; /* sum of all footer bytes */
|
||||
@ -105,8 +107,8 @@ static struct {
|
||||
* connection lifetimes */
|
||||
} 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
|
||||
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;
|
||||
c->basic.time_recv_start = now;
|
||||
++basic.num_responses;
|
||||
|
||||
if (periodic_stats) {
|
||||
if (c->reply.status == 200)
|
||||
++basic.num_200;
|
||||
|
||||
if (c->reply.status == 302)
|
||||
++basic.num_302;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
init(void)
|
||||
{
|
||||
@ -323,6 +350,9 @@ init(void)
|
||||
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_STOP, recv_stop, arg);
|
||||
|
||||
if (periodic_stats)
|
||||
timer_schedule(one_second_timer, arg, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -335,7 +365,8 @@ dump(void)
|
||||
Time lifetime_avg = 0.0, lifetime_stddev =
|
||||
0.0, lifetime_median = 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;
|
||||
u_wide total_size;
|
||||
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",
|
||||
basic.num_conns_issued, basic.num_sent, total_replies, delta);
|
||||
|
||||
@ -367,7 +398,7 @@ dump(void)
|
||||
if (basic.num_conns_issued)
|
||||
conn_period = delta / basic.num_conns_issued;
|
||||
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.max_conns);
|
||||
|
||||
@ -420,7 +451,7 @@ dump(void)
|
||||
}
|
||||
printf
|
||||
("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,
|
||||
reply_rate_avg, basic.reply_rate_max, reply_rate_stddev,
|
||||
basic.num_reply_rates);
|
||||
@ -441,12 +472,17 @@ dump(void)
|
||||
"(total %.1f)\n", 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[3], basic.num_replies[4], basic.num_replies[5]);
|
||||
|
||||
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)
|
||||
- TV_TO_SEC(test_rusage_start.ru_utime));
|
||||
sys = (TV_TO_SEC(test_rusage_stop.ru_stime)
|
||||
@ -463,9 +499,9 @@ dump(void)
|
||||
|
||||
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_sock_fdunavail + basic.num_sock_ftabfull
|
||||
+ 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->timeout_delay = delay;
|
||||
|
||||
if (delay > 0)
|
||||
if (delay > 0 || true)
|
||||
{
|
||||
Any_Type temp;
|
||||
temp.vp = (void *)t;
|
||||
|
Loading…
Reference in New Issue
Block a user