]> arthur.barton.de Git - netdata.git/commitdiff
allow users to set process scheduling priority and nice level; fixes #1712
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Fri, 3 Feb 2017 22:58:43 +0000 (00:58 +0200)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Fri, 3 Feb 2017 22:58:43 +0000 (00:58 +0200)
autogen.sh
configure.ac
src/daemon.c
src/daemon.h
src/main.c

index 3b076d1a12c71eba41bb1e392c1d56f1ed53092f..291fe48167c30250593f5cc03ac1fafd354e651c 100755 (executable)
@@ -1,2 +1,3 @@
-#!/bin/sh
+#!/usr/bin/env sh
+
 autoreconf -ivf
index 08107c9acf7985da329a5952bf74ff4585f50194..fd9b0cd1c001f032f0788892b8ff2eb9f8f02e36 100644 (file)
@@ -47,6 +47,7 @@ AC_CHECK_FUNCS_ONCE(accept4)
 AC_CHECK_TYPES([struct timespec, clockid_t], [], [], [[#include <time.h>]])
 AC_SEARCH_LIBS([clock_gettime], [rt posix4])
 AC_CHECK_FUNCS([clock_gettime])
+AC_CHECK_FUNCS([sched_setscheduler sched_get_priority_min sched_get_priority_max nice])
 
 # Check system type
 case "$host_os" in
index c125511a07d57571eb939ca6a341e50bfd301d21..dd53df979f8ee06eddffec719bafd365d3696523 100644 (file)
@@ -155,13 +155,15 @@ int become_user(const char *username, int pid_fd)
     return(0);
 }
 
-void oom_score_adj(int score) {
+static void oom_score_adj(void) {
+    int score = (int)config_get_number("global", "OOM score", 1000);
+
     int done = 0;
     int fd = open("/proc/self/oom_score_adj", O_WRONLY);
     if(fd != -1) {
         char buf[10 + 1];
         ssize_t len = snprintfz(buf, 10, "%d", score);
-        if(write(fd, buf, len) == len) done = 1;
+        if(len > 0 && write(fd, buf, (size_t)len) == len) done = 1;
         close(fd);
     }
 
@@ -171,25 +173,132 @@ void oom_score_adj(int score) {
         debug(D_SYSTEM, "Adjusted my Out-Of-Memory score to %d.", score);
 }
 
-int sched_setscheduler_idle(void) {
+static void process_nice_level(void) {
+#ifdef HAVE_NICE
+    int nice_level = (int)config_get_number("global", "process nice level", 19);
+    if(nice(nice_level) == -1) error("Cannot set netdata CPU nice level to %d.", nice_level);
+    else debug(D_SYSTEM, "Set netdata nice level to %d.", nice_level);
+#endif // HAVE_NICE
+};
+
+#ifdef HAVE_SCHED_SETSCHEDULER
+
+#define SCHED_FLAG_NONE                      0x00
+#define SCHED_FLAG_PRIORITY_CONFIGURABLE     0x01 // the priority is user configurable
+#define SCHED_FLAG_KEEP_AS_IS                0x04 // do not attempt to set policy, priority or nice()
+#define SCHED_FLAG_USE_NICE                  0x08 // use nice() after setting this policy
+
+struct sched_def {
+    char *name;
+    int policy;
+    int priority;
+    uint8_t flags;
+} scheduler_defaults[] = {
+
+        // the order of array members is important!
+        // the first defined is the default used by netdata
+
+        // the available members are important too!
+        // these are all the possible scheduling policies supported by netdata
+
 #ifdef SCHED_IDLE
-    const struct sched_param param = {
-        .sched_priority = 0
-    };
+        { "idle", SCHED_IDLE, 0, SCHED_FLAG_NONE },
+#endif
 
-    int i = sched_setscheduler(0, SCHED_IDLE, &param);
-    if(i != 0)
-        error("Cannot adjust my scheduling priority to IDLE.");
-    else
-        debug(D_SYSTEM, "Adjusted my scheduling priority to IDLE.");
+#ifdef SCHED_OTHER
+        { "nice",  SCHED_OTHER, 0, SCHED_FLAG_USE_NICE },
+        { "other", SCHED_OTHER, 0, SCHED_FLAG_USE_NICE },
+#endif
 
-    return i;
-#else
-    return -1;
+#ifdef SCHED_RR
+        { "rr", SCHED_RR, 99, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_FIFO
+        { "rr", SCHED_FIFO, 99, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_BATCH
+        { "rr", SCHED_BATCH, 99, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+        // do not change the scheduling priority
+        { "keep", 0, 0, SCHED_FLAG_KEEP_AS_IS },
+        { "none", 0, 0, SCHED_FLAG_KEEP_AS_IS },
+
+        // array termination
+        { NULL, 0, 0, 0 }
+};
+
+static void sched_setscheduler_set(void) {
+
+    if(scheduler_defaults[0].name) {
+        const char *name = scheduler_defaults[0].name;
+        int policy = scheduler_defaults[0].policy, priority = scheduler_defaults[0].priority;
+        uint8_t flags = scheduler_defaults[0].flags;
+        int found = 0;
+
+        // read the configuration
+        name = config_get("global", "process scheduling policy", name);
+        int i;
+        for(i = 0 ; scheduler_defaults[i].name ; i++) {
+            if(!strcmp(name, scheduler_defaults[i].name)) {
+                found = 1;
+                priority = scheduler_defaults[i].priority;
+                flags = scheduler_defaults[i].flags;
+
+                if(flags & SCHED_FLAG_KEEP_AS_IS)
+                    return;
+
+                if(flags & SCHED_FLAG_PRIORITY_CONFIGURABLE)
+                    priority = (int)config_get_number("global", "process scheduling priority", priority);
+
+#ifdef HAVE_SCHED_GET_PRIORITY_MIN
+                if(priority < sched_get_priority_min(policy)) {
+                    error("scheduler %s priority %d is below the minimum %d. Using the minimum.", name, priority, sched_get_priority_min(policy));
+                    priority = sched_get_priority_min(policy);
+                }
+#endif
+#ifdef HAVE_SCHED_GET_PRIORITY_MAX
+                if(priority > sched_get_priority_max(policy)) {
+                    error("scheduler %s priority %d is above the maximum %d. Using the maximum.", name, priority, sched_get_priority_max(policy));
+                    priority = sched_get_priority_max(policy);
+                }
 #endif
+                break;
+            }
+        }
+
+        if(!found) {
+            error("Unknown scheduling policy %s - falling back to nice()", name);
+            goto fallback;
+        }
+
+        const struct sched_param param = {
+                .sched_priority = priority
+        };
+
+        i = sched_setscheduler(0, policy, &param);
+        if(i != 0) {
+            error("Cannot adjust netdata scheduling policy to %s (%d), with priority %d. Falling back to nice", name, policy, priority);
+        }
+        else {
+            debug(D_SYSTEM, "Adjusted netdata scheduling policy to %s (%d), with priority %d.", name, policy, priority);
+            if(!(flags & SCHED_FLAG_USE_NICE))
+                return;
+        }
+    }
+
+fallback:
+    process_nice_level();
 }
+#else
+static void sched_setscheduler_set(void) {
+    process_nice_level();
+}
+#endif
 
-int become_daemon(int dont_fork, const char *user, int oom_score)
+int become_daemon(int dont_fork, const char *user)
 {
     if(!dont_fork) {
         int i = fork();
@@ -239,13 +348,10 @@ int become_daemon(int dont_fork, const char *user, int oom_score)
     umask(0007);
 
     // adjust my Out-Of-Memory score
-    oom_score_adj(oom_score);
+    oom_score_adj();
 
     // never become a problem
-    if(sched_setscheduler_idle() != 0) {
-        if(nice(19) == -1) error("Cannot lower my CPU priority.");
-        else debug(D_SYSTEM, "Set my nice value to 19.");
-    }
+    sched_setscheduler_set();
 
     if(user && *user) {
         if(become_user(user, pidfd) != 0) {
index 561e0fe97dcfb2026bdd8bc3cb97ad1acfccb046..b193602d682e4136aa45b7391ea5162b828ad386 100644 (file)
@@ -8,7 +8,7 @@ extern void sig_handler_reload_health(int signo);
 
 extern int become_user(const char *username, int pid_fd);
 
-extern int become_daemon(int dont_fork, const char *user, int oom_score);
+extern int become_daemon(int dont_fork, const char *user);
 
 extern void netdata_cleanup_and_exit(int i);
 
index 18ad78a8dd0bbdf37cc2488f39d1c3591519f6bc..fb547e440526a1489b60365203416323c134ccb0 100644 (file)
@@ -338,7 +338,6 @@ int main(int argc, char **argv)
     int i, check_config = 0;
     int config_loaded = 0;
     int dont_fork = 0;
-    int oom_score = 1000;
     size_t wanted_stacksize = 0, stacksize = 0;
     pthread_attr_t attr;
 
@@ -617,7 +616,6 @@ int main(int argc, char **argv)
         // --------------------------------------------------------------------
 
         rrd_memory_mode = rrd_memory_mode_id(config_get("global", "memory mode", rrd_memory_mode_name(rrd_memory_mode)));
-        oom_score = (int)config_get_number("global", "OOM score", oom_score);
 
         // --------------------------------------------------------------------
 
@@ -757,7 +755,7 @@ int main(int argc, char **argv)
 #endif /* NETDATA_INTERNAL_CHECKS */
 
     // fork, switch user, create pid file, set process priority
-    if(become_daemon(dont_fork, user, oom_score) == -1)
+    if(become_daemon(dont_fork, user) == -1)
         fatal("Cannot daemonize myself.");
 
     info("netdata started on pid %d.", getpid());