diff --git a/src/iperf.h b/src/iperf.h index 2946b93..e612a9f 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -27,6 +27,7 @@ struct iperf_interval_results struct timeval interval_start_time; struct timeval interval_end_time; float interval_duration; + int omitted; #if defined(linux) || defined(__FreeBSD__) struct tcp_info tcpInfo; /* getsockopt(TCP_INFO) for Linux and FreeBSD */ int this_retrans; diff --git a/src/iperf_api.c b/src/iperf_api.c index 9a0f772..a0dc653 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -938,8 +938,8 @@ iperf_sum_results(struct iperf_test *test) { struct iperf_stream *sp; - SLIST_FOREACH(sp, &test->streams, streams) { - if (test->sender && test->sender_has_retransmits) { + 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)); } } @@ -1563,6 +1563,7 @@ iperf_stats_callback(struct iperf_test *test) struct iperf_interval_results *irp, temp; int prev_total_retransmits; + temp.omitted = test->omitting; SLIST_FOREACH(sp, &test->streams, streams) { rp = sp->result; @@ -1652,14 +1653,14 @@ iperf_print_intermediate(struct iperf_test *test) end_time = timeval_diff(&sp->result->start_time,&irp->interval_end_time); if (test->sender && test->sender_has_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", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits)); + 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)); else - printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits); + printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:""); } else { if (test->json_output) - cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8)); + cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, test->omitting)); else - printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); + printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:""); } } } @@ -1737,12 +1738,12 @@ iperf_print_results(struct iperf_test *test) 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)); 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->retransmits, ""); } 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)); else - printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); + printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, ""); } } else { out_of_order_percent = 100.0 * sp->cnt_error / (sp->packet_count - sp->omitted_packet_count); @@ -1777,7 +1778,7 @@ iperf_print_results(struct iperf_test *test) if (test->json_output) cJSON_AddItemToObject(json_summary_stream, "received", 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_received, bandwidth * 8)); else - printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); + printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, ""); } } @@ -1792,12 +1793,12 @@ iperf_print_results(struct iperf_test *test) 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)); else - printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits); + printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits, ""); } else { 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", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8)); else - printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); + printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf, ""); } unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A'); bandwidth = (double) total_received / (double) end_time; @@ -1807,7 +1808,7 @@ iperf_print_results(struct iperf_test *test) 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", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_received, bandwidth * 8)); else - printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); + printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf, ""); } else { avg_jitter /= test->num_streams; loss_percent = 100.0 * lost_packets / total_packets; @@ -1891,14 +1892,14 @@ 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", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->this_retrans)); + 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)); else - printf(report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->this_retrans); + printf(report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->this_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", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8)); + 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)); else - printf(report_bw_format, sp->socket, st, et, ubuf, nbuf); + printf(report_bw_format, sp->socket, st, et, ubuf, nbuf, irp->omitted?report_omitted:""); } } diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 1e37ef9..79577cd 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -83,48 +83,8 @@ reporter_timer_proc(TimerClientData client_data, struct timeval *nowP) test->reporter_callback(test); } -static void -client_omit_timer_proc(TimerClientData client_data, struct timeval *nowP) -{ - struct iperf_test *test = client_data.p; - TimerClientData cd; - - test->omit_timer = NULL; - test->omitting = 0; - iperf_reset_stats(test); - if (test->verbose && !test->json_output) - printf("Finished omit period, starting real test\n"); - - /* Create timers. */ - if (test->settings->bytes == 0) { - test->done = 0; - cd.p = test; - test->timer = tmr_create(nowP, test_timer_proc, cd, test->duration * SEC_TO_US, 0); - if (test->timer == NULL) { - i_errno = IEINITTEST; - return; - } - } - if (test->stats_interval != 0) { - cd.p = test; - test->stats_timer = tmr_create(nowP, stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); - if (test->stats_timer == NULL) { - i_errno = IEINITTEST; - return; - } - } - if (test->reporter_interval != 0) { - cd.p = test; - test->reporter_timer = tmr_create(nowP, reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1); - if (test->reporter_timer == NULL) { - i_errno = IEINITTEST; - return; - } - } -} - static int -create_client_omit_timer(struct iperf_test * test) +create_client_timers(struct iperf_test * test) { struct timeval now; TimerClientData cd; @@ -133,12 +93,72 @@ create_client_omit_timer(struct iperf_test * test) i_errno = IEINITTEST; return -1; } - test->omitting = 1; cd.p = test; - test->omit_timer = tmr_create(&now, client_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); - if (test->omit_timer == NULL) { - i_errno = IEINITTEST; - return -1; + test->timer = test->stats_timer = test->reporter_timer = NULL; + if (test->settings->bytes == 0) { + test->done = 0; + test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit ) * SEC_TO_US, 0); + if (test->timer == NULL) { + i_errno = IEINITTEST; + return -1; + } + } + if (test->stats_interval != 0) { + test->stats_timer = tmr_create(&now, stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); + if (test->stats_timer == NULL) { + i_errno = IEINITTEST; + return -1; + } + } + if (test->reporter_interval != 0) { + test->reporter_timer = tmr_create(&now, reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1); + if (test->reporter_timer == NULL) { + i_errno = IEINITTEST; + return -1; + } + } + return 0; +} + +static void +client_omit_timer_proc(TimerClientData client_data, struct timeval *nowP) +{ + struct iperf_test *test = client_data.p; + + test->omit_timer = NULL; + test->omitting = 0; + iperf_reset_stats(test); + if (test->verbose && !test->json_output && test->reporter_interval == 0) + printf("Finished omit period, starting real test\n"); + + /* Reset the timers. */ + if (test->stats_timer != NULL) + tmr_reset(nowP, test->stats_timer); + if (test->reporter_timer != NULL) + tmr_reset(nowP, test->reporter_timer); +} + +static int +create_client_omit_timer(struct iperf_test * test) +{ + struct timeval now; + TimerClientData cd; + + if (test->omit == 0) { + test->omit_timer = NULL; + test->omitting = 0; + } else { + if (gettimeofday(&now, NULL) < 0) { + i_errno = IEINITTEST; + return -1; + } + test->omitting = 1; + cd.p = test; + test->omit_timer = tmr_create(&now, client_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); + if (test->omit_timer == NULL) { + i_errno = IEINITTEST; + return -1; + } } return 0; } @@ -172,6 +192,8 @@ iperf_handle_message_client(struct iperf_test *test) case TEST_START: if (iperf_init_test(test) < 0) return -1; + if (create_client_timers(test) < 0) + return -1; if (create_client_omit_timer(test) < 0) return -1; if (!test->reverse) @@ -337,16 +359,18 @@ iperf_run_client(struct iperf_test * test) if (test->state == TEST_RUNNING) { /* Is this our first time really running? */ - if (startup && ! test->omitting) { + if (startup) { startup = 0; - /* Can we switch to SIGALRM mode? There are a bunch of - ** cases where either it won't work or it's ill-advised. + /* Decide which concurrency model to use for the real test. + ** SIGALRM is less overhead but there are a bunch of cases + ** where it either won't work or is ill-advised. */ if (test->may_use_sigalrm && test->settings->rate == 0 && (test->stats_interval == 0 || test->stats_interval > 1) && test->stats_interval == (int) test->stats_interval && (test->reporter_interval == 0 || test->reporter_interval > 1) && test->reporter_interval == (int) test->reporter_interval && + (test->omit == 0 || test->omit > 1) && ! test->reverse) { concurrency_model = CM_SIGALRM; test->multisend = 1; diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index be20799..5ec6600 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -289,7 +289,7 @@ server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP) test->omit_timer = NULL; test->omitting = 0; iperf_reset_stats(test); - if (test->verbose && !test->json_output) + if (test->verbose && !test->json_output && test->reporter_interval == 0) printf("Finished omit period, starting real test\n"); } @@ -299,17 +299,23 @@ create_server_omit_timer(struct iperf_test * test) struct timeval now; TimerClientData cd; - if (gettimeofday(&now, NULL) < 0) { - i_errno = IEINITTEST; - return -1; - } - test->omitting = 1; - cd.p = test; - test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); - if (test->omit_timer == NULL) { - i_errno = IEINITTEST; - return -1; + if (test->omit == 0) { + test->omit_timer = NULL; + test->omitting = 0; + } else { + if (gettimeofday(&now, NULL) < 0) { + i_errno = IEINITTEST; + return -1; + } + test->omitting = 1; + cd.p = test; + test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); + if (test->omit_timer == NULL) { + i_errno = IEINITTEST; + return -1; + } } + return 0; } diff --git a/src/locale.c b/src/locale.c index 9659ce7..7d0bcf6 100644 --- a/src/locale.c +++ b/src/locale.c @@ -191,23 +191,25 @@ const char report_bw_udp_header[] = Datagrams\n"; const char report_bw_format[] = -"[%3d] %6.2f-%-6.2f sec %ss %ss/sec\n"; +"[%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 %d\n"; +"[%3d] %6.2f-%-6.2f sec %ss %ss/sec %d%s\n"; const char report_bw_udp_format[] = "[%3d] %6.2f-%-6.2f sec %ss %ss/sec %5.3f ms %d/%d (%.2g%%)\n"; const char report_sum_bw_format[] = -"[SUM] %6.2f-%-6.2f sec %ss %ss/sec\n"; +"[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 %d\n"; +"[SUM] %6.2f-%-6.2f sec %ss %ss/sec %d%s\n"; const char report_sum_bw_udp_format[] = "[SUM] %6.2f-%-6.2f sec %ss %ss/sec %5.3f ms %d/%d (%.2g%%)\n"; +const char report_omitted[] = " (omitted)"; + const char report_bw_separator[] = "- - - - - - - - - - - - - - - - - - - - - - - - -\n"; diff --git a/src/locale.h b/src/locale.h index b89e8f4..a5cbe17 100644 --- a/src/locale.h +++ b/src/locale.h @@ -41,6 +41,7 @@ extern const char report_bw_udp_format[] ; extern const char report_sum_bw_format[] ; extern const char report_sum_bw_retrans_format[] ; extern const char report_sum_bw_udp_format[] ; +extern const char report_omitted[] ; extern const char report_bw_separator[] ; extern const char report_outoforder[] ; extern const char report_sum_outoforder[] ;