]> arthur.barton.de Git - netdata.git/blobdiff - src/apps_plugin.c
apps.plugin optimization to eliminate several unneeded calls
[netdata.git] / src / apps_plugin.c
index d9167b5ae2c0d650a32209dbc211133d7c10fee6..20ebb3f846ca095c664ad5dcbe2701fcecef1faa 100644 (file)
@@ -13,6 +13,8 @@
 // etc.
 #define RATES_DETAIL 10000ULL
 
+#define MAX_SPARE_FDS 1
+
 int debug = 0;
 
 int update_every = 1;
@@ -86,7 +88,9 @@ struct target {
     unsigned long long io_storage_bytes_written;
     // unsigned long long io_cancelled_write_bytes;
 
-    int *fds;
+    int *target_fds;
+    int target_fds_size;
+
     unsigned long long openfiles;
     unsigned long long openpipes;
     unsigned long long opensockets;
@@ -471,6 +475,8 @@ struct pid_stat {
     unsigned long long io_collected_usec;
     unsigned long long last_io_collected_usec;
 
+    char *fds_dirname;              // the full directory name in /proc/PID/fd
+
     char *stat_filename;
     char *statm_filename;
     char *io_filename;
@@ -490,8 +496,8 @@ static inline struct pid_stat *get_pid_entry(pid_t pid) {
     }
 
     all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
-    all_pids[pid]->fds = callocz(sizeof(int), 100);
-    all_pids[pid]->fds_size = 100;
+    all_pids[pid]->fds = callocz(sizeof(int), MAX_SPARE_FDS);
+    all_pids[pid]->fds_size = MAX_SPARE_FDS;
 
     if(root_of_pids) root_of_pids->prev = all_pids[pid];
     all_pids[pid]->next = root_of_pids;
@@ -518,11 +524,12 @@ static inline void del_pid_entry(pid_t pid) {
     if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
     if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
 
-    if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
-    if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
-    if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
-    if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
-    if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
+    freez(all_pids[pid]->fds);
+    freez(all_pids[pid]->fds_dirname);
+    freez(all_pids[pid]->stat_filename);
+    freez(all_pids[pid]->statm_filename);
+    freez(all_pids[pid]->io_filename);
+    freez(all_pids[pid]->cmdline_filename);
     freez(all_pids[pid]);
 
     all_pids[pid] = NULL;
@@ -600,7 +607,8 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
     if(unlikely(!ff)) goto cleanup;
 
     // if(set_quotes) procfile_set_quotes(ff, "()");
-    if(set_quotes) procfile_set_open_close(ff, "(", ")");
+    if(unlikely(set_quotes))
+        procfile_set_open_close(ff, "(", ")");
 
     ff = procfile_readall(ff);
     if(unlikely(!ff)) goto cleanup;
@@ -611,7 +619,8 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
 
     // p->pid           = str2ul(procfile_lineword(ff, 0, 0+i));
 
-    strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
+    if(unlikely(!p->comm[0]))
+        strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
 
     // p->state         = *(procfile_lineword(ff, 0, 2));
     p->ppid             = (int32_t)str2ul(procfile_lineword(ff, 0, 3));
@@ -1019,70 +1028,60 @@ static inline 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);
 }
 
-static inline int file_descriptor_find_or_add(const char *name)
-{
-    static int last_pos = 0;
-    uint32_t hash = simple_hash(name);
+static inline void all_files_grow() {
+    void *old = all_files;
+    int i;
 
+    // there is no empty slot
     if(unlikely(debug))
-        fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
+        fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
 
-    struct file_descriptor *fd = file_descriptor_find(name, hash);
-    if(fd) {
-        // found
-        if(unlikely(debug))
-            fprintf(stderr, "apps.plugin:   >> found on slot %d\n", fd->pos);
+    all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
 
-        fd->count++;
-        return fd->pos;
-    }
-    // not found
+    // if the address changed, we have to rebuild the index
+    // since all pointers are now invalid
 
-    // check we have enough memory to add it
-    if(!all_files || all_files_len == all_files_size) {
-        void *old = all_files;
-        int i;
-
-        // there is no empty slot
+    if(unlikely(old && old != (void *)all_files)) {
         if(unlikely(debug))
-            fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
+            fprintf(stderr, "apps.plugin:   >> re-indexing.\n");
 
-        all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
+        all_files_index.root = NULL;
+        for(i = 0; i < all_files_size; i++) {
+            if(!all_files[i].count) continue;
+            if(unlikely(file_descriptor_add(&all_files[i]) != (void *)&all_files[i]))
+                error("INTERNAL ERROR: duplicate indexing of fd during realloc.");
+        }
 
-        // if the address changed, we have to rebuild the index
-        // since all pointers are now invalid
-        if(old && old != (void *)all_files) {
-            if(unlikely(debug))
-                fprintf(stderr, "apps.plugin:   >> re-indexing.\n");
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin:   >> re-indexing done.\n");
+    }
 
-            all_files_index.root = NULL;
-            for(i = 0; i < all_files_size; i++) {
-                if(!all_files[i].count) continue;
-                if(unlikely(file_descriptor_add(&all_files[i]) != (void *)&all_files[i]))
-                    error("INTERNAL ERROR: duplicate indexing of fd during realloc.");
-            }
+    // initialize the newly added entries
 
-            if(unlikely(debug))
-                fprintf(stderr, "apps.plugin:   >> re-indexing done.\n");
-        }
-
-        for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
-            all_files[i].count = 0;
-            all_files[i].name = NULL;
+    for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
+        all_files[i].count = 0;
+        all_files[i].name = NULL;
 #ifdef NETDATA_INTERNAL_CHECKS
-            all_files[i].magic = 0x00000000;
+        all_files[i].magic = 0x00000000;
 #endif /* NETDATA_INTERNAL_CHECKS */
-            all_files[i].pos = i;
-        }
-
-        if(!all_files_size) all_files_len = 1;
-        all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
+        all_files[i].pos = i;
     }
 
+    if(unlikely(!all_files_size)) all_files_len = 1;
+    all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
+}
+
+static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t hash, int type) {
+    // check we have enough memory to add it
+    if(!all_files || all_files_len == all_files_size)
+        all_files_grow();
+
     if(unlikely(debug))
         fprintf(stderr, "apps.plugin:   >> searching for empty slot.\n");
 
     // search for an empty slot
+
+    static int last_pos = 0;
     int i, c;
     for(i = 0, c = last_pos ; i < all_files_size ; i++, c++) {
         if(c >= all_files_size) c = 0;
@@ -1100,23 +1099,58 @@ static inline int file_descriptor_find_or_add(const char *name)
             if(unlikely(debug))
                 fprintf(stderr, "apps.plugin:   >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
 
-            if(all_files[c].name) freez((void *)all_files[c].name);
+            freez((void *)all_files[c].name);
             all_files[c].name = NULL;
             last_pos = c;
             break;
         }
     }
+
+    all_files_len++;
+
     if(i == all_files_size) {
         fatal("We should find an empty slot, but there isn't any");
         exit(1);
     }
+    // else we have an empty slot in 'c'
 
     if(unlikely(debug))
         fprintf(stderr, "apps.plugin:   >> updating slot %d.\n", c);
 
-    all_files_len++;
+    all_files[c].name = strdupz(name);
+    all_files[c].hash = hash;
+    all_files[c].type = type;
+    all_files[c].pos  = c;
+    all_files[c].count = 1;
+#ifdef NETDATA_INTERNAL_CHECKS
+    all_files[c].magic = 0x0BADCAFE;
+#endif /* NETDATA_INTERNAL_CHECKS */
+    if(unlikely(file_descriptor_add(&all_files[c]) != (void *)&all_files[c]))
+        error("INTERNAL ERROR: duplicate indexing of fd.");
 
-    // else we have an empty slot in 'c'
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
+
+    return c;
+}
+
+static inline int file_descriptor_find_or_add(const char *name)
+{
+    uint32_t hash = simple_hash(name);
+
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
+
+    struct file_descriptor *fd = file_descriptor_find(name, hash);
+    if(fd) {
+        // found
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin:   >> found on slot %d\n", fd->pos);
+
+        fd->count++;
+        return fd->pos;
+    }
+    // not found
 
     int type;
     if(name[0] == '/') type = FILETYPE_FILE;
@@ -1140,95 +1174,109 @@ static inline int file_descriptor_find_or_add(const char *name)
         type = FILETYPE_OTHER;
     }
 
