]> arthur.barton.de Git - netdata.git/blobdiff - src/plugins.d/apps_plugin.c
added opensips.chart.sh
[netdata.git] / src / plugins.d / apps_plugin.c
index 053ad35c6dcd2d2a9dd434a84fb2d6f6b05d5808..cf16ab41fd5fed1ce061e1736c924869afb21393 100755 (executable)
@@ -1,3 +1,9 @@
+// TODO
+//
+// 1. support -ch option to set global /proc and /sys prefix
+// 2. disable RESET_OR_OVERFLOW check in charts
+
+
 #define __STDC_FORMAT_MACROS
 #include <inttypes.h>
 
@@ -43,19 +49,171 @@ unsigned long long file_counter = 0;
 
 #define PROC_BUFFER 4096
 
+// ----------------------------------------------------------------------------
+// memory debugger
+
+struct allocations {
+       size_t allocations;
+       size_t allocated;
+       size_t allocated_max;
+} allocations = { 0, 0, 0 };
+
+#define MALLOC_MARK (uint32_t)(0x0BADCAFE)
+#define MALLOC_PREFIX (sizeof(uint32_t) * 2)
+#define MALLOC_SUFFIX (sizeof(uint32_t))
+#define MALLOC_OVERHEAD (MALLOC_PREFIX + MALLOC_SUFFIX)
+
+void *mark_allocation(void *allocated_ptr, size_t size_without_overheads) {
+       uint32_t *real_ptr = (uint32_t *)allocated_ptr;
+       real_ptr[0] = MALLOC_MARK;
+       real_ptr[1] = size_without_overheads;
+
+       uint32_t *end_ptr = (uint32_t *)(allocated_ptr + MALLOC_PREFIX + size_without_overheads);
+       end_ptr[0] = MALLOC_MARK;
+
+       // fprintf(stderr, "MEMORY_POINTER: Allocated at %p, returning %p.\n", allocated_ptr, (void *)(allocated_ptr + MALLOC_PREFIX));
+
+       return (void *)(allocated_ptr + MALLOC_PREFIX);
+}
+
+void *check_allocation(const char *file, int line, const char *function, void *marked_ptr, size_t *size_without_overheads_ptr) {
+       uint32_t *real_ptr = (uint32_t *)(marked_ptr - MALLOC_PREFIX);
+
+       // fprintf(stderr, "MEMORY_POINTER: Checking pointer at %p, real %p for %s/%u@%s.\n", marked_ptr, (void *)(marked_ptr - MALLOC_PREFIX), function, line, file);
+
+       if(real_ptr[0] != MALLOC_MARK) fatal("MEMORY: prefix MARK is not valid for %s/%u@%s.", function, line, file);
+
+       size_t size = real_ptr[1];
+
+       uint32_t *end_ptr = (uint32_t *)(marked_ptr + size);
+       if(end_ptr[0] != MALLOC_MARK) fatal("MEMORY: suffix MARK of allocation with size %zu is not valid for %s/%u@%s.", size, function, line, file);
+
+       if(size_without_overheads_ptr) *size_without_overheads_ptr = size;
+
+       return real_ptr;
+}
+
+void *malloc_debug(const char *file, int line, const char *function, size_t size) {
+       void *ptr = malloc(size + MALLOC_OVERHEAD);
+       if(!ptr) fatal("MEMORY: Cannot allocate %zu bytes for %s/%u@%s.", size, function, line, file);
+
+       allocations.allocated += size;
+       allocations.allocations++;
+
+       debug(D_MEMORY, "MEMORY: Allocated %zu bytes for %s/%u@%s."
+               " Status: allocated %zu in %zu allocs."
+               , size
+               , function, line, file
+               , allocations.allocated
+               , allocations.allocations
+       );
+
+       if(allocations.allocated > allocations.allocated_max) {
+               debug(D_MEMORY, "MEMORY: total allocation peak increased from %zu to %zu", allocations.allocated_max, allocations.allocated);
+               allocations.allocated_max = allocations.allocated;
+       }
+
+       size_t csize;
+       check_allocation(file, line, function, mark_allocation(ptr, size), &csize);
+       if(size != csize) {
+               fatal("Invalid size.");
+       }
+
+       return mark_allocation(ptr, size);
+}
+
+void *calloc_debug(const char *file, int line, const char *function, size_t nmemb, size_t size) {
+       void *ptr = malloc_debug(file, line, function, (nmemb * size));
+       bzero(ptr, nmemb * size);
+       return ptr;
+}
+
+void free_debug(const char *file, int line, const char *function, void *ptr) {
+       size_t size;
+       void *real_ptr = check_allocation(file, line, function, ptr, &size);
+
+       bzero(real_ptr, size + MALLOC_OVERHEAD);
+
+       free(real_ptr);
+       allocations.allocated -= size;
+       allocations.allocations--;
+
+       debug(D_MEMORY, "MEMORY: freed %zu bytes for %s/%u@%s."
+               " Status: allocated %zu in %zu allocs."
+               , size
+               , function, line, file
+               , allocations.allocated
+               , allocations.allocations
+       );
+}
+
+void *realloc_debug(const char *file, int line, const char *function, void *ptr, size_t size) {
+       if(!ptr) return malloc_debug(file, line, function, size);
+       if(!size) { free_debug(file, line, function, ptr); return NULL; }
+
+       size_t old_size;
+       void *real_ptr = check_allocation(file, line, function, ptr, &old_size);
+
+       void *new_ptr = realloc(real_ptr, size + MALLOC_OVERHEAD);
+       if(!new_ptr) fatal("MEMORY: Cannot allocate %zu bytes for %s/%u@%s.", size, function, line, file);
+
+       allocations.allocated += size;
+       allocations.allocated -= old_size;
+
+       debug(D_MEMORY, "MEMORY: Re-allocated from %zu to %zu bytes for %s/%u@%s."
+               " Status: allocated %z in %zu allocs."
+               , old_size, size
+               , function, line, file
+               , allocations.allocated
+               , allocations.allocations
+       );
+
+       if(allocations.allocated > allocations.allocated_max) {
+               debug(D_MEMORY, "MEMORY: total allocation peak increased from %zu to %zu", allocations.allocated_max, allocations.allocated);
+               allocations.allocated_max = allocations.allocated;
+       }
+
+       return mark_allocation(new_ptr, size);
+}
+
+char *strdup_debug(const char *file, int line, const char *function, const char *ptr) {
+       size_t size = 0;
+       const char *s = ptr;
+
+       while(*s++) size++;
+       size++;
+
+       char *p = malloc_debug(file, line, function, size);
+       if(!p) fatal("Cannot allocate %zu bytes.", size);
+
+       memcpy(p, ptr, size);
+       return p;
+}
+
+#define malloc(size) malloc_debug(__FILE__, __LINE__, __FUNCTION__, (size))
+#define calloc(nmemb, size) calloc_debug(__FILE__, __LINE__, __FUNCTION__, (nmemb), (size))
+#define realloc(ptr, size) realloc_debug(__FILE__, __LINE__, __FUNCTION__, (ptr), (size))
+#define free(ptr) free_debug(__FILE__, __LINE__, __FUNCTION__, (ptr))
+
+#ifdef strdup
+#undef strdup
+#endif
+#define strdup(ptr) strdup_debug(__FILE__, __LINE__, __FUNCTION__, (ptr))
 
 // ----------------------------------------------------------------------------
 // helper functions
 
+procfile *ff = NULL;
+
 long get_processors(void) {
        int processors = 0;
 
-       procfile *ff = procfile_open("/proc/stat", "");
+       ff = procfile_reopen(ff, "/proc/stat", "", PROCFILE_FLAG_DEFAULT);
        if(!ff) return 1;
 
        ff = procfile_readall(ff);
        if(!ff) {
-               procfile_close(ff);
+               // procfile_close(ff);
                return 1;
        }
 
@@ -68,26 +226,26 @@ long get_processors(void) {
        processors--;
        if(processors < 1) processors = 1;
 
-       procfile_close(ff);
+       // procfile_close(ff);
        return processors;
 }
 
 long get_pid_max(void) {
        long mpid = 32768;
 
-       procfile *ff = procfile_open("/proc/sys/kernel/pid_max", "");
+       ff = procfile_reopen(ff, "/proc/sys/kernel/pid_max", "", PROCFILE_FLAG_DEFAULT);
        if(!ff) return mpid;
 
        ff = procfile_readall(ff);
        if(!ff) {
-               procfile_close(ff);
+               // procfile_close(ff);
                return mpid;
        }
 
        mpid = atol(procfile_lineword(ff, 0, 0));
        if(mpid) mpid = 32768;
 
-       procfile_close(ff);
+       // procfile_close(ff);
        return mpid;
 }
 
@@ -108,7 +266,7 @@ unsigned long long get_hertz(void)
        hz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
 #endif
 
-       error("apps.plugin: ERROR: unknown HZ value. Assuming %llu.", hz);
+       error("Unknown HZ value. Assuming %llu.", hz);
        return hz;
 }
 
@@ -201,7 +359,7 @@ struct target *get_target(const char *id, struct target *target)
        
        w = calloc(sizeof(struct target), 1);
        if(!w) {
-               error("apps.plugin: cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
+               error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
                return NULL;
        }
 
@@ -231,7 +389,7 @@ int read_process_groups(const char *name)
        if(debug) fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
        FILE *fp = fopen(filename, "r");
        if(!fp) {
-               error("apps.plugin: ERROR: cannot open file '%s' (%s)", filename, strerror(errno));
+               error("Cannot open file '%s' (%s)", filename, strerror(errno));
                return 1;
        }
 
@@ -292,7 +450,7 @@ int read_process_groups(const char *name)
                }
 
                if(w) strncpy(w->name, t, MAX_NAME);
