]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
watchdog: reduce watchdog pings in timeout interval
authorAlin Popa <alin.popa@fxdata.ro>
Thu, 2 Apr 2020 07:10:55 +0000 (09:10 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 16 Apr 2020 14:32:05 +0000 (16:32 +0200)
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.

src/core/manager.c
src/shared/watchdog.c
src/shared/watchdog.h

index 4a11054e05c7571a828f54ee0f2012073b0502fb..955ed1e54b539405c4469571ab018a6931d7863d 100644 (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);
index 98fefb39569b51fc2e750bb62d128a1fba0a43c8..b64f423c5101b058bc91b55825a3c3d1ada98c43 100644 (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;
 }
 
index a345e4ba7d9d0df9019d1c87bbe21e8e2371f101..ce739fd8a38e4cccd5824dbd71b4d5875da93afd 100644 (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);