-    all_files[c].name = strdupz(name);
-    all_files[c].hash = hash;
-    all_files[c].type = type;
-    all_files[c].pos  = c;
-    all_files[c].count = 1;
-#ifdef NETDATA_INTERNAL_CHECKS
-    all_files[c].magic = 0x0BADCAFE;
-#endif /* NETDATA_INTERNAL_CHECKS */
-    if(unlikely(file_descriptor_add(&all_files[c]) != (void *)&all_files[c]))
-        error("INTERNAL ERROR: duplicate indexing of fd.");
+    return file_descriptor_set_on_empty_slot(name, hash, type);
+}
 
-    if(unlikely(debug))
-        fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
+static inline void make_all_pid_fds_negative(struct pid_stat *p) {
+    int *fd = p->fds, *end = &p->fds[p->fds_size];
+    while(fd < end) {
+        *fd = -(*fd);
+        fd++;
+    }
+}
 
-    return c;
+static inline void cleanup_negative_pid_fds(struct pid_stat *p) {
+    int *fd = p->fds, *end = &p->fds[p->fds_size];
+    while(fd < end) {
+        if(unlikely(*fd < 0)) {
+            file_descriptor_not_used(-(*fd));
+            *fd++ = 0;
+        }
+        else
+            fd++;
+    }
+}
+
+static inline void zero_pid_fds(struct pid_stat *p, int first, int size) {
+    int *fd = &p->fds[first], *end = &p->fds[first + size];
+    while(fd < end) *fd++ = 0;
 }
 
 static inline int read_pid_file_descriptors(struct pid_stat *p) {
-    char dirname[FILENAME_MAX+1];
-
-    snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid);
-    DIR *fds = opendir(dirname);
-    if(fds) {
-        int c;
-        struct dirent *de;
-        char fdname[FILENAME_MAX + 1];
-        char linkname[FILENAME_MAX + 1];
-
-        // make the array negative
-        for(c = 0 ; c < p->fds_size ; c++)
-            p->fds[c] = -p->fds[c];
-
-        while((de = readdir(fds))) {
-            if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-                continue;
+    if(unlikely(!p->fds_dirname)) {
+        char dirname[FILENAME_MAX+1];
+        snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid);
+        p->fds_dirname = strdupz(dirname);
+    }
 
-            // check if the fds array is small
-            int fdid = (int)str2l(de->d_name);
-            if(fdid < 0) continue;
-            if(fdid >= p->fds_size) {
-                // it is small, extend it
-                if(unlikely(debug))
-                    fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
+    DIR *fds = opendir(p->fds_dirname);
+    if(unlikely(!fds)) return 0;
 
-                p->fds = reallocz(p->fds, (fdid + 100) * sizeof(int));
-                if(!p->fds) {
-                    fatal("Cannot re-allocate fds for %s", p->comm);
-                    break;
-                }
+    struct dirent *de;
+    char fdname[FILENAME_MAX + 1];
+    char linkname[FILENAME_MAX + 1];
 
-                // and initialize it
-                for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0;
-                p->fds_size = fdid + 100;
-            }
+    // we make all pid fds negative, so that
+    // we can detect unused file descriptors
+    // at the end, to free them
+    make_all_pid_fds_negative(p);
+
+    while((de = readdir(fds))) {
+        // we need only files with numeric names
+
+        if(unlikely(de->d_name[0] < '0' || de->d_name[0] > '9'))
+            continue;
+
+        // get its number
+        int fdid = (int)str2l(de->d_name);
+        if(unlikely(fdid < 0)) continue;
+
+        // check if the fds array is small
+        if(unlikely(fdid >= p->fds_size)) {
+            // it is small, extend it
 
-            if(p->fds[fdid] == 0) {
-                // we don't know this fd, get it
-
-                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)) {
-                        if(debug || (p->target && p->target->debug))
-                            error("Cannot read link %s", fdname);
-                    }
-                    continue;
+            if(unlikely(debug))
+                fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
+
+            p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
+
+            // and initialize it
+            zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
+            p->fds_size = fdid + MAX_SPARE_FDS;
+        }
+
+        if(unlikely(p->fds[fdid] == 0)) {
+            // we don't know this fd, get it
+
+            sprintf(fdname, "%s/proc/%d/fd/%s", global_host_prefix, p->pid, de->d_name);
+            ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
+            if(unlikely(l == -1)) {
+                if(debug || (p->target && p->target->debug)) {
+                    if(debug || (p->target && p->target->debug))
+                        error("Cannot read link %s", fdname);
                 }
+                continue;
+            }
+            else
                 linkname[l] = '\0';
-                file_counter++;
 
-                // if another process already has this, we will get
-                // the same id
-                p->fds[fdid] = file_descriptor_find_or_add(linkname);
-            }
+            file_counter++;
 
-            // else make it positive again, we need it
-            // of course, the actual file may have changed, but we don't care so much
-            // FIXME: we could compare the inode as returned by readdir dirent structure
-            else p->fds[fdid] = -p->fds[fdid];
+            // if another process already has this, we will get
+            // the same id
+            p->fds[fdid] = file_descriptor_find_or_add(linkname);
         }
