kernel accel: if switching takes a long time, back off

That can happen even with not many sessions, e.g. on a loaded machine with a
lot of routes
This commit is contained in:
Samuel Thibault 2025-03-30 12:01:16 +02:00
parent b2942b3c53
commit a56de89a4c

View file

@ -140,6 +140,7 @@ char main_quit = 0; // True if we're in the process of exiting.
static char main_reload = 0; // Re-load pending
#define MAX_KERNEL_SWITCHES 20 // Maximum number of kernel switches per 1/10th second
static int kernel_switches = 0; // How many kernel switches we performed since last cleanup
static double last_poll_time = 0; // Last time we polled fds
linked_list *loaded_plugins;
linked_list *plugins[MAX_PLUGIN_TYPES];
@ -1387,7 +1388,7 @@ static int delete_kernel_accel(sessionidt s)
// Enable (set=1) or disable (set=0) kernel PPP acceleration
// This basically calls create/delete_kernel_accel, but also updates routes
// If now is 0, we may delay this if we have already made a lot of switches since last cleanup
static void set_kernel_accel(sessionidt s, int set, int now)
static void set_kernel_accel(sessionidt s, int set, int nodelay)
{
if (set && !can_kernel_accel(s))
/* Still cannot enable it */
@ -1418,10 +1419,14 @@ static void set_kernel_accel(sessionidt s, int set, int now)
}
}
if (set && !now && kernel_switches >= MAX_KERNEL_SWITCHES)
double cur_switch;
now(&cur_switch);
if (set && !nodelay &&
(kernel_switches >= MAX_KERNEL_SWITCHES
|| cur_switch - last_poll_time > 0.02))
{
// We already performed many switches, throttle a bit by just
// marking as pending
// We have already been switching a lot or working at for 20ms since last poll,
// throttle a bit by just marking as pending
sess_local[s].needs_switch = 1;
return;
}
@ -5999,7 +6004,7 @@ static void mainloop(void)
n = epoll_wait(epollfd, events, maxevent, 100); // timeout 100ms (1/10th sec)
STAT(select_called);
TIME = now(NULL);
TIME = now(&last_poll_time);
if (n < 0)
{
if (errno == EINTR ||
@ -6387,7 +6392,7 @@ static void mainloop(void)
// Handle trying to enable kernel accel
{
static double last_switch = 0;
double this_switch;
double this_switch, cur_switch;
double diff;
TIME = now(&this_switch);
@ -6399,14 +6404,21 @@ static void mainloop(void)
{
kernel_switches = 0;
cur_switch = this_switch;
for (i = 1; i <= config->cluster_highest_sessionid; i++)
{
// Delayed kernel switch
if (session[i].ppp.lcp == Opened && sess_local[i].needs_switch)
{
set_kernel_accel(i, can_kernel_accel(i), 0);
TIME = now(&cur_switch);
if (cur_switch - this_switch > 0.02)
// We have already taken 20ms sec doing switches, backoff
break;
}
}
last_switch = this_switch;
last_switch = cur_switch;
}
}