aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJef Poskanzer <jef@mail.acme.com>2013-07-03 12:01:57 -0700
committerJef Poskanzer <jef@mail.acme.com>2013-07-03 12:01:57 -0700
commitc9693599958d82fba625e8facd8d4a92e0cc73ce (patch)
treeed8ca8fd1bc2fd09edd5d0ab609099be4121a937
parent434e786fd065e8aee6d78adaf6ebcdc6909195d1 (diff)
downloadiperf3-c9693599958d82fba625e8facd8d4a92e0cc73ce.tar.gz
Added -I flag to ignore an initial period of data transfer,
defaulting to one second.
-rw-r--r--src/iperf.h5
-rw-r--r--src/iperf3.15
-rw-r--r--src/iperf_api.c197
-rw-r--r--src/iperf_api.h12
-rw-r--r--src/iperf_client_api.c147
-rw-r--r--src/iperf_error.c3
-rw-r--r--src/iperf_server_api.c105
-rw-r--r--src/iperf_udp.c4
-rw-r--r--src/locale.c5
-rw-r--r--src/version.h4
10 files changed, 330 insertions, 157 deletions
diff --git a/src/iperf.h b/src/iperf.h
index 808b6e4..00ae116 100644
--- a/src/iperf.h
+++ b/src/iperf.h
@@ -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 */
diff --git a/src/iperf3.1 b/src/iperf3.1
index 62aa9bc..e3c7030 100644
--- a/src/iperf3.1
+++ b/src/iperf3.1
@@ -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.
diff --git a/src/iperf_api.c b/src/iperf_api.c
index a8776ba..25a4997 100644
--- a/src/iperf_api.c
+++ b/src/iperf_api.c
@@ -87,6 +87,12 @@ iperf_get_control_socket(struct iperf_test *ipt)
}
int
+iperf_get_test_ignore(struct iperf_test *ipt)
+{
+ return ipt->ignore;
+}
+
+int
iperf_get_test_duration(struct iperf_test *ipt)
{
return ipt->duration;
@@ -179,6 +185,12 @@ iperf_set_control_socket(struct iperf_test *ipt, int 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)
{
ipt->duration = 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. */
+ /* Init each stream. */
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;
- }
+ i_errno = IEINITTEST;
+ return -1;
}
-
- /* Init each stream. */
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);
}
diff --git a/src/iperf_api.h b/src/iperf_api.h
index 418eebc..883ca9f 100644
--- a/src/iperf_api.h
+++ b/src/iperf_api.h
@@ -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)
diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c
index dc20e34..9ac8ffd 100644
--- a/src/iperf_client_api.c
+++ b/src/iperf_client_api.c
@@ -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;
}
diff --git a/src/iperf_error.c b/src/iperf_error.c
index c5d9910..ba0ad50 100644
--- a/src/iperf_error.c
+++ b/src/iperf_error.c
@@ -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;
diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c
index f8743fa..0ac42a8 100644
--- a/src/iperf_server_api.c
+++ b/src/iperf_server_api.c
@@ -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)
diff --git a/src/iperf_udp.c b/src/iperf_udp.c
index 0d39890..00f02ed 100644
--- a/src/iperf_udp.c
+++ b/src/iperf_udp.c
@@ -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;
diff --git a/src/locale.c b/src/locale.c
index cee3aa4..ccad751 100644
--- a/src/locale.c
+++ b/src/locale.c
@@ -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";
/* -------------------------------------------------------------------
diff --git a/src/version.h b/src/version.h
index c8dfcbc..4a51b0e 100644
--- a/src/version.h
+++ b/src/version.h
@@ -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"