-        closedir(fds);
 
-        // remove all the negative file descriptors
-        for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
-            file_descriptor_not_used(-p->fds[c]);
-            p->fds[c] = 0;
-        }
+        // else make it positive again, we need it
+        // of course, the actual file may have changed, but we don't care so much
+        // FIXME: we could compare the inode as returned by readdir dirent structure
+
+        else
+            p->fds[fdid] = -p->fds[fdid];
     }
-    else return 0;
+
+    closedir(fds);
+    cleanup_negative_pid_fds(p);
 
     return 1;
 }
@@ -1583,6 +1631,37 @@ static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
     return status;
 }
 
+static inline void assign_target_to_pid(struct pid_stat *p) {
+    uint32_t hash = simple_hash(p->comm);
+    size_t pclen  = strlen(p->comm);
+
+    struct target *w;
+    for(w = apps_groups_root_target; w ; w = w->next) {
+        // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
+
+        // find it - 4 cases:
+        // 1. the target is not a pattern
+        // 2. the target has the prefix
+        // 3. the target has the suffix
+        // 4. the target is something inside cmdline
+
+        if(unlikely(( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
+            || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
+            || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
+            || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
+                ))) {
+
+            if(w->target) p->target = w->target;
+            else p->target = w;
+
+            if(debug || (p->target && p->target->debug))
+                fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
+
+            break;
+        }
+    }
+}
+
 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);