-               if(!count) error("apps.plugin: ERROR: the line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t);
+               if(!count) error("The line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t);
        }
        fclose(fp);
 
@@ -310,13 +468,13 @@ int read_process_groups(const char *name)
 struct pid_stat {
        int32_t pid;
        char comm[MAX_COMPARE_NAME + 1];
-       char state;
+       // char state;
        int32_t ppid;
-       int32_t pgrp;
-       int32_t session;
-       int32_t tty_nr;
-       int32_t tpgid;
-       uint64_t flags;
+       // int32_t pgrp;
+       // int32_t session;
+       // int32_t tty_nr;
+       // int32_t tpgid;
+       // uint64_t flags;
        unsigned long long minflt;
        unsigned long long cminflt;
        unsigned long long majflt;
@@ -325,33 +483,33 @@ struct pid_stat {
        unsigned long long stime;
        unsigned long long cutime;
        unsigned long long cstime;
-       int64_t priority;
-       int64_t nice;
+       // int64_t priority;
+       // int64_t nice;
        int32_t num_threads;
-       int64_t itrealvalue;
-       unsigned long long starttime;
-       unsigned long long vsize;
+       // int64_t itrealvalue;
+       // unsigned long long starttime;
+       // unsigned long long vsize;
        unsigned long long rss;
-       unsigned long long rsslim;
-       unsigned long long starcode;
-       unsigned long long endcode;
-       unsigned long long startstack;
-       unsigned long long kstkesp;
-       unsigned long long kstkeip;
-       uint64_t signal;
-       uint64_t blocked;
-       uint64_t sigignore;
-       uint64_t sigcatch;
-       uint64_t wchan;
-       uint64_t nswap;
-       uint64_t cnswap;
-       int32_t exit_signal;
-       int32_t processor;
-       uint32_t rt_priority;
-       uint32_t policy;
-       unsigned long long delayacct_blkio_ticks;
-       uint64_t guest_time;
-       int64_t cguest_time;
+       // unsigned long long rsslim;
+       // unsigned long long starcode;
+       // unsigned long long endcode;
+       // unsigned long long startstack;
+       // unsigned long long kstkesp;
+       // unsigned long long kstkeip;
+       // uint64_t signal;
+       // uint64_t blocked;
+       // uint64_t sigignore;
+       // uint64_t sigcatch;
+       // uint64_t wchan;
+       // uint64_t nswap;
+       // uint64_t cnswap;
+       // int32_t exit_signal;
+       // int32_t processor;
+       // uint32_t rt_priority;
+       // uint32_t policy;
+       // unsigned long long delayacct_blkio_ticks;
+       // uint64_t guest_time;
+       // int64_t cguest_time;
 
        unsigned long long statm_size;
        unsigned long long statm_resident;
@@ -402,11 +560,11 @@ struct pid_stat {
        struct pid_stat *parent;
        struct pid_stat *prev;
        struct pid_stat *next;
-} *root = NULL, **all_pids;
+} *root_of_pids = NULL, **all_pids;
 
-long pids = 0;
+long all_pids_count = 0;
 
-struct pid_stat *get_entry(pid_t pid)
+struct pid_stat *get_pid_entry(pid_t pid)
 {
        if(all_pids[pid]) {
                all_pids[pid]->new_entry = 0;
@@ -415,31 +573,32 @@ struct pid_stat *get_entry(pid_t pid)
 
        all_pids[pid] = calloc(sizeof(struct pid_stat), 1);
        if(!all_pids[pid]) {
-               error("apps.plugin: ERROR: Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct pid_stat));
+               error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct pid_stat));
                return NULL;
        }
 
        all_pids[pid]->fds = calloc(sizeof(int), 100);
        if(!all_pids[pid]->fds)
-               error("apps.plugin: ERROR: Cannot allocate %ld bytes of memory", (unsigned long)(sizeof(int) * 100));
+               error("Cannot allocate %ld bytes of memory", (unsigned long)(sizeof(int) * 100));
        else all_pids[pid]->fds_size = 100;
 
-       if(root) root->prev = all_pids[pid];
-       all_pids[pid]->next = root;
-       root = all_pids[pid];
+       if(root_of_pids) root_of_pids->prev = all_pids[pid];
+       all_pids[pid]->next = root_of_pids;
+       root_of_pids = all_pids[pid];
 
+       all_pids[pid]->pid = pid;
        all_pids[pid]->new_entry = 1;
 
        return all_pids[pid];
 }
 
-void del_entry(pid_t pid)
+void del_pid_entry(pid_t pid)
 {
        if(!all_pids[pid]) return;
 
        if(debug) fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
 
-       if(root == all_pids[pid]) root = all_pids[pid]->next;
+       if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
        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;
 
@@ -448,6 +607,158 @@ void del_entry(pid_t pid)
        all_pids[pid] = NULL;
 }
 
+
+// ----------------------------------------------------------------------------
+// update pids from proc
+
+int read_proc_pid_stat(struct pid_stat *p) {
+       char filename[FILENAME_MAX + 1];
+
+       snprintf(filename, FILENAME_MAX, "/proc/%d/stat", p->pid);
+
+       ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+       if(!ff) return 1;
+
+       ff = procfile_readall(ff);
+       if(!ff) {
+               // procfile_close(ff);
+               return 1;
+       }
+
+       file_counter++;
+
+       p->comm[0] = '\0';
+       p->comm[MAX_COMPARE_NAME] = '\0';
+       size_t blen = 0;
+
+       char *s = procfile_lineword(ff, 0, 1);
+       if(*s == '(') s++;
+       size_t len = strlen(s);
+       unsigned int i = 0;
+       while(len && s[len - 1] != ')') {
+               if(blen < MAX_COMPARE_NAME) {
+                       strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
+                       blen = strlen(p->comm);
+               }
+
+               i++;
+               s = procfile_lineword(ff, 0, 1+i);
+               len = strlen(s);
+       }
+       if(len && s[len - 1] == ')') s[len - 1] = '\0';
+       if(blen < MAX_COMPARE_NAME)
+               strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
+
+       // p->pid                       = atol(procfile_lineword(ff, 0, 0+i));
+       // comm is at 1
+       // p->state                     = *(procfile_lineword(ff, 0, 2+i));
+       p->ppid                         = atol(procfile_lineword(ff, 0, 3+i));
+       // p->pgrp                      = atol(procfile_lineword(ff, 0, 4+i));
+       // p->session           = atol(procfile_lineword(ff, 0, 5+i));
+       // p->tty_nr            = atol(procfile_lineword(ff, 0, 6+i));
+       // p->tpgid                     = atol(procfile_lineword(ff, 0, 7+i));
+       // p->flags                     = strtoull(procfile_lineword(ff, 0, 8+i), NULL, 10);
+       p->minflt                       = strtoull(procfile_lineword(ff, 0, 9+i), NULL, 10);
+       p->cminflt                      = strtoull(procfile_lineword(ff, 0, 10+i), NULL, 10);
+       p->majflt                       = strtoull(procfile_lineword(ff, 0, 11+i), NULL, 10);
+       p->cmajflt                      = strtoull(procfile_lineword(ff, 0, 12+i), NULL, 10);
+       p->utime                        = strtoull(procfile_lineword(ff, 0, 13+i), NULL, 10);
+       p->stime                        = strtoull(procfile_lineword(ff, 0, 14+i), NULL, 10);
+       p->cutime                       = strtoull(procfile_lineword(ff, 0, 15+i), NULL, 10);
+       p->cstime                       = strtoull(procfile_lineword(ff, 0, 16+i), NULL, 10);
+       // p->priority          = strtoull(procfile_lineword(ff, 0, 17+i), NULL, 10);
+       // p->nice                      = strtoull(procfile_lineword(ff, 0, 18+i), NULL, 10);
+       p->num_threads          = atol(procfile_lineword(ff, 0, 19+i));
+       // p->itrealvalue       = strtoull(procfile_lineword(ff, 0, 20+i), NULL, 10);
+       // p->starttime         = strtoull(procfile_lineword(ff, 0, 21+i), NULL, 10);
+       // p->vsize                     = strtoull(procfile_lineword(ff, 0, 22+i), NULL, 10);
+       p->rss                          = strtoull(procfile_lineword(ff, 0, 23+i), NULL, 10);
+       // p->rsslim            = strtoull(procfile_lineword(ff, 0, 24+i), NULL, 10);
+       // p->starcode          = strtoull(procfile_lineword(ff, 0, 25+i), NULL, 10);
+       // p->endcode           = strtoull(procfile_lineword(ff, 0, 26+i), NULL, 10);
+       // p->startstack        = strtoull(procfile_lineword(ff, 0, 27+i), NULL, 10);
+       // p->kstkesp           = strtoull(procfile_lineword(ff, 0, 28+i), NULL, 10);
+       // p->kstkeip           = strtoull(procfile_lineword(ff, 0, 29+i), NULL, 10);
+       // p->signal            = strtoull(procfile_lineword(ff, 0, 30+i), NULL, 10);
+       // p->blocked           = strtoull(procfile_lineword(ff, 0, 31+i), NULL, 10);
+       // p->sigignore         = strtoull(procfile_lineword(ff, 0, 32+i), NULL, 10);
+       // p->sigcatch          = strtoull(procfile_lineword(ff, 0, 33+i), NULL, 10);
+       // p->wchan                     = strtoull(procfile_lineword(ff, 0, 34+i), NULL, 10);
+       // p->nswap                     = strtoull(procfile_lineword(ff, 0, 35+i), NULL, 10);
+       // p->cnswap            = strtoull(procfile_lineword(ff, 0, 36+i), NULL, 10);
+       // p->exit_signal       = atol(procfile_lineword(ff, 0, 37+i));
+       // p->processor         = atol(procfile_lineword(ff, 0, 38+i));
+       // p->rt_priority       = strtoul(procfile_lineword(ff, 0, 39+i), NULL, 10);
+       // p->policy            = strtoul(procfile_lineword(ff, 0, 40+i), NULL, 10);
+       // p->delayacct_blkio_ticks             = strtoull(procfile_lineword(ff, 0, 41+i), NULL, 10);
+       // p->guest_time        = strtoull(procfile_lineword(ff, 0, 42+i), NULL, 10);
+       // p->cguest_time       = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
+
+       if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: VALUES: %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+
+       // procfile_close(ff);
+       return 0;
+}
+
+int read_proc_pid_statm(struct pid_stat *p) {
+       char filename[FILENAME_MAX + 1];
+
+       snprintf(filename, FILENAME_MAX, "/proc/%d/statm", p->pid);
+
+       ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+       if(!ff) return 1;
+
+       ff = procfile_readall(ff);
+       if(!ff) {
+               // procfile_close(ff);
+               return 1;
+       }
+
+       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);
+
+       // procfile_close(ff);
+       return 0;
+}
+
+int read_proc_pid_io(struct pid_stat *p) {
+       char filename[FILENAME_MAX + 1];
+
+       snprintf(filename, FILENAME_MAX, "/proc/%d/io", p->pid);
+
+       ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+       if(!ff) return 1;
+
+       ff = procfile_readall(ff);
+       if(!ff) {
+               // procfile_close(ff);
+               return 1;
+       }
+
+       file_counter++;
+
+       p->io_logical_bytes_read                = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
+       p->io_logical_bytes_written     = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
+       p->io_read_calls                                = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
+       p->io_write_calls                               = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
+       p->io_storage_bytes_read                = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
+       p->io_storage_bytes_written     = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
+       p->io_cancelled_write_bytes             = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
+
+       // procfile_close(ff);
+       return 0;
+}
+
+
+// ----------------------------------------------------------------------------
+
 #ifdef INCLUDE_CHILDS
 // print a tree view of all processes
 int walk_down(pid_t pid, int level) {
@@ -460,7 +771,7 @@ int walk_down(pid_t pid, int level) {
        b[level+1] = '-';
        b[level+2] = '\0';
 
-       for(p = root; p ; p = p->next) {
+       for(p = root_of_pids; p ; p = p->next) {
                if(p->ppid == pid) {
                        ret += walk_down(p->pid, level+1);
                }
@@ -496,8 +807,8 @@ int walk_down(pid_t pid, int level) {
 
 struct file_descriptor {
        avl avl;
-       unsigned long magic;
-       unsigned long hash;
+       uint32_t magic;
+       uint32_t hash;
        const char *name;
        int type;
        long count;
@@ -524,7 +835,7 @@ avl_tree all_files_index = {
                file_descriptor_compare
 };
 
-static struct file_descriptor *file_descriptor_find(const char *name, unsigned long hash) {
+static struct file_descriptor *file_descriptor_find(const char *name, uint32_t hash) {
        struct file_descriptor *result = NULL, tmp;
        tmp.hash = (hash)?hash:simple_hash(name);
        tmp.name = name;
@@ -570,17 +881,17 @@ void file_descriptor_not_used(int id)
                        }
                }
                else
-                       error("apps.plugin: ERROR: request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
+                       error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
        }
-       else    error("apps.plugin: ERROR: request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
+       else    error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
 }
 
 unsigned long file_descriptor_find_or_add(const char *name)
 {
        static int last_pos = 0;
-       unsigned long hash = simple_hash(name);
+       uint32_t hash = simple_hash(name);
 
-       if(debug) fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %lu\n", name, hash);
+       if(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) {
@@ -594,6 +905,7 @@ unsigned long file_descriptor_find_or_add(const char *name)
        // 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(debug) fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
@@ -604,20 +916,20 @@ unsigned long file_descriptor_find_or_add(const char *name)
                if(old && old != (void *)all_files) {
                        if(debug) fprintf(stderr, "apps.plugin:   >> re-indexing.\n");
                        all_files_index.root = NULL;
-                       int i;
                        for(i = 0; i < all_files_size; i++) {
                                if(!all_files[i].count) continue;
                                file_descriptor_add(&all_files[i]);
                        }
-                       for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
-                               all_files[i].count = 0;
-                               all_files[i].name = NULL;
-                               all_files[i].magic = 0x00000000;
-                               all_files[i].pos = i;
-                       }
                        if(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;
+                       all_files[i].magic = 0x00000000;
+                       all_files[i].pos = i;
+               }
+
                if(!all_files_size) all_files_len = 1;
                all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
        }
@@ -634,7 +946,7 @@ unsigned long file_descriptor_find_or_add(const char *name)
                        if(debug) fprintf(stderr, "apps.plugin:   >> Examining slot %d.\n", c);
 
                        if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
-                               error("apps.plugin: fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
+                               error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
 
                        if(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) free((void *)all_files[c].name);
@@ -686,9 +998,6 @@ unsigned long file_descriptor_find_or_add(const char *name)
 }
 
 
-// ----------------------------------------------------------------------------
-// update pids from proc
-
 // 1. read all files in /proc
 // 2. for each numeric directory:
 //    i.   read /proc/pid/stat
@@ -709,8 +1018,6 @@ int update_from_proc(void)
 {
        static long count_errors = 0;
 
-       char buffer[PROC_BUFFER + 1];
-       char name[PROC_BUFFER + 1];
        char filename[FILENAME_MAX+1];
        DIR *dir = opendir("/proc");
        if(!dir) return 0;
@@ -719,9 +1026,9 @@ int update_from_proc(void)
        struct pid_stat *p = NULL;
 
        // mark them all as un-updated
-       pids = 0;
-       for(p = root; p ; p = p->next) {
-               pids++;
+       all_pids_count = 0;
+       for(p = root_of_pids; p ; p = p->next) {
+               all_pids_count++;
                p->parent = NULL;
                p->updated = 0;
                p->childs = 0;
@@ -734,81 +1041,45 @@ int update_from_proc(void)
                pid_t pid = strtoul(file->d_name, &endptr, 10);
                if(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0') continue;
 
+               p = get_pid_entry(pid);
+               if(!p) continue;
 
                // --------------------------------------------------------------------
                // /proc/<pid>/stat
 
-               snprintf(filename, FILENAME_MAX, "/proc/%s/stat", file->d_name);
-               int fd = open(filename, O_RDONLY);
-               if(fd == -1) {
-                       if(errno != ENOENT && errno != ESRCH) {
-                               if(!count_errors++ || debug)
-                                       error("apps.plugin: ERROR: cannot open file '%s' for reading (%d, %s).", filename, errno, strerror(errno));
-                       }
+               if(read_proc_pid_stat(p)) {
+                       if(!count_errors++ || debug || (p->target && p->target->debug))
+                               error("Cannot process /proc/%d/stat", pid);
+
                        continue;
                }
-               file_counter++;
+               if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0;
 
-               int bytes = read(fd, buffer, PROC_BUFFER);
-               close(fd);
 
-               if(bytes == -1) {
-                       if(!count_errors++ || debug)
-                               error("apps.plugin: ERROR: cannot read from file '%s' (%s).", filename, strerror(errno));
-                       continue;
-               }
+               // --------------------------------------------------------------------
+               // /proc/<pid>/statm
 
-               if(bytes < 10) continue;
-               buffer[bytes] = '\0';
-               if(debug) fprintf(stderr, "apps.plugin: READ stat: %s", buffer);
+               if(read_proc_pid_statm(p)) {
+                       if(!count_errors++ || debug || (p->target && p->target->debug))
+                               error("Cannot process /proc/%d/statm", pid);
 
-               p = get_entry(pid);
-               if(!p) continue;
+                       continue;
+               }
 
-               int parsed = sscanf(buffer,
-                       "%d (%[^)]) %c"                                         // pid, comm, state
-                       " %d %d %d %d %d"                                       // ppid, pgrp, session, tty_nr, tpgid
-                       " %" PRIu64 " %llu %llu %llu %llu"      // flags, minflt, cminflt, majflt, cmajflt
-                       " %llu %llu %llu %llu"                          // utime, stime, cutime, cstime
-                       " %" PRId64 " %" PRId64                         // priority, nice
-                       " %d"                                                           // num_threads
-                       " %" PRId64                                                     // itrealvalue
-                       " %llu"                                                         // starttime
-                       " %llu"                                                         // vsize
-                       " %llu"                                                         // rss
-                       " %llu %llu %llu %llu %llu %llu"        // rsslim, starcode, endcode, startstack, kstkesp, kstkeip
-                       " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 // signal, blocked, sigignore, sigcatch
-                       " %" PRIu64 " %" PRIu64 " %" PRIu64     // wchan, nswap, cnswap
-                       " %d %d"                                                        // exit_signal, processor
-                       " %u %u"                                                        // rt_priority, policy
-                       " %llu %" PRIu64 " %" PRId64            // delayacct_blkio_ticks, guest_time, cguest_time
-                       , &p->pid, name, &p->state
-                       , &p->ppid, &p->pgrp, &p->session, &p->tty_nr, &p->tpgid
-                       , &p->flags, &p->minflt, &p->cminflt, &p->majflt, &p->cmajflt
-                       , &p->utime, &p->stime, &p->cutime, &p->cstime
-                       , &p->priority, &p->nice
-                       , &p->num_threads
-                       , &p->itrealvalue
-                       , &p->starttime
-                       , &p->vsize
-                       , &p->rss
-                       , &p->rsslim, &p->starcode, &p->endcode, &p->startstack, &p->kstkesp, &p->kstkeip
-                       , &p->signal, &p->blocked, &p->sigignore, &p->sigcatch
-                       , &p->wchan, &p->nswap, &p->cnswap
-                       , &p->exit_signal, &p->processor
-                       , &p->rt_priority, &p->policy
-                       , &p->delayacct_blkio_ticks, &p->guest_time, &p->cguest_time
-                       );
-               strncpy(p->comm, name, MAX_COMPARE_NAME);
-               p->comm[MAX_COMPARE_NAME] = '\0';
 
-               if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: VALUES: %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+               // --------------------------------------------------------------------
+               // /proc/<pid>/io
 
-               if(parsed < 39) {
+               if(read_proc_pid_io(p)) {
                        if(!count_errors++ || debug || (p->target && p->target->debug))
-                               error("apps.plugin: ERROR: file %s gave %d results (expected 44)\n", filename, parsed);
+                               error("Cannot process /proc/%d/io", pid);
+
+                       continue;
                }
 
+               // --------------------------------------------------------------------
+               // link it
+
                // check if it is target
                // we do this only once, the first time this pid is loaded
                if(p->new_entry) {
@@ -827,95 +1098,6 @@ int update_from_proc(void)
                        }
                }
 
-               // just a few checks
-               if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0;
-
-
-               // --------------------------------------------------------------------
-               // /proc/<pid>/statm
-
-               snprintf(filename, FILENAME_MAX, "/proc/%s/statm", file->d_name);
-               fd = open(filename, O_RDONLY);
-               if(fd == -1) {
-                       if(errno != ENOENT && errno != ESRCH) {
-                               if(!count_errors++ || debug || (p->target && p->target->debug))
-                                       error("apps.plugin: ERROR: cannot open file '%s' for reading (%d, %s).", filename, errno, strerror(errno));
-                       }
-               }
-               else {
-                       file_counter++;
-                       bytes = read(fd, buffer, PROC_BUFFER);
-                       close(fd);
-
-                       if(bytes == -1) {
-                               if(!count_errors++ || debug || (p->target && p->target->debug))
-                                       error("apps.plugin: ERROR: cannot read from file '%s' (%s).", filename, strerror(errno));
-                       }
-                       else if(bytes > 10) {
-                               buffer[bytes] = '\0';
-                               if(debug || (p->target && p->target->debug))
-                                       fprintf(stderr, "apps.plugin: READ statm: %s", buffer);
-
-                               parsed = sscanf(buffer,
-                                       "%llu %llu %llu %llu %llu %llu %llu"
-                                       , &p->statm_size
-                                       , &p->statm_resident
-                                       , &p->statm_share
-                                       , &p->statm_text
-                                       , &p->statm_lib
-                                       , &p->statm_data
-                                       , &p->statm_dirty
-                                       );
-
-                               if(parsed < 7) {
-                                       if(!count_errors++ || debug || (p->target && p->target->debug))
-                                               error("apps.plugin: ERROR: file %s gave %d results (expected 7)", filename, parsed);
-                               }
-                       }
-               }
-
-               // --------------------------------------------------------------------
-               // /proc/<pid>/io
-
-               snprintf(filename, FILENAME_MAX, "/proc/%s/io", file->d_name);
-               fd = open(filename, O_RDONLY);
-               if(fd == -1) {
-                       if(errno != ENOENT && errno != ESRCH) {
-                               if(!count_errors++ || debug || (p->target && p->target->debug))
-                                       error("apps.plugin: ERROR: cannot open file '%s' for reading (%d, %s).", filename, errno, strerror(errno));
-                       }
-               }
-               else {
-                       file_counter++;
-                       bytes = read(fd, buffer, PROC_BUFFER);
-                       close(fd);
-
-                       if(bytes == -1) {
-                               if(!count_errors++ || debug || (p->target && p->target->debug))
-                                       error("apps.plugin: ERROR: cannot read from file '%s' (%s).", filename, strerror(errno));
-                       }
-                       else if(bytes > 10) {
-                               buffer[bytes] = '\0';
-                               if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: READ io: %s", buffer);
-
-                               parsed = sscanf(buffer,
-                                       "rchar: %llu\nwchar: %llu\nsyscr: %llu\nsyscw: %llu\nread_bytes: %llu\nwrite_bytes: %llu\ncancelled_write_bytes: %llu"
-                                       , &p->io_logical_bytes_read
-                                       , &p->io_logical_bytes_written
-                                       , &p->io_read_calls
-                                       , &p->io_write_calls
-                                       , &p->io_storage_bytes_read
-                                       , &p->io_storage_bytes_written
-                                       , &p->io_cancelled_write_bytes
-                                       );
-
-                               if(parsed < 7) {
-                                       if(!count_errors++ || debug || (p->target && p->target->debug))
-                                               error("apps.plugin: ERROR: file %s gave %d results (expected 7)", filename, parsed);
-                               }
-                       }
-               }
-
                // --------------------------------------------------------------------
                // /proc/<pid>/fd
 
@@ -941,7 +1123,7 @@ int update_from_proc(void)
                                        if(debug) fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
                                        p->fds = realloc(p->fds, (fdid + 100) * sizeof(int));
                                        if(!p->fds) {
-                                               error("apps.plugin: ERROR: cannot re-allocate fds for %s", p->comm);
+                                               error("Cannot re-allocate fds for %s", p->comm);
                                                break;
                                        }
 
@@ -958,7 +1140,7 @@ int update_from_proc(void)
                                        if(l == -1) {
                                                if(debug || (p->target && p->target->debug)) {
                                                        if(!count_errors++ || debug || (p->target && p->target->debug))
-                                                               error("apps.plugin: ERROR: cannot read link %s", fdname);
+                                                               error("Cannot read link %s", fdname);
                                                }
                                                continue;
                                        }
@@ -991,7 +1173,7 @@ int update_from_proc(void)
                p->updated = 1;
        }
        if(count_errors > 1000) {
-               error("apps.plugin: ERROR: %ld more errors encountered\n", count_errors - 1);
+               error("%ld more errors encountered\n", count_errors - 1);
                count_errors = 0;
        }
 
@@ -1022,14 +1204,14 @@ void update_statistics(void)
        struct pid_stat *p = NULL;
 
        // link all parents and update childs count
-       for(p = root; p ; p = p->next) {
+       for(p = root_of_pids; p ; p = p->next) {
                if(p->ppid > 0 && p->ppid <= pid_max && all_pids[p->ppid]) {
                        if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \tparent of %d %s is %d %s\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);
                        
                        p->parent = all_pids[p->ppid];
                        p->parent->childs++;
                }
-               else if(p->ppid != 0) error("apps.plugin: \t\tWRONG! pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
+               else if(p->ppid != 0) error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
        }
 
        // find all the procs with 0 childs and merge them to their parents
@@ -1037,7 +1219,7 @@ void update_statistics(void)
        int found = 1;
        while(found) {
                found = 0;
-               for(p = root; p ; p = p->next) {
+               for(p = root_of_pids; p ; p = p->next) {
                        // if this process does not have any childs, and
                        // is not already merged, and
                        // its parent has childs waiting to be merged, and
@@ -1064,7 +1246,7 @@ void update_statistics(void)
        // init goes always to default target
        if(all_pids[1]) all_pids[1]->target = default_target;
 
-       for(p = root; p ; p = p->next) {
+       for(p = root_of_pids; p ; p = p->next) {
                // if the process is not merged itself
                // then is is a top level process
                if(!p->merged && !p->target) p->target = default_target;
@@ -1083,7 +1265,7 @@ void update_statistics(void)
        found = 1;
        while(found) {
                found = 0;
-               for(p = root; p ; p = p->next) {
+               for(p = root_of_pids; p ; p = p->next) {
                        if(!p->target && p->merged && p->parent && p->parent->target) {
                                p->target = p->parent->target;
                                found++;
@@ -1094,7 +1276,7 @@ void update_statistics(void)
 #ifdef INCLUDE_CHILDS
        // for each killed process, remove its values from the parents
        // sums (we had already added them in a previous loop)
-       for(p = root; p ; p = p->next) {
+       for(p = root_of_pids; p ; p = p->next) {
                if(p->updated) continue;
 
                if(debug) fprintf(stderr, "apps.plugin: UNMERGING %d %s\n", p->pid, p->comm);
@@ -1139,10 +1321,10 @@ void update_statistics(void)
                        }
                }
 
-               if(diff_utime) error("apps.plugin: \t cannot fix up utime %llu", diff_utime);
-               if(diff_stime) error("apps.plugin: \t cannot fix up stime %llu", diff_stime);
-               if(diff_minflt) error("apps.plugin: \t cannot fix up minflt %llu", diff_minflt);
-               if(diff_majflt) error("apps.plugin: \t cannot fix up majflt %llu", diff_majflt);
+               if(diff_utime) error("Cannot fix up utime %llu", diff_utime);
+               if(diff_stime) error("Cannot fix up stime %llu", diff_stime);
+               if(diff_minflt) error("Cannot fix up minflt %llu", diff_minflt);
+               if(diff_majflt) error("Cannot fix up majflt %llu", diff_majflt);
        }
 #endif
 
@@ -1154,7 +1336,7 @@ void update_statistics(void)
 
                w->fds = calloc(sizeof(int), all_files_size);
                if(!w->fds)
-                       error("apps.plugin: ERROR: cannot allocate memory for fds in %s", w->name);
+                       error("Cannot allocate memory for fds in %s", w->name);
        
                w->minflt = 0;
                w->majflt = 0;
@@ -1190,9 +1372,9 @@ void update_statistics(void)
 #endif
 
        // concentrate everything on the targets
-       for(p = root; p ; p = p->next) {
+       for(p = root_of_pids; p ; p = p->next) {
                if(!p->target) {
-                       error("apps.plugin: ERROR: pid %d %s was left without a target!", p->pid, p->comm);
+                       error("pid %d %s was left without a target!", p->pid, p->comm);
                        continue;
                }
 
@@ -1207,6 +1389,12 @@ void update_statistics(void)
                        p->target->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;
                        p->target->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;
 
+                       //if(p->num_threads < 0)
+                       //      error("Negative threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
+
+                       //if(p->num_threads > 10000)
+                       //      error("Excessive threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
+
                        p->target->num_threads += p->num_threads;
                        p->target->rss += p->rss;
 
@@ -1234,7 +1422,7 @@ void update_statistics(void)
                                        if(p->target->fds) p->target->fds[p->fds[c]]++;
                                }
                                else
-                                       error("apps.plugin: ERROR: invalid fd number %d", p->fds[c]);
+                                       error("Invalid fd number %d", p->fds[c]);
                        }
 
                        if(debug || p->target->debug) fprintf(stderr, "apps.plugin: \tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
@@ -1287,7 +1475,7 @@ void update_statistics(void)
 
 //     fprintf(stderr, "\n");
        // cleanup all un-updated processed (exited, killed, etc)
-       for(p = root; p ;) {
+       for(p = root_of_pids; p ;) {
                if(!p->updated) {
 //                     fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name,  p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
                        
@@ -1298,7 +1486,7 @@ void update_statistics(void)
 
                        pid_t r = p->pid;
                        p = p->next;
-                       del_entry(r);
+                       del_pid_entry(r);
                }
                else p = p->next;
        }
@@ -1524,7 +1712,7 @@ void show_dimensions(void)
 
        fprintf(stdout, "BEGIN netdata.apps_files %llu\n", usec);
        fprintf(stdout, "SET files = %llu\n", file_counter);
-       fprintf(stdout, "SET pids = %ld\n", pids);
+       fprintf(stdout, "SET pids = %ld\n", all_pids_count);
        fprintf(stdout, "SET fds = %d\n", all_files_len);
        fprintf(stdout, "SET targets = %ld\n", targets);
        fprintf(stdout, "END\n");
@@ -1691,6 +1879,7 @@ void parse_args(int argc, char **argv)
 
                if(strcmp("debug", argv[i]) == 0) {
                        debug = 1;
+                       debug_flags = 0xffffffff;
                        continue;
                }
 
@@ -1699,7 +1888,7 @@ void parse_args(int argc, char **argv)
                        continue;
                }
 
-               error("apps.plugin: ERROR: cannot understand option %s", argv[i]);
+               error("Cannot understand option %s", argv[i]);
                exit(1);
        }
 
@@ -1707,7 +1896,7 @@ void parse_args(int argc, char **argv)
        if(!name) name = "groups";
 
        if(read_process_groups(name)) {
-               error("apps.plugin: ERROR: cannot read process groups %s", name);
+               error("Cannot read process groups %s", name);
                exit(1);
        }
 }
@@ -1716,7 +1905,12 @@ int main(int argc, char **argv)
 {
        // debug_flags = D_PROCFILE;
 
-       info("apps.plugin: starting...");
+       // set the name for logging
+       program_name = "apps.plugin";
+
+       info("starting...");
+
+       procfile_adaptive_initial_allocation = 1;
 
        unsigned long started_t = time(NULL), current_t;
        Hertz = get_hertz();
@@ -1727,7 +1921,7 @@ int main(int argc, char **argv)
 
        all_pids = calloc(sizeof(struct pid_stat *), pid_max);
        if(!all_pids) {
-               error("apps.plugin: ERROR: cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
+               error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
                printf("DISABLE\n");
                exit(1);
        }
@@ -1739,7 +1933,7 @@ int main(int argc, char **argv)
 
        for(;1; counter++) {
                if(!update_from_proc()) {
-                       error("apps.plugin: ERROR: cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
+                       error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
                        printf("DISABLE\n");
                        exit(1);
                }