Keep track of SACKs and snd_cwnd from tcp_info (Linux only for now).

Committing this WIP so we can get some experimentation done with it.
This commit is contained in:
Bruce A. Mah 2013-12-18 15:09:46 -08:00
parent cfe8c5fb47
commit 5cdc6a4ac8
5 changed files with 95 additions and 16 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011, The Regents of the University of California,
* Copyright (c) 2009-2013, The Regents of the University of California,
* through Lawrence Berkeley National Laboratory (subject to receipt of any
* required approvals from the U.S. Dept. of Energy). All rights reserved.
*
@ -45,6 +45,8 @@ struct iperf_interval_results
char *tcpInfo;
#endif
int interval_retrans;
int interval_sacks;
int snd_cwnd;
TAILQ_ENTRY(iperf_interval_results) irlistentries;
void *custom_data;
};
@ -57,6 +59,8 @@ struct iperf_stream_result
iperf_size_t bytes_sent_this_interval;
int stream_prev_total_retrans;
int stream_retrans;
int stream_prev_total_sacks;
int stream_sacks;
struct timeval start_time;
struct timeval end_time;
TAILQ_HEAD(irlisthead, iperf_interval_results) interval_results;

View File

@ -1595,6 +1595,7 @@ iperf_reset_stats(struct iperf_test *test)
if (test->sender && test->sender_has_retransmits)
rp->stream_prev_total_retrans = get_total_retransmits(sp->socket);
rp->stream_retrans = 0;
rp->stream_sacks = 0;
rp->start_time = now;
}
}
@ -1641,6 +1642,15 @@ iperf_stats_callback(struct iperf_test *test)
temp.interval_retrans = total_retrans - rp->stream_prev_total_retrans;
rp->stream_retrans += temp.interval_retrans;
rp->stream_prev_total_retrans = total_retrans;
long total_sacks = get_sacks(sp->socket);
temp.interval_sacks = total_sacks - rp->stream_prev_total_sacks;
rp->stream_sacks += temp.interval_sacks;
rp->stream_prev_total_sacks = total_sacks;
long snd_cwnd = get_snd_cwnd(sp->socket);
temp.snd_cwnd = snd_cwnd;
}
}
} else {
@ -1673,6 +1683,7 @@ iperf_print_intermediate(struct iperf_test *test)
iperf_size_t bytes = 0;
double bandwidth;
int retransmits = 0;
int sacks = 0;
double start_time, end_time;
cJSON *json_interval;
cJSON *json_interval_streams;
@ -1703,8 +1714,10 @@ iperf_print_intermediate(struct iperf_test *test)
}
bytes += irp->bytes_transferred;
if (test->protocol->id == Ptcp) {
if (test->sender && test->sender_has_retransmits)
if (test->sender && test->sender_has_retransmits) {
retransmits += irp->interval_retrans;
sacks += irp->interval_sacks;
}
} else {
total_packets += irp->interval_packet_count;
lost_packets += irp->interval_cnt_error;
@ -1727,9 +1740,9 @@ iperf_print_intermediate(struct iperf_test *test)
if (test->sender && test->sender_has_retransmits) {
/* Interval sum, TCP with retransmits. */
if (test->json_output)
cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, irp->omitted));
cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d sacks: %d omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, (int64_t) sacks, irp->omitted));
else
iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:"");
iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits, sacks, irp->omitted?report_omitted:"");
} else {
/* Interval sum, TCP without retransmits. */
if (test->json_output)
@ -1763,6 +1776,7 @@ iperf_print_results(struct iperf_test *test)
cJSON *json_summary_streams = NULL;
cJSON *json_summary_stream = NULL;
int total_retransmits = 0;
int total_sacks = 0;
int total_packets = 0, lost_packets = 0;
char ubuf[UNIT_LEN];
char nbuf[UNIT_LEN];
@ -1811,8 +1825,10 @@ iperf_print_results(struct iperf_test *test)
total_received += bytes_received;
if (test->protocol->id == Ptcp) {
if (test->sender_has_retransmits)
if (test->sender_has_retransmits) {
total_retransmits += sp->result->stream_retrans;
total_sacks += sp->result->stream_sacks;
}
} else {
total_packets += (sp->packet_count - sp->omitted_packet_count);
lost_packets += sp->cnt_error;
@ -1826,9 +1842,9 @@ 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 sacks: %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_sacks));
else
iprintf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, report_sender);
iprintf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, sp->result->stream_sacks, 0, report_sender);
} else {
/* Summary, TCP without retransmits. */
if (test->json_output)
@ -1880,9 +1896,9 @@ iperf_print_results(struct iperf_test *test)
if (test->sender_has_retransmits) {
/* Summary sum, TCP with retransmits. */
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits));
cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d sacks: %d", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits, (int64_t) total_sacks));
else
iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits, report_sender);
iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits, total_sacks, report_sender);
} else {
/* Summary sum, TCP without retransmits. */
if (test->json_output)
@ -1988,9 +2004,9 @@ 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 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));
cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d sacks: %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->interval_sacks, (int64_t) irp->snd_cwnd, irp->omitted));
else
iprintf(test, report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->interval_retrans, irp->omitted?report_omitted:"");
iprintf(test, report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->interval_retrans, irp->interval_sacks, irp->snd_cwnd, irp->omitted?report_omitted:"");
} else {
/* Interval, TCP without retransmits. */
if (test->json_output)

View File

@ -162,6 +162,8 @@ int has_tcpinfo(void);
int has_tcpinfo_retransmits(void);
void save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp);
long get_total_retransmits(int socket);
long get_sacks(int socket);
long get_snd_cwnd(int socket);
void print_tcpinfo(struct iperf_test *test);
void build_tcpinfo_message(struct iperf_interval_results *r, char *message);

