Skip to content

Commit

Permalink
Merge pull request #1743 from davidBar-On/issue-1741-reduce-cpu-utili…
Browse files Browse the repository at this point in the history
…zation-in-limited-rate-test

Reduce CPU usage when test baud rate is limited
  • Loading branch information
bmah888 authored Aug 30, 2024
2 parents 5bf93d6 + af81adc commit 4abd5ea
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
9 changes: 9 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -342,5 +342,14 @@ AC_SEARCH_LIBS(clock_gettime, [rt posix4])
# Check for clock_gettime support
AC_CHECK_FUNCS([clock_gettime])

# Check if we need -lrt for nanosleep
AC_SEARCH_LIBS(nanosleep, [rt posix4])
# Check for nanosleep support
AC_CHECK_FUNCS([nanosleep])
# Check if we need -lrt for clock_nanosleep
AC_SEARCH_LIBS(clock_nanosleep, [rt posix4])
# Check for clock_nanosleep support
AC_CHECK_FUNCS([clock_nanosleep])

AC_CONFIG_FILES([Makefile src/Makefile src/version.h examples/Makefile iperf3.spec])
AC_OUTPUT
73 changes: 70 additions & 3 deletions src/iperf_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1881,17 +1881,73 @@ iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP)
struct iperf_time temp_time;
double seconds;
uint64_t bits_per_second;
int64_t missing_rate;
uint64_t bits_sent;

#if defined(HAVE_CLOCK_NANOSLEEP) || defined(HAVE_NANOSLEEP)
struct timespec nanosleep_time;
int64_t time_to_green_light, delta_bits;
int ret;
#endif /* HAVE_CLOCK_NANOSLEEP || HAVE_NANOSLEEP) */
#if defined(HAVE_CLOCK_NANOSLEEP)
int64_t ns;
#endif /* HAVE_CLOCK_NANOSLEEP */

if (sp->test->done || sp->test->settings->rate == 0)
return;
iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);
seconds = iperf_time_in_secs(&temp_time);
bits_per_second = sp->result->bytes_sent * 8 / seconds;
if (bits_per_second < sp->test->settings->rate) {
bits_sent = sp->result->bytes_sent * 8;
bits_per_second = bits_sent / seconds;
missing_rate = sp->test->settings->rate - bits_per_second;

if (missing_rate > 0) {
sp->green_light = 1;
} else {
sp->green_light = 0;
}

#if defined(HAVE_CLOCK_NANOSLEEP) || defined(HAVE_NANOSLEEP)
// If estimated time to next send is large enough, sleep instead of just CPU looping until green light is set
if (missing_rate < 0) {
delta_bits = bits_sent - (seconds * sp->test->settings->rate);
// Calclate time until next data send is required
time_to_green_light = (SEC_TO_NS * delta_bits / sp->test->settings->rate);
// Whether shouuld wait before next send
if (time_to_green_light >= 0) {
#if defined(HAVE_CLOCK_NANOSLEEP)
if (clock_gettime(CLOCK_MONOTONIC, &nanosleep_time) == 0) {
// Calculate absolute end of sleep time
ns = nanosleep_time.tv_nsec + time_to_green_light;
if (ns < SEC_TO_NS) {
nanosleep_time.tv_nsec = ns;
} else {
nanosleep_time.tv_sec += ns / SEC_TO_NS;
nanosleep_time.tv_nsec = ns % SEC_TO_NS;
}
// Sleep until average baud rate reaches the target value
while((ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &nanosleep_time, NULL)) == EINTR);
if (ret == 0) {
sp->green_light = 1;
}
}

#else /* HAVE_NANOSLEEP */
nanosleep_time.tv_sec = 0;
// Sleep until average baud rate reaches the target value or intrupt / error
do {
// nansleep() time should be less than 1 sec
nanosleep_time.tv_nsec = (time_to_green_light >= SEC_TO_NS) ? SEC_TO_NS - 1 : time_to_green_light;
time_to_green_light -= nanosleep_time.tv_nsec;
ret = nanosleep(&nanosleep_time, NULL);
} while (ret == 0 && time_to_green_light > 0);
if (ret == 0) {
sp->green_light = 1;
}
#endif /* HAVE_CLOCK_NANOSLEEP else HAVE_NANOSLEEP */
}
}
#endif /* HAVE_CLOCK_NANOSLEEP || HAVE_NANOSLEEP */
}

/* Verify that average traffic is not greater than the specified limit */
Expand Down Expand Up @@ -1982,7 +2038,11 @@ iperf_send_mt(struct iperf_stream *sp)
if (!streams_active)
break;
}
#if defined(HAVE_CLOCK_NANOSLEEP) || defined(HAVE_NANOSLEEP)
if (!sp->green_light) { /* Should check if green ligh can be set, as pacing timer is not supported in this case */
#else /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP */
if (!no_throttle_check) { /* Throttle check if was not checked for each send */
#endif /* HAVE_CLOCK_NANOSLEEP, HAVE_NANOSLEEP */
iperf_time_now(&now);
if (sp->sender)
iperf_check_throttle(sp, &now);
Expand Down Expand Up @@ -2032,6 +2092,7 @@ iperf_init_test(struct iperf_test *test)
return 0;
}

#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
static void
send_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
{
Expand All @@ -2043,20 +2104,25 @@ send_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
*/
iperf_check_throttle(sp, nowP);
}
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP) */

int
iperf_create_send_timers(struct iperf_test * test)
{
struct iperf_time now;
struct iperf_stream *sp;
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
TimerClientData cd;
struct iperf_time now;

if (iperf_time_now(&now) < 0) {
i_errno = IEINITTEST;
return -1;
}
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP) */

SLIST_FOREACH(sp, &test->streams, streams) {
sp->green_light = 1;
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
if (test->settings->rate != 0 && sp->sender) {
cd.p = sp;
sp->send_timer = tmr_create(NULL, send_timer_proc, cd, test->settings->pacing_timer, 1);
Expand All @@ -2065,6 +2131,7 @@ iperf_create_send_timers(struct iperf_test * test)
return -1;
}
}
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP) */
}
return 0;
}
Expand Down
5 changes: 5 additions & 0 deletions src/iperf_locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,12 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" -b, --bitrate #[KMG][/#] target bitrate in bits/sec (0 for unlimited)\n"
" (default %d Mbit/sec for UDP, unlimited for TCP)\n"
" (optional slash and packet count for burst mode)\n"
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(HAVE_NANOSLEEP)
" --pacing-timer #[KMG] set the timing for pacing, in microseconds (default %d)\n"
#else
" --pacing-timer #[KMG] set the Server timing for pacing, in microseconds (default %d)\n"
" (used by the server only if this option is in its help message)\n"
#endif /* !HAVE_CLOCK_NANOSLEEP && !HAVE_NANOSLEEP */
#if defined(HAVE_SO_MAX_PACING_RATE)
" --fq-rate #[KMG] enable fair-queuing based socket pacing in\n"
" bits/sec (Linux only)\n"
Expand Down

0 comments on commit 4abd5ea

Please sign in to comment.