Added -I flag to ignore an initial period of data transfer,
defaulting to one second.
This commit is contained in:
parent
434e786fd0
commit
c969359995
@ -94,6 +94,7 @@ struct iperf_stream
|
||||
* stream can have a pointer to this
|
||||
*/
|
||||
int packet_count;
|
||||
int ignored_packet_count;
|
||||
double jitter;
|
||||
double prev_transit;
|
||||
int outoforder_packets;
|
||||
@ -134,6 +135,7 @@ struct iperf_test
|
||||
char *server_hostname; /* -c option */
|
||||
char *bind_address; /* -B option */
|
||||
int server_port;
|
||||
int ignore; /* duration of ignore period (-I flag) */
|
||||
int duration; /* total duration of test (-t flag) */
|
||||
|
||||
int ctrl_sck;
|
||||
@ -159,10 +161,12 @@ struct iperf_test
|
||||
fd_set write_set; /* set of write sockets */
|
||||
|
||||
/* Interval related members */
|
||||
int ignoring;
|
||||
double stats_interval;
|
||||
double reporter_interval;
|
||||
void (*stats_callback) (struct iperf_test *);
|
||||
void (*reporter_callback) (struct iperf_test *);
|
||||
Timer *ignore_timer;
|
||||
Timer *timer;
|
||||
int done;
|
||||
Timer *stats_timer;
|
||||
@ -199,6 +203,7 @@ struct iperf_test
|
||||
#define uS_TO_NS 1000
|
||||
#define SEC_TO_US 1000000LL
|
||||
#define UDP_RATE (1024 * 1024) /* 1 Mbps */
|
||||
#define IGNORE 1 /* seconds */
|
||||
#define DURATION 10 /* seconds */
|
||||
|
||||
#define SEC_TO_NS 1000000000LL /* too big for enum/const on some platforms */
|
||||
|
@ -103,6 +103,11 @@ set the IP 'type of service'
|
||||
.BR -Z ", " --zerocopy " "
|
||||
Use a "zero copy" method of sending data, such as sendfile(2),
|
||||
instead of the usual write(2).
|
||||
.TP
|
||||
.BR -I ", " --ignore " \fIn\fR"
|
||||
Ignore the first n seconds of the test, to skip past the TCP slow-start
|
||||
period.
|
||||
The default is 1 second; to not ignore anything, use "-I 0".
|
||||
|
||||
.SH AUTHORS
|
||||
Iperf was originally written by Mark Gates and Alex Warshavsky.
|
||||
|
199
src/iperf_api.c
199
src/iperf_api.c
@ -86,6 +86,12 @@ iperf_get_control_socket(struct iperf_test *ipt)
|
||||
return ipt->ctrl_sck;
|
||||
}
|
||||
|
||||
int
|
||||
iperf_get_test_ignore(struct iperf_test *ipt)
|
||||
{
|
||||
return ipt->ignore;
|
||||
}
|
||||
|
||||
int
|
||||
iperf_get_test_duration(struct iperf_test *ipt)
|
||||
{
|
||||
@ -178,6 +184,12 @@ iperf_set_control_socket(struct iperf_test *ipt, int ctrl_sck)
|
||||
ipt->ctrl_sck = ctrl_sck;
|
||||
}
|
||||
|
||||
void
|
||||
iperf_set_test_ignore(struct iperf_test *ipt, int ignore)
|
||||
{
|
||||
ipt->ignore = ignore;
|
||||
}
|
||||
|
||||
void
|
||||
iperf_set_test_duration(struct iperf_test *ipt, int duration)
|
||||
{
|
||||
@ -317,15 +329,15 @@ iperf_on_test_start(struct iperf_test *test)
|
||||
{
|
||||
if (test->json_output) {
|
||||
if (test->settings->bytes)
|
||||
cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d bytes: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->settings->bytes));
|
||||
cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d ignore: %d bytes: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->ignore, (int64_t) test->settings->bytes));
|
||||
else
|
||||
cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d duration: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->duration));
|
||||
cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d ignore: %d duration: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->ignore, (int64_t) test->duration));
|
||||
} else {
|
||||
if (test->verbose) {
|
||||
if (test->settings->bytes)
|
||||
printf(test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->settings->bytes);
|
||||
printf(test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->ignore, test->settings->bytes);
|
||||
else
|
||||
printf(test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->duration);
|
||||
printf(test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->ignore, test->duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -450,6 +462,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
{"tos", required_argument, NULL, 'S'},
|
||||
{"flowlabel", required_argument, NULL, 'L'},
|
||||
{"zerocopy", no_argument, NULL, 'Z'},
|
||||
{"ignore", required_argument, NULL, 'I'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
|
||||
/* XXX: The following ifdef needs to be split up. linux-congestion is not
|
||||
@ -466,7 +479,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
|
||||
blksize = 0;
|
||||
server_flag = client_flag = rate_flag = 0;
|
||||
while ((flag = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N46S:L:Zh", longopts, NULL)) != -1) {
|
||||
while ((flag = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N46S:L:ZI:h", longopts, NULL)) != -1) {
|
||||
switch (flag) {
|
||||
case 'p':
|
||||
test->server_port = atoi(optarg);
|
||||
@ -498,7 +511,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
test->debug = 1;
|
||||
break;
|
||||
case 'v':
|
||||
fputs(version, stdout);
|
||||
printf("%s\n", version);
|
||||
system("uname -a");
|
||||
exit(0);
|
||||
case 's':
|
||||
@ -612,6 +625,14 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
test->zerocopy = 1;
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'I':
|
||||
test->ignore = atoi(optarg);
|
||||
if (test->ignore < 0 || test->ignore > 60) {
|
||||
i_errno = IEIGNORE;
|
||||
return -1;
|
||||
}
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage_long();
|
||||
@ -662,8 +683,19 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
check_throttle(struct iperf_stream *sp, struct timeval *nowP)
|
||||
int
|
||||
iperf_set_send_state(struct iperf_test *test, char state)
|
||||
{
|
||||
test->state = state;
|
||||
if (Nwrite(test->ctrl_sck, &state, sizeof(state), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
iperf_check_throttle(struct iperf_stream *sp, struct timeval *nowP)
|
||||
{
|
||||
double seconds;
|
||||
uint64_t bits_per_second;
|
||||
@ -703,7 +735,7 @@ iperf_send(struct iperf_test *test, fd_set *write_setP)
|
||||
}
|
||||
test->bytes_sent += r;
|
||||
if (test->settings->rate != 0)
|
||||
check_throttle(sp, &now);
|
||||
iperf_check_throttle(sp, &now);
|
||||
if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes)
|
||||
break;
|
||||
}
|
||||
@ -737,104 +769,24 @@ iperf_recv(struct iperf_test *test, fd_set *read_setP)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
|
||||
test->done = 1;
|
||||
test->timer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
|
||||
if (test->done)
|
||||
return;
|
||||
test->stats_callback(test);
|
||||
}
|
||||
|
||||
static void
|
||||
reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
|
||||
if (test->done)
|
||||
return;
|
||||
test->reporter_callback(test);
|
||||
}
|
||||
|
||||
static void
|
||||
send_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_stream *sp = client_data.p;
|
||||
|
||||
/* All we do here is set or clear the flag saying that this stream may
|
||||
** be sent to. The actual sending gets done in the send proc, after
|
||||
** checking the flag.
|
||||
*/
|
||||
check_throttle(sp, nowP);
|
||||
}
|
||||
|
||||
int
|
||||
iperf_init_test(struct iperf_test *test)
|
||||
{
|
||||
struct iperf_stream *sp;
|
||||
struct timeval now;
|
||||
TimerClientData cd;
|
||||
struct iperf_stream *sp;
|
||||
|
||||
if (test->protocol->init) {
|
||||
if (test->protocol->init(test) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create timers. */
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
if (test->settings->bytes == 0) {
|
||||
test->done = 0;
|
||||
cd.p = test;
|
||||
test->timer = tmr_create(&now, test_timer_proc, cd, test->duration * SEC_TO_US, 0);
|
||||
if (test->timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (test->stats_interval != 0) {
|
||||
cd.p = test;
|
||||
test->stats_timer = tmr_create(&now, stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
|
||||
if (test->stats_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (test->reporter_interval != 0) {
|
||||
cd.p = test;
|
||||
test->reporter_timer = tmr_create(&now, reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
|
||||
if (test->reporter_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init each stream. */
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
SLIST_FOREACH(sp, &test->streams, streams) {
|
||||
sp->result->start_time = now;
|
||||
sp->green_light = 1;
|
||||
if (test->settings->rate != 0) {
|
||||
cd.p = sp;
|
||||
sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, 100000L, 1);
|
||||
/* (Repeat every tenth second - arbitrary often value.) */
|
||||
if (sp->send_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (test->on_test_start)
|
||||
@ -852,7 +804,6 @@ int
|
||||
iperf_exchange_parameters(struct iperf_test *test)
|
||||
{
|
||||
int s, msg;
|
||||
char state;
|
||||
|
||||
if (test->role == 'c') {
|
||||
|
||||
@ -865,11 +816,8 @@ iperf_exchange_parameters(struct iperf_test *test)
|
||||
return -1;
|
||||
|
||||
if ((s = test->protocol->listen(test)) < 0) {
|
||||
state = SERVER_ERROR;
|
||||
if (Nwrite(test->ctrl_sck, &state, sizeof(state), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, SERVER_ERROR) != 0)
|
||||
return -1;
|
||||
}
|
||||
msg = htonl(i_errno);
|
||||
if (Nwrite(test->ctrl_sck, (char*) &msg, sizeof(msg), Ptcp) < 0) {
|
||||
i_errno = IECTRLWRITE;
|
||||
@ -887,11 +835,8 @@ iperf_exchange_parameters(struct iperf_test *test)
|
||||
test->prot_listener = s;
|
||||
|
||||
// Send the control message to create streams and start the test
|
||||
test->state = CREATE_STREAMS;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, CREATE_STREAMS) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -953,6 +898,8 @@ send_parameters(struct iperf_test *test)
|
||||
cJSON_AddTrueToObject(j, "tcp");
|
||||
else if (test->protocol->id == Pudp)
|
||||
cJSON_AddTrueToObject(j, "udp");
|
||||
if (test->ignore)
|
||||
cJSON_AddIntToObject(j, "ignore", test->ignore);
|
||||
if (test->duration)
|
||||
cJSON_AddIntToObject(j, "time", test->duration);
|
||||
if (test->settings->bytes)
|
||||
@ -1001,6 +948,8 @@ get_parameters(struct iperf_test *test)
|
||||
set_protocol(test, Ptcp);
|
||||
if ((j_p = cJSON_GetObjectItem(j, "udp")) != NULL)
|
||||
set_protocol(test, Pudp);
|
||||
if ((j_p = cJSON_GetObjectItem(j, "ignore")) != NULL)
|
||||
test->ignore = j_p->valueint;
|
||||
if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)
|
||||
test->duration = j_p->valueint;
|
||||
if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)
|
||||
@ -1313,6 +1262,7 @@ iperf_defaults(struct iperf_test *testp)
|
||||
{
|
||||
struct protocol *tcp, *udp;
|
||||
|
||||
testp->ignore = IGNORE;
|
||||
testp->duration = DURATION;
|
||||
testp->server_port = PORT;
|
||||
testp->ctrl_sck = -1;
|
||||
@ -1398,6 +1348,8 @@ iperf_free_test(struct iperf_test *test)
|
||||
free(test->server_hostname);
|
||||
free(test->bind_address);
|
||||
free(test->settings);
|
||||
if (test->ignore_timer != NULL)
|
||||
tmr_cancel(test->ignore_timer);
|
||||
if (test->timer != NULL)
|
||||
tmr_cancel(test->timer);
|
||||
if (test->stats_timer != NULL)
|
||||
@ -1431,6 +1383,10 @@ iperf_reset_test(struct iperf_test *test)
|
||||
SLIST_REMOVE_HEAD(&test->streams, streams);
|
||||
iperf_free_stream(sp);
|
||||
}
|
||||
if (test->ignore_timer != NULL) {
|
||||
tmr_cancel(test->ignore_timer);
|
||||
test->ignore_timer = NULL;
|
||||
}
|
||||
if (test->timer != NULL) {
|
||||
tmr_cancel(test->timer);
|
||||
test->timer = NULL;
|
||||
@ -1450,6 +1406,7 @@ iperf_reset_test(struct iperf_test *test)
|
||||
test->sender = 0;
|
||||
test->sender_has_retransmits = 0;
|
||||
set_protocol(test, Ptcp);
|
||||
test->ignore = IGNORE;
|
||||
test->duration = DURATION;
|
||||
test->state = 0;
|
||||
test->server_hostname = NULL;
|
||||
@ -1475,6 +1432,32 @@ iperf_reset_test(struct iperf_test *test)
|
||||
}
|
||||
|
||||
|
||||
/* Reset all of a test's stats back to zero. Called when the ignoring
|
||||
** period is over.
|
||||
*/
|
||||
void
|
||||
iperf_reset_stats(struct iperf_test *test)
|
||||
{
|
||||
struct timeval now;
|
||||
struct iperf_stream *sp;
|
||||
struct iperf_stream_result *rp;
|
||||
|
||||
test->bytes_sent = 0;
|
||||
gettimeofday(&now, NULL);
|
||||
SLIST_FOREACH(sp, &test->streams, streams) {
|
||||
sp->ignored_packet_count = sp->packet_count;
|
||||
sp->jitter = 0;
|
||||
sp->outoforder_packets = 0;
|
||||
sp->cnt_error = 0;
|
||||
rp = sp->result;
|
||||
rp->bytes_sent = rp->bytes_received = 0;
|
||||
rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
|
||||
rp->retransmits = 0;
|
||||
rp->start_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
@ -1649,7 +1632,7 @@ iperf_print_results(struct iperf_test *test)
|
||||
if (test->sender_has_retransmits)
|
||||
total_retransmits += sp->result->retransmits;
|
||||
} else {
|
||||
total_packets += sp->packet_count;
|
||||
total_packets += (sp->packet_count - sp->ignored_packet_count);
|
||||
lost_packets += sp->cnt_error;
|
||||
avg_jitter += sp->jitter;
|
||||
}
|
||||
@ -1673,13 +1656,13 @@ iperf_print_results(struct iperf_test *test)
|
||||
printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf);
|
||||
}
|
||||
} else {
|
||||
out_of_order_percent = 100.0 * sp->cnt_error / sp->packet_count;
|
||||
out_of_order_percent = 100.0 * sp->cnt_error / (sp->packet_count - sp->ignored_packet_count);
|
||||
if (test->json_output)
|
||||
cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f outoforder: %d packets: %d percent: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) sp->cnt_error, (int64_t) sp->packet_count, out_of_order_percent));
|
||||
cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f outoforder: %d packets: %d percent: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) sp->cnt_error, (int64_t) (sp->packet_count - sp->ignored_packet_count), out_of_order_percent));
|
||||
else {
|
||||
printf(report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, sp->cnt_error, sp->packet_count, out_of_order_percent);
|
||||
printf(report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, sp->cnt_error, (sp->packet_count - sp->ignored_packet_count), out_of_order_percent);
|
||||
if (test->role == 'c')
|
||||
printf(report_datagrams, sp->socket, sp->packet_count);
|
||||
printf(report_datagrams, sp->socket, (sp->packet_count - sp->ignored_packet_count));
|
||||
if (sp->outoforder_packets > 0)
|
||||
printf(report_sum_outoforder, start_time, end_time, sp->cnt_error);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ struct iperf_stream;
|
||||
|
||||
/* Getter routines for some fields inside iperf_test. */
|
||||
int iperf_get_control_socket( struct iperf_test* ipt );
|
||||
int iperf_get_test_ignore( struct iperf_test* ipt );
|
||||
int iperf_get_test_duration( struct iperf_test* ipt );
|
||||
char iperf_get_test_role( struct iperf_test* ipt );
|
||||
int iperf_get_test_blksize( struct iperf_test* ipt );
|
||||
@ -62,6 +63,7 @@ int iperf_get_test_may_use_sigalrm( struct iperf_test* ipt );
|
||||
|
||||
/* Setter routines for some fields inside iperf_test. */
|
||||
void iperf_set_control_socket( struct iperf_test* ipt, int ctrl_sck );
|
||||
void iperf_set_test_ignore( struct iperf_test* ipt, int ignore );
|
||||
void iperf_set_test_duration( struct iperf_test* ipt, int duration );
|
||||
void iperf_set_test_reporter_interval( struct iperf_test* ipt, double reporter_interval );
|
||||
void iperf_set_test_stats_interval( struct iperf_test* ipt, double stats_interval );
|
||||
@ -103,14 +105,12 @@ void connect_msg(struct iperf_stream * sp);
|
||||
*/
|
||||
void iperf_stats_callback(struct iperf_test * test);
|
||||
|
||||
|
||||
/**
|
||||
* iperf_reporter_callback -- handles the report printing
|
||||
*
|
||||
*/
|
||||
void iperf_reporter_callback(struct iperf_test * test);
|
||||
|
||||
|
||||
/**
|
||||
* iperf_new_test -- return a new iperf_test with default values
|
||||
*
|
||||
@ -121,7 +121,6 @@ struct iperf_test *iperf_new_test();
|
||||
|
||||
int iperf_defaults(struct iperf_test * testp);
|
||||
|
||||
|
||||
/**
|
||||
* iperf_free_test -- free resources used by test, calls iperf_free_stream to
|
||||
* free streams
|
||||
@ -129,7 +128,6 @@ int iperf_defaults(struct iperf_test * testp);
|
||||
*/
|
||||
void iperf_free_test(struct iperf_test * testp);
|
||||
|
||||
|
||||
/**
|
||||
* iperf_new_stream -- return a net iperf_stream with default values
|
||||
*
|
||||
@ -163,6 +161,8 @@ long get_tcpinfo_total_retransmits(struct iperf_interval_results *irp);
|
||||
void print_tcpinfo(struct iperf_test *test);
|
||||
void build_tcpinfo_message(struct iperf_interval_results *r, char *message);
|
||||
|
||||
int iperf_set_send_state(struct iperf_test *test, char state);
|
||||
void iperf_check_throttle(struct iperf_stream *sp, struct timeval *nowP);
|
||||
int iperf_send(struct iperf_test *, fd_set *) /* __attribute__((hot)) */;
|
||||
int iperf_recv(struct iperf_test *, fd_set *);
|
||||
void sig_handler(int);
|
||||
@ -174,6 +174,7 @@ int iperf_exchange_results(struct iperf_test *);
|
||||
int iperf_init_test(struct iperf_test *);
|
||||
int iperf_parse_arguments(struct iperf_test *, int, char **);
|
||||
void iperf_reset_test(struct iperf_test *);
|
||||
void iperf_reset_stats(struct iperf_test * test);
|
||||
|
||||
struct protocol *get_protocol(struct iperf_test *, int);
|
||||
int set_protocol(struct iperf_test *, int);
|
||||
@ -222,7 +223,8 @@ enum {
|
||||
IEINTERVAL = 9, // Report interval too large. Maxumum value = %dMAX_INTERVAL
|
||||
IEMSS = 10, // MSS too large. Maximum value = %dMAX_MSS
|
||||
IENOSENDFILE = 11, // This OS does not support sendfile
|
||||
IEUNIMP = 12, // Not implemented yet
|
||||
IEIGNORE = 12, // Bogus value for --ignore
|
||||
IEUNIMP = 13, // Not implemented yet
|
||||
/* Test errors */
|
||||
IENEWTEST = 100, // Unable to create a new test (check perror)
|
||||
IEINITTEST = 101, // Test initialization failed (check perror)
|
||||
|
@ -54,6 +54,133 @@ iperf_create_streams(struct iperf_test *test)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
|
||||
test->timer = NULL;
|
||||
test->done = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
|
||||
if (test->done)
|
||||
return;
|
||||
test->stats_callback(test);
|
||||
}
|
||||
|
||||
static void
|
||||
reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
|
||||
if (test->done)
|
||||
return;
|
||||
test->reporter_callback(test);
|
||||
}
|
||||
|
||||
static void
|
||||
client_ignore_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
TimerClientData cd;
|
||||
|
||||
test->ignore_timer = NULL;
|
||||
test->ignoring = 0;
|
||||
iperf_reset_stats(test);
|
||||
if (test->verbose && !test->json_output)
|
||||
printf("Finished ignore period, starting real test\n");
|
||||
|
||||
/* Create timers. */
|
||||
if (test->settings->bytes == 0) {
|
||||
test->done = 0;
|
||||
cd.p = test;
|
||||
test->timer = tmr_create(nowP, test_timer_proc, cd, test->duration * SEC_TO_US, 0);
|
||||
if (test->timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (test->stats_interval != 0) {
|
||||
cd.p = test;
|
||||
test->stats_timer = tmr_create(nowP, stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
|
||||
if (test->stats_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (test->reporter_interval != 0) {
|
||||
cd.p = test;
|
||||
test->reporter_timer = tmr_create(nowP, reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
|
||||
if (test->reporter_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
create_client_ignore_timer(struct iperf_test * test)
|
||||
{
|
||||
struct timeval now;
|
||||
TimerClientData cd;
|
||||
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
test->ignoring = 1;
|
||||
cd.p = test;
|
||||
test->ignore_timer = tmr_create(&now, client_ignore_timer_proc, cd, test->ignore * SEC_TO_US, 0);
|
||||
if (test->ignore_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
send_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_stream *sp = client_data.p;
|
||||
|
||||
/* All we do here is set or clear the flag saying that this stream may
|
||||
** be sent to. The actual sending gets done in the send proc, after
|
||||
** checking the flag.
|
||||
*/
|
||||
iperf_check_throttle(sp, nowP);
|
||||
}
|
||||
|
||||
static int
|
||||
create_send_timers(struct iperf_test * test)
|
||||
{
|
||||
struct timeval now;
|
||||
struct iperf_stream *sp;
|
||||
TimerClientData cd;
|
||||
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
SLIST_FOREACH(sp, &test->streams, streams) {
|
||||
sp->green_light = 1;
|
||||
if (test->settings->rate != 0) {
|
||||
cd.p = sp;
|
||||
sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, 100000L, 1);
|
||||
/* (Repeat every tenth second - arbitrary often value.) */
|
||||
if (sp->send_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iperf_handle_message_client(struct iperf_test *test)
|
||||
{
|
||||
@ -83,6 +210,10 @@ iperf_handle_message_client(struct iperf_test *test)
|
||||
case TEST_START:
|
||||
if (iperf_init_test(test) < 0)
|
||||
return -1;
|
||||
if (create_client_ignore_timer(test) < 0)
|
||||
return -1;
|
||||
if (create_send_timers(test) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case TEST_RUNNING:
|
||||
break;
|
||||
@ -170,11 +301,8 @@ iperf_client_end(struct iperf_test *test)
|
||||
/* show final summary */
|
||||
test->reporter_callback(test);
|
||||
|
||||
test->state = IPERF_DONE;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, IPERF_DONE) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -245,8 +373,8 @@ iperf_run_client(struct iperf_test * test)
|
||||
|
||||
if (test->state == TEST_RUNNING) {
|
||||
|
||||
/* Is this our first time in TEST_RUNNING mode? */
|
||||
if (startup) {
|
||||
/* Is this our first time really running? */
|
||||
if (startup && ! test->ignoring) {
|
||||
startup = 0;
|
||||
/* Can we switch to SIGALRM mode? There are a bunch of
|
||||
** cases where either it won't work or it's ill-advised.
|
||||
@ -287,6 +415,8 @@ iperf_run_client(struct iperf_test * test)
|
||||
}
|
||||
|
||||
/* Is the test done yet? */
|
||||
if (test->ignoring)
|
||||
continue; /* not done */
|
||||
if (test->settings->bytes == 0) {
|
||||
if (!test->done)
|
||||
continue; /* not done */
|
||||
@ -297,11 +427,8 @@ iperf_run_client(struct iperf_test * test)
|
||||
/* Yes, done! Send TEST_END. */
|
||||
cpu_util(&test->cpu_util);
|
||||
test->stats_callback(test);
|
||||
test->state = TEST_END;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, TEST_END) != 0)
|
||||
return -1;
|
||||
}
|
||||
/* And if we were doing SIGALRM, go back to select for the end. */
|
||||
concurrency_model = CM_SELECT;
|
||||
}
|
||||
|
@ -99,6 +99,9 @@ iperf_strerror(int i_errno)
|
||||
case IENOSENDFILE:
|
||||
snprintf(errstr, len, "this OS does not support sendfile");
|
||||
break;
|
||||
case IEIGNORE:
|
||||
snprintf(errstr, len, "bogus value for --ignore");
|
||||
break;
|
||||
case IEUNIMP:
|
||||
snprintf(errstr, len, "an option you are trying to set is not implemented yet");
|
||||
break;
|
||||
|
@ -121,11 +121,8 @@ iperf_accept(struct iperf_test *test)
|
||||
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
|
||||
test->ctrl_sck = s;
|
||||
|
||||
test->state = PARAM_EXCHANGE;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0)
|
||||
return -1;
|
||||
}
|
||||
if (iperf_exchange_parameters(test) < 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -180,20 +177,14 @@ iperf_handle_message_server(struct iperf_test *test)
|
||||
FD_CLR(sp->socket, &test->write_set);
|
||||
close(sp->socket);
|
||||
}
|
||||
test->state = EXCHANGE_RESULTS;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0)
|
||||
return -1;
|
||||
}
|
||||
if (iperf_sum_results(test) < 0)
|
||||
return -1;
|
||||
if (iperf_exchange_results(test) < 0)
|
||||
return -1;
|
||||
test->state = DISPLAY_RESULTS;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0)
|
||||
return -1;
|
||||
}
|
||||
if (test->on_test_finish)
|
||||
test->on_test_finish(test);
|
||||
test->reporter_callback(test);
|
||||
@ -251,6 +242,7 @@ iperf_test_reset(struct iperf_test *test)
|
||||
|
||||
test->role = 's';
|
||||
set_protocol(test, Ptcp);
|
||||
test->ignore = IGNORE;
|
||||
test->duration = DURATION;
|
||||
test->state = 0;
|
||||
test->server_hostname = NULL;
|
||||
@ -278,6 +270,46 @@ iperf_test_reset(struct iperf_test *test)
|
||||
memset(test->cookie, 0, COOKIE_SIZE);
|
||||
}
|
||||
|
||||
static void
|
||||
server_ignore_timer_proc(TimerClientData client_data, struct timeval *nowP)
|
||||
{
|
||||
struct iperf_test *test = client_data.p;
|
||||
|
||||
test->ignore_timer = NULL;
|
||||
test->ignoring = 0;
|
||||
iperf_reset_stats(test);
|
||||
if (test->verbose && !test->json_output)
|
||||
printf("Finished ignore period, starting real test\n");
|
||||
}
|
||||
|
||||
static int
|
||||
create_server_ignore_timer(struct iperf_test * test)
|
||||
{
|
||||
struct timeval now;
|
||||
TimerClientData cd;
|
||||
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
test->ignoring = 1;
|
||||
cd.p = test;
|
||||
test->ignore_timer = tmr_create(&now, server_ignore_timer_proc, cd, test->ignore * SEC_TO_US, 0);
|
||||
if (test->ignore_timer == NULL) {
|
||||
i_errno = IEINITTEST;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_server(struct iperf_test *test)
|
||||
{
|
||||
/* Close open test sockets */
|
||||
close(test->ctrl_sck);
|
||||
close(test->listener);
|
||||
}
|
||||
|
||||
int
|
||||
iperf_run_server(struct iperf_test *test)
|
||||
{
|
||||
@ -317,6 +349,7 @@ iperf_run_server(struct iperf_test *test)
|
||||
|
||||
result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now));
|
||||
if (result < 0 && errno != EINTR) {
|
||||
cleanup_server(test);
|
||||
i_errno = IESELECT;
|
||||
return -1;
|
||||
}
|
||||
@ -324,27 +357,34 @@ iperf_run_server(struct iperf_test *test)
|
||||
if (FD_ISSET(test->listener, &read_set)) {
|
||||
if (test->state != CREATE_STREAMS) {
|
||||
if (iperf_accept(test) < 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
FD_CLR(test->listener, &read_set);
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(test->ctrl_sck, &read_set)) {
|
||||
if (iperf_handle_message_server(test) < 0)
|
||||
if (iperf_handle_message_server(test) < 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
FD_CLR(test->ctrl_sck, &read_set);
|
||||
}
|
||||
|
||||
if (test->state == CREATE_STREAMS) {
|
||||
if (FD_ISSET(test->prot_listener, &read_set)) {
|
||||
|
||||
if ((s = test->protocol->accept(test)) < 0)
|
||||
if ((s = test->protocol->accept(test)) < 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!is_closed(s)) {
|
||||
sp = iperf_new_stream(test, s);
|
||||
if (!sp)
|
||||
if (!sp) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_SET(s, &test->read_set);
|
||||
FD_SET(s, &test->write_set);
|
||||
@ -366,6 +406,7 @@ iperf_run_server(struct iperf_test *test)
|
||||
FD_CLR(test->listener, &test->read_set);
|
||||
close(test->listener);
|
||||
if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
|
||||
cleanup_server(test);
|
||||
i_errno = IELISTEN;
|
||||
return -1;
|
||||
}
|
||||
@ -375,30 +416,38 @@ iperf_run_server(struct iperf_test *test)
|
||||
}
|
||||
}
|
||||
test->prot_listener = -1;
|
||||
test->state = TEST_START;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
if (iperf_set_send_state(test, TEST_START) != 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
if (iperf_init_test(test) < 0)
|
||||
}
|
||||
if (iperf_init_test(test) < 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
test->state = TEST_RUNNING;
|
||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
}
|
||||
if (create_server_ignore_timer(test) < 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (test->state == TEST_RUNNING) {
|
||||
if (test->reverse) {
|
||||
// Reverse mode. Server sends.
|
||||
if (iperf_send(test, &write_set) < 0)
|
||||
if (iperf_send(test, &write_set) < 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
// Regular mode. Server receives.
|
||||
if (iperf_recv(test, &read_set) < 0)
|
||||
if (iperf_recv(test, &read_set) < 0) {
|
||||
cleanup_server(test);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the timers. */
|
||||
@ -408,9 +457,7 @@ iperf_run_server(struct iperf_test *test)
|
||||
}
|
||||
}
|
||||
|
||||
/* Close open test sockets */
|
||||
close(test->ctrl_sck);
|
||||
close(test->listener);
|
||||
cleanup_server(test);
|
||||
|
||||
if (test->json_output) {
|
||||
if (iperf_json_finish(test) < 0)
|
||||
|
@ -37,7 +37,7 @@ iperf_udp_recv(struct iperf_stream *sp)
|
||||
{
|
||||
int r;
|
||||
int size = sp->settings->blksize;
|
||||
int sec, usec, pcount;
|
||||
uint32_t sec, usec, pcount;
|
||||
double transit = 0, d = 0;
|
||||
struct timeval sent_time, arrival_time;
|
||||
|
||||
@ -93,7 +93,7 @@ int
|
||||
iperf_udp_send(struct iperf_stream *sp)
|
||||
{
|
||||
int r;
|
||||
uint64_t sec, usec, pcount;
|
||||
uint32_t sec, usec, pcount;
|
||||
int size = sp->settings->blksize;
|
||||
struct timeval before;
|
||||
|
||||
|
@ -99,6 +99,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
|
||||
" -S, --tos N set the IP 'type of service'\n"
|
||||
/* " -L, --flowlabel N set the IPv6 'flow label'\n" */
|
||||
" -Z, --zerocopy use a 'zero copy' method of sending data\n"
|
||||
" -I, --ignore N ignore the first n seconds\n"
|
||||
|
||||
#ifdef NOT_YET_SUPPORTED /* still working on these */
|
||||
" -D, --daemon run the server as a daemon\n"
|
||||
@ -163,10 +164,10 @@ const char wait_server_threads[] =
|
||||
"Waiting for server threads to complete. Interrupt again to force quit.\n";
|
||||
|
||||
const char test_start_time[] =
|
||||
"Starting Test: protocol: %s, %d streams, %d byte blocks, %d second test\n";
|
||||
"Starting Test: protocol: %s, %d streams, %d byte blocks, ignoring %d seconds, %d second test\n";
|
||||
|
||||
const char test_start_bytes[] =
|
||||
"Starting Test: protocol: %s, %d streams, %d byte blocks, %llu bytes to send\n";
|
||||
"Starting Test: protocol: %s, %d streams, %d byte blocks, ignoring %d seconds, %llu bytes to send\n";
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
|
@ -7,5 +7,5 @@
|
||||
* for complete information.
|
||||
*/
|
||||
|
||||
#define IPERF_VERSION "3.0-BETA5"
|
||||
#define IPERF_VERSION_DATE "28 March 2013"
|
||||
#define IPERF_VERSION "3.0-BETA6"
|
||||
#define IPERF_VERSION_DATE "27 June 2013"
|
||||
|
Loading…
Reference in New Issue
Block a user