Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce CPU usage when test baud rate is limited #1743

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading