From 69376ec7ed079a090fd06f9c3ff1f7b3b6d37aae Mon Sep 17 00:00:00 2001 From: Jef Poskanzer Date: Mon, 28 Oct 2013 17:13:30 -0700 Subject: [PATCH] Fix retransmit accounting so it works right with the --omit flag. --- src/iperf.h | 6 +++--- src/iperf_api.c | 47 ++++++++++++++---------------------------- src/iperf_api.h | 3 +-- src/iperf_client_api.c | 2 -- src/iperf_server_api.c | 2 -- src/tcp_info.c | 17 ++++++++++++--- 6 files changed, 33 insertions(+), 44 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 21f098c..9639eda 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -30,12 +30,11 @@ struct iperf_interval_results int omitted; #if defined(linux) || defined(__FreeBSD__) struct tcp_info tcpInfo; /* getsockopt(TCP_INFO) for Linux and FreeBSD */ - int this_retrans; #else /* Just placeholders, never accessed. */ char *tcpInfo; - int this_retrans; #endif + int interval_retrans; TAILQ_ENTRY(iperf_interval_results) irlistentries; void *custom_data; }; @@ -46,7 +45,8 @@ struct iperf_stream_result iperf_size_t bytes_sent; iperf_size_t bytes_received_this_interval; iperf_size_t bytes_sent_this_interval; - int retransmits; + int stream_prev_total_retrans; + int stream_retrans; struct timeval start_time; struct timeval end_time; TAILQ_HEAD(irlisthead, iperf_interval_results) interval_results; diff --git a/src/iperf_api.c b/src/iperf_api.c index 712da1f..e35e102 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -952,22 +952,6 @@ iperf_exchange_parameters(struct iperf_test *test) return 0; } -/*************************************************************/ - -int -iperf_sum_results(struct iperf_test *test) -{ - struct iperf_stream *sp; - - if (test->sender && test->sender_has_retransmits) { - SLIST_FOREACH(sp, &test->streams, streams) { - sp->result->retransmits = get_tcpinfo_total_retransmits(TAILQ_LAST(&sp->result->interval_results, irlisthead)); - } - } - return 0; -} - - /*************************************************************/ int @@ -1131,7 +1115,7 @@ send_results(struct iperf_test *test) } else { cJSON_AddItemToArray(j_streams, j_stream); bytes_transferred = test->sender ? sp->result->bytes_sent : sp->result->bytes_received; - retransmits = (test->sender && test->sender_has_retransmits) ? sp->result->retransmits : -1; + retransmits = (test->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1; cJSON_AddIntToObject(j_stream, "id", sp->id); cJSON_AddIntToObject(j_stream, "bytes", bytes_transferred); cJSON_AddIntToObject(j_stream, "retransmits", retransmits); @@ -1231,7 +1215,7 @@ get_results(struct iperf_test *test) sp->result->bytes_received = bytes_transferred; } else { sp->result->bytes_sent = bytes_transferred; - sp->result->retransmits = retransmits; + sp->result->stream_retrans = retransmits; } } } @@ -1567,7 +1551,9 @@ iperf_reset_stats(struct iperf_test *test) rp = sp->result; rp->bytes_sent = rp->bytes_received = 0; rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0; - rp->retransmits = 0; + if (test->sender && test->sender_has_retransmits) + rp->stream_prev_total_retrans = get_total_retransmits(sp->socket); + rp->stream_retrans = 0; rp->start_time = now; } } @@ -1588,7 +1574,6 @@ iperf_stats_callback(struct iperf_test *test) struct iperf_stream *sp; struct iperf_stream_result *rp = NULL; struct iperf_interval_results *irp, temp; - int prev_total_retransmits; temp.omitted = test->omitting; SLIST_FOREACH(sp, &test->streams, streams) { @@ -1610,12 +1595,10 @@ iperf_stats_callback(struct iperf_test *test) if (test->protocol->id == Ptcp && has_tcpinfo()) { save_tcpinfo(sp, &temp); if (test->sender && test->sender_has_retransmits) { - irp = TAILQ_LAST(&rp->interval_results, irlisthead); - if (irp == NULL) - prev_total_retransmits = 0; - else - prev_total_retransmits = get_tcpinfo_total_retransmits(irp); - temp.this_retrans = get_tcpinfo_total_retransmits(&temp) - prev_total_retransmits; + long total_retrans = get_total_retransmits(sp->socket); + temp.interval_retrans = total_retrans - rp->stream_prev_total_retrans; + rp->stream_retrans += temp.interval_retrans; + rp->stream_prev_total_retrans = total_retrans; } } add_to_interval_list(rp, &temp); @@ -1661,7 +1644,7 @@ iperf_print_intermediate(struct iperf_test *test) } bytes += irp->bytes_transferred; if (test->sender && test->sender_has_retransmits) - retransmits += irp->this_retrans; + retransmits += irp->interval_retrans; } if (bytes < 0) { /* this can happen if timer goes off just when client exits */ iperf_err(test, "error: bytes < 0!"); @@ -1748,7 +1731,7 @@ iperf_print_results(struct iperf_test *test) if (test->protocol->id == Ptcp) { if (test->sender_has_retransmits) - total_retransmits += sp->result->retransmits; + total_retransmits += sp->result->stream_retrans; } else { total_packets += (sp->packet_count - sp->omitted_packet_count); lost_packets += sp->cnt_error; @@ -1763,9 +1746,9 @@ iperf_print_results(struct iperf_test *test) fputs(" Sent\n", stdout); if (test->sender_has_retransmits) { if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "sent", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->retransmits)); + cJSON_AddItemToObject(json_summary_stream, "sent", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans)); else - printf(report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->retransmits, ""); + printf(report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, ""); } else { if (test->json_output) cJSON_AddItemToObject(json_summary_stream, "sent", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8)); @@ -1919,9 +1902,9 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON * if (test->sender && test->sender_has_retransmits) { if (test->json_output) - cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->this_retrans, irp->omitted)); + cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, irp->omitted)); else - printf(report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->this_retrans, irp->omitted?report_omitted:""); + printf(report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->interval_retrans, irp->omitted?report_omitted:""); } else { if (test->json_output) cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, irp->omitted)); diff --git a/src/iperf_api.h b/src/iperf_api.h index 3ae7941..16c3433 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -161,7 +161,7 @@ void iperf_free_stream(struct iperf_stream * sp); int has_tcpinfo(void); int has_tcpinfo_retransmits(void); void save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp); -long get_tcpinfo_total_retransmits(struct iperf_interval_results *irp); +long get_total_retransmits(int socket); void print_tcpinfo(struct iperf_test *test); void build_tcpinfo_message(struct iperf_interval_results *r, char *message); @@ -173,7 +173,6 @@ void sig_handler(int); void usage(); void usage_long(); void warning(char *); -int iperf_sum_results(struct iperf_test *); int iperf_exchange_results(struct iperf_test *); int iperf_init_test(struct iperf_test *); int iperf_create_send_timers(struct iperf_test *); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index ff455ea..fe6a970 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -203,8 +203,6 @@ iperf_handle_message_client(struct iperf_test *test) case TEST_RUNNING: break; case EXCHANGE_RESULTS: - if (iperf_sum_results(test) < 0) - return -1; if (iperf_exchange_results(test) < 0) return -1; break; diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index bfa43e2..20bda6f 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -192,8 +192,6 @@ iperf_handle_message_server(struct iperf_test *test) } 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; if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0) diff --git a/src/tcp_info.c b/src/tcp_info.c index a063a42..d0cd7da 100644 --- a/src/tcp_info.c +++ b/src/tcp_info.c @@ -86,17 +86,28 @@ save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp) /*************************************************************/ long -get_tcpinfo_total_retransmits(struct iperf_interval_results *irp) +get_total_retransmits(int socket) { +#if defined(linux) || defined(__FreeBSD__) + struct tcp_info ti; + socklen_t l = sizeof(ti); + + if (getsockopt(socket, IPPROTO_TCP, TCP_INFO, (void *)&ti, &l) < 0) + return -1; + #if defined(linux) && defined(TCP_MD5SIG) - return irp->tcpInfo.tcpi_total_retrans; + return ti.tcpi_total_retrans; #else #if defined(__FreeBSD__) && __FreeBSD_version >= 600000 - return irp->tcpInfo.__tcpi_retransmits; + return ti.__tcpi_retransmits; #else return -1; #endif #endif + +#else + return -1; +#endif } #ifdef notdef