@@ -1635,32 +1714,7 @@ static inline int collect_data_for_pid(pid_t pid) {
         if(unlikely(debug))
             fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
 
-        uint32_t hash = simple_hash(p->comm);
-        size_t pclen  = strlen(p->comm);
-
-        struct target *w;
-        for(w = apps_groups_root_target; w ; w = w->next) {
-            // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
-
-            // find it - 4 cases:
-            // 1. the target is not a pattern
-            // 2. the target has the prefix
-            // 3. the target has the suffix
-            // 4. the target is something inside cmdline
-            if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
-                   || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
-                   || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
-                   || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
-                    ) {
-                if(w->target) p->target = w->target;
-                else p->target = w;
-
-                if(debug || (p->target && p->target->debug))
-                    fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
-
-                break;
-            }
-        }
+        assign_target_to_pid(p);
     }
 
     // --------------------------------------------------------------------
@@ -1711,7 +1765,7 @@ static int collect_data_for_all_processes_from_proc(void) {
         }
 
         if(include_exited_childs) {
-            qsort((void *)all_pids_sortlist, all_pids_count, sizeof(pid_t), compar_pid);
+            qsort((void *)all_pids_sortlist, (size_t)all_pids_count, sizeof(pid_t), compar_pid);
             for(slc = 0; slc < all_pids_count; slc++)
                 collect_data_for_pid(all_pids_sortlist[slc]);
         }
