@cryptotaxi247 / netdata-1 / commits / 3274015c7

apps.plugin now reports exited children resources too

Costa Tsaousis (ktsaou) committed Jun 27, 2016 at 10:34 UTC 3274015c70404e31f3719ff26e79167684389b0b
2 files changed +153 -379
src/apps_plugin.c
+150 -376
@@ -47,8 +47,8 @@
47 #define MAX_NAME 100
48 #define MAX_CMDLINE 1024
49
50 -long processors = 1;
51 -long pid_max = 32768;
50 +int processors = 1;
51 +pid_t pid_max = 32768;
52 int debug = 0;
53
54 int update_every = 1;
@@ -58,160 +58,6 @@ int proc_pid_cmdline_is_needed = 0;
58 char *host_prefix = "";
59 char *config_dir = CONFIG_DIR;
60
61 -#ifdef NETDATA_INTERNAL_CHECKS
62 -// ----------------------------------------------------------------------------
63 -// memory debugger
64 -// do not use in production systems - it mis-aligns allocated memory
65 -
66 -struct allocations {
67 - size_t allocations;
68 - size_t allocated;
69 - size_t allocated_max;
70 -} allocations = { 0, 0, 0 };
71 -
72 -#define MALLOC_MARK (uint32_t)(0x0BADCAFE)
73 -#define MALLOC_PREFIX (sizeof(uint32_t) * 2)
74 -#define MALLOC_SUFFIX (sizeof(uint32_t))
75 -#define MALLOC_OVERHEAD (MALLOC_PREFIX + MALLOC_SUFFIX)
76 -
77 -void *mark_allocation(void *allocated_ptr, size_t size_without_overheads) {
78 - uint32_t *real_ptr = (uint32_t *)allocated_ptr;
79 - real_ptr[0] = MALLOC_MARK;
80 - real_ptr[1] = (uint32_t) size_without_overheads;
81 -
82 - uint32_t *end_ptr = (uint32_t *)(allocated_ptr + MALLOC_PREFIX + size_without_overheads);
83 - end_ptr[0] = MALLOC_MARK;
84 -
85 - // fprintf(stderr, "MEMORY_POINTER: Allocated at %p, returning %p.\n", allocated_ptr, (void *)(allocated_ptr + MALLOC_PREFIX));
86 -
87 - return allocated_ptr + MALLOC_PREFIX;
88 -}
89 -
90 -void *check_allocation(const char *file, int line, const char *function, void *marked_ptr, size_t *size_without_overheads_ptr) {
91 - uint32_t *real_ptr = (uint32_t *)(marked_ptr - MALLOC_PREFIX);
92 -
93 - // 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);
94 -
95 - if(real_ptr[0] != MALLOC_MARK) fatal("MEMORY: prefix MARK is not valid for %s/%d@%s.", function, line, file);
96 -
97 - size_t size = real_ptr[1];
98 -
99 - uint32_t *end_ptr = (uint32_t *)(marked_ptr + size);
100 - if(end_ptr[0] != MALLOC_MARK) fatal("MEMORY: suffix MARK of allocation with size %zu is not valid for %s/%d@%s.", size, function, line, file);
101 -
102 - if(size_without_overheads_ptr) *size_without_overheads_ptr = size;
103 -
104 - return real_ptr;
105 -}
106 -
107 -void *malloc_debug(const char *file, int line, const char *function, size_t size) {
108 - void *ptr = malloc(size + MALLOC_OVERHEAD);
109 - if(!ptr) fatal("MEMORY: Cannot allocate %zu bytes for %s/%d@%s.", size, function, line, file);
110 -
111 - allocations.allocated += size;
112 - allocations.allocations++;
113 -
114 - debug(D_MEMORY, "MEMORY: Allocated %zu bytes for %s/%d@%s."
115 - " Status: allocated %zu in %zu allocs."
116 - , size
117 - , function, line, file
118 - , allocations.allocated
119 - , allocations.allocations
120 - );
121 -
122 - if(allocations.allocated > allocations.allocated_max) {
123 - debug(D_MEMORY, "MEMORY: total allocation peak increased from %zu to %zu", allocations.allocated_max, allocations.allocated);
124 - allocations.allocated_max = allocations.allocated;
125 - }
126 -
127 - size_t csize;
128 - check_allocation(file, line, function, mark_allocation(ptr, size), &csize);
129 - if(size != csize) {
130 - fatal("Invalid size.");
131 - }
132 -
133 - return mark_allocation(ptr, size);
134 -}
135 -
136 -void *calloc_debug(const char *file, int line, const char *function, size_t nmemb, size_t size) {
137 - void *ptr = malloc_debug(file, line, function, (nmemb * size));
138 - bzero(ptr, nmemb * size);
139 - return ptr;
140 -}
141 -
142 -void free_debug(const char *file, int line, const char *function, void *ptr) {
143 - size_t size;
144 - void *real_ptr = check_allocation(file, line, function, ptr, &size);
145 -
146 - bzero(real_ptr, size + MALLOC_OVERHEAD);
147 -
148 - free(real_ptr);
149 - allocations.allocated -= size;
150 - allocations.allocations--;
151 -
152 - debug(D_MEMORY, "MEMORY: freed %zu bytes for %s/%d@%s."
153 - " Status: allocated %zu in %zu allocs."
154 - , size
155 - , function, line, file
156 - , allocations.allocated
157 - , allocations.allocations
158 - );
159 -}
160 -
161 -void *realloc_debug(const char *file, int line, const char *function, void *ptr, size_t size) {
162 - if(!ptr) return malloc_debug(file, line, function, size);
163 - if(!size) { free_debug(file, line, function, ptr); return NULL; }
164 -
165 - size_t old_size;
166 - void *real_ptr = check_allocation(file, line, function, ptr, &old_size);
167 -
168 - void *new_ptr = realloc(real_ptr, size + MALLOC_OVERHEAD);
169 - if(!new_ptr) fatal("MEMORY: Cannot allocate %zu bytes for %s/%d@%s.", size, function, line, file);
170 -
171 - allocations.allocated += size;
172 - allocations.allocated -= old_size;
173 -
174 - debug(D_MEMORY, "MEMORY: Re-allocated from %zu to %zu bytes for %s/%d@%s."
175 - " Status: allocated %zu in %zu allocs."
176 - , old_size, size
177 - , function, line, file
178 - , allocations.allocated
179 - , allocations.allocations
180 - );
181 -
182 - if(allocations.allocated > allocations.allocated_max) {
183 - debug(D_MEMORY, "MEMORY: total allocation peak increased from %zu to %zu", allocations.allocated_max, allocations.allocated);
184 - allocations.allocated_max = allocations.allocated;
185 - }
186 -
187 - return mark_allocation(new_ptr, size);
188 -}
189 -
190 -char *strdup_debug(const char *file, int line, const char *function, const char *ptr) {
191 - size_t size = 0;
192 - const char *s = ptr;
193 -
194 - while(*s++) size++;
195 - size++;
196 -
197 - char *p = malloc_debug(file, line, function, size);
198 - if(!p) fatal("Cannot allocate %zu bytes.", size);
199 -
200 - memcpy(p, ptr, size);
201 - return p;
202 -}
203 -
204 -#define malloc(size) malloc_debug(__FILE__, __LINE__, __FUNCTION__, (size))
205 -#define calloc(nmemb, size) calloc_debug(__FILE__, __LINE__, __FUNCTION__, (nmemb), (size))
206 -#define realloc(ptr, size) realloc_debug(__FILE__, __LINE__, __FUNCTION__, (ptr), (size))
207 -#define free(ptr) free_debug(__FILE__, __LINE__, __FUNCTION__, (ptr))
208 -
209 -#ifdef strdup
210 -#undef strdup
211 -#endif
212 -#define strdup(ptr) strdup_debug(__FILE__, __LINE__, __FUNCTION__, (ptr))
213 -
214 -#endif /* NETDATA_INTERNAL_CHECKS */
61
62 // ----------------------------------------------------------------------------
63
@@ -254,9 +100,9 @@ long get_system_cpus(void) {
100 return processors;
101 }
102
257 -long get_system_pid_max(void) {
103 +pid_t get_system_pid_max(void) {
104 procfile *ff = NULL;
259 - long mpid = 32768;
105 + pid_t mpid = 32768;
106
107 char filename[FILENAME_MAX + 1];
108 snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
@@ -269,7 +115,7 @@ long get_system_pid_max(void) {
115 return mpid;
116 }
117
272 - mpid = atol(procfile_lineword(ff, 0, 0));
118 + mpid = (pid_t)atoi(procfile_lineword(ff, 0, 0));
119 if(!mpid) mpid = 32768;
120
121 procfile_close(ff);
@@ -304,14 +150,14 @@ struct target {
150 unsigned long long num_threads;
151 unsigned long long rss;
152
307 - unsigned long long fix_minflt;
308 - unsigned long long fix_cminflt;
309 - unsigned long long fix_majflt;
310 - unsigned long long fix_cmajflt;
311 - unsigned long long fix_utime;
312 - unsigned long long fix_stime;
313 - unsigned long long fix_cutime;
314 - unsigned long long fix_cstime;
153 + long long fix_minflt;
154 + long long fix_cminflt;
155 + long long fix_majflt;
156 + long long fix_cmajflt;
157 + long long fix_utime;
158 + long long fix_stime;
159 + long long fix_cutime;
160 + long long fix_cstime;
161
162 unsigned long long statm_size;
163 unsigned long long statm_resident;
@@ -675,14 +521,20 @@ struct pid_stat {
521 // we will subtract these values from the old
522 // target
523 unsigned long long last_minflt;
678 - unsigned long long last_cminflt;
524 unsigned long long last_majflt;
680 - unsigned long long last_cmajflt;
525 unsigned long long last_utime;
526 unsigned long long last_stime;
527 +
528 + unsigned long long last_cminflt;
529 + unsigned long long last_cmajflt;
530 unsigned long long last_cutime;
531 unsigned long long last_cstime;
532
533 + unsigned long long last_fix_cminflt;
534 + unsigned long long last_fix_cmajflt;
535 + unsigned long long last_fix_cutime;
536 + unsigned long long last_fix_cstime;
537 +
538 unsigned long long last_io_logical_bytes_read;
539 unsigned long long last_io_logical_bytes_written;
540 unsigned long long last_io_read_calls;
@@ -691,27 +543,10 @@ struct pid_stat {
543 unsigned long long last_io_storage_bytes_written;
544 unsigned long long last_io_cancelled_write_bytes;
545
694 -#ifdef AGGREGATE_CHILDREN_TO_PARENTS
695 - unsigned long long old_utime;
696 - unsigned long long old_stime;
697 - unsigned long long old_minflt;
698 - unsigned long long old_majflt;
699 -
700 - unsigned long long old_cutime;
701 - unsigned long long old_cstime;
702 - unsigned long long old_cminflt;
703 - unsigned long long old_cmajflt;
704 -
705 - unsigned long long fix_cutime;
706 - unsigned long long fix_cstime;
546 unsigned long long fix_cminflt;
547 unsigned long long fix_cmajflt;
709 -
710 - unsigned long long diff_cutime;
711 - unsigned long long diff_cstime;
712 - unsigned long long diff_cminflt;
713 - unsigned long long diff_cmajflt;
714 -#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
548 + unsigned long long fix_cutime;
549 + unsigned long long fix_cstime;
550
551 int *fds; // array of fds it uses
552 int fds_size; // the size of the fds array
@@ -765,7 +600,8 @@ void del_pid_entry(pid_t pid)
600 {
601 if(!all_pids[pid]) return;
602
768 - if(debug) fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
603 + if(unlikely(debug))
604 + fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
605
606 if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
607 if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
@@ -898,7 +734,7 @@ int read_proc_pid_stat(struct pid_stat *p) {
734 // p->guest_time = strtoull(procfile_lineword(ff, 0, 42+i), NULL, 10);
735 // p->cguest_time = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
736
901 - if(debug || (p->target && p->target->debug))
737 + if(unlikely(debug || (p->target && p->target->debug)))
738 fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
739
740 // procfile_close(ff);
@@ -1048,13 +884,16 @@ void file_descriptor_not_used(int id)
884 }
885 #endif /* NETDATA_INTERNAL_CHECKS */
886
1051 - if(debug) fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
887 + if(unlikely(debug))
888 + fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
889
890 if(all_files[id].count > 0) {
891 all_files[id].count--;
892
893 if(!all_files[id].count) {
1057 - if(debug) fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id);
894 + if(unlikely(debug))
895 + fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id);
896 +
897 file_descriptor_remove(&all_files[id]);
898 #ifdef NETDATA_INTERNAL_CHECKS
899 all_files[id].magic = 0x00000000;
@@ -1073,12 +912,15 @@ int file_descriptor_find_or_add(const char *name)
912 static int last_pos = 0;
913 uint32_t hash = simple_hash(name);
914
1076 - if(debug) fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
915 + if(unlikely(debug))
916 + fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
917
918 struct file_descriptor *fd = file_descriptor_find(name, hash);
919 if(fd) {
920 // found
1081 - if(debug) fprintf(stderr, "apps.plugin: >> found on slot %d\n", fd->pos);
921 + if(unlikely(debug))
922 + fprintf(stderr, "apps.plugin: >> found on slot %d\n", fd->pos);
923 +
924 fd->count++;
925 return fd->pos;
926 }
@@ -1090,19 +932,25 @@ int file_descriptor_find_or_add(const char *name)
932 int i;
933
934 // there is no empty slot
1093 - if(debug) fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
935 + if(unlikely(debug))
936 + fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
937 +
938 all_files = realloc(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
939
940 // if the address changed, we have to rebuild the index
941 // since all pointers are now invalid
942 if(old && old != (void *)all_files) {
1099 - if(debug) fprintf(stderr, "apps.plugin: >> re-indexing.\n");
943 + if(unlikely(debug))
944 + fprintf(stderr, "apps.plugin: >> re-indexing.\n");
945 +
946 all_files_index.root = NULL;
947 for(i = 0; i < all_files_size; i++) {
948 if(!all_files[i].count) continue;
949 file_descriptor_add(&all_files[i]);
950 }
1105 - if(debug) fprintf(stderr, "apps.plugin: >> re-indexing done.\n");
951 +
952 + if(unlikely(debug))
953 + fprintf(stderr, "apps.plugin: >> re-indexing done.\n");
954 }
955
956 for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
@@ -1118,7 +966,8 @@ int file_descriptor_find_or_add(const char *name)
966 all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
967 }
968
1121 - if(debug) fprintf(stderr, "apps.plugin: >> searching for empty slot.\n");
969 + if(unlikely(debug))
970 + fprintf(stderr, "apps.plugin: >> searching for empty slot.\n");
971
972 // search for an empty slot
973 int i, c;
@@ -1127,14 +976,17 @@ int file_descriptor_find_or_add(const char *name)
976 if(c == 0) continue;
977
978 if(!all_files[c].count) {
1130 - if(debug) fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c);
979 + if(unlikely(debug))
980 + fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c);
981
982 #ifdef NETDATA_INTERNAL_CHECKS
983 if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
984 error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
985 #endif /* NETDATA_INTERNAL_CHECKS */
986
1137 - 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);
987 + if(unlikely(debug))
988 + 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);
989 +
990 if(all_files[c].name) free((void *)all_files[c].name);
991 all_files[c].name = NULL;
992 last_pos = c;
@@ -1145,7 +997,9 @@ int file_descriptor_find_or_add(const char *name)
997 fatal("We should find an empty slot, but there isn't any");
998 exit(1);
999 }
1148 - if(debug) fprintf(stderr, "apps.plugin: >> updating slot %d.\n", c);
1000 +
1001 + if(unlikely(debug))
1002 + fprintf(stderr, "apps.plugin: >> updating slot %d.\n", c);
1003
1004 all_files_len++;
1005
@@ -1161,11 +1015,15 @@ int file_descriptor_find_or_add(const char *name)
1015 else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
1016 else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
1017 else if(strncmp(name, "anon_inode:", 11) == 0) {
1164 - if(debug) fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
1018 + if(unlikely(debug))
1019 + fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
1020 +
1021 type = FILETYPE_OTHER;
1022 }
1023 else {
1168 - if(debug) fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
1024 + if(unlikely(debug))
1025 + fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
1026 +
1027 type = FILETYPE_OTHER;
1028 }
1029
@@ -1179,7 +1037,8 @@ int file_descriptor_find_or_add(const char *name)
1037 #endif /* NETDATA_INTERNAL_CHECKS */
1038 file_descriptor_add(&all_files[c]);
1039
1182 - if(debug) fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
1040 + if(unlikely(debug))
1041 + fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
1042
1043 return c;
1044 }
@@ -1208,7 +1067,9 @@ int read_pid_file_descriptors(struct pid_stat *p) {
1067 if(fdid < 0) continue;
1068 if(fdid >= p->fds_size) {
1069 // it is small, extend it
1211 - if(debug) fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
1070 + if(unlikely(debug))
1071 + fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
1072 +
1073 p->fds = realloc(p->fds, (fdid + 100) * sizeof(int));
1074 if(!p->fds) {
1075 fatal("Cannot re-allocate fds for %s", p->comm);
@@ -1297,15 +1158,21 @@ int collect_data_for_all_processes_from_proc(void)
1158 p->merged = 0;
1159 p->new_entry = 0;
1160
1300 - p->last_minflt = p->minflt;
1301 - p->last_cminflt = p->cminflt;
1302 - p->last_majflt = p->majflt;
1303 - p->last_cmajflt = p->cmajflt;
1161 + p->last_minflt = p->minflt;
1162 + p->last_majflt = p->majflt;
1163 p->last_utime = p->utime;
1164 p->last_stime = p->stime;
1165 +
1166 + p->last_cminflt = p->cminflt;
1167 + p->last_cmajflt = p->cmajflt;
1168 p->last_cutime = p->cutime;
1169 p->last_cstime = p->cstime;
1170
1171 + p->last_fix_cminflt = p->fix_cminflt;
1172 + p->last_fix_cmajflt = p->fix_cmajflt;
1173 + p->last_fix_cutime = p->fix_cutime;
1174 + p->last_fix_cstime = p->fix_cstime;
1175 +
1176 p->last_io_logical_bytes_read = p->io_logical_bytes_read;
1177 p->last_io_logical_bytes_written = p->io_logical_bytes_written;
1178 p->last_io_read_calls = p->io_read_calls;
@@ -1320,8 +1187,13 @@ int collect_data_for_all_processes_from_proc(void)
1187 pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
1188
1189 // make sure we read a valid number
1323 - if(unlikely(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0'))
1190 + if(unlikely(endptr == file->d_name || *endptr != '\0'))
1191 + continue;
1192 +
1193 + if(unlikely(pid <= 0 || pid > pid_max)) {
1194 + error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
1195 continue;
1196 + }
1197
1198 p = get_pid_entry(pid);
1199 if(unlikely(!p)) continue;
@@ -1388,7 +1260,9 @@ int collect_data_for_all_processes_from_proc(void)
1260 // check if it is target
1261 // we do this only once, the first time this pid is loaded
1262 if(unlikely(p->new_entry)) {
1391 - if(debug) fprintf(stderr, "apps.plugin: \tJust added %s\n", p->comm);
1263 + if(unlikely(debug))
1264 + fprintf(stderr, "apps.plugin: \tJust added %s\n", p->comm);
1265 +
1266 uint32_t hash = simple_hash(p->comm);
1267 size_t pclen = strlen(p->comm);
1268
@@ -1434,49 +1308,6 @@ int collect_data_for_all_processes_from_proc(void)
1308 return 1;
1309 }
1310
1437 -
1438 -// ----------------------------------------------------------------------------
1439 -
1440 -#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1441 -// print a tree view of all processes
1442 -int debug_childrens_aggregations(pid_t pid, int level) {
1443 - struct pid_stat *p = NULL;
1444 - char b[level+3];
1445 - int i, ret = 0;
1446 -
1447 - for(i = 0; i < level; i++) b[i] = '\t';
1448 - b[level] = '|';
1449 - b[level+1] = '-';
1450 - b[level+2] = '\0';
1451 -
1452 - for(p = root_of_pids; p ; p = p->next) {
1453 - if(p->ppid == pid) {
1454 - ret += debug_childrens_aggregations(p->pid, level+1);
1455 - }
1456 - }
1457 -
1458 - p = all_pids[pid];
1459 - if(p) {
1460 - if(!p->updated) ret += 1;
1461 - if(ret) fprintf(stderr, "%s %s %d [%s, %s] c=%d u=%llu+%llu, s=%llu+%llu, cu=%llu+%llu, cs=%llu+%llu, n=%llu+%llu, j=%llu+%llu, cn=%llu+%llu, cj=%llu+%llu\n"
1462 - , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->children_count
1463 - , p->utime, p->utime - p->old_utime
1464 - , p->stime, p->stime - p->old_stime
1465 - , p->cutime, p->cutime - p->old_cutime
1466 - , p->cstime, p->cstime - p->old_cstime
1467 - , p->minflt, p->minflt - p->old_minflt
1468 - , p->majflt, p->majflt - p->old_majflt
1469 - , p->cminflt, p->cminflt - p->old_cminflt
1470 - , p->cmajflt, p->cmajflt - p->old_cmajflt
1471 - );
1472 - }
1473 -
1474 - return ret;
1475 -}
1476 -#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1477 -
1478 -
1479 -
1311 // ----------------------------------------------------------------------------
1312 // update statistics on the targets
1313
@@ -1501,81 +1332,41 @@ void link_all_processes_to_their_parents(void) {
1332 for(p = root_of_pids; p ; p = p->next) {
1333 // for each process found running
1334
1504 - if(p->ppid > 0
1505 - && p->ppid <= pid_max
1506 - && all_pids[p->ppid]
1507 - ) {
1335 + if(likely(p->ppid > 0 && all_pids[p->ppid])) {
1336 // for valid processes
1337
1510 - if(debug || (p->target && p->target->debug))
1338 + if(unlikely(debug || (p->target && p->target->debug)))
1339 fprintf(stderr, "apps.plugin: \tparent of %d (%s) is %d (%s)\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);
1340
1341 p->parent = all_pids[p->ppid];
1342 p->parent->children_count++;
1515 - }
1516 - else if(p->ppid != 0)
1517 - error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1518 - }
1519 -}
1343
1521 -#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1522 -void aggregate_children_to_parents(void) {
1523 - struct pid_stat *p = NULL;
1344 + if(unlikely(!p->updated)) {
1345 + struct pid_stat *pp = p;
1346
1525 - // for each killed process, remove its values from the parents
1526 - // sums (we had already added them in a previous loop)
1527 - for(p = root_of_pids; p ; p = p->next) {
1528 - if(p->updated) continue;
1529 -
1530 - if(debug) fprintf(stderr, "apps.plugin: UNMERGING %d %s\n", p->pid, p->comm);
1531 -
1532 - unsigned long long diff_utime = p->utime + p->cutime + p->fix_cutime;
1533 - unsigned long long diff_stime = p->stime + p->cstime + p->fix_cstime;
1534 - unsigned long long diff_minflt = p->minflt + p->cminflt + p->fix_cminflt;
1535 - unsigned long long diff_majflt = p->majflt + p->cmajflt + p->fix_cmajflt;
1536 -
1537 - struct pid_stat *t = p;
1538 - while((t = t->parent)) {
1539 - if(!t->updated) continue;
1540 -
1541 - unsigned long long x;
1542 - if(diff_utime && t->diff_cutime) {
1543 - x = (t->diff_cutime < diff_utime)?t->diff_cutime:diff_utime;
1544 - diff_utime -= x;
1545 - t->diff_cutime -= x;
1546 - t->fix_cutime += x;
1547 - if(debug) fprintf(stderr, "apps.plugin: \t cutime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1548 - }
1549 - if(diff_stime && t->diff_cstime) {
1550 - x = (t->diff_cstime < diff_stime)?t->diff_cstime:diff_stime;
1551 - diff_stime -= x;
1552 - t->diff_cstime -= x;
1553 - t->fix_cstime += x;
1554 - if(debug) fprintf(stderr, "apps.plugin: \t cstime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1555 - }
1556 - if(diff_minflt && t->diff_cminflt) {
1557 - x = (t->diff_cminflt < diff_minflt)?t->diff_cminflt:diff_minflt;
1558 - diff_minflt -= x;
1559 - t->diff_cminflt -= x;
1560 - t->fix_cminflt += x;
1561 - if(debug) fprintf(stderr, "apps.plugin: \t cminflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1562 - }
1563 - if(diff_majflt && t->diff_cmajflt) {
1564 - x = (t->diff_cmajflt < diff_majflt)?t->diff_cmajflt:diff_majflt;
1565 - diff_majflt -= x;
1566 - t->diff_cmajflt -= x;
1567 - t->fix_cmajflt += x;
1568 - if(debug) fprintf(stderr, "apps.plugin: \t cmajflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1347 + // find the first parent that
1348 + // has been updated
1349 + while(pp && !pp->updated)
1350 + pp = pp->parent;
1351 +
1352 + if(likely(pp)) {
1353 + // this is an exited child with a parent
1354 + // remove the known time from the parent's data
1355 + pp->fix_cminflt += p->minflt + p->cminflt + p->fix_cminflt;
1356 + pp->fix_cmajflt += p->majflt + p->cmajflt + p->fix_cmajflt;
1357 + pp->fix_cutime += p->utime + p->cutime + p->fix_cutime;
1358 + pp->fix_cstime += p->stime + p->cstime + p->fix_cstime;
1359 +
1360 + if(unlikely(debug))
1361 + fprintf(stderr, "apps.plugin: \tfixing child counters of %d (%s) to %d (%s). Fixes: cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, pp->pid, pp->comm, pp->fix_cutime, pp->fix_cstime, pp->fix_cminflt, pp->fix_cmajflt);
1362 + }
1363 }
1364 }
1571 -
1572 - if(diff_utime) error("Cannot fix up utime %llu", diff_utime);
1573 - if(diff_stime) error("Cannot fix up stime %llu", diff_stime);
1574 - if(diff_minflt) error("Cannot fix up minflt %llu", diff_minflt);
1575 - if(diff_majflt) error("Cannot fix up majflt %llu", diff_majflt);
1365 + else if(unlikely(p->ppid != 0))
1366 + error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1367 }
1368 }
1578 -#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1369 +
1370
1371 void cleanup_non_existing_pids(void) {
1372 int c;
@@ -1603,8 +1394,9 @@ void apply_apps_groups_targets_inheritance(void) {
1394
1395 // children that do not have a target
1396 // inherit their target from their parent
1606 - int found = 1;
1397 + int found = 1, loops = 0;
1398 while(found) {
1399 + if(unlikely(debug)) loops++;
1400 found = 0;
1401 for(p = root_of_pids; p ; p = p->next) {
1402 // if this process does not have a target
@@ -1626,6 +1418,7 @@ void apply_apps_groups_targets_inheritance(void) {
1418 // repeat, until nothing more can be done.
1419 found = 1;
1420 while(found) {
1421 + if(unlikely(debug)) loops++;
1422 found = 0;
1423 for(p = root_of_pids; p ; p = p->next) {
1424 // if this process does not have any children
@@ -1658,7 +1451,7 @@ void apply_apps_groups_targets_inheritance(void) {
1451 }
1452 }
1453
1661 - if(debug)
1454 + if(unlikely(debug))
1455 fprintf(stderr, "apps.plugin: merged %d processes\n", found);
1456 }
1457
@@ -1667,25 +1460,18 @@ void apply_apps_groups_targets_inheritance(void) {
1460 all_pids[1]->target = apps_groups_default_target;
1461
1462 // give a default target on all top level processes
1463 + if(unlikely(debug)) loops++;
1464 for(p = root_of_pids; p ; p = p->next) {
1465 // if the process is not merged itself
1466 // then is is a top level process
1467 if(!p->merged && !p->target)
1468 p->target = apps_groups_default_target;
1675 -
1676 -#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1677 - // by the way, update the diffs
1678 - // will be used later for subtracting killed process times
1679 - p->diff_cutime = p->utime - p->cutime;
1680 - p->diff_cstime = p->stime - p->cstime;
1681 - p->diff_cminflt = p->minflt - p->cminflt;
1682 - p->diff_cmajflt = p->majflt - p->cmajflt;
1683 -#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1469 }
1470
1471 // give a target to all merged child processes
1472 found = 1;
1473 while(found) {
1474 + if(unlikely(debug)) loops++;
1475 found = 0;
1476 for(p = root_of_pids; p ; p = p->next) {
1477 if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
@@ -1697,6 +1483,9 @@ void apply_apps_groups_targets_inheritance(void) {
1483 }
1484 }
1485 }
1486 +
1487 + if(unlikely(debug))
1488 + fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
1489 }
1490
1491 long zero_all_targets(struct target *root) {
@@ -1749,10 +1538,13 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1538 }
1539
1540 if(likely(p->updated)) {
1752 - w->cutime += p->cutime; // - p->fix_cutime;
1753 - w->cstime += p->cstime; // - p->fix_cstime;
1754 - w->cminflt += p->cminflt; // - p->fix_cminflt;
1755 - w->cmajflt += p->cmajflt; // - p->fix_cmajflt;
1541 + if(unlikely(debug && (p->fix_cutime || p->fix_cstime || p->fix_cminflt || p->fix_cmajflt)))
1542 + fprintf(stderr, "apps.plugin: \tadding child counters of %d (%s) to target %s. Currents: cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu, Fixes: cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, w->name, p->cutime, p->cstime, p->cminflt, p->cmajflt, p->fix_cutime, p->fix_cstime, p->fix_cminflt, p->fix_cmajflt);
1543 +
1544 + w->cutime += p->cutime - p->fix_cutime;
1545 + w->cstime += p->cstime - p->fix_cstime;
1546 + w->cminflt += p->cminflt - p->fix_cminflt;
1547 + w->cmajflt += p->cmajflt - p->fix_cmajflt;
1548
1549 w->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;
1550 w->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;
@@ -1800,7 +1592,7 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1592 }
1593
1594 if(unlikely(debug || w->debug))
1803 - fprintf(stderr, "apps.plugin: \tAggregating %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, w->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1595 + fprintf(stderr, "apps.plugin: \tAggregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, fix_cutime=%llu, fix_cstime=%llu, fix_cminflt=%llu, fix_cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->fix_cutime, p->fix_cstime, p->fix_cminflt, p->fix_cmajflt);
1596
1597 /* if(p->utime - p->old_utime > 100) fprintf(stderr, "BIG CHANGE: %d %s utime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->utime - p->old_utime, p->old_utime, p->utime);
1598 if(p->cutime - p->old_cutime > 100) fprintf(stderr, "BIG CHANGE: %d %s cutime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cutime - p->old_cutime, p->old_cutime, p->cutime);
@@ -1811,16 +1603,6 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1603 if(p->cminflt - p->old_cminflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cminflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cminflt - p->old_cminflt, p->old_cminflt, p->cminflt);
1604 if(p->cmajflt - p->old_cmajflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cmajflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cmajflt - p->old_cmajflt, p->old_cmajflt, p->cmajflt);
1605 */
1814 -#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1815 - p->old_utime = p->utime;
1816 - p->old_cutime = p->cutime;
1817 - p->old_stime = p->stime;
1818 - p->old_cstime = p->cstime;
1819 - p->old_minflt = p->minflt;
1820 - p->old_majflt = p->majflt;
1821 - p->old_cminflt = p->cminflt;
1822 - p->old_cmajflt = p->cmajflt;
1823 -#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1606
1607 if(o) {
1608 // since the process switched target
@@ -1831,17 +1613,16 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1613 // IMPORTANT
1614 // We add/subtract the last/OLD values we added to the target
1615
1834 - w->fix_cutime -= p->last_cutime;
1835 - w->fix_cstime -= p->last_cstime;
1836 - w->fix_cminflt -= p->last_cminflt;
1837 - w->fix_cmajflt -= p->last_cmajflt;
1616 + w->fix_cutime -= (p->last_cutime - p->last_fix_cutime);
1617 + w->fix_cstime -= (p->last_cstime - p->last_fix_cstime);
1618 + w->fix_cminflt -= (p->last_cminflt - p->last_fix_cminflt);
1619 + w->fix_cmajflt -= (p->last_cmajflt - p->last_fix_cmajflt);
1620
1621 w->fix_utime -= p->last_utime;
1622 w->fix_stime -= p->last_stime;
1623 w->fix_minflt -= p->last_minflt;
1624 w->fix_majflt -= p->last_majflt;
1625
1844 -
1626 w->fix_io_logical_bytes_read -= p->last_io_logical_bytes_read;
1627 w->fix_io_logical_bytes_written -= p->last_io_logical_bytes_written;
1628 w->fix_io_read_calls -= p->last_io_read_calls;
@@ -1852,10 +1633,10 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1633
1634 // ---
1635
1855 - o->fix_cutime += p->last_cutime;
1856 - o->fix_cstime += p->last_cstime;
1857 - o->fix_cminflt += p->last_cminflt;
1858 - o->fix_cmajflt += p->last_cmajflt;
1636 + o->fix_cutime += (p->last_cutime - p->last_fix_cutime);
1637 + o->fix_cstime += (p->last_cstime - p->last_fix_cstime);
1638 + o->fix_cminflt += (p->last_cminflt - p->last_fix_cminflt);
1639 + o->fix_cmajflt += (p->last_cmajflt - p->last_fix_cmajflt);
1640
1641 o->fix_utime += p->last_utime;
1642 o->fix_stime += p->last_stime;
@@ -1884,10 +1665,11 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1665 w->fix_majflt += p->majflt;
1666 w->fix_utime += p->utime;
1667 w->fix_stime += p->stime;
1887 - w->fix_cminflt += p->cminflt;
1888 - w->fix_cmajflt += p->cmajflt;
1889 - w->fix_cutime += p->cutime;
1890 - w->fix_cstime += p->cstime;
1668 +
1669 + w->fix_cminflt += (p->cminflt - p->fix_cminflt);
1670 + w->fix_cmajflt += (p->cmajflt - p->fix_cmajflt);
1671 + w->fix_cutime += (p->cutime - p->fix_cutime);
1672 + w->fix_cstime += (p->cstime - p->fix_cstime);
1673
1674 w->fix_io_logical_bytes_read += p->io_logical_bytes_read;
1675 w->fix_io_logical_bytes_written += p->io_logical_bytes_written;
@@ -1967,19 +1749,10 @@ void calculate_netdata_statistics(void)
1749 link_all_processes_to_their_parents();
1750 apply_apps_groups_targets_inheritance();
1751
1970 -#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1971 - aggregate_children_to_parents();
1972 -#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1973 -
1752 zero_all_targets(users_root_target);
1753 zero_all_targets(groups_root_target);
1754 apps_groups_targets = zero_all_targets(apps_groups_root_target);
1755
1978 -#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1979 - if(debug)
1980 - debug_childrens_aggregations(0, 1);
1981 -#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1982 -
1756 // this has to be done, before the cleanup
1757 struct pid_stat *p = NULL;
1758 struct target *w = NULL, *o = NULL;
@@ -2099,7 +1872,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
1872 for (w = root; w ; w = w->next) {
1873 if(w->target || (!w->processes && !w->exposed)) continue;
1874
2102 - fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + w->fix_utime + w->fix_stime);
1875 + fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + w->fix_utime + w->fix_stime + w->cutime + w->cstime + w->fix_cutime + w->fix_cstime);
1876 }
1877 fprintf(stdout, "END\n");
1878
@@ -2107,7 +1880,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
1880 for (w = root; w ; w = w->next) {
1881 if(w->target || (!w->processes && !w->exposed)) continue;
1882
2110 - fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->fix_utime);
1883 + fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->fix_utime + w->cutime + w->fix_cutime);
1884 }
1885 fprintf(stdout, "END\n");
1886
@@ -2115,7 +1888,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
1888 for (w = root; w ; w = w->next) {
1889 if(w->target || (!w->processes && !w->exposed)) continue;
1890
2118 - fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + w->fix_stime);
1891 + fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + w->fix_stime + w->cstime + w->fix_cstime);
1892 }
1893 fprintf(stdout, "END\n");
1894
@@ -2147,7 +1920,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
1920 for (w = root; w ; w = w->next) {
1921 if(w->target || (!w->processes && !w->exposed)) continue;
1922
2150 - fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + w->fix_minflt);
1923 + fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + w->fix_minflt + w->cminflt + w->fix_cminflt);
1924 }
1925 fprintf(stdout, "END\n");
1926
@@ -2155,7 +1928,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
1928 for (w = root; w ; w = w->next) {
1929 if(w->target || (!w->processes && !w->exposed)) continue;
1930
2158 - fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + w->fix_majflt);
1931 + fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + w->fix_majflt + w->cmajflt + w->fix_cmajflt);
1932 }
1933 fprintf(stdout, "END\n");
1934
@@ -2239,7 +2012,7 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
2012
2013 // we have something new to show
2014 // update the charts
2242 - fprintf(stdout, "CHART %s.cpu '' '%s CPU Time (%ld%% = %ld core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2015 + 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);
2016 for (w = root; w ; w = w->next) {
2017 if(w->target || (!w->processes && !w->exposed)) continue;
2018
@@ -2267,18 +2040,18 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
2040 fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
2041 }
2042
2270 - fprintf(stdout, "CHART %s.cpu_user '' '%s CPU User Time (%ld%% = %ld core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2043 + 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);
2044 for (w = root; w ; w = w->next) {
2045 if(w->target || (!w->processes && !w->exposed)) continue;
2046
2274 - fprintf(stdout, "DIMENSION %s '' incremental 100 %ld noreset\n", w->name, hz * processors);
2047 + fprintf(stdout, "DIMENSION %s '' incremental 100 %d noreset\n", w->name, hz);
2048 }
2049
2277 - fprintf(stdout, "CHART %s.cpu_system '' '%s CPU System Time (%ld%% = %ld core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2050 + 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);
2051 for (w = root; w ; w = w->next) {
2052 if(w->target || (!w->processes && !w->exposed)) continue;
2053
2281 - fprintf(stdout, "DIMENSION %s '' incremental 100 %ld noreset\n", w->name, hz * processors);
2054 + fprintf(stdout, "DIMENSION %s '' incremental 100 %d noreset\n", w->name, hz);
2055 }
2056
2057 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);
@@ -2488,7 +2261,8 @@ int main(int argc, char **argv)
2261 send_collected_data_to_netdata(users_root_target, "users", dt);
2262 send_collected_data_to_netdata(groups_root_target, "groups", dt);
2263
2491 - if(debug) fprintf(stderr, "apps.plugin: done Loop No %llu\n", counter);
2264 + if(unlikely(debug))
2265 + fprintf(stderr, "apps.plugin: done Loop No %llu\n", counter);
2266
2267 current_t = time(NULL);
2268
web/index.html
+3 -3
@@ -1325,19 +1325,19 @@ var menuData = {
1325
1326 'apps': {
1327 title: 'Applications',
1328 - info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported).<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
1328 + info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported).',
1329 height: 1.5
1330 },
1331
1332 'users': {
1333 title: 'Users',
1334 - info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
1334 + info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user.',
1335 height: 1.5
1336 },
1337
1338 'groups': {
1339 title: 'User Groups',
1340 - info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
1340 + info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group.',
1341 height: 1.5
1342 },
1343