Skip to content

Commit

Permalink
Allow specifying precision.
Browse files Browse the repository at this point in the history
This gives better control over the normal text output, for instance:

with --precision 4:

onnecting to host 10.2.8.1, port 5201
[  5] local 10.2.8.86 port 55430 connected to 10.2.8.1 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  72538.45 KBytes  72531.4849 KBytes/sec    0   6506.10 KBytes
[  5]   1.00-2.00   sec  49024.00 KBytes  49023.2169 KBytes/sec    0   6506.10 KBytes
[  5]   2.00-3.00   sec  48640.00 KBytes  48641.7019 KBytes/sec    0   6506.10 KBytes
...
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-60.00  sec  2907.71 MBytes  49624.8823 KBytes/sec    0             sender
[  5]   0.00-60.04  sec  2878.48 MBytes  49092.3559 KBytes/sec                  receiver

Signed-off-by: Ben Greear <greearb@candelatech.com>
  • Loading branch information
greearb committed Feb 11, 2019
1 parent dd0f0cb commit 72bb459
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 48 deletions.
1 change: 1 addition & 0 deletions src/iperf.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ struct iperf_settings
iperf_size_t bytes; /* number of bytes to send */
iperf_size_t blocks; /* number of blocks (packets) to send */
char unit_format; /* -f */
int unit_precision; /* --precision */
int num_ostreams; /* SCTP initmsg settings */
#if defined(HAVE_SSL)
char *authtoken; /* Authentication token */
Expand Down
49 changes: 30 additions & 19 deletions src/iperf_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{
{"port", required_argument, NULL, 'p'},
{"format", required_argument, NULL, 'f'},
{"precision", required_argument, NULL, 'r'},
{"interval", required_argument, NULL, 'i'},
{"daemon", no_argument, NULL, 'D'},
{"one-off", no_argument, NULL, '1'},
Expand Down Expand Up @@ -841,11 +842,18 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
char *client_username = NULL, *client_rsa_public_key = NULL, *server_rsa_private_key = NULL;
#endif /* HAVE_SSL */

while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rr:w:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
switch (flag) {
case 'p':
test->server_port = atoi(optarg);
break;
case 'r':
test->settings->unit_precision = atoi(optarg);
if (test->settings->unit_precision < -1)
test->settings->unit_precision = 1;
else if (test->settings->unit_precision > 30)
test->settings->unit_precision = 30;
break;
case 'f':
if (!optarg) {
i_errno = IEBADFORMAT;
Expand Down Expand Up @@ -2264,6 +2272,7 @@ iperf_defaults(struct iperf_test *testp)

testp->settings->domain = AF_UNSPEC;
testp->settings->unit_format = 'a';
testp->settings->unit_precision = -1; /* auto */
testp->settings->socket_bufsize = 0; /* use autotuning */
testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
testp->settings->rate = 0;
Expand Down Expand Up @@ -2822,9 +2831,9 @@ iperf_print_intermediate(struct iperf_test *test)
if (sp) {
irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* use 1st stream for timing info */

unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A', test->settings->unit_precision);
bandwidth = (double) bytes / (double) irp->interval_duration;
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision);

iperf_time_diff(&sp->result->start_time,&irp->interval_start_time, &temp_time);
start_time = iperf_time_in_secs(&temp_time);
Expand Down Expand Up @@ -3048,14 +3057,15 @@ iperf_print_results(struct iperf_test *test)
avg_jitter += sp->jitter;
}

unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A', test->settings->unit_precision);

if (sender_time > 0.0) {
bandwidth = (double) bytes_sent / (double) sender_time;
}
else {
bandwidth = 0.0;
}
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision);
if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
if (test->sender_has_retransmits) {
/* Sender summary, TCP and SCTP with retransmits. */
Expand Down Expand Up @@ -3138,28 +3148,28 @@ iperf_print_results(struct iperf_test *test)
percent_sent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 );
percent_received = (int) ( ( (double) bytes_received / (double) sb.st_size ) * 100.0 );
}
unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A');
unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A', test->settings->unit_precision);
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d received: %d size: %d percent_sent: %d percent_received: %d filename: %s", (int64_t) bytes_sent, (int64_t) bytes_received, (int64_t) sb.st_size, (int64_t) percent_sent, (int64_t) percent_received, test->diskfile_name));
else
if (stream_must_be_sender) {
iperf_printf(test, report_diskfile, ubuf, sbuf, percent_sent, test->diskfile_name);
}
else {
unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A', test->settings->unit_precision);
iperf_printf(test, report_diskfile, ubuf, sbuf, percent_received, test->diskfile_name);
}
}
}

unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A', test->settings->unit_precision);
if (receiver_time > 0) {
bandwidth = (double) bytes_received / (double) receiver_time;
}
else {
bandwidth = 0.0;
}
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision);
if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
/* Receiver summary, TCP and SCTP */
if (test->json_output)
Expand Down Expand Up @@ -3201,15 +3211,15 @@ iperf_print_results(struct iperf_test *test)
}

if (test->num_streams > 1 || test->json_output) {
unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A', test->settings->unit_precision);
/* If no tests were run, arbitrarily set bandwidth to 0. */
if (sender_time > 0.0) {
bandwidth = (double) total_sent / (double) sender_time;
}
else {
bandwidth = 0.0;
}
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision);
if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
if (test->sender_has_retransmits) {
/* Summary sum, TCP with retransmits. */
Expand All @@ -3236,15 +3246,15 @@ iperf_print_results(struct iperf_test *test)
iperf_printf(test, report_sum_bw_format, mbuf, start_time, sender_time, ubuf, nbuf, report_sender);
}
}
unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A', test->settings->unit_precision);
/* If no tests were run, set received bandwidth to 0 */
if (receiver_time > 0.0) {
bandwidth = (double) total_received / (double) receiver_time;
}
else {
bandwidth = 0.0;
}
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision);
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, bandwidth * 8, stream_must_be_sender));
else
Expand Down Expand Up @@ -3274,20 +3284,20 @@ iperf_print_results(struct iperf_test *test)
* server. Output whatever we have.
*/
if (! (test->role == 's' && !stream_must_be_sender) ) {
unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A', test->settings->unit_precision);
iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, sender_total_packets, 0.0, "sender");
}
if (! (test->role == 's' && stream_must_be_sender) ) {

unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A', test->settings->unit_precision);
/* Compute received bandwidth. */
if (end_time > 0.0) {
bandwidth = (double) total_received / (double) receiver_time;
}
else {
bandwidth = 0.0;
}
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision);
iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, receiver_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, receiver_total_packets, lost_percent, "receiver");
}
}
Expand Down Expand Up @@ -3454,14 +3464,14 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *
}
}

unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');
unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A', test->settings->unit_precision);
if (irp->interval_duration > 0.0) {
bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
}
else {
bandwidth = 0.0;
}
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision);

iperf_time_diff(&sp->result->start_time, &irp->interval_start_time, &temp_time);
st = iperf_time_in_secs(&temp_time);
Expand All @@ -3474,7 +3484,7 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *
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 rtt: %d rttvar: %d pmtu: %d omitted: %b sender: %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, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender));
else {
unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A');
unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A', test->settings->unit_precision);
iperf_printf(test, report_bw_retrans_cwnd_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:"");
}
} else {
Expand Down Expand Up @@ -4071,4 +4081,5 @@ iflush(struct iperf_test *test)
if (rv < 0) {
iperf_errexit(test, "fflush on outfile failed: %s\n", strerror(errno));
}
return rv;
}
1 change: 1 addition & 0 deletions src/iperf_locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
"Server or Client:\n"
" -p, --port # server port to listen on/connect to\n"
" -f, --format [kmgtKMGT] format to report: Kbits, Mbits, Gbits, Tbits\n"
" -r, --precision [-1 - 30] decimal precision for format to report\n"
" -i, --interval # seconds between periodic throughput reports\n"
" -F, --file name xmit/recv the specified file\n"
#if defined(HAVE_CPU_AFFINITY)
Expand Down
20 changes: 10 additions & 10 deletions src/t_units.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,37 +73,37 @@ main(int argc, char **argv)
llu = (iperf_size_t) d;
assert(llu == unit_atoi("3t"));

unit_snprintf(s, 11, 1024.0, 'A');
unit_snprintf(s, 11, 1024.0, 'A', -1);
assert(strncmp(s, "1.00 KByte", 11) == 0);

unit_snprintf(s, 11, 1024.0 * 1024.0, 'A');
unit_snprintf(s, 11, 1024.0 * 1024.0, 'A', -1);
assert(strncmp(s, "1.00 MByte", 11) == 0);

unit_snprintf(s, 11, 1000.0, 'k');
unit_snprintf(s, 11, 1000.0, 'k', -1);
assert(strncmp(s, "8.00 Kbit", 11) == 0);

unit_snprintf(s, 11, 1000.0 * 1000.0, 'a');
unit_snprintf(s, 11, 1000.0 * 1000.0, 'a', -1);
assert(strncmp(s, "8.00 Mbit", 11) == 0);

d = 4.0 * 1024 * 1024 * 1024;
unit_snprintf(s, 11, d, 'A');
unit_snprintf(s, 11, d, 'A', -1);
assert(strncmp(s, "4.00 GByte", 11) == 0);

