]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #1713 from ktsaou/master
authorCosta Tsaousis <costa@tsaousis.gr>
Sat, 4 Feb 2017 00:36:21 +0000 (02:36 +0200)
committerGitHub <noreply@github.com>
Sat, 4 Feb 2017 00:36:21 +0000 (02:36 +0200)
minor fixes and user configurable process scheduling priority

12 files changed:
README.md
autogen.sh
configure.ac
netdata-installer.sh
src/apps_plugin.c
src/daemon.c
src/daemon.h
src/main.c
src/plugin_tc.c
web/dashboard.js
web/dashboard_info.js
web/index.html

index 808c70071740c93a28b9acdfc817f6d8ee14fba5..faf72a07ef35949cca496fd1f0216929ce4d893e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# netdata [![Build Status](https://travis-ci.org/firehol/netdata.svg?branch=master)](https://travis-ci.org/firehol/netdata) [![Coverity Scan Build Status](https://scan.coverity.com/projects/9140/badge.svg)](https://scan.coverity.com/projects/firehol-netdata) [![Code Climate](https://codeclimate.com/github/firehol/netdata/badges/gpa.svg)](https://codeclimate.com/github/firehol/netdata) [![Docker Pulls](https://img.shields.io/docker/pulls/titpetric/netdata.svg)](https://hub.docker.com/r/titpetric/netdata/)
+# netdata [![Build Status](https://travis-ci.org/firehol/netdata.svg?branch=master)](https://travis-ci.org/firehol/netdata) [![Coverity Scan Build Status](https://scan.coverity.com/projects/9140/badge.svg)](https://scan.coverity.com/projects/firehol-netdata) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a994873f30d045b9b4b83606c3eb3498)](https://www.codacy.com/app/netdata/netdata?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=firehol/netdata&amp;utm_campaign=Badge_Grade) [![Code Climate](https://codeclimate.com/github/firehol/netdata/badges/gpa.svg)](https://codeclimate.com/github/firehol/netdata) [![Docker Pulls](https://img.shields.io/docker/pulls/titpetric/netdata.svg)](https://hub.docker.com/r/titpetric/netdata/)
 > *New to netdata? Here is a live demo: [http://my-netdata.io](http://my-netdata.io)*
 
 **netdata** is a system for **distributed real-time performance and health monitoring**.
index 3b076d1a12c71eba41bb1e392c1d56f1ed53092f..38e2ed1597fa8bf86e3f7caa6623e24c930c3748 100755 (executable)
@@ -1,2 +1,2 @@
-#!/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 fa69de196d1076dd2a48551639685b4431e334a4..9b080caed1d641ca43d26c39714e16ec2217662a 100755 (executable)
@@ -1,9 +1,20 @@
 #!/usr/bin/env bash
 
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
+
+netdata_source_dir="$(pwd)"
+installer_dir="$(dirname "${0}")"
+
+if [ "${netdata_source_dir}" != "${installer_dir}" -a "${installer_dir}" != "." ]
+    then
+    echo >&2 "Warninng: you are currently in '${netdata_source_dir}' but the installer is in '${installer_dir}'."
+fi
+
 # reload the user profile
 [ -f /etc/profile ] && . /etc/profile
 
-export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
+# make sure /etc/profile does not change our current directory
+cd "${netdata_source_dir}" || exit 1
 
 # fix PKG_CHECK_MODULES error
 if [ -d /usr/share/aclocal ]
@@ -18,7 +29,7 @@ umask 002
 # Be nice on production environments
 renice 19 $$ >/dev/null 2>/dev/null
 
-processors=$(cat /proc/cpuinfo  | grep ^processor | wc -l)
+processors=$(grep ^processor </proc/cpuinfo | wc -l)
 [ $(( processors )) -lt 1 ] && processors=1
 
 # you can set CFLAGS before running installer
@@ -382,7 +393,7 @@ run() {
 
     printf >&2 "\n"
     printf >&2 ":-----------------------------------------------------------------------------\n"
-    printf >&2 "Running command:\n"
+    printf >&2 "Running command (in $(pwd)):\n"
     printf >&2 "\n"
     printf >&2 "%q " "${@}"
     printf >&2 "\n"
index 738bd85a6cf23b31ccd606c367b662f4647c7e24..128b198561d551622f97ead759d6a3b8459e4ea2 100644 (file)
@@ -848,7 +848,7 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
             if(p->comm[0])
                 fprintf(stderr, "apps.plugin: \tpid %d (%s) changed name to '%s'\n", p->pid, p->comm, comm);
             else
-                fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", p->pid, p->comm);
+                fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", p->pid, comm);
         }
 
         strncpyz(p->comm, comm, MAX_COMPARE_NAME);
index c125511a07d57571eb939ca6a341e50bfd301d21..dddafec6e615e9644d87aecd1e32899cff318eae 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, 0, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_FIFO
+        { "fifo", SCHED_FIFO, 0, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_BATCH
+        { "batch", SCHED_BATCH, 0, SCHED_FLAG_USE_NICE },
+#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());
index 7aef4ab5bc637337068464d66eba4f2cc5cc7473..5fdbf32584bc330725e4274d274019687a561a92 100644 (file)
@@ -283,29 +283,31 @@ static inline void tc_device_commit(struct tc_device *d) {
     //
     // so, here we remove the isleaf flag from nodes in the middle
     // and we add the hasparent flag to leaf nodes we found their parent
-    for(c = d->classes; c; c = c->next) {
-        if(unlikely(!c->updated)) continue;
-
-        //debug(D_TC_LOOP, "TC: In device '%s', %s '%s'  has leafid: '%s' and parentid '%s'.",
-        //    d->id,
-        //    c->isqdisc?"qdisc":"class",
-        //    c->id,
-        //    c->leafid?c->leafid:"NULL",
-        //    c->parentid?c->parentid:"NULL");
-
-        // find if c is leaf or not
-        for(x = d->classes; x; x = x->next) {
-            if(unlikely(!x->updated || c == x || !x->parentid)) continue;
-
-            // classes have both parentid and leafid
-            // qdiscs have only parentid
-            // the following works for both (it is an OR)
-
-            if( (c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
-                (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) {
-                // debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id);
-                c->isleaf = 0;
-                x->hasparent = 1;
+    if(likely(!d->enabled_all_classes_qdiscs)) {
+        for(c = d->classes; c; c = c->next) {
+            if(unlikely(!c->updated)) continue;
+
+            //debug(D_TC_LOOP, "TC: In device '%s', %s '%s'  has leafid: '%s' and parentid '%s'.",
+            //    d->id,
+            //    c->isqdisc?"qdisc":"class",
+            //    c->id,
+            //    c->leafid?c->leafid:"NULL",
+            //    c->parentid?c->parentid:"NULL");
+
+            // find if c is leaf or not
+            for(x = d->classes; x; x = x->next) {
+                if(unlikely(!x->updated || c == x || !x->parentid)) continue;
+
+                // classes have both parentid and leafid
+                // qdiscs have only parentid
+                // the following works for both (it is an OR)
+
+                if((c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
+                   (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) {
+                    // debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id);
+                    c->isleaf = 0;
+                    x->hasparent = 1;
+                }
             }
         }
     }
index 346a8e9c10d0e3b5e42eb7364c6146c461a7d4df..02e171d4af7d3c330f722b655a98dcf6f2ef4660 100644 (file)
@@ -363,6 +363,28 @@ var NETDATA = window.NETDATA || {};
         callback: {} // only used for resetting back to defaults
     };
 
+    NETDATA.localStorageTested = -1;
+    NETDATA.localStorageTest = function() {
+        if(NETDATA.localStorageTested !== -1)
+            return NETDATA.localStorageTested;
+
+        if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+            var test = 'test';
+            try {
+                localStorage.setItem(test, test);
+                localStorage.removeItem(test);
+                NETDATA.localStorageTested = true;
+            }
+            catch (e) {
+                NETDATA.localStorageTested = false;
+            }
+        }
+        else
+            NETDATA.localStorageTested = false;
+
+        return NETDATA.localStorageTested;
+    };
+
     NETDATA.localStorageGet = function(key, def, callback) {
         var ret = def;
 
@@ -371,7 +393,7 @@ var NETDATA = window.NETDATA || {};
             NETDATA.localStorage.callback[key.toString()] = callback;
         }
 
-        if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+        if(NETDATA.localStorageTest() === true) {
             try {
                 // console.log('localStorage: loading "' + key.toString() + '"');
                 ret = localStorage.getItem(key.toString());
@@ -413,7 +435,7 @@ var NETDATA = window.NETDATA || {};
             NETDATA.localStorage.callback[key.toString()] = callback;
         }
 
-        if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+        if(NETDATA.localStorageTest() === true) {
             // console.log('localStorage: saving "' + key.toString() + '" with value "' + JSON.stringify(value) + '"');
             try {
                 localStorage.setItem(key.toString(), JSON.stringify(value));
index 7d7f726e3b3783d15ec857d5676737cd5abea66a..871a4f8f657701ef236be5cbcc247c5cc1309833 100644 (file)
@@ -412,15 +412,12 @@ netdataDashboard.context = {
         ]
     },
 
-    'mem.committed': {
-        colors: NETDATA.colors[3]
-    },
-    
     'mem.pgfaults': {
        info: 'A <a href="https://en.wikipedia.org/wiki/Page_fault" target="_blank">page fault</a> is a type of interrupt, called trap, raised by computer hardware when a running program accesses a memory page that is mapped into the virtual address space, but not actually loaded into main memory. If the page is loaded in memory at the time the fault is generated, but is not marked in the memory management unit as being loaded in memory, then it is called a <b>minor</b> or soft page fault. A <b>major</b> page fault is generated when the system needs to load the memory page from disk or swap memory. These values are read from <code>/proc/vmstat</code>.'
     },
 
     'mem.committed': {
+        colors: NETDATA.colors[3],
         info: 'Committed Memory, read from <code>/proc/meminfo</code>, is the sum of all memory which has been allocated by processes.'
     },
 
index 55a605aa786767155de45bc8051e2125b1d3c9dc..c9685ba3a0b6133ec2f3d893ca7b2548c9be0194 100644 (file)
         // --------------------------------------------------------------------
         // check options that should be processed before loading netdata.js
 
+        var localStorageTested = -1;
+        function localStorageTest() {
+            if(localStorageTested !== -1)
+                return localStorageTested;
+
+            if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+                var test = 'test';
+                try {
+                    localStorage.setItem(test, test);
+                    localStorage.removeItem(test);
+                    localStorageTested = true;
+                }
+                catch (e) {
+                    localStorageTested = false;
+                }
+            }
+            else
+                localStorageTested = false;
+
+            return localStorageTested;
+        }
+
         function loadLocalStorage(name) {
             var ret = null;
 
             try {
-                if(typeof Storage !== "undefined" && typeof localStorage === 'object')
+                if(localStorageTest() === true)
                     ret = localStorage.getItem(name);
             }
             catch(error) {
         function saveLocalStorage(name, value) {
             // console.log('saving: ' + name.toString() + ' = ' + value.toString());
             try {
-                if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+                if(localStorageTest() === true) {
                     localStorage.setItem(name, value.toString());
                     return true;
                 }
     </div>
 </body>
 </html>
-<script type="text/javascript" src="dashboard.js?v20170127-1"></script>
+<script type="text/javascript" src="dashboard.js?v20170204-1"></script>