diff options
author | Lennart Weller <lhw@ring0.de> | 2017-01-24 15:21:09 +0000 |
---|---|---|
committer | Lennart Weller <lhw@ring0.de> | 2017-01-24 15:21:09 +0000 |
commit | 3ed3b02ed96ddab1c084811f3579b3a2aec83e04 (patch) | |
tree | 7a61ab288ae47800c4f11be5677d6ad8288dcd98 /src/apps_plugin.c | |
parent | New upstream version 1.4.0+dfsg (diff) | |
download | netdata-3ed3b02ed96ddab1c084811f3579b3a2aec83e04.tar.xz netdata-3ed3b02ed96ddab1c084811f3579b3a2aec83e04.zip |
New upstream version 1.5.0+dfsgupstream/1.5.0+dfsg
Diffstat (limited to 'src/apps_plugin.c')
-rw-r--r-- | src/apps_plugin.c | 1060 |
1 files changed, 566 insertions, 494 deletions
diff --git a/src/apps_plugin.c b/src/apps_plugin.c index f22a575ba..0a72190aa 100644 --- a/src/apps_plugin.c +++ b/src/apps_plugin.c @@ -13,6 +13,8 @@ // etc. #define RATES_DETAIL 10000ULL +#define MAX_SPARE_FDS 1 + int debug = 0; int update_every = 1; @@ -30,6 +32,8 @@ int show_guest_time_old = 0; int enable_guest_charts = 0; int enable_file_charts = 1; +int enable_users_charts = 1; +int enable_groups_charts = 1; // ---------------------------------------------------------------------------- @@ -84,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; @@ -119,7 +125,7 @@ long apps_groups_targets = 0; struct target *users_root_target = NULL; struct target *groups_root_target = NULL; -struct target *get_users_target(uid_t uid) +static struct target *get_users_target(uid_t uid) { struct target *w; for(w = users_root_target ; w ; w = w->next) @@ -187,10 +193,11 @@ struct target *get_groups_target(gid_t gid) // find or create a new target // there are targets that are just aggregated to other target (the second argument) -struct target *get_apps_groups_target(const char *id, struct target *target) { - int tdebug = 0, thidden = 0, ends_with = 0; +static struct target *get_apps_groups_target(const char *id, struct target *target, const char *name) { + int tdebug = 0, thidden = target?target->hidden:0, ends_with = 0; const char *nid = id; + // extract the options while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') { if(nid[0] == '-') thidden = 1; if(nid[0] == '+') tdebug = 1; @@ -199,6 +206,7 @@ struct target *get_apps_groups_target(const char *id, struct target *target) { } uint32_t hash = simple_hash(id); + // find if it already exists struct target *w, *last = apps_groups_root_target; for(w = apps_groups_root_target ; w ; w = w->next) { if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0) @@ -207,11 +215,37 @@ struct target *get_apps_groups_target(const char *id, struct target *target) { last = w; } + // find an existing target + if(unlikely(!target)) { + while(*name == '-') { + if(*name == '-') thidden = 1; + name++; + } + for(target = apps_groups_root_target ; target ; target = target->next) { + if(!target->target && strcmp(name, target->name) == 0) + break; + } + if(unlikely(debug)) { + if(unlikely(target)) + fprintf(stderr, "apps.plugin: REUSING TARGET NAME '%s' on ID '%s'\n", target->name, target->id); + else + fprintf(stderr, "apps.plugin: NEW TARGET NAME '%s' on ID '%s'\n", name, id); + } + } + + if(target && target->target) + fatal("Internal Error: request to link process '%s' to target '%s' which is linked to target '%s'", id, target->id, target->target->id); + w = callocz(sizeof(struct target), 1); strncpyz(w->id, nid, MAX_NAME); w->idhash = simple_hash(w->id); - strncpyz(w->name, nid, MAX_NAME); + if(unlikely(!target)) + // copy the name + strncpyz(w->name, name, MAX_NAME); + else + // copy the id + strncpyz(w->name, nid, MAX_NAME); strncpyz(w->compare, nid, MAX_COMPARE_NAME); size_t len = strlen(w->compare); @@ -239,7 +273,7 @@ struct target *get_apps_groups_target(const char *id, struct target *target) { fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n" , w->id , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact")) - , w->target?w->target->id:w->id + , w->target?w->target->name:w->name , (w->hidden)?"hidden":"-" , (w->debug)?"debug":"-" ); @@ -248,11 +282,11 @@ struct target *get_apps_groups_target(const char *id, struct target *target) { } // read the apps_groups.conf file -int read_apps_groups_conf(const char *name) +static int read_apps_groups_conf(const char *file) { char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name); + snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, file); if(unlikely(debug)) fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename); @@ -272,59 +306,45 @@ int read_apps_groups_conf(const char *name) for(line = 0; line < lines ;line++) { unsigned long word, words = procfile_linewords(ff, line); - struct target *w = NULL; + if(!words) continue; + + char *name = procfile_lineword(ff, line, 0); + if(!name || !*name) continue; - char *t = procfile_lineword(ff, line, 0); - if(!t || !*t) continue; + // find a possibly existing target + struct target *w = NULL; + // loop through all words, skipping the first one (the name) for(word = 0; word < words ;word++) { char *s = procfile_lineword(ff, line, word); if(!s || !*s) continue; if(*s == '#') break; - if(t == s) continue; + // is this the first word? skip it + if(s == name) continue; - struct target *n = get_apps_groups_target(s, w); + // add this target + struct target *n = get_apps_groups_target(s, w, name); if(!n) { error("Cannot create target '%s' (line %lu, word %lu)", s, line, word); continue; } - if(!w) w = n; - } - - if(w) { - int tdebug = 0, thidden = 0; - - while(t[0] == '-' || t[0] == '+') { - if(t[0] == '-') thidden = 1; - if(t[0] == '+') tdebug = 1; - t++; - } - - strncpyz(w->name, t, MAX_NAME); - w->hidden = thidden; - w->debug = tdebug; - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: AGGREGATION TARGET NAME '%s' on ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n" - , w->name - , w->id - , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact")) - , w->target?w->target->id:w->id - , (w->hidden)?"hidden":"-" - , (w->debug)?"debug":"-" - ); + // just some optimization + // to avoid searching for a target for each process + if(!w) w = n->target?n->target:n; } } procfile_close(ff); - apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing + apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL, "other"); // match nothing if(!apps_groups_default_target) - error("Cannot create default target"); - else - strncpyz(apps_groups_default_target->name, "other", MAX_NAME); + fatal("Cannot create default target"); + + // allow the user to override group 'other' + if(apps_groups_default_target->target) + apps_groups_default_target = apps_groups_default_target->target; return 0; } @@ -467,15 +487,15 @@ struct pid_stat { long all_pids_count = 0; -struct pid_stat *get_pid_entry(pid_t pid) { +static inline struct pid_stat *get_pid_entry(pid_t pid) { if(all_pids[pid]) { all_pids[pid]->new_entry = 0; return all_pids[pid]; } 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; @@ -489,7 +509,7 @@ struct pid_stat *get_pid_entry(pid_t pid) { return all_pids[pid]; } -void del_pid_entry(pid_t pid) { +static inline void del_pid_entry(pid_t pid) { if(!all_pids[pid]) { error("attempted to free pid %d that is not allocated.", pid); return; @@ -517,7 +537,7 @@ void del_pid_entry(pid_t pid) { // ---------------------------------------------------------------------------- // update pids from proc -int read_proc_pid_cmdline(struct pid_stat *p) { +static inline int read_proc_pid_cmdline(struct pid_stat *p) { if(unlikely(!p->cmdline_filename)) { char filename[FILENAME_MAX + 1]; @@ -548,7 +568,7 @@ cleanup: return 0; } -int read_proc_pid_ownership(struct pid_stat *p) { +static inline int read_proc_pid_ownership(struct pid_stat *p) { if(unlikely(!p->stat_filename)) { error("pid %d does not have a stat_filename", p->pid); return 0; @@ -569,7 +589,7 @@ int read_proc_pid_ownership(struct pid_stat *p) { return 1; } -int read_proc_pid_stat(struct pid_stat *p) { +static inline int read_proc_pid_stat(struct pid_stat *p) { static procfile *ff = NULL; if(unlikely(!p->stat_filename)) { @@ -590,89 +610,89 @@ int read_proc_pid_stat(struct pid_stat *p) { if(unlikely(!ff)) goto cleanup; p->last_stat_collected_usec = p->stat_collected_usec; - p->stat_collected_usec = time_usec(); + p->stat_collected_usec = now_realtime_usec(); file_counter++; - // p->pid = atol(procfile_lineword(ff, 0, 0+i)); + // p->pid = str2ul(procfile_lineword(ff, 0, 0+i)); strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME); // p->state = *(procfile_lineword(ff, 0, 2)); - p->ppid = (int32_t) atol(procfile_lineword(ff, 0, 3)); - // p->pgrp = atol(procfile_lineword(ff, 0, 4)); - // p->session = atol(procfile_lineword(ff, 0, 5)); - // p->tty_nr = atol(procfile_lineword(ff, 0, 6)); - // p->tpgid = atol(procfile_lineword(ff, 0, 7)); - // p->flags = strtoull(procfile_lineword(ff, 0, 8), NULL, 10); + p->ppid = (int32_t)str2ul(procfile_lineword(ff, 0, 3)); + // p->pgrp = str2ul(procfile_lineword(ff, 0, 4)); + // p->session = str2ul(procfile_lineword(ff, 0, 5)); + // p->tty_nr = str2ul(procfile_lineword(ff, 0, 6)); + // p->tpgid = str2ul(procfile_lineword(ff, 0, 7)); + // p->flags = str2ull(procfile_lineword(ff, 0, 8)); unsigned long long last; last = p->minflt_raw; - p->minflt_raw = strtoull(procfile_lineword(ff, 0, 9), NULL, 10); - p->minflt = (p->minflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->minflt_raw = str2ull(procfile_lineword(ff, 0, 9)); + p->minflt = (p->minflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->cminflt_raw; - p->cminflt_raw = strtoull(procfile_lineword(ff, 0, 10), NULL, 10); - p->cminflt = (p->cminflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->cminflt_raw = str2ull(procfile_lineword(ff, 0, 10)); + p->cminflt = (p->cminflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->majflt_raw; - p->majflt_raw = strtoull(procfile_lineword(ff, 0, 11), NULL, 10); - p->majflt = (p->majflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->majflt_raw = str2ull(procfile_lineword(ff, 0, 11)); + p->majflt = (p->majflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->cmajflt_raw; - p->cmajflt_raw = strtoull(procfile_lineword(ff, 0, 12), NULL, 10); - p->cmajflt = (p->cmajflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->cmajflt_raw = str2ull(procfile_lineword(ff, 0, 12)); + p->cmajflt = (p->cmajflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->utime_raw; - p->utime_raw = strtoull(procfile_lineword(ff, 0, 13), NULL, 10); - p->utime = (p->utime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->utime_raw = str2ull(procfile_lineword(ff, 0, 13)); + p->utime = (p->utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->stime_raw; - p->stime_raw = strtoull(procfile_lineword(ff, 0, 14), NULL, 10); - p->stime = (p->stime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->stime_raw = str2ull(procfile_lineword(ff, 0, 14)); + p->stime = (p->stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->cutime_raw; - p->cutime_raw = strtoull(procfile_lineword(ff, 0, 15), NULL, 10); - p->cutime = (p->cutime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->cutime_raw = str2ull(procfile_lineword(ff, 0, 15)); + p->cutime = (p->cutime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->cstime_raw; - p->cstime_raw = strtoull(procfile_lineword(ff, 0, 16), NULL, 10); - p->cstime = (p->cstime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); - - // p->priority = strtoull(procfile_lineword(ff, 0, 17), NULL, 10); - // p->nice = strtoull(procfile_lineword(ff, 0, 18), NULL, 10); - p->num_threads = (int32_t) atol(procfile_lineword(ff, 0, 19)); - // p->itrealvalue = strtoull(procfile_lineword(ff, 0, 20), NULL, 10); - // p->starttime = strtoull(procfile_lineword(ff, 0, 21), NULL, 10); - // p->vsize = strtoull(procfile_lineword(ff, 0, 22), NULL, 10); - // p->rss = strtoull(procfile_lineword(ff, 0, 23), NULL, 10); - // p->rsslim = strtoull(procfile_lineword(ff, 0, 24), NULL, 10); - // p->starcode = strtoull(procfile_lineword(ff, 0, 25), NULL, 10); - // p->endcode = strtoull(procfile_lineword(ff, 0, 26), NULL, 10); - // p->startstack = strtoull(procfile_lineword(ff, 0, 27), NULL, 10); - // p->kstkesp = strtoull(procfile_lineword(ff, 0, 28), NULL, 10); - // p->kstkeip = strtoull(procfile_lineword(ff, 0, 29), NULL, 10); - // p->signal = strtoull(procfile_lineword(ff, 0, 30), NULL, 10); - // p->blocked = strtoull(procfile_lineword(ff, 0, 31), NULL, 10); - // p->sigignore = strtoull(procfile_lineword(ff, 0, 32), NULL, 10); - // p->sigcatch = strtoull(procfile_lineword(ff, 0, 33), NULL, 10); - // p->wchan = strtoull(procfile_lineword(ff, 0, 34), NULL, 10); - // p->nswap = strtoull(procfile_lineword(ff, 0, 35), NULL, 10); - // p->cnswap = strtoull(procfile_lineword(ff, 0, 36), NULL, 10); - // p->exit_signal = atol(procfile_lineword(ff, 0, 37)); - // p->processor = atol(procfile_lineword(ff, 0, 38)); - // p->rt_priority = strtoul(procfile_lineword(ff, 0, 39), NULL, 10); - // p->policy = strtoul(procfile_lineword(ff, 0, 40), NULL, 10); - // p->delayacct_blkio_ticks = strtoull(procfile_lineword(ff, 0, 41), NULL, 10); + p->cstime_raw = str2ull(procfile_lineword(ff, 0, 16)); + p->cstime = (p->cstime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + + // p->priority = str2ull(procfile_lineword(ff, 0, 17)); + // p->nice = str2ull(procfile_lineword(ff, 0, 18)); + p->num_threads = (int32_t)str2ul(procfile_lineword(ff, 0, 19)); + // p->itrealvalue = str2ull(procfile_lineword(ff, 0, 20)); + // p->starttime = str2ull(procfile_lineword(ff, 0, 21)); + // p->vsize = str2ull(procfile_lineword(ff, 0, 22)); + // p->rss = str2ull(procfile_lineword(ff, 0, 23)); + // p->rsslim = str2ull(procfile_lineword(ff, 0, 24)); + // p->starcode = str2ull(procfile_lineword(ff, 0, 25)); + // p->endcode = str2ull(procfile_lineword(ff, 0, 26)); + // p->startstack = str2ull(procfile_lineword(ff, 0, 27)); + // p->kstkesp = str2ull(procfile_lineword(ff, 0, 28)); + // p->kstkeip = str2ull(procfile_lineword(ff, 0, 29)); + // p->signal = str2ull(procfile_lineword(ff, 0, 30)); + // p->blocked = str2ull(procfile_lineword(ff, 0, 31)); + // p->sigignore = str2ull(procfile_lineword(ff, 0, 32)); + // p->sigcatch = str2ull(procfile_lineword(ff, 0, 33)); + // p->wchan = str2ull(procfile_lineword(ff, 0, 34)); + // p->nswap = str2ull(procfile_lineword(ff, 0, 35)); + // p->cnswap = str2ull(procfile_lineword(ff, 0, 36)); + // p->exit_signal = str2ul(procfile_lineword(ff, 0, 37)); + // p->processor = str2ul(procfile_lineword(ff, 0, 38)); + // p->rt_priority = str2ul(procfile_lineword(ff, 0, 39)); + // p->policy = str2ul(procfile_lineword(ff, 0, 40)); + // p->delayacct_blkio_ticks = str2ull(procfile_lineword(ff, 0, 41)); if(enable_guest_charts) { last = p->gtime_raw; - p->gtime_raw = strtoull(procfile_lineword(ff, 0, 42), NULL, 10); - p->gtime = (p->gtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->gtime_raw = str2ull(procfile_lineword(ff, 0, 42)); + p->gtime = (p->gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); last = p->cgtime_raw; - p->cgtime_raw = strtoull(procfile_lineword(ff, 0, 43), NULL, 10); - p->cgtime = (p->cgtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); + p->cgtime_raw = str2ull(procfile_lineword(ff, 0, 43)); + p->cgtime = (p->cgtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec); if (show_guest_time || p->gtime || p->cgtime) { p->utime -= (p->utime >= p->gtime) ? p->gtime : p->utime; @@ -715,7 +735,7 @@ cleanup: return 0; } -int read_proc_pid_statm(struct pid_stat *p) { +static inline int read_proc_pid_statm(struct pid_stat *p) { static procfile *ff = NULL; if(unlikely(!p->statm_filename)) { @@ -732,13 +752,13 @@ int read_proc_pid_statm(struct pid_stat *p) { file_counter++; - p->statm_size = strtoull(procfile_lineword(ff, 0, 0), NULL, 10); - p->statm_resident = strtoull(procfile_lineword(ff, 0, 1), NULL, 10); - p->statm_share = strtoull(procfile_lineword(ff, 0, 2), NULL, 10); - // p->statm_text = strtoull(procfile_lineword(ff, 0, 3), NULL, 10); - // p->statm_lib = strtoull(procfile_lineword(ff, 0, 4), NULL, 10); - // p->statm_data = strtoull(procfile_lineword(ff, 0, 5), NULL, 10); - // p->statm_dirty = strtoull(procfile_lineword(ff, 0, 6), NULL, 10); + p->statm_size = str2ull(procfile_lineword(ff, 0, 0)); + p->statm_resident = str2ull(procfile_lineword(ff, 0, 1)); + p->statm_share = str2ull(procfile_lineword(ff, 0, 2)); + // p->statm_text = str2ull(procfile_lineword(ff, 0, 3)); + // p->statm_lib = str2ull(procfile_lineword(ff, 0, 4)); + // p->statm_data = str2ull(procfile_lineword(ff, 0, 5)); + // p->statm_dirty = str2ull(procfile_lineword(ff, 0, 6)); return 1; @@ -753,7 +773,7 @@ cleanup: return 0; } -int read_proc_pid_io(struct pid_stat *p) { +static inline int read_proc_pid_io(struct pid_stat *p) { static procfile *ff = NULL; if(unlikely(!p->io_filename)) { @@ -772,37 +792,37 @@ int read_proc_pid_io(struct pid_stat *p) { file_counter++; p->last_io_collected_usec = p->io_collected_usec; - p->io_collected_usec = time_usec(); + p->io_collected_usec = now_realtime_usec(); unsigned long long last; last = p->io_logical_bytes_read_raw; - p->io_logical_bytes_read_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10); - p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); + p->io_logical_bytes_read_raw = str2ull(procfile_lineword(ff, 0, 1)); + p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); last = p->io_logical_bytes_written_raw; - p->io_logical_bytes_written_raw = strtoull(procfile_lineword(ff, 1, 1), NULL, 10); - p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); + p->io_logical_bytes_written_raw = str2ull(procfile_lineword(ff, 1, 1)); + p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); // last = p->io_read_calls_raw; - // p->io_read_calls_raw = strtoull(procfile_lineword(ff, 2, 1), NULL, 10); - // p->io_read_calls = (p->io_read_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); + // p->io_read_calls_raw = str2ull(procfile_lineword(ff, 2, 1)); + // p->io_read_calls = (p->io_read_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); // last = p->io_write_calls_raw; - // p->io_write_calls_raw = strtoull(procfile_lineword(ff, 3, 1), NULL, 10); - // p->io_write_calls = (p->io_write_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); + // p->io_write_calls_raw = str2ull(procfile_lineword(ff, 3, 1)); + // p->io_write_calls = (p->io_write_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); last = p->io_storage_bytes_read_raw; - p->io_storage_bytes_read_raw = strtoull(procfile_lineword(ff, 4, 1), NULL, 10); - p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); + p->io_storage_bytes_read_raw = str2ull(procfile_lineword(ff, 4, 1)); + p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); last = p->io_storage_bytes_written_raw; - p->io_storage_bytes_written_raw = strtoull(procfile_lineword(ff, 5, 1), NULL, 10); - p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); + p->io_storage_bytes_written_raw = str2ull(procfile_lineword(ff, 5, 1)); + p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); // last = p->io_cancelled_write_bytes_raw; - // p->io_cancelled_write_bytes_raw = strtoull(procfile_lineword(ff, 6, 1), NULL, 10); - // p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); + // p->io_cancelled_write_bytes_raw = str2ull(procfile_lineword(ff, 6, 1)); + // p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec); if(unlikely(global_iterations_counter == 1)) { p->io_logical_bytes_read = 0; @@ -831,10 +851,11 @@ unsigned long long global_utime = 0; unsigned long long global_stime = 0; unsigned long long global_gtime = 0; -int read_proc_stat() { +static inline int read_proc_stat() { static char filename[FILENAME_MAX + 1] = ""; static procfile *ff = NULL; - static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0, collected_usec = 0, last_collected_usec = 0; + static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0; + static usec_t collected_usec = 0, last_collected_usec = 0; if(unlikely(!ff)) { snprintfz(filename, FILENAME_MAX, "%s/proc/stat", global_host_prefix); @@ -846,34 +867,34 @@ int read_proc_stat() { if(unlikely(!ff)) goto cleanup; last_collected_usec = collected_usec; - collected_usec = time_usec(); + collected_usec = now_realtime_usec(); file_counter++; unsigned long long last; last = utime_raw; - utime_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10); - global_utime = (utime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec); + utime_raw = str2ull(procfile_lineword(ff, 0, 1)); + global_utime = (utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec); // nice time, on user time last = ntime_raw; - ntime_raw = strtoull(procfile_lineword(ff, 0, 2), NULL, 10); - global_utime += (ntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec); + ntime_raw = str2ull(procfile_lineword(ff, 0, 2)); + global_utime += (ntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec); last = stime_raw; - stime_raw = strtoull(procfile_lineword(ff, 0, 3), NULL, 10); - global_stime = (stime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec); + stime_raw = str2ull(procfile_lineword(ff, 0, 3)); + global_stime = (stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec); last = gtime_raw; - gtime_raw = strtoull(procfile_lineword(ff, 0, 10), NULL, 10); - global_gtime = (gtime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec); + gtime_raw = str2ull(procfile_lineword(ff, 0, 10)); + global_gtime = (gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec); if(enable_guest_charts) { // guest nice time, on guest time last = gntime_raw; - gntime_raw = strtoull(procfile_lineword(ff, 0, 11), NULL, 10); - global_gtime += (gntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec); + gntime_raw = str2ull(procfile_lineword(ff, 0, 11)); + global_gtime += (gntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec); // remove guest time from user time global_utime -= (global_utime > global_gtime) ? global_gtime : global_utime; @@ -966,7 +987,7 @@ static struct file_descriptor *file_descriptor_find(const char *name, uint32_t h #define FILETYPE_TIMERFD 7 #define FILETYPE_SIGNALFD 8 -void file_descriptor_not_used(int id) +static inline void file_descriptor_not_used(int id) { if(id > 0 && id < all_files_size) { @@ -987,7 +1008,9 @@ void file_descriptor_not_used(int id) if(unlikely(debug)) fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id); - file_descriptor_remove(&all_files[id]); + if(unlikely(file_descriptor_remove(&all_files[id]) != (void *)&all_files[id])) + error("INTERNAL ERROR: removal of unused fd from index, removed a different fd"); + #ifdef NETDATA_INTERNAL_CHECKS all_files[id].magic = 0x00000000; #endif /* NETDATA_INTERNAL_CHECKS */ @@ -1000,69 +1023,60 @@ void file_descriptor_not_used(int id) else error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size); } -int file_descriptor_find_or_add(const char *name) -{ - static 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); - - fd->count++; - return fd->pos; - } - // not found + all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor)); - // check we have enough memory to add it - if(!all_files || all_files_len == all_files_size) { - void *old = all_files; - int i; + // if the address changed, we have to rebuild the index + // since all pointers are now invalid - // 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)); - - // 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"); + 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."); + } - all_files_index.root = NULL; - for(i = 0; i < all_files_size; i++) { - if(!all_files[i].count) continue; - file_descriptor_add(&all_files[i]); - } + if(unlikely(debug)) + fprintf(stderr, "apps.plugin: >> re-indexing done.\n"); + } - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> re-indexing done.\n"); - } + // initialize the newly added entries - 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; @@ -1080,23 +1094,58 @@ 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; @@ -1120,23 +1169,10 @@ 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 */ - file_descriptor_add(&all_files[c]); - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name); - - return c; + return file_descriptor_set_on_empty_slot(name, hash, type); } -int read_pid_file_descriptors(struct pid_stat *p) { +static inline int read_pid_file_descriptors(struct pid_stat *p) { char dirname[FILENAME_MAX+1]; snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid); @@ -1156,22 +1192,18 @@ int read_pid_file_descriptors(struct pid_stat *p) { continue; // check if the fds array is small - int fdid = atoi(de->d_name); + int fdid = (int)str2l(de->d_name); if(fdid < 0) continue; if(fdid >= p->fds_size) { // it is small, extend it 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); + 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 + 100) * sizeof(int)); - if(!p->fds) { - fatal("Cannot re-allocate fds for %s", p->comm); - break; - } + p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int)); // and initialize it - for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0; - p->fds_size = fdid + 100; + for(c = p->fds_size ; c < (fdid + MAX_SPARE_FDS) ; c++) p->fds[c] = 0; + p->fds_size = fdid + MAX_SPARE_FDS; } if(p->fds[fdid] == 0) { @@ -1214,7 +1246,7 @@ int read_pid_file_descriptors(struct pid_stat *p) { // ---------------------------------------------------------------------------- -int print_process_and_parents(struct pid_stat *p, unsigned long long time) { +static inline int print_process_and_parents(struct pid_stat *p, unsigned long long time) { char *prefix = "\\_ "; int indent = 0; @@ -1253,13 +1285,13 @@ int print_process_and_parents(struct pid_stat *p, unsigned long long time) { return indent + 1; } -void print_process_tree(struct pid_stat *p, char *msg) { +static inline void print_process_tree(struct pid_stat *p, char *msg) { log_date(stderr); fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited"); print_process_and_parents(p, p->stat_collected_usec); } -void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) { +static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) { int found = 0; struct pid_stat *p = NULL; @@ -1329,7 +1361,7 @@ void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int typ } } -unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) { +static inline unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) { unsigned long long absorbed = 0; if(*field > *pfield) { @@ -1346,7 +1378,7 @@ unsigned long long remove_exited_child_from_parent(unsigned long long *field, un return absorbed; } -void process_exited_processes() { +static inline void process_exited_processes() { struct pid_stat *p; for(p = root_of_pids; p ; p = p->next) { @@ -1439,11 +1471,11 @@ void process_exited_processes() { ); } - p->utime_raw = utime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL); - p->stime_raw = stime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL); - p->gtime_raw = gtime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL); - p->minflt_raw = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL); - p->majflt_raw = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL); + p->utime_raw = utime * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); + p->stime_raw = stime * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); + p->gtime_raw = gtime * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); + p->minflt_raw = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); + p->majflt_raw = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0; if(unlikely(debug)) @@ -1459,7 +1491,7 @@ void process_exited_processes() { } } -void link_all_processes_to_their_parents(void) { +static inline void link_all_processes_to_their_parents(void) { struct pid_stat *p, *pp; // link all children to their parents @@ -1562,15 +1594,15 @@ static inline int managed_log(struct pid_stat *p, uint32_t log, int status) { return status; } -void collect_data_for_pid(pid_t pid) { +static inline int collect_data_for_pid(pid_t pid) { if(unlikely(pid <= 0 || pid > pid_max)) { error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max); - return; + return 0; } struct pid_stat *p = get_pid_entry(pid); - if(unlikely(!p || p->read)) return; - p->read = 1; + if(unlikely(!p || p->read)) return 0; + p->read = 1; // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist); @@ -1579,7 +1611,7 @@ void collect_data_for_pid(pid_t pid) { if(unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p)))) // there is no reason to proceed if we cannot get its status - return; + return 0; read_proc_pid_ownership(p); @@ -1599,7 +1631,7 @@ void collect_data_for_pid(pid_t pid) { if(unlikely(!managed_log(p, PID_LOG_STATM, read_proc_pid_statm(p)))) // there is no reason to proceed if we cannot get its memory status - return; + return 0; // -------------------------------------------------------------------- // link it @@ -1658,9 +1690,11 @@ void collect_data_for_pid(pid_t pid) { p->updated = 1; p->keep = 0; p->keeploops = 0; + + return 1; } -int collect_data_for_all_processes_from_proc(void) { +static int collect_data_for_all_processes_from_proc(void) { struct pid_stat *p = NULL; if(all_pids_count) { @@ -1688,7 +1722,7 @@ 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]); } @@ -1714,6 +1748,9 @@ int collect_data_for_all_processes_from_proc(void) { } closedir(dir); + if(!all_pids_count) + return 0; + // normally this is done // however we may have processes exited while we collected values // so let's find the exited ones @@ -1743,7 +1780,7 @@ int collect_data_for_all_processes_from_proc(void) { // 9. find the unique file count for each target // check: update_apps_groups_statistics() -void cleanup_exited_pids(void) { +static void cleanup_exited_pids(void) { int c; struct pid_stat *p = NULL; @@ -1771,7 +1808,7 @@ void cleanup_exited_pids(void) { } } -void apply_apps_groups_targets_inheritance(void) { +static void apply_apps_groups_targets_inheritance(void) { struct pid_stat *p = NULL; // children that do not have a target @@ -1881,16 +1918,13 @@ void apply_apps_groups_targets_inheritance(void) { fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops); } -long zero_all_targets(struct target *root) { +static long zero_all_targets(struct target *root) { struct target *w; long count = 0; 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; @@ -1920,132 +1954,168 @@ 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; } -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(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); + 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; + + case FILETYPE_TIMERFD: + w->opentimerfds++; + break; + + case FILETYPE_SIGNALFD: + w->opensignalfds++; + break; + + case FILETYPE_EVENTPOLL: + w->openeventpolls++; + break; + + default: + w->openother++; + break; } } -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; + } + + 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; - freez(w->fds); - w->fds = NULL; + 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); } -void calculate_netdata_statistics(void) { +static void calculate_netdata_statistics(void) { + apply_apps_groups_targets_inheritance(); zero_all_targets(users_root_target); @@ -2056,19 +2126,18 @@ 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; @@ -2079,14 +2148,12 @@ 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; @@ -2097,16 +2164,15 @@ 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(); } @@ -2114,72 +2180,58 @@ 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; double minflt_fix_ratio = 1.0, majflt_fix_ratio = 1.0, cminflt_fix_ratio = 1.0, cmajflt_fix_ratio = 1.0; -unsigned long long send_resource_usage_to_netdata() { +static usec_t send_resource_usage_to_netdata() { static struct timeval last = { 0, 0 }; static struct rusage me_last; struct timeval now; struct rusage me; - unsigned long long usec; - unsigned long long cpuuser; - unsigned long long cpusyst; + usec_t usec; + usec_t cpuuser; + usec_t cpusyst; if(!last.tv_sec) { - gettimeofday(&last, NULL); + now_realtime_timeval(&last); getrusage(RUSAGE_SELF, &me_last); // the first time, give a zero to allow // netdata calibrate to the current time - // usec = update_every * 1000000ULL; + // usec = update_every * USEC_PER_SEC; usec = 0ULL; cpuuser = 0; cpusyst = 0; } else { - gettimeofday(&now, NULL); + now_realtime_timeval(&now); getrusage(RUSAGE_SELF, &me); - usec = usec_dt(&now, &last); - cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec; - cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec; + usec = dt_usec(&now, &last); + cpuuser = me.ru_utime.tv_sec * USEC_PER_SEC + me.ru_utime.tv_usec; + cpusyst = me.ru_stime.tv_sec * USEC_PER_SEC + me.ru_stime.tv_usec; memmove(&last, &now, sizeof(struct timeval)); 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" @@ -2214,7 +2266,7 @@ unsigned long long 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" @@ -2233,7 +2285,7 @@ unsigned long long send_resource_usage_to_netdata() { return usec; } -void normalize_data(struct target *root) { +static void normalize_data(struct target *root) { struct target *w; // childs processing introduces spikes @@ -2379,7 +2431,7 @@ void normalize_data(struct target *root) { } } -void send_collected_data_to_netdata(struct target *root, const char *type, unsigned long long usec) { +static void send_collected_data_to_netdata(struct target *root, const char *type, usec_t usec) { struct target *w; send_BEGIN(type, "cpu", usec); @@ -2510,7 +2562,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig // ---------------------------------------------------------------------------- // generate the charts -void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title) +static void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title) { struct target *w; int newly_added = 0; @@ -2530,112 +2582,112 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const // 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); } } } @@ -2644,20 +2696,25 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const // ---------------------------------------------------------------------------- // parse command line arguments -void parse_args(int argc, char **argv) +static void parse_args(int argc, char **argv) { int i, freq = 0; char *name = NULL; for(i = 1; i < argc; i++) { if(!freq) { - int n = atoi(argv[i]); + int n = (int)str2l(argv[i]); if(n > 0) { freq = n; continue; } } + if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0) { + printf("apps.plugin %s\n", VERSION); + exit(0); + } + if(strcmp("debug", argv[i]) == 0) { debug = 1; // debug_flags = 0xffffffff; @@ -2694,35 +2751,52 @@ void parse_args(int argc, char **argv) continue; } + if(strcmp("no-users", argv[i]) == 0 || strcmp("without-users", argv[i]) == 0) { + enable_users_charts = 0; + continue; + } + + if(strcmp("no-groups", argv[i]) == 0 || strcmp("without-groups", argv[i]) == 0) { + enable_groups_charts = 0; + continue; + } + if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) { fprintf(stderr, - "apps.plugin\n" - "(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" + "\n" + , VERSION ); exit(1); } @@ -2740,7 +2814,7 @@ void parse_args(int argc, char **argv) if(!name) name = "groups"; if(read_apps_groups_conf(name)) { - error("Cannot read process groups %s", name); + error("Cannot read process groups '%s/apps_%s.conf'. There are no internal defaults. Failing.", config_dir, name); exit(1); } } @@ -2786,8 +2860,7 @@ int main(int argc, char **argv) procfile_adaptive_initial_allocation = 1; - time_t started_t = time(NULL); - time_t current_t; + time_t started_t = now_realtime_sec(); get_system_HZ(); get_system_pid_max(); get_system_cpus(); @@ -2797,8 +2870,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" @@ -2818,7 +2890,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" @@ -2829,22 +2901,23 @@ int main(int argc, char **argv) , RATES_DETAIL ); -#ifndef PROFILING_MODE - unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL; - unsigned long long sunow; -#endif /* PROFILING_MODE */ - + usec_t step = update_every * USEC_PER_SEC; global_iterations_counter = 1; for(;1; global_iterations_counter++) { -#ifndef PROFILING_MODE - // delay until it is our time to run - while((sunow = time_usec()) < sunext) - sleep_usec(sunext - sunow); - - // find the next time we need to run - while(time_usec() > sunext) - sunext += update_every * 1000000ULL; -#endif /* PROFILING_MODE */ + 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..."); @@ -2855,36 +2928,35 @@ int main(int argc, char **argv) calculate_netdata_statistics(); normalize_data(apps_groups_root_target); - unsigned long long dt = send_resource_usage_to_netdata(); + usec_t dt = send_resource_usage_to_netdata(); // this is smart enough to show only newly added apps, when needed send_charts_updates_to_netdata(apps_groups_root_target, "apps", "Apps"); - send_charts_updates_to_netdata(users_root_target, "users", "Users"); - send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups"); + + if(likely(enable_users_charts)) + send_charts_updates_to_netdata(users_root_target, "users", "Users"); + + if(likely(enable_groups_charts)) + send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups"); send_collected_data_to_netdata(apps_groups_root_target, "apps", dt); - send_collected_data_to_netdata(users_root_target, "users", dt); - send_collected_data_to_netdata(groups_root_target, "groups", dt); - show_guest_time_old = show_guest_time; + if(likely(enable_users_charts)) + send_collected_data_to_netdata(users_root_target, "users", dt); - //if(puts(buffer_tostring(output)) == EOF) - if(write(STDOUT_FILENO, buffer_tostring(output), buffer_strlen(output)) == -1) - fatal("Cannot send chart values to netdata."); + if(likely(enable_groups_charts)) + send_collected_data_to_netdata(groups_root_target, "groups", dt); - // fflush(stdout); - buffer_flush(output); + fflush(stdout); + + show_guest_time_old = show_guest_time; if(unlikely(debug)) fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter); - current_t = time(NULL); + time_t current_t = now_realtime_sec(); -#ifndef PROFILING_MODE // restart check (14400 seconds) if(current_t - started_t > 14400) exit(0); -#else - if(current_t - started_t > 10) exit(0); -#endif /* PROFILING_MODE */ } } |