Skip to content

Commit 783095e

Browse files
committed
Fix #1741 - reduce CPU usage when test baud rate is limited
1 parent f89aee0 commit 783095e

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

configure.ac

+9
Original file line numberDiff line numberDiff line change
@@ -342,5 +342,14 @@ AC_SEARCH_LIBS(clock_gettime, [rt posix4])
342342
# Check for clock_gettime support
343343
AC_CHECK_FUNCS([clock_gettime])
344344

345+
# Check if we need -lrt for nanosleep
346+
AC_SEARCH_LIBS(nanosleep, [rt posix4])
347+
# Check for nanosleep support
348+
AC_CHECK_FUNCS([nanosleep])
349+
# Check if we need -lrt for clock_nanosleep
350+
AC_SEARCH_LIBS(clock_nanosleep, [rt posix4])
351+
# Check for clock_nanosleep support
352+
AC_CHECK_FUNCS([clock_nanosleep])
353+
345354
AC_CONFIG_FILES([Makefile src/Makefile src/version.h examples/Makefile iperf3.spec])
346355
AC_OUTPUT

src/iperf_api.c

+72-3
Original file line numberDiff line numberDiff line change
@@ -1639,10 +1639,12 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
16391639
test->use_pkcs1_padding = 1;
16401640
break;
16411641
#endif /* HAVE_SSL */
1642+
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
16421643
case OPT_PACING_TIMER:
16431644
test->settings->pacing_timer = unit_atoi(optarg);
16441645
client_flag = 1;
16451646
break;
1647+
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP */
16461648
case OPT_CONNECT_TIMEOUT:
16471649
test->settings->connect_timeout = unit_atoi(optarg);
16481650
client_flag = 1;
@@ -1881,17 +1883,73 @@ iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP)
18811883
struct iperf_time temp_time;
18821884
double seconds;
18831885
uint64_t bits_per_second;
1886+
int64_t missing_rate;
1887+
uint64_t bits_sent;
1888+
1889+
#if defined(HAVE_CLOCK_NANOSLEEP) || defined(HAVE_NANOSLEEP)
1890+
struct timespec nanosleep_time;
1891+
int64_t time_to_green_ligh, delta_bits;
1892+
int ret;
1893+
#endif /* HAVE_CLOCK_NANOSLEEP || HAVE_NANOSLEEP) */
1894+
#if defined(HAVE_CLOCK_NANOSLEEP)
1895+
int64_t ns;
1896+
#endif /* HAVE_CLOCK_NANOSLEEP */
18841897

18851898
if (sp->test->done || sp->test->settings->rate == 0)
18861899
return;
18871900
iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);
18881901
seconds = iperf_time_in_secs(&temp_time);
1889-
bits_per_second = sp->result->bytes_sent * 8 / seconds;
1890-
if (bits_per_second < sp->test->settings->rate) {
1902+
bits_sent = sp->result->bytes_sent * 8;
1903+
bits_per_second = bits_sent / seconds;
1904+
missing_rate = sp->test->settings->rate - bits_per_second;
1905+
1906+
if (missing_rate > 0) {
18911907
sp->green_light = 1;
18921908
} else {
18931909
sp->green_light = 0;
18941910
}
1911+
1912+
#if defined(HAVE_CLOCK_NANOSLEEP) || defined(HAVE_NANOSLEEP)
1913+
// If estimated time to next send is large enough, sleep instead of just CPU looping until green light is set
1914+
if (missing_rate < 0) {
1915+
delta_bits = bits_sent - (seconds * sp->test->settings->rate);
1916+
// Calclate time until next data send is required
1917+
time_to_green_ligh = (SEC_TO_NS * delta_bits / sp->test->settings->rate);
1918+
// Whether shouuld wait before next send
1919+
if (time_to_green_ligh >= 0) {
1920+
#if defined(HAVE_CLOCK_NANOSLEEP)
1921+
if (clock_gettime(CLOCK_MONOTONIC, &nanosleep_time) == 0) {
1922+
// Calculate absolute end of sleep time
1923+
ns = nanosleep_time.tv_nsec + time_to_green_ligh;
1924+
if (ns < SEC_TO_NS) {
1925+
nanosleep_time.tv_nsec = ns;
1926+
} else {
1927+
nanosleep_time.tv_sec += ns / SEC_TO_NS;
1928+
nanosleep_time.tv_nsec = ns % SEC_TO_NS;
1929+
}
1930+
// Sleep until average baud rate reaches the target value
1931+
while((ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &nanosleep_time, NULL)) == EINTR);
1932+
if (ret == 0) {
1933+
sp->green_light = 1;
1934+
}
1935+
}
1936+
1937+
#else /* HAVE_NANOSLEEP */
1938+
nanosleep_time.tv_sec = 0;
1939+
// Sleep until average baud rate reaches the target value or intrupt / error
1940+
do {
1941+
// nansleep() time should be less than 1 sec
1942+
nanosleep_time.tv_nsec = (time_to_green_ligh >= SEC_TO_NS) ? SEC_TO_NS - 1 : time_to_green_ligh;
1943+
time_to_green_ligh -= nanosleep_time.tv_nsec;
1944+
ret = nanosleep(&nanosleep_time, NULL);
1945+
} while (ret == 0 && time_to_green_ligh > 0);
1946+
if (ret == 0) {
1947+
sp->green_light = 1;
1948+
}
1949+
#endif /* HAVE_CLOCK_NANOSLEEP else HAVE_NANOSLEEP */
1950+
}
1951+
}
1952+
#endif /* HAVE_CLOCK_NANOSLEEP || HAVE_NANOSLEEP */
18951953
}
18961954

18971955
/* Verify that average traffic is not greater than the specified limit */
@@ -1982,7 +2040,11 @@ iperf_send_mt(struct iperf_stream *sp)
19822040
if (!streams_active)
19832041
break;
19842042
}
2043+
#if defined(HAVE_CLOCK_NANOSLEEP) || defined(HAVE_NANOSLEEP)
2044+
if (!sp->green_light) { /* Should check if green ligh can be set, as pacing timer is not supported in this case */
2045+
#else /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP */
19852046
if (!no_throttle_check) { /* Throttle check if was not checked for each send */
2047+
#endif /* HAVE_CLOCK_NANOSLEEP, HAVE_NANOSLEEP */
19862048
iperf_time_now(&now);
19872049
if (sp->sender)
19882050
iperf_check_throttle(sp, &now);
@@ -2032,6 +2094,7 @@ iperf_init_test(struct iperf_test *test)
20322094
return 0;
20332095
}
20342096

2097+
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
20352098
static void
20362099
send_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
20372100
{
@@ -2043,20 +2106,25 @@ send_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
20432106
*/
20442107
iperf_check_throttle(sp, nowP);
20452108
}
2109+
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP) */
20462110

20472111
int
20482112
iperf_create_send_timers(struct iperf_test * test)
20492113
{
2050-
struct iperf_time now;
20512114
struct iperf_stream *sp;
2115+
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
20522116
TimerClientData cd;
2117+
struct iperf_time now;
20532118

20542119
if (iperf_time_now(&now) < 0) {
20552120
i_errno = IEINITTEST;
20562121
return -1;
20572122
}
2123+
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP) */
2124+
20582125
SLIST_FOREACH(sp, &test->streams, streams) {
20592126
sp->green_light = 1;
2127+
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
20602128
if (test->settings->rate != 0 && sp->sender) {
20612129
cd.p = sp;
20622130
sp->send_timer = tmr_create(NULL, send_timer_proc, cd, test->settings->pacing_timer, 1);
@@ -2065,6 +2133,7 @@ iperf_create_send_timers(struct iperf_test * test)
20652133
return -1;
20662134
}
20672135
}
2136+
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP) */
20682137
}
20692138
return 0;
20702139
}

src/iperf_locale.c

+2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
163163
" -b, --bitrate #[KMG][/#] target bitrate in bits/sec (0 for unlimited)\n"
164164
" (default %d Mbit/sec for UDP, unlimited for TCP)\n"
165165
" (optional slash and packet count for burst mode)\n"
166+
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
166167
" --pacing-timer #[KMG] set the timing for pacing, in microseconds (default %d)\n"
168+
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP */
167169
#if defined(HAVE_SO_MAX_PACING_RATE)
168170
" --fq-rate #[KMG] enable fair-queuing based socket pacing in\n"
169171
" bits/sec (Linux only)\n"

0 commit comments

Comments
 (0)