From 432ef7ebb3abfedcb87b717b251eb72fc1a2d0c3 Mon Sep 17 00:00:00 2001 From: "Bruce A. Mah" Date: Thu, 23 Oct 2014 11:10:39 -0700 Subject: [PATCH] Retrieve RTT information on platforms supporting it. This value is available on the sender side, expressed in microseconds. It's available in the JSON output. In the JSON output we also output the maximum observed RTT per-stream. Note that since the observation interval is many times the RTT, it's not clear how good this value would be at capturing the largest computed RTT value over the lifetime of each stream. While here, also determine the maximum observed snd_cwnd value over the lifetime of each stream. This all works pretty well on Linux, but on FreeBSD (which should theoretically be supported) we don't do a good job of supporting the tcp_info structure. We need to make this code a lot more portable, rather than just assuming the world of platforms is "Linux" vs. "everything else". Fixing this requires some rearchitecting of the way that we retrieve, compute, and print statistics. Part of a fix for #215. --- src/iperf.h | 3 +++ src/iperf_api.c | 11 +++++++++-- src/iperf_api.h | 1 + src/tcp_info.c | 23 +++++++++++++++++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 6b55559..b1ff1e8 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -77,6 +77,7 @@ struct iperf_interval_results int snd_cwnd; TAILQ_ENTRY(iperf_interval_results) irlistentries; void *custom_data; + int rtt; }; struct iperf_stream_result @@ -89,6 +90,8 @@ struct iperf_stream_result int stream_retrans; int stream_prev_total_sacks; int stream_sacks; + int stream_max_rtt; + int stream_max_snd_cwnd; 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 d9b3983..b8f7891 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -2015,6 +2015,13 @@ iperf_stats_callback(struct iperf_test *test) rp->stream_prev_total_retrans = total_retrans; temp.snd_cwnd = get_snd_cwnd(&temp); + if (temp.snd_cwnd > rp->stream_max_snd_cwnd) { + rp->stream_max_snd_cwnd = temp.snd_cwnd; + } + temp.rtt = get_rtt(&temp); + if (temp.rtt > rp->stream_max_rtt) { + rp->stream_max_rtt = temp.rtt; + } } } } else { @@ -2211,7 +2218,7 @@ iperf_print_results(struct iperf_test *test) if (test->sender_has_retransmits) { /* Summary, TCP with retransmits. */ if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "sender", 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)); + cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_rtt: %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, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_rtt)); else iprintf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); } else { @@ -2395,7 +2402,7 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON * if (test->sender && test->sender_has_retransmits) { /* Interval, TCP with 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 snd_cwnd: %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, (int64_t) irp->snd_cwnd, 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 snd_cwnd: %d rtt: %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, (int64_t) irp->snd_cwnd, (int64_t) irp->rtt, irp->omitted)); else { unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A'); iprintf(test, report_bw_retrans_cwnd_format, sp->socket, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:""); diff --git a/src/iperf_api.h b/src/iperf_api.h index 368f498..0fe85b8 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -197,6 +197,7 @@ int has_tcpinfo_retransmits(void); void save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp); long get_total_retransmits(struct iperf_interval_results *irp); long get_snd_cwnd(struct iperf_interval_results *irp); +long get_rtt(struct iperf_interval_results *irp); void print_tcpinfo(struct iperf_test *test); void build_tcpinfo_message(struct iperf_interval_results *r, char *message); diff --git a/src/tcp_info.c b/src/tcp_info.c index cd3154c..ebf44e9 100644 --- a/src/tcp_info.c +++ b/src/tcp_info.c @@ -100,8 +100,9 @@ save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp) iperf_err(sp->test, "getsockopt - %s", strerror(errno)); if (sp->test->debug) { - printf("tcpi_snd_cwnd %u tcpi_snd_mss %u\n", - irp->tcpInfo.tcpi_snd_cwnd, irp->tcpInfo.tcpi_snd_mss); + printf("tcpi_snd_cwnd %u tcpi_snd_mss %u tcpi_rtt %u\n", + irp->tcpInfo.tcpi_snd_cwnd, irp->tcpInfo.tcpi_snd_mss, + irp->tcpInfo.tcpi_rtt); } #endif @@ -140,6 +141,24 @@ get_snd_cwnd(struct iperf_interval_results *irp) #endif } +/*************************************************************/ +/* + * Return rtt in usec. + */ +long +get_rtt(struct iperf_interval_results *irp) +{ +#if defined(linux) && defined(TCP_MD5SIG) + return irp->tcpInfo.tcpi_rtt; +#else +#if defined(__FreeBSD__) && __FreeBSD_version >= 600000 + return irp->tcpInfo.tcpi_rtt; +#else + return -1; +#endif +#endif +} + /*************************************************************/ void build_tcpinfo_message(struct iperf_interval_results *r, char *message)