View File

@ -224,7 +224,7 @@ const char report_bw_header[] =
"[ ID] Interval Transfer Bandwidth\n";
const char report_bw_retrans_header[] =
"[ ID] Interval Transfer Bandwidth Retransmits\n";
"[ ID] Interval Transfer Bandwidth Retr SACK CWND\n";
const char report_bw_udp_header[] =
"[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams\n";
@ -236,7 +236,7 @@ const char report_bw_format[] =
"[%3d] %6.2f-%-6.2f sec %ss %ss/sec %s\n";
const char report_bw_retrans_format[] =
"[%3d] %6.2f-%-6.2f sec %ss %ss/sec %3d %s\n";
"[%3d] %6.2f-%-6.2f sec %ss %ss/sec %3d %3d %3d %s\n";
const char report_bw_udp_format[] =
"[%3d] %6.2f-%-6.2f sec %ss %ss/sec %5.3f ms %d/%d (%.2g%%) %s\n";
@ -251,7 +251,7 @@ const char report_sum_bw_format[] =
"[SUM] %6.2f-%-6.2f sec %ss %ss/sec %s\n";
const char report_sum_bw_retrans_format[] =
"[SUM] %6.2f-%-6.2f sec %ss %ss/sec %3d %s\n";
"[SUM] %6.2f-%-6.2f sec %ss %ss/sec %3d %3d %s\n";
const char report_sum_bw_udp_format[] =
"[SUM] %6.2f-%-6.2f sec %ss %ss/sec %5.3f ms %d/%d (%.2g%%) %s\n";

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011, The Regents of the University of California,
* Copyright (c) 2009-2013, The Regents of the University of California,
* through Lawrence Berkeley National Laboratory (subject to receipt of any
* required approvals from the U.S. Dept. of Energy). All rights reserved.
*
@ -96,6 +96,11 @@ get_total_retransmits(int socket)
return -1;
#if defined(linux) && defined(TCP_MD5SIG)
#if 0
printf("tcpi_sacked %d\n", ti.tcpi_sacked);
printf("tcpi_snd_cwnd %d\n", ti.tcpi_snd_cwnd);
printf("tcpi_total_retrans %d\n", ti.tcpi_total_retrans);
#endif
return ti.tcpi_total_retrans;
#else
#if defined(__FreeBSD__) && __FreeBSD_version >= 600000
@ -110,6 +115,58 @@ get_total_retransmits(int socket)
#endif
}
/*************************************************************/
long
get_sacks(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 ti.tcpi_sacked;
#else
#if defined(__FreeBSD__) && __FreeBSD_version >= 600000
return ti.__tcpi_sacked;
#else
return -1;
#endif
#endif
#else
return -1;
#endif
}
/*************************************************************/
long
get_snd_cwnd(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 ti.tcpi_snd_cwnd;
#else
#if defined(__FreeBSD__) && __FreeBSD_version >= 600000
return ti.tcpi_snd_cwnd;
#else
return -1;
#endif
#endif
#else
return -1;
#endif
}
#ifdef notdef
/*************************************************************/
//print_tcpinfo(struct iperf_interval_results *r)