@@ -1914,9 +1968,6 @@ static long zero_all_targets(struct target *root) {
     for (w = root; w ; w = w->next) {
         count++;
 
-        if(w->fds) freez(w->fds);
-        w->fds = NULL;
-
         w->minflt = 0;
         w->majflt = 0;
         w->utime = 0;
@@ -1946,132 +1997,168 @@ static long zero_all_targets(struct target *root) {
         w->io_storage_bytes_read = 0;
         w->io_storage_bytes_written = 0;
         // w->io_cancelled_write_bytes = 0;
+
+        // zero file counters
+        if(w->target_fds) {
+            memset(w->target_fds, 0, sizeof(int) * w->target_fds_size);
+            w->openfiles = 0;
+            w->openpipes = 0;
+            w->opensockets = 0;
+            w->openinotifies = 0;
+            w->openeventfds = 0;
+            w->opentimerfds = 0;
+            w->opensignalfds = 0;
+            w->openeventpolls = 0;
+            w->openother = 0;
+        }
     }
 
     return count;
 }
 
-static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
-    (void)o;
+static inline void reallocate_target_fds(struct target *w) {
+    if(unlikely(!w))
+        return;
 
-    if(unlikely(!w->fds))
-        w->fds = callocz(sizeof(int), (size_t) all_files_size);
-
-    if(likely(p->updated)) {
-        w->cutime  += p->cutime;
-        w->cstime  += p->cstime;
-        w->cgtime  += p->cgtime;
-        w->cminflt += p->cminflt;
-        w->cmajflt += p->cmajflt;
-
-        w->utime  += p->utime;
-        w->stime  += p->stime;
-        w->gtime  += p->gtime;
-        w->minflt += p->minflt;
-        w->majflt += p->majflt;
-
-        // 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->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_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->processes++;
-        w->num_threads += p->num_threads;
-
-        if(likely(w->fds)) {
-            int c;
-            for(c = 0; c < p->fds_size ;c++) {
-                if(p->fds[c] == 0) continue;
-
-                if(likely(p->fds[c] < all_files_size)) {
-                    if(w->fds) w->fds[p->fds[c]]++;
-                }
-                else
-                    error("Invalid fd number %d", p->fds[c]);
-            }
-        }
+    if(unlikely(!w->target_fds || w->target_fds_size < all_files_size)) {
+        w->target_fds = reallocz(w->target_fds, sizeof(int) * all_files_size);
+        memset(&w->target_fds[w->target_fds_size], 0, sizeof(int) * (all_files_size - w->target_fds_size));
+        w->target_fds_size = all_files_size;
+    }
+}
+
+static inline void aggregate_fd_on_target(int fd, struct target *w) {
+    if(unlikely(!w))
+        return;
+
+    if(unlikely(w->target_fds[fd])) {
+        // it is already aggregated
+        // just increase its usage counter
+        w->target_fds[fd]++;
+        return;
+    }
+
+    // increase its usage counter
+    // so that we will not add it again
+    w->target_fds[fd]++;
+
+    switch(all_files[fd].type) {
+        case FILETYPE_FILE:
+            w->openfiles++;
+            break;
+
+        case FILETYPE_PIPE:
+            w->openpipes++;
+            break;
+
+        case FILETYPE_SOCKET:
+            w->opensockets++;
+            break;
+
+        case FILETYPE_INOTIFY:
+            w->openinotifies++;
+            break;
+
+        case FILETYPE_EVENTFD:
+            w->openeventfds++;
+            break;
 
-        if(unlikely(debug || w->debug))
-            fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+        case FILETYPE_TIMERFD:
+            w->opentimerfds++;
+            break;
+
+        case FILETYPE_SIGNALFD:
+            w->opensignalfds++;
+            break;
+
+        case FILETYPE_EVENTPOLL:
+            w->openeventpolls++;
+            break;
+
+        default:
+            w->openother++;
+            break;
     }
 }
 
-static inline void count_targets_fds(struct target *root) {
-    int c;
-    struct target *w;
+static inline void aggregate_pid_fds_on_targets(struct pid_stat *p) {
 
-    for (w = root; w ; w = w->next) {
-        if(!w->fds) continue;
-
-        w->openfiles = 0;
-        w->openpipes = 0;
-        w->opensockets = 0;
-        w->openinotifies = 0;
-        w->openeventfds = 0;
-        w->opentimerfds = 0;
-        w->opensignalfds = 0;
-        w->openeventpolls = 0;
-        w->openother = 0;
-
-        for(c = 1; c < all_files_size ;c++) {
-            if(w->fds[c] > 0)
-                switch(all_files[c].type) {
-                case FILETYPE_FILE:
-                    w->openfiles++;
-                    break;
-
-                case FILETYPE_PIPE:
-                    w->openpipes++;
-                    break;
-
-                case FILETYPE_SOCKET:
-                    w->opensockets++;
-                    break;
-
-                case FILETYPE_INOTIFY:
-                    w->openinotifies++;
-                    break;
-
-                case FILETYPE_EVENTFD:
-                    w->openeventfds++;
-                    break;
-
-                case FILETYPE_TIMERFD:
-                    w->opentimerfds++;
-                    break;
-
-                case FILETYPE_SIGNALFD:
-                    w->opensignalfds++;
-                    break;
-
-                case FILETYPE_EVENTPOLL:
-                    w->openeventpolls++;
-                    break;
-
-                default:
-                    w->openother++;
-            }
-        }
+    if(unlikely(!p->updated)) {
+        // the process is not running
+        return;
+    }
 
-        freez(w->fds);
-        w->fds = NULL;
+    struct target *w = p->target, *u = p->user_target, *g = p->group_target;
+
+    reallocate_target_fds(w);
+    reallocate_target_fds(u);
+    reallocate_target_fds(g);
+
+    int c, size = p->fds_size, *fds = p->fds;
+    for(c = 0; c < size ;c++) {
+        int fd = fds[c];
+
+        if(likely(fd <= 0 || fd >= all_files_size))
+            continue;
+
+        aggregate_fd_on_target(fd, w);
+        aggregate_fd_on_target(fd, u);
+        aggregate_fd_on_target(fd, g);
     }
 }
 
+static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
+    (void)o;
+
+    if(unlikely(!p->updated)) {
+        // the process is not running
+        return;
+    }
+
+    if(unlikely(!w)) {
+        error("pid %d %s was left without a target!", p->pid, p->comm);
+        return;
+    }
+
+    w->cutime  += p->cutime;
+    w->cstime  += p->cstime;
+    w->cgtime  += p->cgtime;
+    w->cminflt += p->cminflt;
+    w->cmajflt += p->cmajflt;
+
+    w->utime  += p->utime;
+    w->stime  += p->stime;
+    w->gtime  += p->gtime;
+    w->minflt += p->minflt;
+    w->majflt += p->majflt;
+
+    // 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->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_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->processes++;
+    w->num_threads += p->num_threads;
+
+    if(unlikely(debug || w->debug))
+        fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+}
+
 static void calculate_netdata_statistics(void) {
+
     apply_apps_groups_targets_inheritance();
 
     zero_all_targets(users_root_target);
@@ -2082,19 +2169,18 @@ static void calculate_netdata_statistics(void) {
     struct pid_stat *p = NULL;
     struct target *w = NULL, *o = NULL;
 
-    // concentrate everything on the apps_groups_targets
+    // concentrate everything on the targets
     for(p = root_of_pids; p ; p = p->next) {
 
         // --------------------------------------------------------------------
-        // apps_groups targets
-        if(likely(p->target))
-            aggregate_pid_on_target(p->target, p, NULL);
-        else
-            error("pid %d %s was left without a target!", p->pid, p->comm);
+        // apps_groups target
+
+        aggregate_pid_on_target(p->target, p, NULL);
 
 
         // --------------------------------------------------------------------
-        // user targets
+        // user target
+
         o = p->user_target;
         if(likely(p->user_target && p->user_target->uid == p->uid))
             w = p->user_target;
@@ -2105,14 +2191,12 @@ static void calculate_netdata_statistics(void) {
             w = p->user_target = get_users_target(p->uid);
         }
 
-        if(likely(w))
-            aggregate_pid_on_target(w, p, o);
-        else
-            error("pid %d %s was left without a user target!", p->pid, p->comm);
+        aggregate_pid_on_target(w, p, o);
 
 
         // --------------------------------------------------------------------
-        // group targets
+        // user group target
+
         o = p->group_target;
         if(likely(p->group_target && p->group_target->gid == p->gid))
             w = p->group_target;
@@ -2123,16 +2207,15 @@ static void calculate_netdata_statistics(void) {
             w = p->group_target = get_groups_target(p->gid);
         }
 
-        if(likely(w))
-            aggregate_pid_on_target(w, p, o);
-        else
-            error("pid %d %s was left without a group target!", p->pid, p->comm);
+        aggregate_pid_on_target(w, p, o);
 
-    }
 
-    count_targets_fds(apps_groups_root_target);
-    count_targets_fds(users_root_target);
-    count_targets_fds(groups_root_target);
+        // --------------------------------------------------------------------
+        // aggregate all file descriptors
+
+        if(enable_file_charts)
+            aggregate_pid_fds_on_targets(p);
+    }
 
     cleanup_exited_pids();
 }
@@ -2140,32 +2223,18 @@ static void calculate_netdata_statistics(void) {
 // ----------------------------------------------------------------------------
 // update chart dimensions
 
-BUFFER *output = NULL;
 int print_calculated_number(char *str, calculated_number value) { (void)str; (void)value; return 0; }
 
 static inline void send_BEGIN(const char *type, const char *id, unsigned long long usec) {
-    // fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
-    buffer_strcat(output, "BEGIN ");
-    buffer_strcat(output, type);
-    buffer_strcat(output, ".");
-    buffer_strcat(output, id);
-    buffer_strcat(output, " ");
-    buffer_print_llu(output, usec);
-    buffer_strcat(output, "\n");
+    fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
 }
 
 static inline void send_SET(const char *name, unsigned long long value) {
-    // fprintf(stdout, "SET %s = %llu\n", name, value);
-    buffer_strcat(output, "SET ");
-    buffer_strcat(output, name);
-    buffer_strcat(output, " = ");
-    buffer_print_llu(output, value);
-    buffer_strcat(output, "\n");
+    fprintf(stdout, "SET %s = %llu\n", name, value);
 }
 
 static inline void send_END(void) {
-    // fprintf(stdout, "END\n");
-    buffer_strcat(output, "END\n");
+    fprintf(stdout, "END\n");
 }
 
 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;
@@ -2205,7 +2274,7 @@ static usec_t send_resource_usage_to_netdata() {
         memmove(&me_last, &me, sizeof(struct rusage));
     }
 
-    buffer_sprintf(output,
+    fprintf(stdout,
         "BEGIN netdata.apps_cpu %llu\n"
         "SET user = %llu\n"
         "SET system = %llu\n"
@@ -2240,7 +2309,7 @@ static usec_t send_resource_usage_to_netdata() {
         );
 
     if(include_exited_childs)
-        buffer_sprintf(output,
+        fprintf(stdout,
             "BEGIN netdata.apps_children_fix %llu\n"
             "SET cutime = %llu\n"
             "SET cstime = %llu\n"
@@ -2556,112 +2625,112 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
 
     // we have something new to show
     // update the charts
-    buffer_sprintf(output, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
+    fprintf(stdout, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
     for (w = root; w ; w = w->next) {
         if(unlikely(w->exposed))
-            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
     }
 
-    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);
+    fprintf(stdout, "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);
+            fprintf(stdout, "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);
+    fprintf(stdout, "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);
+            fprintf(stdout, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
     }
 
-    buffer_sprintf(output, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20005 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20005 %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);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
     }
 
-    buffer_sprintf(output, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes stacked 20004 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes 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 1 1\n", w->name);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
     }
 
-    buffer_sprintf(output, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
+    fprintf(stdout, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
     for (w = root; w ; w = w->next) {
         if(unlikely(w->exposed))
-            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
     }
 
-    buffer_sprintf(output, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
+    fprintf(stdout, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
     for (w = root; w ; w = w->next) {
         if(unlikely(w->exposed))
-            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
     }
 
     if(show_guest_time) {
-        buffer_sprintf(output, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every);
+        fprintf(stdout, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every);
         for (w = root; w; w = w->next) {
             if(unlikely(w->exposed))
-                buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+                fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
         }
     }
 
-    buffer_sprintf(output, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20010 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20010 %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 %llu\n", w->name, RATES_DETAIL);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
     }
 
-    buffer_sprintf(output, "CHART %s.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %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 %llu\n", w->name, RATES_DETAIL);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
     }
 
-    buffer_sprintf(output, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %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 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
     }
 
-    buffer_sprintf(output, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %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 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
     }
 
-    buffer_sprintf(output, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %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 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
     }
 
-    buffer_sprintf(output, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
+    fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %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 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+            fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
     }
 
     if(enable_file_charts) {
-        buffer_sprintf(output, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type,
+        fprintf(stdout, "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);
+                fprintf(stdout, "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",
+        fprintf(stdout, "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);
+                fprintf(stdout, "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,
+        fprintf(stdout, "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);
+                fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
         }
     }
 }
@@ -2737,35 +2806,38 @@ static void parse_args(int argc, char **argv)
 
         if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
             fprintf(stderr,
-                    "apps.plugin %s\n"
-                    "(C) 2016 Costa Tsaousis"
-                    "GPL v3+\n"
-                    "This program is a data collector plugin for netdata.\n"
                     "\n"
-                    "Valid command line options:\n"
+                    " netdata apps.plugin %s\n"
+                    " Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
+                    " Released under GNU Public License v3 or later.\n"
+                    " All rights reserved.\n"
+                    "\n"
+                    " This program is a data collector plugin for netdata.\n"
+                    "\n"
+                    " Valid command line options:\n"
                     "\n"
-                    "SECONDS           set the data collection frequency\n"
+                    " SECONDS           set the data collection frequency\n"
                     "\n"
-                    "debug             enable debugging (lot of output)\n"
+                    " debug             enable debugging (lot of output)\n"
                     "\n"
-                    "with-childs\n"
-                    "without-childs    enable / disable aggregating exited\n"
-                    "                  children resources into parents\n"
-                    "                  (default is enabled)\n"
+                    " with-childs\n"
+                    " without-childs    enable / disable aggregating exited\n"
+                    "                   children resources into parents\n"
+                    "                   (default is enabled)\n"
                     "\n"
-                    "with-guest\n"
-                    "without-guest     enable / disable reporting guest charts\n"
-                    "                  (default is disabled)\n"
+                    " with-guest\n"
+                    " 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"
+                    " 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"
+                    " NAME              read apps_NAME.conf instead of\n"
+                    "                   apps_groups.conf\n"
+                    "                   (default NAME=groups)\n"
                     "\n"
-                    "version           print program version and exit\n"
+                    " version           print program version and exit\n"
                     "\n"
                     , VERSION
             );
@@ -2841,8 +2913,7 @@ int main(int argc, char **argv)
     all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
     all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
 
-    output = buffer_create(1024);
-    buffer_sprintf(output,
+    fprintf(stdout,
         "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
         "DIMENSION user '' incremental 1 1000\n"
         "DIMENSION system '' incremental 1 1000\n"
@@ -2862,7 +2933,7 @@ int main(int argc, char **argv)
         );
 
     if(include_exited_childs)
-        buffer_sprintf(output,
+        fprintf(stdout,
             "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
             "DIMENSION cutime '' absolute 1 %2$llu\n"
             "DIMENSION cstime '' absolute 1 %2$llu\n"
@@ -2879,10 +2950,17 @@ int main(int argc, char **argv)
         usec_t now = now_realtime_usec();
         usec_t next = now - (now % step) + step;
 
+#ifdef NETDATA_PROFILING
+#warning "compiling for profiling"
+        static int profiling_count=0;
+        profiling_count++;
+        if(unlikely(profiling_count > 1000)) exit(0);
+#else
         while(now < next) {
             sleep_usec(next - now);
             now = now_realtime_usec();
         }
+#endif
 
         if(!collect_data_for_all_processes_from_proc()) {
             error("Cannot collect /proc data for running processes. Disabling apps.plugin...");
@@ -2912,13 +2990,9 @@ int main(int argc, char **argv)
         if(likely(enable_groups_charts))
             send_collected_data_to_netdata(groups_root_target, "groups", dt);
 
-        show_guest_time_old = show_guest_time;
-
-        if(write(STDOUT_FILENO, buffer_tostring(output), buffer_strlen(output)) == -1)
-            fatal("Cannot send chart values to netdata.");
+        fflush(stdout);
 
-        // fflush(stdout);
-        buffer_flush(output);
+        show_guest_time_old = show_guest_time;
 
         if(unlikely(debug))
             fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter);