-# 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&utm_medium=referral&utm_content=firehol/netdata&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**.
-#!/bin/sh
+#!/usr/bin/env sh
autoreconf -ivf
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
#!/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 ]
# 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
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"
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);
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);
}
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, ¶m);
- 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, ¶m);
+ 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();
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) {
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);
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;
// --------------------------------------------------------------------
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);
// --------------------------------------------------------------------
#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());
//
// 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;
+ }
}
}
}
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;
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());
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));
]
},
- '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.'
},
// --------------------------------------------------------------------
// 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>