watchdog: reduce watchdog pings in timeout interval

The watchdog ping is performed for every iteration of manager event
loop. This results in a lot of ioctls on watchdog device driver
especially during boot or if services are aggressively using sd_notify.
Depending on the watchdog device driver this may have performance
impact on embedded systems.
The patch skips sending the watchdog to device driver if the ping is
requested before half of the watchdog timeout.
This commit is contained in:
Alin Popa 2020-04-02 09:10:55 +02:00 committed by Lennart Poettering
parent 0f6d7be844
commit c5f8a179a2
3 changed files with 39 additions and 6 deletions

View File

@ -2931,12 +2931,10 @@ int manager_loop(Manager *m) {
if (manager_dispatch_dbus_queue(m) > 0)
continue;
/* Sleep for half the watchdog time */
if (timestamp_is_set(m->runtime_watchdog) && MANAGER_IS_SYSTEM(m)) {
wait_usec = m->runtime_watchdog / 2;
if (wait_usec <= 0)
wait_usec = 1;
} else
/* Sleep for watchdog runtime wait time */
if (MANAGER_IS_SYSTEM(m))
wait_usec = watchdog_runtime_wait();
else
wait_usec = USEC_INFINITY;
r = sd_event_run(m->event, wait_usec);

View File

@ -16,6 +16,7 @@
static int watchdog_fd = -1;
static char *watchdog_device = NULL;
static usec_t watchdog_timeout = USEC_INFINITY;
static usec_t watchdog_last_ping = USEC_INFINITY;
static int update_timeout(void) {
int r;
@ -57,6 +58,8 @@ static int update_timeout(void) {
r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
if (r < 0)
return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
watchdog_last_ping = now(clock_boottime_or_monotonic());
}
return 0;
@ -114,9 +117,38 @@ int watchdog_set_timeout(usec_t *usec) {
return r;
}
usec_t watchdog_runtime_wait(void) {
usec_t rtwait;
usec_t ntime;
if (!timestamp_is_set(watchdog_timeout))
return USEC_INFINITY;
/* Sleep half the watchdog timeout since the last succesful ping at most */
if (timestamp_is_set(watchdog_last_ping)) {
ntime = now(clock_boottime_or_monotonic());
assert(ntime >= watchdog_last_ping);
rtwait = usec_sub_unsigned(watchdog_last_ping + (watchdog_timeout / 2), ntime);
} else
rtwait = watchdog_timeout / 2;
return rtwait;
}
int watchdog_ping(void) {
usec_t ntime;
int r;
ntime = now(clock_boottime_or_monotonic());
/* Never ping earlier than watchdog_timeout/4 and try to ping
* by watchdog_timeout/2 plus scheduling latencies the latest */
if (timestamp_is_set(watchdog_last_ping)) {
assert(ntime >= watchdog_last_ping);
if ((ntime - watchdog_last_ping) < (watchdog_timeout / 4))
return 0;
}
if (watchdog_fd < 0) {
r = open_watchdog();
if (r < 0)
@ -127,6 +159,8 @@ int watchdog_ping(void) {
if (r < 0)
return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
watchdog_last_ping = ntime;
return 0;
}

View File

@ -10,6 +10,7 @@ int watchdog_set_device(char *path);
int watchdog_set_timeout(usec_t *usec);
int watchdog_ping(void);
void watchdog_close(bool disarm);
usec_t watchdog_runtime_wait(void);
static inline void watchdog_free_device(void) {
(void) watchdog_set_device(NULL);