]> arthur.barton.de Git - netdata.git/blobdiff - src/apps_plugin.c
faster number parsing
[netdata.git] / src / apps_plugin.c
index bf953fc1bbfa589c63a4e5323e09a4a0775135c2..d9167b5ae2c0d650a32209dbc211133d7c10fee6 100644 (file)
@@ -13,8 +13,6 @@
 // etc.
 #define RATES_DETAIL 10000ULL
 
-int processors = 1;
-pid_t pid_max = 32768;
 int debug = 0;
 
 int update_every = 1;
@@ -22,7 +20,6 @@ unsigned long long global_iterations_counter = 1;
 unsigned long long file_counter = 0;
 int proc_pid_cmdline_is_needed = 0;
 int include_exited_childs = 1;
-char *host_prefix = "";
 char *config_dir = CONFIG_DIR;
 
 pid_t *all_pids_sortlist = NULL;
@@ -32,6 +29,9 @@ int show_guest_time = 0;
 int show_guest_time_old = 0;
 
 int enable_guest_charts = 0;
+int enable_file_charts = 1;
+int enable_users_charts = 1;
+int enable_groups_charts = 1;
 
 // ----------------------------------------------------------------------------
 
@@ -40,62 +40,6 @@ void netdata_cleanup_and_exit(int ret) {
 }
 
 
-// ----------------------------------------------------------------------------
-// system functions
-// to retrieve settings of the system
-
-long get_system_cpus(void) {
-    procfile *ff = NULL;
-
-    int processors = 0;
-
-    char filename[FILENAME_MAX + 1];
-    snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
-
-    ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
-    if(!ff) return 1;
-
-    ff = procfile_readall(ff);
-    if(!ff) {
-        procfile_close(ff);
-        return 1;
-    }
-
-    unsigned int i;
-    for(i = 0; i < procfile_lines(ff); i++) {
-        if(!procfile_linewords(ff, i)) continue;
-
-        if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0) processors++;
-    }
-    processors--;
-    if(processors < 1) processors = 1;
-
-    procfile_close(ff);
-    return processors;
-}
-
-pid_t get_system_pid_max(void) {
-    procfile *ff = NULL;
-    pid_t mpid = 32768;
-
-    char filename[FILENAME_MAX + 1];
-    snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
-    ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
-    if(!ff) return mpid;
-
-    ff = procfile_readall(ff);
-    if(!ff) {
-        procfile_close(ff);
-        return mpid;
-    }
-
-    mpid = (pid_t)atoi(procfile_lineword(ff, 0, 0));
-    if(!mpid) mpid = 32768;
-
-    procfile_close(ff);
-    return mpid;
-}
-
 // ----------------------------------------------------------------------------
 // target
 // target is the structure that process data are aggregated
