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.
This commit is contained in:
Bruce A. Mah 2014-10-23 11:10:39 -07:00
parent 8634b34804
commit 432ef7ebb3
4 changed files with 34 additions and 4 deletions

View File

@ -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;

View File

@ -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:"");

View File

@ -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);

View File

@ -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)