unit_snprintf(s, 11, d, 'a');
unit_snprintf(s, 11, d, 'a', -1);
assert(strncmp(s, "34.4 Gbit", 11) == 0);

d = 4.0 * 1024 * 1024 * 1024 * 1024;
unit_snprintf(s, 11, d, 'A');
unit_snprintf(s, 11, d, 'A', -1);
assert(strncmp(s, "4.00 TByte", 11) == 0);

unit_snprintf(s, 11, d, 'a');
unit_snprintf(s, 11, d, 'a', -1);
assert(strncmp(s, "35.2 Tbit", 11) == 0);

d = 4.0 * 1024 * 1024 * 1024 * 1024 * 1024;
unit_snprintf(s, 11, d, 'A');
unit_snprintf(s, 11, d, 'A', -1);
assert(strncmp(s, "4096 TByte", 11) == 0);

unit_snprintf(s, 11, d, 'a');
unit_snprintf(s, 11, d, 'a', -1);
assert(strncmp(s, "36029 Tbit", 11) == 0);

return 0;
Expand Down
61 changes: 44 additions & 17 deletions src/units.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

/*---------------------------------------------------------------
* Copyright (c) 1999,2000,2001,2002,2003
* The Board of Trustees of the University of Illinois
Expand Down Expand Up @@ -263,14 +264,18 @@ extern "C"
* adaptive picks the "best" one based on the number.
* s should be at least 11 chars long
* (4 digits + space + 5 chars max + null)
* If precision == -1, treat that as old behavior that tries to do 4 characters,
* otherwise, use it as decimial precision.
* ------------------------------------------------------------------- */

void unit_snprintf(char *s, int inLen,
double inNum, char inFormat)
double inNum, char inFormat, int precision)
{
int conv;
const char *suffix;
const char *format;
char format_custom[40];
int p = precision;

/* convert to bits for [bkmga] */
if (!isupper((int) inFormat))
Expand Down Expand Up @@ -303,14 +308,30 @@ extern "C"

if (isupper((int) inFormat))
{
while (tmpNum >= 1024.0 && conv < TERA_CONV)
double max = 1024.0;
int z;
for (z = 0; z<precision - 2; z++) {
max *= 10;
}
precision -= z; // We effectively increase precision above.
if (p > 2 && precision < 2)
precision = 2;
while (tmpNum >= max && conv < TERA_CONV)
{
tmpNum /= 1024.0;
conv++;
}
} else
{
while (tmpNum >= 1000.0 && conv < TERA_CONV)
double max = 1000.0;
int z;
for (z = 0; z<precision - 2; z++) {
max *= 10;
}
precision -= z; // We effectively increase precision above.
if (p > 2 && precision < 2)
precision = 2;
while (tmpNum >= max && conv < TERA_CONV)
{
tmpNum /= 1000.0;
conv++;
Expand All @@ -330,22 +351,28 @@ extern "C"
suffix = label_byte[conv];
}

/* print such that we always fit in 4 places */
if (inNum < 9.995)
{ /* 9.995 would be rounded to 10.0 */
format = "%4.2f %s";/* #.## */
} else if (inNum < 99.95)
{ /* 99.95 would be rounded to 100 */
format = "%4.1f %s";/* ##.# */
} else if (inNum < 999.5)
{ /* 999.5 would be rounded to 1000 */
format = "%4.0f %s";/* ### */
} else
{ /* 1000-1024 fits in 4 places If not using
if (precision == -1) {
/* print such that we always fit in 4 places */
if (inNum < 9.995)
{ /* 9.995 would be rounded to 10.0 */
format = "%4.2f %s";/* #.## */
} else if (inNum < 99.95)
{ /* 99.95 would be rounded to 100 */
format = "%4.1f %s";/* ##.# */
} else if (inNum < 999.5)
{ /* 999.5 would be rounded to 1000 */
format = "%4.0f %s";/* ### */
} else
{ /* 1000-1024 fits in 4 places If not using
* Adaptive sizes then this code will not
* control spaces */
format = "%4.0f %s";/* #### */
}
format = "%4.0f %s";/* #### */
}
}
else {
snprintf(format_custom, sizeof(format_custom), "%%0.%df %%s", precision);
format = format_custom;
}
snprintf(s, inLen, format, inNum, suffix);
} /* end unit_snprintf */

Expand Down
4 changes: 2 additions & 2 deletions src/units.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
* file for complete information.
*/
enum {
UNIT_LEN = 32
UNIT_LEN = 64
};

double unit_atof( const char *s );
double unit_atof_rate( const char *s );
iperf_size_t unit_atoi( const char *s );
void unit_snprintf( char *s, int inLen, double inNum, char inFormat );
void unit_snprintf( char *s, int inLen, double inNum, char inFormat, int precision );

0 comments on commit 72bb459

Please sign in to comment.