@@ -124,23 +68,23 @@ struct target {
     unsigned long long cstime;
     unsigned long long cgtime;
     unsigned long long num_threads;
-    unsigned long long rss;
+    // unsigned long long rss;
 
     unsigned long long statm_size;
     unsigned long long statm_resident;
     unsigned long long statm_share;
-    unsigned long long statm_text;
-    unsigned long long statm_lib;
-    unsigned long long statm_data;
-    unsigned long long statm_dirty;
+    // unsigned long long statm_text;
+    // unsigned long long statm_lib;
+    // unsigned long long statm_data;
+    // unsigned long long statm_dirty;
 
     unsigned long long io_logical_bytes_read;
     unsigned long long io_logical_bytes_written;
-    unsigned long long io_read_calls;
-    unsigned long long io_write_calls;
+    // unsigned long long io_read_calls;
+    // unsigned long long io_write_calls;
     unsigned long long io_storage_bytes_read;
     unsigned long long io_storage_bytes_written;
-    unsigned long long io_cancelled_write_bytes;
+    // unsigned long long io_cancelled_write_bytes;
 
     int *fds;
     unsigned long long openfiles;
@@ -177,7 +121,7 @@ long apps_groups_targets = 0;
 struct target *users_root_target = NULL;
 struct target *groups_root_target = NULL;
 
-struct target *get_users_target(uid_t uid)
+static struct target *get_users_target(uid_t uid)
 {
     struct target *w;
     for(w = users_root_target ; w ; w = w->next)
@@ -245,10 +189,11 @@ struct target *get_groups_target(gid_t gid)
 
 // find or create a new target
 // there are targets that are just aggregated to other target (the second argument)
-struct target *get_apps_groups_target(const char *id, struct target *target) {
-    int tdebug = 0, thidden = 0, ends_with = 0;
+static struct target *get_apps_groups_target(const char *id, struct target *target, const char *name) {
+    int tdebug = 0, thidden = target?target->hidden:0, ends_with = 0;
     const char *nid = id;
 
+    // extract the options
     while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
         if(nid[0] == '-') thidden = 1;
         if(nid[0] == '+') tdebug = 1;
@@ -257,6 +202,7 @@ struct target *get_apps_groups_target(const char *id, struct target *target) {
     }
     uint32_t hash = simple_hash(id);
 
+    // find if it already exists
     struct target *w, *last = apps_groups_root_target;
     for(w = apps_groups_root_target ; w ; w = w->next) {
         if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
@@ -265,11 +211,37 @@ struct target *get_apps_groups_target(const char *id, struct target *target) {
         last = w;
     }
 
+    // find an existing target
+    if(unlikely(!target)) {
+        while(*name == '-') {
+            if(*name == '-') thidden = 1;
+            name++;
+        }
+        for(target = apps_groups_root_target ; target ; target = target->next) {
+            if(!target->target && strcmp(name, target->name) == 0)
+                break;
+        }
+        if(unlikely(debug)) {
+            if(unlikely(target))
+                fprintf(stderr, "apps.plugin: REUSING TARGET NAME '%s' on ID '%s'\n", target->name, target->id);
+            else
+                fprintf(stderr, "apps.plugin: NEW TARGET NAME '%s' on ID '%s'\n", name, id);
+        }
+    }
+
+    if(target && target->target)
+        fatal("Internal Error: request to link process '%s' to target '%s' which is linked to target '%s'", id, target->id, target->target->id);
+
     w = callocz(sizeof(struct target), 1);
     strncpyz(w->id, nid, MAX_NAME);
     w->idhash = simple_hash(w->id);
 
-    strncpyz(w->name, nid, MAX_NAME);
+    if(unlikely(!target))
+        // copy the name
+        strncpyz(w->name, name, MAX_NAME);
+    else
+        // copy the id
+        strncpyz(w->name, nid, MAX_NAME);
 
     strncpyz(w->compare, nid, MAX_COMPARE_NAME);
     size_t len = strlen(w->compare);
@@ -297,7 +269,7 @@ struct target *get_apps_groups_target(const char *id, struct target *target) {
         fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
                 , w->id
                 , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
-                , w->target?w->target->id:w->id
+                , w->target?w->target->name:w->name
                 , (w->hidden)?"hidden":"-"
                 , (w->debug)?"debug":"-"
         );
@@ -306,11 +278,11 @@ struct target *get_apps_groups_target(const char *id, struct target *target) {
 }
 
 // read the apps_groups.conf file
-int read_apps_groups_conf(const char *name)
+static int read_apps_groups_conf(const char *file)
 {
     char filename[FILENAME_MAX + 1];
 
-    snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
+    snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, file);
 
     if(unlikely(debug))
         fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
@@ -323,68 +295,52 @@ int read_apps_groups_conf(const char *name)
     procfile_set_quotes(ff, "'\"");
 
     ff = procfile_readall(ff);
-    if(!ff) {
-        procfile_close(ff);
+    if(!ff)
         return 1;
-    }
 
     unsigned long line, lines = procfile_lines(ff);
 
     for(line = 0; line < lines ;line++) {
         unsigned long word, words = procfile_linewords(ff, line);
-        struct target *w = NULL;
+        if(!words) continue;
 
-        char *t = procfile_lineword(ff, line, 0);
-        if(!t || !*t) continue;
+        char *name = procfile_lineword(ff, line, 0);
+        if(!name || !*name) continue;
 
+        // find a possibly existing target
+        struct target *w = NULL;
+
+        // loop through all words, skipping the first one (the name)
         for(word = 0; word < words ;word++) {
             char *s = procfile_lineword(ff, line, word);
             if(!s || !*s) continue;
             if(*s == '#') break;
 
-            if(t == s) continue;
+            // is this the first word? skip it
+            if(s == name) continue;
 
-            struct target *n = get_apps_groups_target(s, w);
+            // add this target
+            struct target *n = get_apps_groups_target(s, w, name);
             if(!n) {
                 error("Cannot create target '%s' (line %lu, word %lu)", s, line, word);
                 continue;
             }
 
-            if(!w) w = n;
-        }
-
-        if(w) {
-            int tdebug = 0, thidden = 0;
-
-            while(t[0] == '-' || t[0] == '+') {
-                if(t[0] == '-') thidden = 1;
-                if(t[0] == '+') tdebug = 1;
-                t++;
-            }
-
-            strncpyz(w->name, t, MAX_NAME);
-            w->hidden = thidden;
-            w->debug = tdebug;
-
-            if(unlikely(debug))
-                fprintf(stderr, "apps.plugin: AGGREGATION TARGET NAME '%s' on ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
-                        , w->name
-                        , w->id
-                        , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
-                        , w->target?w->target->id:w->id
-                        , (w->hidden)?"hidden":"-"
-                        , (w->debug)?"debug":"-"
-                );
+            // just some optimization
+            // to avoid searching for a target for each process
+            if(!w) w = n->target?n->target:n;
         }
     }
 
     procfile_close(ff);
 
-    apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
+    apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL, "other"); // match nothing
     if(!apps_groups_default_target)
-        error("Cannot create default target");
-    else
-        strncpyz(apps_groups_default_target->name, "other", MAX_NAME);
+        fatal("Cannot create default target");
+
+    // allow the user to override group 'other'
+    if(apps_groups_default_target->target)
+        apps_groups_default_target = apps_groups_default_target->target;
 
     return 0;
 }
@@ -445,7 +401,7 @@ struct pid_stat {
     // int64_t itrealvalue;
     // unsigned long long starttime;
     // unsigned long long vsize;
-    unsigned long long rss;
+    // unsigned long long rss;
     // unsigned long long rsslim;
     // unsigned long long starcode;
     // unsigned long long endcode;
@@ -471,26 +427,26 @@ struct pid_stat {
     unsigned long long statm_size;
     unsigned long long statm_resident;
     unsigned long long statm_share;
-    unsigned long long statm_text;
-    unsigned long long statm_lib;
-    unsigned long long statm_data;
-    unsigned long long statm_dirty;
+    // unsigned long long statm_text;
+    // unsigned long long statm_lib;
+    // unsigned long long statm_data;
+    // unsigned long long statm_dirty;
 
     unsigned long long io_logical_bytes_read_raw;
     unsigned long long io_logical_bytes_written_raw;
-    unsigned long long io_read_calls_raw;
-    unsigned long long io_write_calls_raw;
+    // unsigned long long io_read_calls_raw;
+    // unsigned long long io_write_calls_raw;
     unsigned long long io_storage_bytes_read_raw;
     unsigned long long io_storage_bytes_written_raw;
-    unsigned long long io_cancelled_write_bytes_raw;
+    // unsigned long long io_cancelled_write_bytes_raw;
 
     unsigned long long io_logical_bytes_read;
     unsigned long long io_logical_bytes_written;
-    unsigned long long io_read_calls;
-    unsigned long long io_write_calls;
+    // unsigned long long io_read_calls;
+    // unsigned long long io_write_calls;
     unsigned long long io_storage_bytes_read;
     unsigned long long io_storage_bytes_written;
-    unsigned long long io_cancelled_write_bytes;
+    // unsigned long long io_cancelled_write_bytes;
 
     int *fds;                       // array of fds it uses
     int fds_size;                   // the size of the fds array
@@ -527,7 +483,7 @@ struct pid_stat {
 
 long all_pids_count = 0;
 
-struct pid_stat *get_pid_entry(pid_t pid) {
+static inline struct pid_stat *get_pid_entry(pid_t pid) {
     if(all_pids[pid]) {
         all_pids[pid]->new_entry = 0;
         return all_pids[pid];
@@ -549,7 +505,7 @@ struct pid_stat *get_pid_entry(pid_t pid) {
     return all_pids[pid];
 }
 
-void del_pid_entry(pid_t pid) {
+static inline void del_pid_entry(pid_t pid) {
     if(!all_pids[pid]) {
         error("attempted to free pid %d that is not allocated.", pid);
         return;
@@ -577,11 +533,11 @@ void del_pid_entry(pid_t pid) {
 // ----------------------------------------------------------------------------
 // update pids from proc
 
-int read_proc_pid_cmdline(struct pid_stat *p) {
-    
+static inline int read_proc_pid_cmdline(struct pid_stat *p) {
+
     if(unlikely(!p->cmdline_filename)) {
         char filename[FILENAME_MAX + 1];
-        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", global_host_prefix, p->pid);
         p->cmdline_filename = strdupz(filename);
     }
 
@@ -608,7 +564,7 @@ cleanup:
     return 0;
 }
 
-int read_proc_pid_ownership(struct pid_stat *p) {
+static inline int read_proc_pid_ownership(struct pid_stat *p) {
     if(unlikely(!p->stat_filename)) {
         error("pid %d does not have a stat_filename", p->pid);
         return 0;
@@ -629,12 +585,12 @@ int read_proc_pid_ownership(struct pid_stat *p) {
     return 1;
 }
 
-int read_proc_pid_stat(struct pid_stat *p) {
+static inline int read_proc_pid_stat(struct pid_stat *p) {
     static procfile *ff = NULL;
 
     if(unlikely(!p->stat_filename)) {
         char filename[FILENAME_MAX + 1];
-        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", global_host_prefix, p->pid);
         p->stat_filename = strdupz(filename);
     }
 
@@ -650,89 +606,89 @@ int read_proc_pid_stat(struct pid_stat *p) {
     if(unlikely(!ff)) goto cleanup;
 
     p->last_stat_collected_usec = p->stat_collected_usec;
-    p->stat_collected_usec = time_usec();
+    p->stat_collected_usec = now_realtime_usec();
     file_counter++;
 
-    // p->pid           = atol(procfile_lineword(ff, 0, 0+i));
+    // p->pid           = str2ul(procfile_lineword(ff, 0, 0+i));
 
     strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
 
     // p->state         = *(procfile_lineword(ff, 0, 2));
-    p->ppid             = (int32_t) atol(procfile_lineword(ff, 0, 3));
-    // p->pgrp          = atol(procfile_lineword(ff, 0, 4));
-    // p->session       = atol(procfile_lineword(ff, 0, 5));
-    // p->tty_nr        = atol(procfile_lineword(ff, 0, 6));
-    // p->tpgid         = atol(procfile_lineword(ff, 0, 7));
-    // p->flags         = strtoull(procfile_lineword(ff, 0, 8), NULL, 10);
+    p->ppid             = (int32_t)str2ul(procfile_lineword(ff, 0, 3));
+    // p->pgrp          = str2ul(procfile_lineword(ff, 0, 4));
+    // p->session       = str2ul(procfile_lineword(ff, 0, 5));
+    // p->tty_nr        = str2ul(procfile_lineword(ff, 0, 6));
+    // p->tpgid         = str2ul(procfile_lineword(ff, 0, 7));
+    // p->flags         = str2ull(procfile_lineword(ff, 0, 8));
 
     unsigned long long last;
 
     last = p->minflt_raw;
-    p->minflt_raw       = strtoull(procfile_lineword(ff, 0, 9), NULL, 10);
-    p->minflt = (p->minflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+    p->minflt_raw       = str2ull(procfile_lineword(ff, 0, 9));
+    p->minflt = (p->minflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
     last = p->cminflt_raw;
-    p->cminflt_raw      = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
-    p->cminflt = (p->cminflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+    p->cminflt_raw      = str2ull(procfile_lineword(ff, 0, 10));
+    p->cminflt = (p->cminflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
     last = p->majflt_raw;
-    p->majflt_raw       = strtoull(procfile_lineword(ff, 0, 11), NULL, 10);
-    p->majflt = (p->majflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+    p->majflt_raw       = str2ull(procfile_lineword(ff, 0, 11));
+    p->majflt = (p->majflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
     last = p->cmajflt_raw;
-    p->cmajflt_raw      = strtoull(procfile_lineword(ff, 0, 12), NULL, 10);
-    p->cmajflt = (p->cmajflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+    p->cmajflt_raw      = str2ull(procfile_lineword(ff, 0, 12));
+    p->cmajflt = (p->cmajflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
     last = p->utime_raw;
-    p->utime_raw        = strtoull(procfile_lineword(ff, 0, 13), NULL, 10);
-    p->utime = (p->utime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+    p->utime_raw        = str2ull(procfile_lineword(ff, 0, 13));
+    p->utime = (p->utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
     last = p->stime_raw;
-    p->stime_raw        = strtoull(procfile_lineword(ff, 0, 14), NULL, 10);
-    p->stime = (p->stime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+    p->stime_raw        = str2ull(procfile_lineword(ff, 0, 14));
+    p->stime = (p->stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
     last = p->cutime_raw;
-    p->cutime_raw       = strtoull(procfile_lineword(ff, 0, 15), NULL, 10);
-    p->cutime = (p->cutime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+    p->cutime_raw       = str2ull(procfile_lineword(ff, 0, 15));
+    p->cutime = (p->cutime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
     last = p->cstime_raw;
-    p->cstime_raw       = strtoull(procfile_lineword(ff, 0, 16), NULL, 10);
-    p->cstime = (p->cstime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-    // p->priority      = strtoull(procfile_lineword(ff, 0, 17), NULL, 10);
-    // p->nice          = strtoull(procfile_lineword(ff, 0, 18), NULL, 10);
-    p->num_threads      = (int32_t) atol(procfile_lineword(ff, 0, 19));
-    // p->itrealvalue   = strtoull(procfile_lineword(ff, 0, 20), NULL, 10);
-    // p->starttime     = strtoull(procfile_lineword(ff, 0, 21), NULL, 10);
-    // p->vsize         = strtoull(procfile_lineword(ff, 0, 22), NULL, 10);
-    p->rss              = strtoull(procfile_lineword(ff, 0, 23), NULL, 10);
-    // p->rsslim        = strtoull(procfile_lineword(ff, 0, 24), NULL, 10);
-    // p->starcode      = strtoull(procfile_lineword(ff, 0, 25), NULL, 10);
-    // p->endcode       = strtoull(procfile_lineword(ff, 0, 26), NULL, 10);
-    // p->startstack    = strtoull(procfile_lineword(ff, 0, 27), NULL, 10);
-    // p->kstkesp       = strtoull(procfile_lineword(ff, 0, 28), NULL, 10);
-    // p->kstkeip       = strtoull(procfile_lineword(ff, 0, 29), NULL, 10);
-    // p->signal        = strtoull(procfile_lineword(ff, 0, 30), NULL, 10);
-    // p->blocked       = strtoull(procfile_lineword(ff, 0, 31), NULL, 10);
-    // p->sigignore     = strtoull(procfile_lineword(ff, 0, 32), NULL, 10);
-    // p->sigcatch      = strtoull(procfile_lineword(ff, 0, 33), NULL, 10);
-    // p->wchan         = strtoull(procfile_lineword(ff, 0, 34), NULL, 10);
-    // p->nswap         = strtoull(procfile_lineword(ff, 0, 35), NULL, 10);
-    // p->cnswap        = strtoull(procfile_lineword(ff, 0, 36), NULL, 10);
-    // p->exit_signal   = atol(procfile_lineword(ff, 0, 37));
-    // p->processor     = atol(procfile_lineword(ff, 0, 38));
-    // p->rt_priority   = strtoul(procfile_lineword(ff, 0, 39), NULL, 10);
-    // p->policy        = strtoul(procfile_lineword(ff, 0, 40), NULL, 10);
-    // p->delayacct_blkio_ticks = strtoull(procfile_lineword(ff, 0, 41), NULL, 10);
+    p->cstime_raw       = str2ull(procfile_lineword(ff, 0, 16));
+    p->cstime = (p->cstime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    // p->priority      = str2ull(procfile_lineword(ff, 0, 17));
+    // p->nice          = str2ull(procfile_lineword(ff, 0, 18));
+    p->num_threads      = (int32_t)str2ul(procfile_lineword(ff, 0, 19));
+    // p->itrealvalue   = str2ull(procfile_lineword(ff, 0, 20));
+    // p->starttime     = str2ull(procfile_lineword(ff, 0, 21));
+    // p->vsize         = str2ull(procfile_lineword(ff, 0, 22));
+    // p->rss           = str2ull(procfile_lineword(ff, 0, 23));
+    // p->rsslim        = str2ull(procfile_lineword(ff, 0, 24));
+    // p->starcode      = str2ull(procfile_lineword(ff, 0, 25));
+    // p->endcode       = str2ull(procfile_lineword(ff, 0, 26));
+    // p->startstack    = str2ull(procfile_lineword(ff, 0, 27));
+    // p->kstkesp       = str2ull(procfile_lineword(ff, 0, 28));
+    // p->kstkeip       = str2ull(procfile_lineword(ff, 0, 29));
+    // p->signal        = str2ull(procfile_lineword(ff, 0, 30));
+    // p->blocked       = str2ull(procfile_lineword(ff, 0, 31));
+    // p->sigignore     = str2ull(procfile_lineword(ff, 0, 32));
+    // p->sigcatch      = str2ull(procfile_lineword(ff, 0, 33));
+    // p->wchan         = str2ull(procfile_lineword(ff, 0, 34));
+    // p->nswap         = str2ull(procfile_lineword(ff, 0, 35));
+    // p->cnswap        = str2ull(procfile_lineword(ff, 0, 36));
+    // p->exit_signal   = str2ul(procfile_lineword(ff, 0, 37));
+    // p->processor     = str2ul(procfile_lineword(ff, 0, 38));
+    // p->rt_priority   = str2ul(procfile_lineword(ff, 0, 39));
+    // p->policy        = str2ul(procfile_lineword(ff, 0, 40));
+    // p->delayacct_blkio_ticks = str2ull(procfile_lineword(ff, 0, 41));
 
     if(enable_guest_charts) {
         last = p->gtime_raw;
-        p->gtime_raw        = strtoull(procfile_lineword(ff, 0, 42), NULL, 10);
-        p->gtime = (p->gtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+        p->gtime_raw        = str2ull(procfile_lineword(ff, 0, 42));
+        p->gtime = (p->gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
         last = p->cgtime_raw;
-        p->cgtime_raw       = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
-        p->cgtime = (p->cgtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+        p->cgtime_raw       = str2ull(procfile_lineword(ff, 0, 43));
+        p->cgtime = (p->cgtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
         if (show_guest_time || p->gtime || p->cgtime) {
             p->utime -= (p->utime >= p->gtime) ? p->gtime : p->utime;
@@ -742,7 +698,7 @@ int read_proc_pid_stat(struct pid_stat *p) {
     }
 
     if(unlikely(debug || (p->target && p->target->debug)))
-        fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+        fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", global_host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
 
     if(unlikely(global_iterations_counter == 1)) {
         p->minflt           = 0;
@@ -771,16 +727,16 @@ cleanup:
     p->cstime           = 0;
     p->cgtime           = 0;
     p->num_threads      = 0;
-    p->rss              = 0;
+    // p->rss              = 0;
     return 0;
 }
 
-int read_proc_pid_statm(struct pid_stat *p) {
+static inline int read_proc_pid_statm(struct pid_stat *p) {
     static procfile *ff = NULL;
 
     if(unlikely(!p->statm_filename)) {
         char filename[FILENAME_MAX + 1];
-        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", global_host_prefix, p->pid);
         p->statm_filename = strdupz(filename);
     }
 
@@ -792,13 +748,13 @@ int read_proc_pid_statm(struct pid_stat *p) {
 
     file_counter++;
 
-    p->statm_size           = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
-    p->statm_resident       = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
-    p->statm_share          = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
-    p->statm_text           = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
-    p->statm_lib            = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
-    p->statm_data           = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
-    p->statm_dirty          = strtoull(procfile_lineword(ff, 0, 6), NULL, 10);
+    p->statm_size           = str2ull(procfile_lineword(ff, 0, 0));
+    p->statm_resident       = str2ull(procfile_lineword(ff, 0, 1));
+    p->statm_share          = str2ull(procfile_lineword(ff, 0, 2));
+    // p->statm_text           = str2ull(procfile_lineword(ff, 0, 3));
+    // p->statm_lib            = str2ull(procfile_lineword(ff, 0, 4));
+    // p->statm_data           = str2ull(procfile_lineword(ff, 0, 5));
+    // p->statm_dirty          = str2ull(procfile_lineword(ff, 0, 6));
 
     return 1;
 
@@ -806,19 +762,19 @@ cleanup:
     p->statm_size           = 0;
     p->statm_resident       = 0;
     p->statm_share          = 0;
-    p->statm_text           = 0;
-    p->statm_lib            = 0;
-    p->statm_data           = 0;
-    p->statm_dirty          = 0;
+    // p->statm_text           = 0;
+    // p->statm_lib            = 0;
+    // p->statm_data           = 0;
+    // p->statm_dirty          = 0;
     return 0;
 }
 
-int read_proc_pid_io(struct pid_stat *p) {
+static inline int read_proc_pid_io(struct pid_stat *p) {
     static procfile *ff = NULL;
 
     if(unlikely(!p->io_filename)) {
         char filename[FILENAME_MAX + 1];
-        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", global_host_prefix, p->pid);
         p->io_filename = strdupz(filename);
     }
 
@@ -832,46 +788,46 @@ int read_proc_pid_io(struct pid_stat *p) {
     file_counter++;
 
     p->last_io_collected_usec = p->io_collected_usec;
-    p->io_collected_usec = time_usec();
+    p->io_collected_usec = now_realtime_usec();
 
     unsigned long long last;
 
     last = p->io_logical_bytes_read_raw;
-    p->io_logical_bytes_read_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
-    p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    p->io_logical_bytes_read_raw = str2ull(procfile_lineword(ff, 0, 1));
+    p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
     last = p->io_logical_bytes_written_raw;
-    p->io_logical_bytes_written_raw = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
-    p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    p->io_logical_bytes_written_raw = str2ull(procfile_lineword(ff, 1, 1));
+    p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-    last = p->io_read_calls_raw;
-    p->io_read_calls_raw = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
-    p->io_read_calls = (p->io_read_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    // last = p->io_read_calls_raw;
+    // p->io_read_calls_raw = str2ull(procfile_lineword(ff, 2, 1));
+    // p->io_read_calls = (p->io_read_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-    last = p->io_write_calls_raw;
-    p->io_write_calls_raw = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
-    p->io_write_calls = (p->io_write_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    // last = p->io_write_calls_raw;
+    // p->io_write_calls_raw = str2ull(procfile_lineword(ff, 3, 1));
+    // p->io_write_calls = (p->io_write_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
     last = p->io_storage_bytes_read_raw;
-    p->io_storage_bytes_read_raw = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
-    p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    p->io_storage_bytes_read_raw = str2ull(procfile_lineword(ff, 4, 1));
+    p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
     last = p->io_storage_bytes_written_raw;
-    p->io_storage_bytes_written_raw = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
-    p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    p->io_storage_bytes_written_raw = str2ull(procfile_lineword(ff, 5, 1));
+    p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-    last = p->io_cancelled_write_bytes_raw;
-    p->io_cancelled_write_bytes_raw = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
-    p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    // last = p->io_cancelled_write_bytes_raw;
+    // p->io_cancelled_write_bytes_raw = str2ull(procfile_lineword(ff, 6, 1));
+    // p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
     if(unlikely(global_iterations_counter == 1)) {
         p->io_logical_bytes_read        = 0;
         p->io_logical_bytes_written     = 0;
-        p->io_read_calls                = 0;
-        p->io_write_calls               = 0;
+        // p->io_read_calls             = 0;
+        // p->io_write_calls            = 0;
         p->io_storage_bytes_read        = 0;
         p->io_storage_bytes_written     = 0;
-        p->io_cancelled_write_bytes     = 0;
+        // p->io_cancelled_write_bytes  = 0;
     }
 
     return 1;
@@ -879,11 +835,11 @@ int read_proc_pid_io(struct pid_stat *p) {
 cleanup:
     p->io_logical_bytes_read        = 0;
     p->io_logical_bytes_written     = 0;
-    p->io_read_calls                = 0;
-    p->io_write_calls               = 0;
+    // p->io_read_calls             = 0;
+    // p->io_write_calls            = 0;
     p->io_storage_bytes_read        = 0;
     p->io_storage_bytes_written     = 0;
-    p->io_cancelled_write_bytes     = 0;
+    // p->io_cancelled_write_bytes  = 0;
     return 0;
 }
 
@@ -891,13 +847,14 @@ unsigned long long global_utime = 0;
 unsigned long long global_stime = 0;
 unsigned long long global_gtime = 0;
 
-int read_proc_stat() {
+static inline int read_proc_stat() {
     static char filename[FILENAME_MAX + 1] = "";
     static procfile *ff = NULL;
-    static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0, collected_usec = 0, last_collected_usec = 0;
+    static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0;
+    static usec_t collected_usec = 0, last_collected_usec = 0;
 
     if(unlikely(!ff)) {
-        snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
+        snprintfz(filename, FILENAME_MAX, "%s/proc/stat", global_host_prefix);
         ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
         if(unlikely(!ff)) goto cleanup;
     }
@@ -906,34 +863,34 @@ int read_proc_stat() {
     if(unlikely(!ff)) goto cleanup;
 
     last_collected_usec = collected_usec;
-    collected_usec = time_usec();
+    collected_usec = now_realtime_usec();
 
     file_counter++;
 
     unsigned long long last;
 
     last = utime_raw;
-    utime_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
-    global_utime = (utime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+    utime_raw = str2ull(procfile_lineword(ff, 0, 1));
+    global_utime = (utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
     // nice time, on user time
     last = ntime_raw;
-    ntime_raw = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
-    global_utime += (ntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+    ntime_raw = str2ull(procfile_lineword(ff, 0, 2));
+    global_utime += (ntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
     last = stime_raw;
-    stime_raw = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
-    global_stime = (stime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+    stime_raw = str2ull(procfile_lineword(ff, 0, 3));
+    global_stime = (stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
     last = gtime_raw;
-    gtime_raw = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
-    global_gtime = (gtime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+    gtime_raw = str2ull(procfile_lineword(ff, 0, 10));
+    global_gtime = (gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
     if(enable_guest_charts) {
         // guest nice time, on guest time
         last = gntime_raw;
-        gntime_raw = strtoull(procfile_lineword(ff, 0, 11), NULL, 10);
-        global_gtime += (gntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+        gntime_raw = str2ull(procfile_lineword(ff, 0, 11));
+        global_gtime += (gntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
         // remove guest time from user time
         global_utime -= (global_utime > global_gtime) ? global_gtime : global_utime;
@@ -1026,7 +983,7 @@ static struct file_descriptor *file_descriptor_find(const char *name, uint32_t h
 #define FILETYPE_TIMERFD 7
 #define FILETYPE_SIGNALFD 8
 
-void file_descriptor_not_used(int id)
+static inline void file_descriptor_not_used(int id)
 {
     if(id > 0 && id < all_files_size) {
 
@@ -1047,7 +1004,9 @@ void file_descriptor_not_used(int id)
                 if(unlikely(debug))
                     fprintf(stderr, "apps.plugin:   >> slot %d is empty.\n", id);
 
-                file_descriptor_remove(&all_files[id]);
+                if(unlikely(file_descriptor_remove(&all_files[id]) != (void *)&all_files[id]))
+                    error("INTERNAL ERROR: removal of unused fd from index, removed a different fd");
+
 #ifdef NETDATA_INTERNAL_CHECKS
                 all_files[id].magic = 0x00000000;
 #endif /* NETDATA_INTERNAL_CHECKS */
@@ -1060,7 +1019,7 @@ void file_descriptor_not_used(int id)
     else    error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
 }
 
-int file_descriptor_find_or_add(const char *name)
+static inline int file_descriptor_find_or_add(const char *name)
 {
     static int last_pos = 0;
     uint32_t hash = simple_hash(name);
@@ -1099,7 +1058,8 @@ int file_descriptor_find_or_add(const char *name)
             all_files_index.root = NULL;
             for(i = 0; i < all_files_size; i++) {
                 if(!all_files[i].count) continue;
-                file_descriptor_add(&all_files[i]);
+                if(unlikely(file_descriptor_add(&all_files[i]) != (void *)&all_files[i]))
+                    error("INTERNAL ERROR: duplicate indexing of fd during realloc.");
             }
 
             if(unlikely(debug))
@@ -1188,7 +1148,8 @@ int file_descriptor_find_or_add(const char *name)
 #ifdef NETDATA_INTERNAL_CHECKS
     all_files[c].magic = 0x0BADCAFE;
 #endif /* NETDATA_INTERNAL_CHECKS */
-    file_descriptor_add(&all_files[c]);
+    if(unlikely(file_descriptor_add(&all_files[c]) != (void *)&all_files[c]))
+        error("INTERNAL ERROR: duplicate indexing of fd.");
 
     if(unlikely(debug))
         fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
@@ -1196,10 +1157,10 @@ int file_descriptor_find_or_add(const char *name)
     return c;
 }
 
-int read_pid_file_descriptors(struct pid_stat *p) {
+static inline int read_pid_file_descriptors(struct pid_stat *p) {
     char dirname[FILENAME_MAX+1];
 
-    snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", host_prefix, p->pid);
+    snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid);
     DIR *fds = opendir(dirname);
     if(fds) {
         int c;
@@ -1216,7 +1177,7 @@ int read_pid_file_descriptors(struct pid_stat *p) {
                 continue;
 
             // check if the fds array is small
-            int fdid = atoi(de->d_name);
+            int fdid = (int)str2l(de->d_name);
             if(fdid < 0) continue;
             if(fdid >= p->fds_size) {
                 // it is small, extend it
@@ -1237,7 +1198,7 @@ int read_pid_file_descriptors(struct pid_stat *p) {
             if(p->fds[fdid] == 0) {
                 // we don't know this fd, get it
 
-                sprintf(fdname, "%s/proc/%d/fd/%s", host_prefix, p->pid, de->d_name);
+                sprintf(fdname, "%s/proc/%d/fd/%s", global_host_prefix, p->pid, de->d_name);
                 ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
                 if(l == -1) {
                     if(debug || (p->target && p->target->debug)) {
@@ -1274,7 +1235,7 @@ int read_pid_file_descriptors(struct pid_stat *p) {
 
 // ----------------------------------------------------------------------------
 
-int print_process_and_parents(struct pid_stat *p, unsigned long long time) {
+static inline int print_process_and_parents(struct pid_stat *p, unsigned long long time) {
     char *prefix = "\\_ ";
     int indent = 0;
 
@@ -1313,13 +1274,13 @@ int print_process_and_parents(struct pid_stat *p, unsigned long long time) {
     return indent + 1;
 }
 
-void print_process_tree(struct pid_stat *p, char *msg) {
+static inline void print_process_tree(struct pid_stat *p, char *msg) {
     log_date(stderr);
     fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited");
     print_process_and_parents(p, p->stat_collected_usec);
 }
 
-void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) {
+static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) {
     int found = 0;
     struct pid_stat *p = NULL;
 
@@ -1333,14 +1294,14 @@ void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int typ
                     found++;
                 }
                 break;
-                
+
             case 2:
                 if(p->cmajflt > lost) {
                     fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
                     found++;
                 }
                 break;
-                
+
             case 3:
                 if(p->cutime > lost) {
                     fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
@@ -1369,11 +1330,11 @@ void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int typ
             case 1:
                 fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
                 break;
-                
+
             case 2:
                 fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
                 break;
-                
+
             case 3:
                 fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
                 break;
@@ -1389,7 +1350,7 @@ void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int typ
     }
 }
 
-unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) {
+static inline unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) {
     unsigned long long absorbed = 0;
 
     if(*field > *pfield) {
@@ -1406,7 +1367,7 @@ unsigned long long remove_exited_child_from_parent(unsigned long long *field, un
     return absorbed;
 }
 
-void process_exited_processes() {
+static inline void process_exited_processes() {
     struct pid_stat *p;
 
     for(p = root_of_pids; p ; p = p->next) {
@@ -1499,11 +1460,11 @@ void process_exited_processes() {
                         );
             }
 
-            p->utime_raw   = utime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-            p->stime_raw   = stime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-            p->gtime_raw   = gtime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-            p->minflt_raw  = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-            p->majflt_raw  = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
+            p->utime_raw   = utime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL);
+            p->stime_raw   = stime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL);
+            p->gtime_raw   = gtime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL);
+            p->minflt_raw  = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL);
+            p->majflt_raw  = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL);
             p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0;
 
             if(unlikely(debug))
@@ -1519,7 +1480,7 @@ void process_exited_processes() {
     }
 }
 
-void link_all_processes_to_their_parents(void) {
+static inline void link_all_processes_to_their_parents(void) {
     struct pid_stat *p, *pp;
 
     // link all children to their parents
@@ -1588,19 +1549,19 @@ static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
                 p->log_thrown |= log;
                 switch(log) {
                     case PID_LOG_IO:
-                        error("Cannot process %s/proc/%d/io (command '%s')", host_prefix, p->pid, p->comm);
+                        error("Cannot process %s/proc/%d/io (command '%s')", global_host_prefix, p->pid, p->comm);
                         break;
 
                     case PID_LOG_STATM:
-                        error("Cannot process %s/proc/%d/statm (command '%s')", host_prefix, p->pid, p->comm);
+                        error("Cannot process %s/proc/%d/statm (command '%s')", global_host_prefix, p->pid, p->comm);
                         break;
 
                     case PID_LOG_CMDLINE:
-                        error("Cannot process %s/proc/%d/cmdline (command '%s')", host_prefix, p->pid, p->comm);
+                        error("Cannot process %s/proc/%d/cmdline (command '%s')", global_host_prefix, p->pid, p->comm);
                         break;
 
                     case PID_LOG_FDS:
-                        error("Cannot process entries in %s/proc/%d/fd (command '%s')", host_prefix, p->pid, p->comm);
+                        error("Cannot process entries in %s/proc/%d/fd (command '%s')", global_host_prefix, p->pid, p->comm);
                         break;
 
                     case PID_LOG_STAT:
@@ -1622,15 +1583,15 @@ static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
     return status;
 }
 
-void collect_data_for_pid(pid_t pid) {
+static inline int collect_data_for_pid(pid_t pid) {
     if(unlikely(pid <= 0 || pid > pid_max)) {
         error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
-        return;
+        return 0;
     }
 
     struct pid_stat *p = get_pid_entry(pid);
-    if(unlikely(!p || p->read)) return;
-    p->read             = 1;
+    if(unlikely(!p || p->read)) return 0;
+    p->read = 1;
 
     // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist);
 
@@ -1639,7 +1600,7 @@ void collect_data_for_pid(pid_t pid) {
 
     if(unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p))))
         // there is no reason to proceed if we cannot get its status
-        return;
+        return 0;
 
     read_proc_pid_ownership(p);
 
@@ -1659,7 +1620,7 @@ void collect_data_for_pid(pid_t pid) {
 
     if(unlikely(!managed_log(p, PID_LOG_STATM, read_proc_pid_statm(p))))
         // there is no reason to proceed if we cannot get its memory status
-        return;
+        return 0;
 
     // --------------------------------------------------------------------
     // link it
@@ -1705,7 +1666,8 @@ void collect_data_for_pid(pid_t pid) {
     // --------------------------------------------------------------------
     // /proc/<pid>/fd
 
-    managed_log(p, PID_LOG_FDS, read_pid_file_descriptors(p));
+    if(enable_file_charts)
+            managed_log(p, PID_LOG_FDS, read_pid_file_descriptors(p));
 
     // --------------------------------------------------------------------
     // done!
@@ -1717,9 +1679,11 @@ void collect_data_for_pid(pid_t pid) {
     p->updated = 1;
     p->keep = 0;
     p->keeploops = 0;
+
+    return 1;
 }
 
-int collect_data_for_all_processes_from_proc(void) {
+static int collect_data_for_all_processes_from_proc(void) {
     struct pid_stat *p = NULL;
 
     if(all_pids_count) {
@@ -1755,7 +1719,7 @@ int collect_data_for_all_processes_from_proc(void) {
 
     char dirname[FILENAME_MAX + 1];
 
-    snprintfz(dirname, FILENAME_MAX, "%s/proc", host_prefix);
+    snprintfz(dirname, FILENAME_MAX, "%s/proc", global_host_prefix);
     DIR *dir = opendir(dirname);
     if(!dir) return 0;
 
@@ -1773,6 +1737,9 @@ int collect_data_for_all_processes_from_proc(void) {
     }
     closedir(dir);
 
+    if(!all_pids_count)
+        return 0;
+
     // normally this is done
     // however we may have processes exited while we collected values
     // so let's find the exited ones
@@ -1802,7 +1769,7 @@ int collect_data_for_all_processes_from_proc(void) {
 // 9. find the unique file count for each target
 // check: update_apps_groups_statistics()
 
-void cleanup_exited_pids(void) {
+static void cleanup_exited_pids(void) {
     int c;
     struct pid_stat *p = NULL;
 
@@ -1830,7 +1797,7 @@ void cleanup_exited_pids(void) {
     }
 }
 
-void apply_apps_groups_targets_inheritance(void) {
+static void apply_apps_groups_targets_inheritance(void) {
     struct pid_stat *p = NULL;
 
     // children that do not have a target
@@ -1940,7 +1907,7 @@ void apply_apps_groups_targets_inheritance(void) {
         fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
 }
 
-long zero_all_targets(struct target *root) {
+static long zero_all_targets(struct target *root) {
     struct target *w;
     long count = 0;
 
@@ -1961,30 +1928,30 @@ long zero_all_targets(struct target *root) {
         w->cstime = 0;
         w->cgtime = 0;
         w->num_threads = 0;
-        w->rss = 0;
+        // w->rss = 0;
         w->processes = 0;
 
         w->statm_size = 0;
         w->statm_resident = 0;
         w->statm_share = 0;
-        w->statm_text = 0;
-        w->statm_lib = 0;
-        w->statm_data = 0;
-        w->statm_dirty = 0;
+        // w->statm_text = 0;
+        // w->statm_lib = 0;
+        // w->statm_data = 0;
+        // w->statm_dirty = 0;
 
         w->io_logical_bytes_read = 0;
         w->io_logical_bytes_written = 0;
-        w->io_read_calls = 0;
-        w->io_write_calls = 0;
+        // w->io_read_calls = 0;
+        // w->io_write_calls = 0;
         w->io_storage_bytes_read = 0;
         w->io_storage_bytes_written = 0;
-        w->io_cancelled_write_bytes = 0;
+        // w->io_cancelled_write_bytes = 0;
     }
 
     return count;
 }
 
-void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
+static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
     (void)o;
 
     if(unlikely(!w->fds))
@@ -2003,23 +1970,23 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
         w->minflt += p->minflt;
         w->majflt += p->majflt;
 
-        w->rss += p->rss;
+        // w->rss += p->rss;
 
         w->statm_size += p->statm_size;
         w->statm_resident += p->statm_resident;
         w->statm_share += p->statm_share;
-        w->statm_text += p->statm_text;
-        w->statm_lib += p->statm_lib;
-        w->statm_data += p->statm_data;
-        w->statm_dirty += p->statm_dirty;
+        // w->statm_text += p->statm_text;
+        // w->statm_lib += p->statm_lib;
+        // w->statm_data += p->statm_data;
+        // w->statm_dirty += p->statm_dirty;
 
         w->io_logical_bytes_read    += p->io_logical_bytes_read;
         w->io_logical_bytes_written += p->io_logical_bytes_written;
-        w->io_read_calls            += p->io_read_calls;
-        w->io_write_calls           += p->io_write_calls;
+        // w->io_read_calls            += p->io_read_calls;
+        // w->io_write_calls           += p->io_write_calls;
         w->io_storage_bytes_read    += p->io_storage_bytes_read;
         w->io_storage_bytes_written += p->io_storage_bytes_written;
-        w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
+        // w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
 
         w->processes++;
         w->num_threads += p->num_threads;
@@ -2042,7 +2009,7 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
     }
 }
 
-void count_targets_fds(struct target *root) {
+static inline void count_targets_fds(struct target *root) {
     int c;
     struct target *w;
 
@@ -2104,7 +2071,7 @@ void count_targets_fds(struct target *root) {
     }
 }
 
-void calculate_netdata_statistics(void) {
+static void calculate_netdata_statistics(void) {
     apply_apps_groups_targets_inheritance();
 
     zero_all_targets(users_root_target);
@@ -2204,38 +2171,38 @@ static inline void send_END(void) {
 double utime_fix_ratio = 1.0, stime_fix_ratio = 1.0, gtime_fix_ratio = 1.0, cutime_fix_ratio = 1.0, cstime_fix_ratio = 1.0, cgtime_fix_ratio = 1.0;
 double minflt_fix_ratio = 1.0, majflt_fix_ratio = 1.0, cminflt_fix_ratio = 1.0, cmajflt_fix_ratio = 1.0;
 
-unsigned long long send_resource_usage_to_netdata() {
+static usec_t send_resource_usage_to_netdata() {
     static struct timeval last = { 0, 0 };
     static struct rusage me_last;
 
     struct timeval now;
     struct rusage me;
 
-    unsigned long long usec;
-    unsigned long long cpuuser;
-    unsigned long long cpusyst;
+    usec_t usec;
+    usec_t cpuuser;
+    usec_t cpusyst;
 
     if(!last.tv_sec) {
-        gettimeofday(&last, NULL);
+        now_realtime_timeval(&last);
         getrusage(RUSAGE_SELF, &me_last);
 
         // the first time, give a zero to allow
         // netdata calibrate to the current time
-        // usec = update_every * 1000000ULL;
+        // usec = update_every * USEC_PER_SEC;
         usec = 0ULL;
         cpuuser = 0;
         cpusyst = 0;
     }
     else {
-        gettimeofday(&now, NULL);
+        now_realtime_timeval(&now);
         getrusage(RUSAGE_SELF, &me);
 
-        usec = usec_dt(&now, &last);
-        cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec;
-        cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec;
+        usec = dt_usec(&now, &last);
+        cpuuser = me.ru_utime.tv_sec * USEC_PER_SEC + me.ru_utime.tv_usec;
+        cpusyst = me.ru_stime.tv_sec * USEC_PER_SEC + me.ru_stime.tv_usec;
 
-        bcopy(&now, &last, sizeof(struct timeval));
-        bcopy(&me, &me_last, sizeof(struct rusage));
+        memmove(&last, &now, sizeof(struct timeval));
+        memmove(&me_last, &me, sizeof(struct rusage));
     }
 
     buffer_sprintf(output,
@@ -2292,7 +2259,7 @@ unsigned long long send_resource_usage_to_netdata() {
     return usec;
 }
 
-void normalize_data(struct target *root) {
+static void normalize_data(struct target *root) {
     struct target *w;
 
     // childs processing introduces spikes
@@ -2438,7 +2405,7 @@ void normalize_data(struct target *root) {
     }
 }
 
-void send_collected_data_to_netdata(struct target *root, const char *type, unsigned long long usec) {
+static void send_collected_data_to_netdata(struct target *root, const char *type, usec_t usec) {
     struct target *w;
 
     send_BEGIN(type, "cpu", usec);
@@ -2492,6 +2459,13 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
     }
     send_END();
 
+    send_BEGIN(type, "vmem", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->statm_size);
+    }
+    send_END();
+
     send_BEGIN(type, "minor_faults", usec);
     for (w = root; w ; w = w->next) {
         if(unlikely(w->exposed))
@@ -2534,33 +2508,35 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
     }
     send_END();
 
-    send_BEGIN(type, "files", usec);
-    for (w = root; w ; w = w->next) {
-        if(unlikely(w->exposed))
-            send_SET(w->name, w->openfiles);
-    }
-    send_END();
+    if(enable_file_charts) {
+        send_BEGIN(type, "files", usec);
+        for (w = root; w; w = w->next) {
+            if (unlikely(w->exposed))
+                send_SET(w->name, w->openfiles);
+        }
+        send_END();
 
-    send_BEGIN(type, "sockets", usec);
-    for (w = root; w ; w = w->next) {
-        if(unlikely(w->exposed))
-            send_SET(w->name, w->opensockets);
-    }
-    send_END();
+        send_BEGIN(type, "sockets", usec);
+        for (w = root; w; w = w->next) {
+            if (unlikely(w->exposed))
+                send_SET(w->name, w->opensockets);
+        }
+        send_END();
 
-    send_BEGIN(type, "pipes", usec);
-    for (w = root; w ; w = w->next) {
-        if(unlikely(w->exposed))
-            send_SET(w->name, w->openpipes);
+        send_BEGIN(type, "pipes", usec);
+        for (w = root; w; w = w->next) {
+            if (unlikely(w->exposed))
+                send_SET(w->name, w->openpipes);
+        }
+        send_END();
     }
-    send_END();
 }
 
 
 // ----------------------------------------------------------------------------
 // generate the charts
 
-void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title)
+static void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title)
 {
     struct target *w;
     int newly_added = 0;
@@ -2586,7 +2562,13 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
             buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
     }
 
-    buffer_sprintf(output, "CHART %s.mem '' '%s Dedicated Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
+    buffer_sprintf(output, "CHART %s.mem '' '%s Real Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
+    }
+
+    buffer_sprintf(output, "CHART %s.vmem '' '%s Virtual Memory Size' 'MB' mem %s.vmem stacked 20004 %d\n", type, title, type, update_every);
     for (w = root; w ; w = w->next) {
         if(unlikely(w->exposed))
             buffer_sprintf(output, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
@@ -2660,22 +2642,27 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
             buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
     }
 
-    buffer_sprintf(output, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type, title, type, update_every);
-    for (w = root; w ; w = w->next) {
-        if(unlikely(w->exposed))
-            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
-    }
+    if(enable_file_charts) {
+        buffer_sprintf(output, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type,
+                       title, type, update_every);
+        for (w = root; w; w = w->next) {
+            if (unlikely(w->exposed))
+                buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+        }
 
-    buffer_sprintf(output, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n", type, title, type, update_every);
-    for (w = root; w ; w = w->next) {
-        if(unlikely(w->exposed))
-            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
-    }
+        buffer_sprintf(output, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n",
+                       type, title, type, update_every);
+        for (w = root; w; w = w->next) {
+            if (unlikely(w->exposed))
+                buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+        }
 
-    buffer_sprintf(output, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type, title, type, update_every);
-    for (w = root; w ; w = w->next) {
-        if(unlikely(w->exposed))
-            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+        buffer_sprintf(output, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type,
+                       title, type, update_every);
+        for (w = root; w; w = w->next) {
+            if (unlikely(w->exposed))
+                buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+        }
     }
 }
 
@@ -2683,20 +2670,25 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
 // ----------------------------------------------------------------------------
 // parse command line arguments
 
-void parse_args(int argc, char **argv)
+static void parse_args(int argc, char **argv)
 {
     int i, freq = 0;
     char *name = NULL;
 
     for(i = 1; i < argc; i++) {
         if(!freq) {
-            int n = atoi(argv[i]);
+            int n = (int)str2l(argv[i]);
             if(n > 0) {
                 freq = n;
                 continue;
             }
         }
 
+        if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0) {
+            printf("apps.plugin %s\n", VERSION);
+            exit(0);
+        }
+
         if(strcmp("debug", argv[i]) == 0) {
             debug = 1;
             // debug_flags = 0xffffffff;
@@ -2723,9 +2715,29 @@ void parse_args(int argc, char **argv)
             continue;
         }
 
+        if(strcmp("with-files", argv[i]) == 0) {
+            enable_file_charts = 1;
+            continue;
+        }
+
+        if(strcmp("no-files", argv[i]) == 0 || strcmp("without-files", argv[i]) == 0) {
+            enable_file_charts = 0;
+            continue;
+        }
+
+        if(strcmp("no-users", argv[i]) == 0 || strcmp("without-users", argv[i]) == 0) {
+            enable_users_charts = 0;
+            continue;
+        }
+
+        if(strcmp("no-groups", argv[i]) == 0 || strcmp("without-groups", argv[i]) == 0) {
+            enable_groups_charts = 0;
+            continue;
+        }
+
         if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
             fprintf(stderr,
-                    "apps.plugin\n"
+                    "apps.plugin %s\n"
                     "(C) 2016 Costa Tsaousis"
                     "GPL v3+\n"
                     "This program is a data collector plugin for netdata.\n"
@@ -2745,9 +2757,17 @@ void parse_args(int argc, char **argv)
                     "without-guest     enable / disable reporting guest charts\n"
                     "                  (default is disabled)\n"
                     "\n"
+                    "with-files\n"
+                    "without-files     enable / disable reporting files, sockets, pipes\n"
+                    "                  (default is enabled)\n"
+                    "\n"
                     "NAME              read apps_NAME.conf instead of\n"
                     "                  apps_groups.conf\n"
                     "                  (default NAME=groups)\n"
+                    "\n"
+                    "version           print program version and exit\n"
+                    "\n"
+                    , VERSION
             );
             exit(1);
         }
@@ -2765,7 +2785,7 @@ void parse_args(int argc, char **argv)
     if(!name) name = "groups";
 
     if(read_apps_groups_conf(name)) {
-        error("Cannot read process groups %s", name);
+        error("Cannot read process groups '%s/apps_%s.conf'. There are no internal defaults. Failing.", config_dir, name);
         exit(1);
     }
 }
@@ -2786,12 +2806,12 @@ int main(int argc, char **argv)
     error_log_errors_per_period = 100;
     error_log_throttle_period = 3600;
 
-    host_prefix = getenv("NETDATA_HOST_PREFIX");
-    if(host_prefix == NULL) {
+    global_host_prefix = getenv("NETDATA_HOST_PREFIX");
+    if(global_host_prefix == NULL) {
         // info("NETDATA_HOST_PREFIX is not passed from netdata");
-        host_prefix = "";
+        global_host_prefix = "";
     }
-    // else info("Found NETDATA_HOST_PREFIX='%s'", host_prefix);
+    // else info("Found NETDATA_HOST_PREFIX='%s'", global_host_prefix);
 
     config_dir = getenv("NETDATA_CONFIG_DIR");
     if(config_dir == NULL) {
@@ -2811,11 +2831,10 @@ int main(int argc, char **argv)
 
     procfile_adaptive_initial_allocation = 1;
 
-    time_t started_t = time(NULL);
-    time_t current_t;
-    get_HZ();
-    pid_max = get_system_pid_max();
-    processors = get_system_cpus();
+    time_t started_t = now_realtime_sec();
+    get_system_HZ();
+    get_system_pid_max();
+    get_system_cpus();
 
     parse_args(argc, argv);
 
@@ -2854,22 +2873,16 @@ int main(int argc, char **argv)
             , RATES_DETAIL
             );
 
-#ifndef PROFILING_MODE
-    unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL;
-    unsigned long long sunow;
-#endif /* PROFILING_MODE */
-
+    usec_t step = update_every * USEC_PER_SEC;
     global_iterations_counter = 1;
     for(;1; global_iterations_counter++) {
-#ifndef PROFILING_MODE
-        // delay until it is our time to run
-        while((sunow = time_usec()) < sunext)
-            sleep_usec(sunext - sunow);
+        usec_t now = now_realtime_usec();
+        usec_t next = now - (now % step) + step;
 
-        // find the next time we need to run
-        while(time_usec() > sunext)
-            sunext += update_every * 1000000ULL;
-#endif /* PROFILING_MODE */
+        while(now < next) {
+            sleep_usec(next - now);
+            now = now_realtime_usec();
+        }
 
         if(!collect_data_for_all_processes_from_proc()) {
             error("Cannot collect /proc data for running processes. Disabling apps.plugin...");
@@ -2880,20 +2893,27 @@ int main(int argc, char **argv)
         calculate_netdata_statistics();
         normalize_data(apps_groups_root_target);
 
-        unsigned long long dt = send_resource_usage_to_netdata();
+        usec_t dt = send_resource_usage_to_netdata();
 
         // this is smart enough to show only newly added apps, when needed
         send_charts_updates_to_netdata(apps_groups_root_target, "apps", "Apps");
-        send_charts_updates_to_netdata(users_root_target, "users", "Users");
-        send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups");
+
+        if(likely(enable_users_charts))
+            send_charts_updates_to_netdata(users_root_target, "users", "Users");
+
+        if(likely(enable_groups_charts))
+            send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups");
 
         send_collected_data_to_netdata(apps_groups_root_target, "apps", dt);
-        send_collected_data_to_netdata(users_root_target, "users", dt);
-        send_collected_data_to_netdata(groups_root_target, "groups", dt);
+
+        if(likely(enable_users_charts))
+            send_collected_data_to_netdata(users_root_target, "users", dt);
+
+        if(likely(enable_groups_charts))
+            send_collected_data_to_netdata(groups_root_target, "groups", dt);
 
         show_guest_time_old = show_guest_time;
 
-        //if(puts(buffer_tostring(output)) == EOF)
         if(write(STDOUT_FILENO, buffer_tostring(output), buffer_strlen(output)) == -1)
             fatal("Cannot send chart values to netdata.");
 
@@ -2903,13 +2923,9 @@ int main(int argc, char **argv)
         if(unlikely(debug))
             fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter);
 
-        current_t = time(NULL);
+        time_t current_t = now_realtime_sec();
 
-#ifndef PROFILING_MODE
         // restart check (14400 seconds)
         if(current_t - started_t > 14400) exit(0);
-#else
-        if(current_t - started_t > 10) exit(0);
-#endif /* PROFILING_MODE */
     }
 }