+// 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>
#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;
}
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;
}
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;
}
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;
}
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;
}
}
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);
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;
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;
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;
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;
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) {
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);
}
struct file_descriptor {
avl avl;
- unsigned long magic;
- unsigned long hash;
+ uint32_t magic;
+ uint32_t hash;
const char *name;
int type;
long count;
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;
}
}
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) {
// 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);
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;
}
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);
}
-// ----------------------------------------------------------------------------
-// update pids from proc
-
// 1. read all files in /proc
// 2. for each numeric directory:
// i. read /proc/pid/stat
{
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;
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;
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) {
}
}
- // 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
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;
}
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;
}
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;
}
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
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
// 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;
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++;
#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);
}
}
- 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
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;
#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;
}
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;
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);
// 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);
pid_t r = p->pid;
p = p->next;
- del_entry(r);
+ del_pid_entry(r);
}
else p = p->next;
}
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");
if(strcmp("debug", argv[i]) == 0) {
debug = 1;
+ debug_flags = 0xffffffff;
continue;
}
continue;
}
- error("apps.plugin: ERROR: cannot understand option %s", argv[i]);
+ error("Cannot understand option %s", argv[i]);
exit(1);
}
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);
}
}
{
// 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();
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);
}
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);
}