apps.plugin: major new features and optimizations: now it reports system usage (all apps charts, cpu, memory, disk, etc) per username and per user group; apps.plugin is now almost a total re-write, 10% faster than the previous after the new features added; fixed a bug at the dashboard where some info was not presented; #146, #106, #85
Costa Tsaousis (ktsaou) committed
Apr 8, 2016 at 05:49 UTC
da9e1df4cbde9208d30b99937046b667e82e88a1
6 files changed
+889
-449
.gitignore
+5
@@ -64,3 +64,8 @@ system/netdata-init-d
64
65
netdata-installer.log
66
netdata-uninstaller.sh
67
+
68
+gmon.out
69
+gmon.txt
70
+
71
+apps.plugin-profiler.sh
src/apps_plugin.c
+820
-444
@@ -13,6 +13,7 @@
13
#include <sys/types.h>
14
#include <sys/time.h>
15
#include <sys/wait.h>
16
+#include <sys/stat.h>
17
18
#include <sys/resource.h>
19
#include <sys/stat.h>
@@ -27,9 +28,14 @@
28
#include <dirent.h>
29
#include <arpa/inet.h>
30
31
+#include <sys/types.h>
32
+#include <pwd.h>
33
+#include <grp.h>
34
+
35
+#include "avl.h"
36
+
37
#include "common.h"
38
#include "log.h"
32
-#include "avl.h"
39
#include "procfile.h"
40
41
#define MAX_COMPARE_NAME 15
@@ -50,6 +56,7 @@ char *config_dir = CONFIG_DIR;
56
#ifdef NETDATA_INTERNAL_CHECKS
57
// ----------------------------------------------------------------------------
58
// memory debugger
59
+// do not use in production systems - it mis-aligns allocated memory
60
61
struct allocations {
62
size_t allocations;
@@ -203,11 +210,12 @@ char *strdup_debug(const char *file, int line, const char *function, const char
210
211
212
// ----------------------------------------------------------------------------
206
-// helper functions
213
+// system functions
214
+// to retrieve settings of the system
215
216
procfile *ff = NULL;
217
210
-long get_processors(void) {
218
+long get_system_cpus(void) {
219
int processors = 0;
220
221
char filename[FILENAME_MAX + 1];
@@ -235,7 +243,7 @@ long get_processors(void) {
243
return processors;
244
}
245
238
-long get_pid_max(void) {
246
+long get_system_pid_max(void) {
247
long mpid = 32768;
248
249
char filename[FILENAME_MAX + 1];
@@ -256,7 +264,7 @@ long get_pid_max(void) {
264
return mpid;
265
}
266
259
-unsigned long long get_hertz(void)
267
+unsigned long long get_system_hertz(void)
268
{
269
unsigned long long myhz = 1;
270
@@ -280,13 +288,18 @@ unsigned long long get_hertz(void)
288
289
// ----------------------------------------------------------------------------
290
// target
283
-// target is the point to aggregate a process tree values
291
+// target is the structure that process data are aggregated
292
293
struct target {
294
char compare[MAX_COMPARE_NAME + 1];
295
+ uint32_t hash;
296
+
297
char id[MAX_NAME + 1];
298
char name[MAX_NAME + 1];
299
300
+ uid_t uid;
301
+ gid_t gid;
302
+
303
unsigned long long minflt;
304
unsigned long long cminflt;
305
unsigned long long majflt;
@@ -347,25 +360,103 @@ struct target {
360
int hidden; // if set, we set the hidden flag on the dimension
361
int debug;
362
350
- struct target *target; // the one that will be reported to netdata
363
+ struct target *target; // the one that will be reported to netdata
364
struct target *next;
352
-} *target_root = NULL, *default_target = NULL;
365
+};
366
354
-long targets = 0;
367
356
-// find or create a target
357
-// there are targets that are just agregated to other target (the second argument)
358
-struct target *get_target(const char *id, struct target *target)
368
+// ----------------------------------------------------------------------------
369
+// apps_groups.conf
370
+// aggregate all processes in groups, to have a limited number of dimensions
371
+
372
+struct target *apps_groups_root_target = NULL;
373
+struct target *apps_groups_default_target = NULL;
374
+long apps_groups_targets = 0;
375
+
376
+struct target *users_root_target = NULL;
377
+struct target *groups_root_target = NULL;
378
+
379
+struct target *get_users_target(uid_t uid)
380
+{
381
+ struct target *w;
382
+ for(w = users_root_target ; w ; w = w->next)
383
+ if(w->uid == uid) return w;
384
+
385
+ w = calloc(sizeof(struct target), 1);
386
+ if(unlikely(!w)) {
387
+ error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
388
+ return NULL;
389
+ }
390
+
391
+ snprintf(w->compare, MAX_COMPARE_NAME, "%d", uid);
392
+ w->hash = simple_hash(w->compare);
393
+
394
+ snprintf(w->id, MAX_NAME, "%d", uid);
395
+
396
+ struct passwd *pw = getpwuid(uid);
397
+ if(!pw)
398
+ snprintf(w->name, MAX_NAME, "%d", uid);
399
+ else
400
+ snprintf(w->name, MAX_NAME, "%s", pw->pw_name);
401
+
402
+ w->uid = uid;
403
+
404
+ w->next = users_root_target;
405
+ users_root_target = w;
406
+
407
+ if(unlikely(debug))
408
+ fprintf(stderr, "apps.plugin: added uid %d ('%s') target\n", w->uid, w->name);
409
+
410
+ return w;
411
+}
412
+
413
+struct target *get_groups_target(gid_t gid)
414
+{
415
+ struct target *w;
416
+ for(w = groups_root_target ; w ; w = w->next)
417
+ if(w->gid == gid) return w;
418
+
419
+ w = calloc(sizeof(struct target), 1);
420
+ if(unlikely(!w)) {
421
+ error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
422
+ return NULL;
423
+ }
424
+
425
+ snprintf(w->compare, MAX_COMPARE_NAME, "%d", gid);
426
+ w->hash = simple_hash(w->compare);
427
+
428
+ snprintf(w->id, MAX_NAME, "%d", gid);
429
+
430
+ struct group *gr = getgrgid(gid);
431
+ if(!gr)
432
+ snprintf(w->name, MAX_NAME, "%d", gid);
433
+ else
434
+ snprintf(w->name, MAX_NAME, "%s", gr->gr_name);
435
+
436
+ w->gid = gid;
437
+
438
+ w->next = groups_root_target;
439
+ groups_root_target = w;
440
+
441
+ if(unlikely(debug))
442
+ fprintf(stderr, "apps.plugin: added gid %d ('%s') target\n", w->gid, w->name);
443
+
444
+ return w;
445
+}
446
+
447
+// find or create a new target
448
+// there are targets that are just aggregated to other target (the second argument)
449
+struct target *get_apps_groups_target(const char *id, struct target *target)
450
{
451
const char *nid = id;
452
if(nid[0] == '-') nid++;
453
454
struct target *w;
364
- for(w = target_root ; w ; w = w->next)
455
+ for(w = apps_groups_root_target ; w ; w = w->next)
456
if(strncmp(nid, w->id, MAX_NAME) == 0) return w;
457
458
w = calloc(sizeof(struct target), 1);
368
- if(!w) {
459
+ if(unlikely(!w)) {
460
error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
461
return NULL;
462
}
@@ -373,29 +464,34 @@ struct target *get_target(const char *id, struct target *target)
464
strncpy(w->id, nid, MAX_NAME);
465
strncpy(w->name, nid, MAX_NAME);
466
strncpy(w->compare, nid, MAX_COMPARE_NAME);
467
+ w->hash = simple_hash(w->compare);
468
+
469
if(id[0] == '-') w->hidden = 1;
470
471
w->target = target;
472
380
- w->next = target_root;
381
- target_root = w;
473
+ w->next = apps_groups_root_target;
474
+ apps_groups_root_target = w;
475
383
- if(debug) fprintf(stderr, "apps.plugin: adding hook for process '%s', compare '%s' on target '%s'\n", w->id, w->compare, w->target?w->target->id:"");
476
+ if(unlikely(debug))
477
+ fprintf(stderr, "apps.plugin: adding hook for process '%s', compare '%s' on target '%s'\n", w->id, w->compare, w->target?w->target->id:"");
478
479
return w;
480
}
481
388
-// read the process groups file
389
-int read_process_groups(const char *name)
482
+// read the apps_groups.conf file
483
+int read_apps_groups_conf(const char *name)
484
{
485
char buffer[4096+1];
486
char filename[FILENAME_MAX + 1];
487
488
snprintf(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
489
396
- if(debug) fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
490
+ if(unlikely(debug))
491
+ fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
492
+
493
FILE *fp = fopen(filename, "r");
398
- if(!fp) {
494
+ if(unlikely(!fp)) {
495
error("Cannot open file '%s'", filename);
496
return 1;
497
}
@@ -465,7 +561,7 @@ int read_process_groups(const char *name)
561
blen = strlen(buffer);
562
}
563
468
- struct target *n = get_target(buffer, w);
564
+ struct target *n = get_apps_groups_target(buffer, w);
565
n->hidden = whidden;
566
n->debug = wdebug;
567
if(!w) w = n;
@@ -481,8 +577,8 @@ int read_process_groups(const char *name)
577
}
578
fclose(fp);
579
484
- default_target = get_target("+p!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
485
- strncpy(default_target->name, "other", MAX_NAME);
580
+ apps_groups_default_target = get_apps_groups_target("+p!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
581
+ strncpy(apps_groups_default_target->name, "other", MAX_NAME);
582
583
return 0;
584
}
@@ -538,6 +634,9 @@ struct pid_stat {
634
// uint64_t guest_time;
635
// int64_t cguest_time;
636
637
+ uid_t uid;
638
+ gid_t gid;
639
+
640
unsigned long long statm_size;
641
unsigned long long statm_resident;
642
unsigned long long statm_share;
@@ -554,7 +653,29 @@ struct pid_stat {
653
unsigned long long io_storage_bytes_written;
654
unsigned long long io_cancelled_write_bytes;
655
557
-#ifdef INCLUDE_CHILDS
656
+ // we need the last values
657
+ // for all incremental counters
658
+ // so that when a process switches users/groups
659
+ // we will subtract these values from the old
660
+ // target
661
+ unsigned long long last_minflt;
662
+ unsigned long long last_cminflt;
663
+ unsigned long long last_majflt;
664
+ unsigned long long last_cmajflt;
665
+ unsigned long long last_utime;
666
+ unsigned long long last_stime;
667
+ unsigned long long last_cutime;
668
+ unsigned long long last_cstime;
669
+
670
+ unsigned long long last_io_logical_bytes_read;
671
+ unsigned long long last_io_logical_bytes_written;
672
+ unsigned long long last_io_read_calls;
673
+ unsigned long long last_io_write_calls;
674
+ unsigned long long last_io_storage_bytes_read;
675
+ unsigned long long last_io_storage_bytes_written;
676
+ unsigned long long last_io_cancelled_write_bytes;
677
+
678
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
679
unsigned long long old_utime;
680
unsigned long long old_stime;
681
unsigned long long old_minflt;
@@ -574,19 +695,24 @@ struct pid_stat {
695
unsigned long long diff_cstime;
696
unsigned long long diff_cminflt;
697
unsigned long long diff_cmajflt;
577
-#endif /* INCLUDE_CHILDS */
698
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
699
579
- int *fds; // array of fds it uses
580
- int fds_size; // the size of the fds array
700
+ int *fds; // array of fds it uses
701
+ int fds_size; // the size of the fds array
702
582
- int children_count; // number of processes directly referencing this
583
- int updated; // 1 when update
584
- int merged; // 1 when it has been merged to its parent
703
+ int children_count; // number of processes directly referencing this
704
+ int updated; // 1 when update
705
+ int merged; // 1 when it has been merged to its parent
706
int new_entry;
586
- struct target *target;
707
+
708
+ struct target *target; // app_groups.conf targets
709
+ struct target *user_target; // uid based targets
710
+ struct target *group_target; // gid based targets
711
+
712
struct pid_stat *parent;
713
struct pid_stat *prev;
714
struct pid_stat *next;
715
+
716
} *root_of_pids = NULL, **all_pids;
717
718
long all_pids_count = 0;
@@ -638,11 +764,31 @@ void del_pid_entry(pid_t pid)
764
// ----------------------------------------------------------------------------
765
// update pids from proc
766
767
+int read_proc_pid_ownership(struct pid_stat *p) {
768
+ char filename[FILENAME_MAX + 1];
769
+
770
+ snprintf(filename, FILENAME_MAX, "%s/proc/%d", host_prefix, p->pid);
771
+
772
+ // ----------------------------------------
773
+ // read uid and gid
774
+
775
+ struct stat st;
776
+ if(stat(filename, &st) != 0)
777
+ return 1;
778
+
779
+ p->uid = st.st_uid;
780
+ p->gid = st.st_gid;
781
+
782
+ return 0;
783
+}
784
+
785
int read_proc_pid_stat(struct pid_stat *p) {
786
char filename[FILENAME_MAX + 1];
787
788
snprintf(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
789
790
+ // ----------------------------------------
791
+
792
ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
793
if(!ff) return 1;
794
@@ -784,51 +930,10 @@ int read_proc_pid_io(struct pid_stat *p) {
930
}
931
932
787
-// ----------------------------------------------------------------------------
788
-
789
-#ifdef INCLUDE_CHILDS
790
-// print a tree view of all processes
791
-int walk_down(pid_t pid, int level) {
792
- struct pid_stat *p = NULL;
793
- char b[level+3];
794
- int i, ret = 0;
795
-
796
- for(i = 0; i < level; i++) b[i] = '\t';
797
- b[level] = '|';
798
- b[level+1] = '-';
799
- b[level+2] = '\0';
800
-
801
- for(p = root_of_pids; p ; p = p->next) {
802
- if(p->ppid == pid) {
803
- ret += walk_down(p->pid, level+1);
804
- }
805
- }
806
-
807
- p = all_pids[pid];
808
- if(p) {
809
- if(!p->updated) ret += 1;
810
- 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"
811
- , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->children_count
812
- , p->utime, p->utime - p->old_utime
813
- , p->stime, p->stime - p->old_stime
814
- , p->cutime, p->cutime - p->old_cutime
815
- , p->cstime, p->cstime - p->old_cstime
816
- , p->minflt, p->minflt - p->old_minflt
817
- , p->majflt, p->majflt - p->old_majflt
818
- , p->cminflt, p->cminflt - p->old_cminflt
819
- , p->cmajflt, p->cmajflt - p->old_cmajflt
820
- );
821
- }
822
-
823
- return ret;
824
-}
825
-#endif /* INCLUDE_CHILDS */
826
-
827
-
933
// ----------------------------------------------------------------------------
934
// file descriptor
935
// this is used to keep a global list of all open files of the system
831
-// it is needed in order to figure out the unique files a process tree has open
936
+// it is needed in order to calculate the unique files processes have open
937
938
#define FILE_DESCRIPTORS_INCREASE_STEP 100
939
@@ -868,11 +973,13 @@ int file_descriptor_iterator(avl *a) { if(a) {}; return 0; }
973
avl_tree all_files_index = {
974
NULL,
975
file_descriptor_compare,
976
+#ifndef AVL_WITHOUT_PTHREADS
977
#ifdef AVL_LOCK_WITH_MUTEX
978
PTHREAD_MUTEX_INITIALIZER
979
#else
980
PTHREAD_RWLOCK_INITIALIZER
981
#endif
982
+#endif /* AVL_WITHOUT_PTHREADS */
983
};
984
985
static struct file_descriptor *file_descriptor_find(const char *name, uint32_t hash) {
@@ -1049,6 +1156,81 @@ int file_descriptor_find_or_add(const char *name)
1156
return c;
1157
}
1158
1159
+int read_pid_file_descriptors(struct pid_stat *p) {
1160
+ char dirname[FILENAME_MAX+1];
1161
+
1162
+ snprintf(dirname, FILENAME_MAX, "%s/proc/%d/fd", host_prefix, p->pid);
1163
+ DIR *fds = opendir(dirname);
1164
+ if(fds) {
1165
+ int c;
1166
+ struct dirent *de;
1167
+ char fdname[FILENAME_MAX + 1];
1168
+ char linkname[FILENAME_MAX + 1];
1169
+
1170
+ // make the array negative
1171
+ for(c = 0 ; c < p->fds_size ; c++)
1172
+ p->fds[c] = -p->fds[c];
1173
+
1174
+ while((de = readdir(fds))) {
1175
+ if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
1176
+ continue;
1177
+
1178
+ // check if the fds array is small
1179
+ int fdid = atoi(de->d_name);
1180
+ if(fdid < 0) continue;
1181
+ if(fdid >= p->fds_size) {
1182
+ // it is small, extend it
1183
+ if(debug) fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
1184
+ p->fds = realloc(p->fds, (fdid + 100) * sizeof(int));
1185
+ if(!p->fds) {
1186
+ error("Cannot re-allocate fds for %s", p->comm);
1187
+ break;
1188
+ }
1189
+
1190
+ // and initialize it
1191
+ for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0;
1192
+ p->fds_size = fdid + 100;
1193
+ }
1194
+
1195
+ if(p->fds[fdid] == 0) {
1196
+ // we don't know this fd, get it
1197
+
1198
+ sprintf(fdname, "%s/proc/%d/fd/%s", host_prefix, p->pid, de->d_name);
1199
+ ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
1200
+ if(l == -1) {
1201
+ if(debug || (p->target && p->target->debug)) {
1202
+ if(debug || (p->target && p->target->debug))
1203
+ error("Cannot read link %s", fdname);
1204
+ }
1205
+ continue;
1206
+ }
1207
+ linkname[l] = '\0';
1208
+ file_counter++;
1209
+
1210
+ // if another process already has this, we will get
1211
+ // the same id
1212
+ p->fds[fdid] = file_descriptor_find_or_add(linkname);
1213
+ }
1214
+
1215
+ // else make it positive again, we need it
1216
+ // of course, the actual file may have changed, but we don't care so much
1217
+ // FIXME: we could compare the inode as returned by readdir direct structure
1218
+ else p->fds[fdid] = -p->fds[fdid];
1219
+ }
1220
+ closedir(fds);
1221
+
1222
+ // remove all the negative file descriptors
1223
+ for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
1224
+ file_descriptor_not_used(-p->fds[c]);
1225
+ p->fds[c] = 0;
1226
+ }
1227
+ }
1228
+ else return 1;
1229
+
1230
+ return 0;
1231
+}
1232
+
1233
+// ----------------------------------------------------------------------------
1234
1235
// 1. read all files in /proc
1236
// 2. for each numeric directory:
@@ -1066,11 +1248,10 @@ int file_descriptor_find_or_add(const char *name)
1248
// to avoid filling up all disk space
1249
// if debug is enabled, all errors are printed
1250
1069
-int update_from_proc(void)
1251
+int collect_data_for_all_processes_from_proc(void)
1252
{
1253
static long count_errors = 0;
1254
1073
- char filename[FILENAME_MAX+1];
1255
char dirname[FILENAME_MAX + 1];
1256
1257
snprintf(dirname, FILENAME_MAX, "%s/proc", host_prefix);
@@ -1089,35 +1270,65 @@ int update_from_proc(void)
1270
p->children_count = 0;
1271
p->merged = 0;
1272
p->new_entry = 0;
1273
+
1274
+ p->last_minflt = p->minflt;
1275
+ p->last_cminflt = p->cminflt;
1276
+ p->last_majflt = p->majflt;
1277
+ p->last_cmajflt = p->cmajflt;
1278
+ p->last_utime = p->utime;
1279
+ p->last_stime = p->stime;
1280
+ p->last_cutime = p->cutime;
1281
+ p->last_cstime = p->cstime;
1282
+
1283
+ p->last_io_logical_bytes_read = p->io_logical_bytes_read;
1284
+ p->last_io_logical_bytes_written = p->io_logical_bytes_written;
1285
+ p->last_io_read_calls = p->io_read_calls;
1286
+ p->last_io_write_calls = p->io_write_calls;
1287
+ p->last_io_storage_bytes_read = p->io_storage_bytes_read;
1288
+ p->last_io_storage_bytes_written = p->io_storage_bytes_written;
1289
+ p->last_io_cancelled_write_bytes = p->io_cancelled_write_bytes;
1290
}
1291
1292
while((file = readdir(dir))) {
1293
char *endptr = file->d_name;
1294
pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
1097
- if(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0') continue;
1295
+
1296
+ // make sure we read a valid number
1297
+ if(unlikely(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0'))
1298
+ continue;
1299
1300
p = get_pid_entry(pid);
1100
- if(!p) continue;
1301
+ if(unlikely(!p)) continue;
1302
+
1303
1304
// --------------------------------------------------------------------
1305
// /proc/<pid>/stat
1306
1105
- if(read_proc_pid_stat(p)) {
1307
+ if(unlikely(read_proc_pid_stat(p))) {
1308
if(!count_errors++ || debug || (p->target && p->target->debug))
1309
error("Cannot process %s/proc/%d/stat", host_prefix, pid);
1310
1311
+ // there is no reason to proceed if we cannot get its status
1312
continue;
1313
}
1111
- if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0;
1314
+
1315
+ // check its parent pid
1316
+ if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
1317
+ if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
1318
+ error("Pid %d states invalid parent pid %d. Using 0.", pid, p->ppid);
1319
+
1320
+ p->ppid = 0;
1321
+ }
1322
1323
1324
// --------------------------------------------------------------------
1325
// /proc/<pid>/statm
1326
1117
- if(read_proc_pid_statm(p)) {
1118
- if(!count_errors++ || debug || (p->target && p->target->debug))
1327
+ if(unlikely(read_proc_pid_statm(p))) {
1328
+ if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
1329
error("Cannot process %s/proc/%d/statm", host_prefix, pid);
1330
1331
+ // there is no reason to proceed if we cannot get its memory status
1332
continue;
1333
}
1334
@@ -1125,8 +1336,8 @@ int update_from_proc(void)
1336
// --------------------------------------------------------------------
1337
// /proc/<pid>/io
1338
1128
- if(read_proc_pid_io(p)) {
1129
- if(!count_errors++ || debug || (p->target && p->target->debug))
1339
+ if(unlikely(read_proc_pid_io(p))) {
1340
+ if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
1341
error("Cannot process %s/proc/%d/io", host_prefix, pid);
1342
1343
// on systems without /proc/X/io
@@ -1134,23 +1345,33 @@ int update_from_proc(void)
1345
// continue;
1346
}
1347
1348
+ // --------------------------------------------------------------------
1349
+ // <pid> ownership
1350
+
1351
+ if(unlikely(read_proc_pid_ownership(p))) {
1352
+ if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
1353
+ error("Cannot stat %s/proc/%d", host_prefix, pid);
1354
+ }
1355
+
1356
// --------------------------------------------------------------------
1357
// link it
1358
1359
// check if it is target
1360
// we do this only once, the first time this pid is loaded
1142
- if(p->new_entry) {
1361
+ if(unlikely(p->new_entry)) {
1362
if(debug) fprintf(stderr, "apps.plugin: \tJust added %s\n", p->comm);
1363
+ uint32_t hash = simple_hash(p->comm);
1364
1365
struct target *w;
1146
- for(w = target_root; w ; w = w->next) {
1366
+ for(w = apps_groups_root_target; w ; w = w->next) {
1367
// if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1368
1149
- if(strcmp(w->compare, p->comm) == 0) {
1369
+ if(w->hash == hash && strcmp(w->compare, p->comm) == 0) {
1370
if(w->target) p->target = w->target;
1371
else p->target = w;
1372
1153
- if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1373
+ if(debug || (p->target && p->target->debug))
1374
+ fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1375
}
1376
}
1377
}
@@ -1158,69 +1379,9 @@ int update_from_proc(void)
1379
// --------------------------------------------------------------------
1380
// /proc/<pid>/fd
1381
1161
- snprintf(filename, FILENAME_MAX, "%s/proc/%s/fd", host_prefix, file->d_name);
1162
- DIR *fds = opendir(filename);
1163
- if(fds) {
1164
- int c;
1165
- struct dirent *de;
1166
- char fdname[FILENAME_MAX + 1];
1167
- char linkname[FILENAME_MAX + 1];
1168
-
1169
- // make the array negative
1170
- for(c = 0 ; c < p->fds_size ; c++) p->fds[c] = -p->fds[c];
1171
-
1172
- while((de = readdir(fds))) {
1173
- if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
1174
-
1175
- // check if the fds array is small
1176
- int fdid = atoi(de->d_name);
1177
- if(fdid < 0) continue;
1178
- if(fdid >= p->fds_size) {
1179
- // it is small, extend it
1180
- if(debug) fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
1181
- p->fds = realloc(p->fds, (fdid + 100) * sizeof(int));
1182
- if(!p->fds) {
1183
- error("Cannot re-allocate fds for %s", p->comm);
1184
- break;
1185
- }
1186
-
1187
- // and initialize it
1188
- for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0;
1189
- p->fds_size = fdid + 100;
1190
- }
1191
-
1192
- if(p->fds[fdid] == 0) {
1193
- // we don't know this fd, get it
1194
-
1195
- sprintf(fdname, "%s/proc/%s/fd/%s", host_prefix, file->d_name, de->d_name);
1196
- ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
1197
- if(l == -1) {
1198
- if(debug || (p->target && p->target->debug)) {
1199
- if(!count_errors++ || debug || (p->target && p->target->debug))
1200
- error("Cannot read link %s", fdname);
1201
- }
1202
- continue;
1203
- }
1204
- linkname[l] = '\0';
1205
- file_counter++;
1206
-
1207
- // if another process already has this, we will get
1208
- // the same id
1209
- p->fds[fdid] = file_descriptor_find_or_add(linkname);
1210
- }
1211
-
1212
- // else make it positive again, we need it
1213
- // of course, the actual file may have changed, but we don't care so much
1214
- // FIXME: we could compare the inode as returned by readdir direct structure
1215
- else p->fds[fdid] = -p->fds[fdid];
1216
- }
1217
- closedir(fds);
1218
-
1219
- // remove all the negative file descriptors
1220
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
1221
- file_descriptor_not_used(-p->fds[c]);
1222
- p->fds[c] = 0;
1223
- }
1382
+ if(unlikely(read_pid_file_descriptors(p))) {
1383
+ if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
1384
+ error("Cannot process entries in %s/proc/%d/fd", host_prefix, pid);
1385
}
1386
1387
// --------------------------------------------------------------------
@@ -1229,7 +1390,8 @@ int update_from_proc(void)
1390
// mark it as updated
1391
p->updated = 1;
1392
}
1232
- if(count_errors > 1000) {
1393
+
1394
+ if(unlikely(count_errors > 1000)) {
1395
error("%ld more errors encountered\n", count_errors - 1);
1396
count_errors = 0;
1397
}
@@ -1240,6 +1402,48 @@ int update_from_proc(void)
1402
}
1403
1404
1405
+// ----------------------------------------------------------------------------
1406
+
1407
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1408
+// print a tree view of all processes
1409
+int debug_childrens_aggregations(pid_t pid, int level) {
1410
+ struct pid_stat *p = NULL;
1411
+ char b[level+3];
1412
+ int i, ret = 0;
1413
+
1414
+ for(i = 0; i < level; i++) b[i] = '\t';
1415
+ b[level] = '|';
1416
+ b[level+1] = '-';
1417
+ b[level+2] = '\0';
1418
+
1419
+ for(p = root_of_pids; p ; p = p->next) {
1420
+ if(p->ppid == pid) {
1421
+ ret += debug_childrens_aggregations(p->pid, level+1);
1422
+ }
1423
+ }
1424
+
1425
+ p = all_pids[pid];
1426
+ if(p) {
1427
+ if(!p->updated) ret += 1;
1428
+ 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"
1429
+ , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->children_count
1430
+ , p->utime, p->utime - p->old_utime
1431
+ , p->stime, p->stime - p->old_stime
1432
+ , p->cutime, p->cutime - p->old_cutime
1433
+ , p->cstime, p->cstime - p->old_cstime
1434
+ , p->minflt, p->minflt - p->old_minflt
1435
+ , p->majflt, p->majflt - p->old_majflt
1436
+ , p->cminflt, p->cminflt - p->old_cminflt
1437
+ , p->cmajflt, p->cmajflt - p->old_cmajflt
1438
+ );
1439
+ }
1440
+
1441
+ return ret;
1442
+}
1443
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1444
+
1445
+
1446
+
1447
// ----------------------------------------------------------------------------
1448
// update statistics on the targets
1449
@@ -1250,17 +1454,15 @@ int update_from_proc(void)
1454
// 4. go from top to bottom, linking all childs without a target, to their parent target
1455
// after this step, all processes have a target
1456
// [5. for each killed pid (updated = 0), remove its usage from its target]
1253
-// 6. zero all targets
1254
-// 7. concentrate all values on the targets
1457
+// 6. zero all apps_groups_targets
1458
+// 7. concentrate all values on the apps_groups_targets
1459
// 8. remove all killed processes
1460
// 9. find the unique file count for each target
1461
+// check: update_apps_groups_statistics()
1462
1258
-void update_statistics(void)
1259
-{
1260
- int c;
1463
+void link_all_processes_to_their_parents(void) {
1464
struct pid_stat *p = NULL;
1465
1263
-
1466
// link all children to their parents
1467
// and update children count on parents
1468
for(p = root_of_pids; p ; p = p->next) {
@@ -1281,7 +1483,90 @@ void update_statistics(void)
1483
else if(p->ppid != 0)
1484
error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1485
}
1486
+}
1487
+
1488
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1489
+void aggregate_children_to_parents(void) {
1490
+ struct pid_stat *p = NULL;
1491
+
1492
+ // for each killed process, remove its values from the parents
1493
+ // sums (we had already added them in a previous loop)
1494
+ for(p = root_of_pids; p ; p = p->next) {
1495
+ if(p->updated) continue;
1496
+
1497
+ if(debug) fprintf(stderr, "apps.plugin: UNMERGING %d %s\n", p->pid, p->comm);
1498
+
1499
+ unsigned long long diff_utime = p->utime + p->cutime + p->fix_cutime;
1500
+ unsigned long long diff_stime = p->stime + p->cstime + p->fix_cstime;
1501
+ unsigned long long diff_minflt = p->minflt + p->cminflt + p->fix_cminflt;
1502
+ unsigned long long diff_majflt = p->majflt + p->cmajflt + p->fix_cmajflt;
1503
+
1504
+ struct pid_stat *t = p;
1505
+ while((t = t->parent)) {
1506
+ if(!t->updated) continue;
1507
+
1508
+ unsigned long long x;
1509
+ if(diff_utime && t->diff_cutime) {
1510
+ x = (t->diff_cutime < diff_utime)?t->diff_cutime:diff_utime;
1511
+ diff_utime -= x;
1512
+ t->diff_cutime -= x;
1513
+ t->fix_cutime += x;
1514
+ if(debug) fprintf(stderr, "apps.plugin: \t cutime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1515
+ }
1516
+ if(diff_stime && t->diff_cstime) {
1517
+ x = (t->diff_cstime < diff_stime)?t->diff_cstime:diff_stime;
1518
+ diff_stime -= x;
1519
+ t->diff_cstime -= x;
1520
+ t->fix_cstime += x;
1521
+ if(debug) fprintf(stderr, "apps.plugin: \t cstime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1522
+ }
1523
+ if(diff_minflt && t->diff_cminflt) {
1524
+ x = (t->diff_cminflt < diff_minflt)?t->diff_cminflt:diff_minflt;
1525
+ diff_minflt -= x;
1526
+ t->diff_cminflt -= x;
1527
+ t->fix_cminflt += x;
1528
+ if(debug) fprintf(stderr, "apps.plugin: \t cminflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1529
+ }
1530
+ if(diff_majflt && t->diff_cmajflt) {
1531
+ x = (t->diff_cmajflt < diff_majflt)?t->diff_cmajflt:diff_majflt;
1532
+ diff_majflt -= x;
1533
+ t->diff_cmajflt -= x;
1534
+ t->fix_cmajflt += x;
1535
+ if(debug) fprintf(stderr, "apps.plugin: \t cmajflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1536
+ }
1537
+ }
1538
+
1539
+ if(diff_utime) error("Cannot fix up utime %llu", diff_utime);
1540
+ if(diff_stime) error("Cannot fix up stime %llu", diff_stime);
1541
+ if(diff_minflt) error("Cannot fix up minflt %llu", diff_minflt);
1542
+ if(diff_majflt) error("Cannot fix up majflt %llu", diff_majflt);
1543
+ }
1544
+}
1545
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1546
1547
+void cleanup_non_existing_pids(void) {
1548
+ int c;
1549
+ struct pid_stat *p = NULL;
1550
+
1551
+ for(p = root_of_pids; p ;) {
1552
+ if(!p->updated) {
1553
+// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1554
+
1555
+ for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
1556
+ file_descriptor_not_used(p->fds[c]);
1557
+ p->fds[c] = 0;
1558
+ }
1559
+
1560
+ pid_t r = p->pid;
1561
+ p = p->next;
1562
+ del_pid_entry(r);
1563
+ }
1564
+ else p = p->next;
1565
+ }
1566
+}
1567
+
1568
+void apply_apps_groups_targets_inheritance(void) {
1569
+ struct pid_stat *p = NULL;
1570
1571
// children that do not have a target
1572
// inherit their target from their parent
@@ -1346,23 +1631,23 @@ void update_statistics(void)
1631
1632
// init goes always to default target
1633
if(all_pids[1])
1349
- all_pids[1]->target = default_target;
1634
+ all_pids[1]->target = apps_groups_default_target;
1635
1636
// give a default target on all top level processes
1637
for(p = root_of_pids; p ; p = p->next) {
1638
// if the process is not merged itself
1639
// then is is a top level process
1640
if(!p->merged && !p->target)
1356
- p->target = default_target;
1641
+ p->target = apps_groups_default_target;
1642
1358
-#ifdef INCLUDE_CHILDS
1643
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1644
// by the way, update the diffs
1645
// will be used later for subtracting killed process times
1646
p->diff_cutime = p->utime - p->cutime;
1647
p->diff_cstime = p->stime - p->cstime;
1648
p->diff_cminflt = p->minflt - p->cminflt;
1649
p->diff_cmajflt = p->majflt - p->cmajflt;
1365
-#endif /* INCLUDE_CHILDS */
1650
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1651
}
1652
1653
// give a target to all merged child processes
@@ -1379,71 +1664,17 @@ void update_statistics(void)
1664
}
1665
}
1666
}
1667
+}
1668
1383
-#ifdef INCLUDE_CHILDS
1384
- // for each killed process, remove its values from the parents
1385
- // sums (we had already added them in a previous loop)
1386
- for(p = root_of_pids; p ; p = p->next) {
1387
- if(p->updated) continue;
1388
-
1389
- if(debug) fprintf(stderr, "apps.plugin: UNMERGING %d %s\n", p->pid, p->comm);
1390
-
1391
- unsigned long long diff_utime = p->utime + p->cutime + p->fix_cutime;
1392
- unsigned long long diff_stime = p->stime + p->cstime + p->fix_cstime;
1393
- unsigned long long diff_minflt = p->minflt + p->cminflt + p->fix_cminflt;
1394
- unsigned long long diff_majflt = p->majflt + p->cmajflt + p->fix_cmajflt;
1395
-
1396
- struct pid_stat *t = p;
1397
- while((t = t->parent)) {
1398
- if(!t->updated) continue;
1399
-
1400
- unsigned long long x;
1401
- if(diff_utime && t->diff_cutime) {
1402
- x = (t->diff_cutime < diff_utime)?t->diff_cutime:diff_utime;
1403
- diff_utime -= x;
1404
- t->diff_cutime -= x;
1405
- t->fix_cutime += x;
1406
- if(debug) fprintf(stderr, "apps.plugin: \t cutime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1407
- }
1408
- if(diff_stime && t->diff_cstime) {
1409
- x = (t->diff_cstime < diff_stime)?t->diff_cstime:diff_stime;
1410
- diff_stime -= x;
1411
- t->diff_cstime -= x;
1412
- t->fix_cstime += x;
1413
- if(debug) fprintf(stderr, "apps.plugin: \t cstime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1414
- }
1415
- if(diff_minflt && t->diff_cminflt) {
1416
- x = (t->diff_cminflt < diff_minflt)?t->diff_cminflt:diff_minflt;
1417
- diff_minflt -= x;
1418
- t->diff_cminflt -= x;
1419
- t->fix_cminflt += x;
1420
- if(debug) fprintf(stderr, "apps.plugin: \t cminflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1421
- }
1422
- if(diff_majflt && t->diff_cmajflt) {
1423
- x = (t->diff_cmajflt < diff_majflt)?t->diff_cmajflt:diff_majflt;
1424
- diff_majflt -= x;
1425
- t->diff_cmajflt -= x;
1426
- t->fix_cmajflt += x;
1427
- if(debug) fprintf(stderr, "apps.plugin: \t cmajflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
1428
- }
1429
- }
1430
-
1431
- if(diff_utime) error("Cannot fix up utime %llu", diff_utime);
1432
- if(diff_stime) error("Cannot fix up stime %llu", diff_stime);
1433
- if(diff_minflt) error("Cannot fix up minflt %llu", diff_minflt);
1434
- if(diff_majflt) error("Cannot fix up majflt %llu", diff_majflt);
1435
- }
1436
-#endif /* INCLUDE_CHILDS */
1437
-
1438
- // zero all the targets
1439
- targets = 0;
1669
+long zero_all_targets(struct target *root) {
1670
struct target *w;
1441
- for (w = target_root; w ; w = w->next) {
1442
- targets++;
1671
+ long count = 0;
1672
1444
- w->fds = calloc(sizeof(int), (size_t) all_files_size);
1445
- if(!w->fds)
1446
- error("Cannot allocate memory for fds in %s", w->name);
1673
+ for (w = root; w ; w = w->next) {
1674
+ count++;
1675
+
1676
+ if(w->fds) free(w->fds);
1677
+ w->fds = NULL;
1678
1679
w->minflt = 0;
1680
w->majflt = 0;
@@ -1474,131 +1705,175 @@ void update_statistics(void)
1705
w->io_cancelled_write_bytes = 0;
1706
}
1707
1477
-#ifdef INCLUDE_CHILDS
1478
- if(debug) walk_down(0, 1);
1479
-#endif /* INCLUDE_CHILDS */
1708
+ return count;
1709
+}
1710
1481
- // concentrate everything on the targets
1482
- for(p = root_of_pids; p ; p = p->next) {
1483
- if(!p->target) {
1484
- error("pid %d %s was left without a target!", p->pid, p->comm);
1485
- continue;
1486
- }
1711
+void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
1712
+ if(unlikely(!w->fds)) {
1713
+ w->fds = calloc(sizeof(int), (size_t) all_files_size);
1714
+ if(unlikely(!w->fds))
1715
+ error("Cannot allocate memory for fds in %s", w->name);
1716
+ }
1717
1488
- if(p->updated) {
1489
- p->target->cutime += p->cutime; // - p->fix_cutime;
1490
- p->target->cstime += p->cstime; // - p->fix_cstime;
1491
- p->target->cminflt += p->cminflt; // - p->fix_cminflt;
1492
- p->target->cmajflt += p->cmajflt; // - p->fix_cmajflt;
1718
+ if(likely(p->updated)) {
1719
+ w->cutime += p->cutime; // - p->fix_cutime;
1720
+ w->cstime += p->cstime; // - p->fix_cstime;
1721
+ w->cminflt += p->cminflt; // - p->fix_cminflt;
1722
+ w->cmajflt += p->cmajflt; // - p->fix_cmajflt;
1723
1494
- p->target->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;
1495
- p->target->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;
1496
- p->target->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;
1497
- p->target->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;
1724
+ w->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;
1725
+ w->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;
1726
+ w->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;
1727
+ w->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;
1728
1499
- //if(p->num_threads < 0)
1500
- // error("Negative threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
1729
+ //if(p->num_threads < 0)
1730
+ // error("Negative threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
1731
1502
- //if(p->num_threads > 10000)
1503
- // error("Excessive threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
1732
+ //if(p->num_threads > 10000)
1733
+ // error("Excessive threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
1734
1505
- p->target->num_threads += p->num_threads;
1506
- p->target->rss += p->rss;
1735
+ w->num_threads += p->num_threads;
1736
+ w->rss += p->rss;
1737
1508
- p->target->statm_size += p->statm_size;
1509
- p->target->statm_resident += p->statm_resident;
1510
- p->target->statm_share += p->statm_share;
1511
- p->target->statm_text += p->statm_text;
1512
- p->target->statm_lib += p->statm_lib;
1513
- p->target->statm_data += p->statm_data;
1514
- p->target->statm_dirty += p->statm_dirty;
1738
+ w->statm_size += p->statm_size;
1739
+ w->statm_resident += p->statm_resident;
1740
+ w->statm_share += p->statm_share;
1741
+ w->statm_text += p->statm_text;
1742
+ w->statm_lib += p->statm_lib;
1743
+ w->statm_data += p->statm_data;
1744
+ w->statm_dirty += p->statm_dirty;
1745
1516
- p->target->io_logical_bytes_read += p->io_logical_bytes_read;
1517
- p->target->io_logical_bytes_written += p->io_logical_bytes_written;
1518
- p->target->io_read_calls += p->io_read_calls;
1519
- p->target->io_write_calls += p->io_write_calls;
1520
- p->target->io_storage_bytes_read += p->io_storage_bytes_read;
1521
- p->target->io_storage_bytes_written += p->io_storage_bytes_written;
1522
- p->target->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1746
+ w->io_logical_bytes_read += p->io_logical_bytes_read;
1747
+ w->io_logical_bytes_written += p->io_logical_bytes_written;
1748
+ w->io_read_calls += p->io_read_calls;
1749
+ w->io_write_calls += p->io_write_calls;
1750
+ w->io_storage_bytes_read += p->io_storage_bytes_read;
1751
+ w->io_storage_bytes_written += p->io_storage_bytes_written;
1752
+ w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1753
1524
- p->target->processes++;
1754
+ w->processes++;
1755
1756
+ if(likely(w->fds)) {
1757
+ int c;
1758
for(c = 0; c < p->fds_size ;c++) {
1759
if(p->fds[c] == 0) continue;
1528
- if(p->fds[c] < all_files_size) {
1529
- if(p->target->fds) p->target->fds[p->fds[c]]++;
1760
+
1761
+ if(likely(p->fds[c] < all_files_size)) {
1762
+ if(w->fds) w->fds[p->fds[c]]++;
1763
}
1764
else
1765
error("Invalid fd number %d", p->fds[c]);
1766
}
1767
+ }
1768
1535
- if(debug || p->target->debug) fprintf(stderr, "apps.plugin: \tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1536
-
1537
-/* 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);
1538
- 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);
1539
- if(p->stime - p->old_stime > 100) fprintf(stderr, "BIG CHANGE: %d %s stime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->stime - p->old_stime, p->old_stime, p->stime);
1540
- if(p->cstime - p->old_cstime > 100) fprintf(stderr, "BIG CHANGE: %d %s cstime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cstime - p->old_cstime, p->old_cstime, p->cstime);
1541
- if(p->minflt - p->old_minflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s minflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->minflt - p->old_minflt, p->old_minflt, p->minflt);
1542
- if(p->majflt - p->old_majflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s majflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->majflt - p->old_majflt, p->old_majflt, p->majflt);
1543
- 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);
1544
- 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);
1769
+ if(unlikely(debug || w->debug))
1770
+ fprintf(stderr, "apps.plugin: \tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1771
+
1772
+/* 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);
1773
+ 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);
1774
+ if(p->stime - p->old_stime > 100) fprintf(stderr, "BIG CHANGE: %d %s stime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->stime - p->old_stime, p->old_stime, p->stime);
1775
+ if(p->cstime - p->old_cstime > 100) fprintf(stderr, "BIG CHANGE: %d %s cstime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cstime - p->old_cstime, p->old_cstime, p->cstime);
1776
+ if(p->minflt - p->old_minflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s minflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->minflt - p->old_minflt, p->old_minflt, p->minflt);
1777
+ if(p->majflt - p->old_majflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s majflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->majflt - p->old_majflt, p->old_majflt, p->majflt);
1778
+ 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);
1779
+ 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);
1780
*/
1546
-#ifdef INCLUDE_CHILDS
1547
- p->old_utime = p->utime;
1548
- p->old_cutime = p->cutime;
1549
- p->old_stime = p->stime;
1550
- p->old_cstime = p->cstime;
1551
- p->old_minflt = p->minflt;
1552
- p->old_majflt = p->majflt;
1553
- p->old_cminflt = p->cminflt;
1554
- p->old_cmajflt = p->cmajflt;
1555
-#endif /* INCLUDE_CHILDS */
1556
- }
1557
- else {
1558
- // since the process has exited, the user
1559
- // will see a drop in our charts, because the incremental
1560
- // values of this process will not be there
1561
-
1562
- // add them to the fix_* values and they will be added to
1563
- // the reported values, so that the report goes steady
1564
- p->target->fix_minflt += p->minflt;
1565
- p->target->fix_majflt += p->majflt;
1566
- p->target->fix_utime += p->utime;
1567
- p->target->fix_stime += p->stime;
1568
- p->target->fix_cminflt += p->cminflt;
1569
- p->target->fix_cmajflt += p->cmajflt;
1570
- p->target->fix_cutime += p->cutime;
1571
- p->target->fix_cstime += p->cstime;
1572
-
1573
- p->target->fix_io_logical_bytes_read += p->io_logical_bytes_read;
1574
- p->target->fix_io_logical_bytes_written += p->io_logical_bytes_written;
1575
- p->target->fix_io_read_calls += p->io_read_calls;
1576
- p->target->fix_io_write_calls += p->io_write_calls;
1577
- p->target->fix_io_storage_bytes_read += p->io_storage_bytes_read;
1578
- p->target->fix_io_storage_bytes_written += p->io_storage_bytes_written;
1579
- p->target->fix_io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1781
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1782
+ p->old_utime = p->utime;
1783
+ p->old_cutime = p->cutime;
1784
+ p->old_stime = p->stime;
1785
+ p->old_cstime = p->cstime;
1786
+ p->old_minflt = p->minflt;
1787
+ p->old_majflt = p->majflt;
1788
+ p->old_cminflt = p->cminflt;
1789
+ p->old_cmajflt = p->cmajflt;
1790
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1791
+
1792
+ if(o) {
1793
+ // since the process switched target
1794
+ // for all incremental values
1795
+ // we have to subtract its OLD values from the new target
1796
+ // and add its OLD values to the old target
1797
+
1798
+ // IMPORTANT
1799
+ // We add/subtract the last/OLD values we added to the target
1800
+
1801
+ w->fix_cutime -= p->last_cutime;
1802
+ w->fix_cstime -= p->last_cstime;
1803
+ w->fix_cminflt -= p->last_cminflt;
1804
+ w->fix_cmajflt -= p->last_cmajflt;
1805
+
1806
+ w->fix_utime -= p->last_utime;
1807
+ w->fix_stime -= p->last_stime;
1808
+ w->fix_minflt -= p->last_minflt;
1809
+ w->fix_majflt -= p->last_majflt;
1810
+
1811
+
1812
+ w->fix_io_logical_bytes_read -= p->last_io_logical_bytes_read;
1813
+ w->fix_io_logical_bytes_written -= p->last_io_logical_bytes_written;
1814
+ w->fix_io_read_calls -= p->last_io_read_calls;
1815
+ w->fix_io_write_calls -= p->last_io_write_calls;
1816
+ w->fix_io_storage_bytes_read -= p->last_io_storage_bytes_read;
1817
+ w->fix_io_storage_bytes_written -= p->last_io_storage_bytes_written;
1818
+ w->fix_io_cancelled_write_bytes -= p->last_io_cancelled_write_bytes;
1819
+
1820
+ // ---
1821
+
1822
+ o->fix_cutime += p->last_cutime;
1823
+ o->fix_cstime += p->last_cstime;
1824
+ o->fix_cminflt += p->last_cminflt;
1825
+ o->fix_cmajflt += p->last_cmajflt;
1826
+
1827
+ o->fix_utime += p->last_utime;
1828
+ o->fix_stime += p->last_stime;
1829
+ o->fix_minflt += p->last_minflt;
1830
+ o->fix_majflt += p->last_majflt;
1831
+
1832
+ o->fix_io_logical_bytes_read += p->last_io_logical_bytes_read;
1833
+ o->fix_io_logical_bytes_written += p->last_io_logical_bytes_written;
1834
+ o->fix_io_read_calls += p->last_io_read_calls;
1835
+ o->fix_io_write_calls += p->last_io_write_calls;
1836
+ o->fix_io_storage_bytes_read += p->last_io_storage_bytes_read;
1837
+ o->fix_io_storage_bytes_written += p->last_io_storage_bytes_written;
1838
+ o->fix_io_cancelled_write_bytes += p->last_io_cancelled_write_bytes;
1839
}
1840
}
1841
+ else {
1842
+ // if(o) fprintf(stderr, "apps.plugin: \t\tpid %d (%s) is not updated by OLD target %s (%s) is present.\n", p->pid, p->comm, o->id, o->name);
1843
+
1844
+ // since the process has exited, the user
1845
+ // will see a drop in our charts, because the incremental
1846
+ // values of this process will not be there
1847
+
1848
+ // add them to the fix_* values and they will be added to
1849
+ // the reported values, so that the report goes steady
1850
+ w->fix_minflt += p->minflt;
1851
+ w->fix_majflt += p->majflt;
1852
+ w->fix_utime += p->utime;
1853
+ w->fix_stime += p->stime;
1854
+ w->fix_cminflt += p->cminflt;
1855
+ w->fix_cmajflt += p->cmajflt;
1856
+ w->fix_cutime += p->cutime;
1857
+ w->fix_cstime += p->cstime;
1858
+
1859
+ w->fix_io_logical_bytes_read += p->io_logical_bytes_read;
1860
+ w->fix_io_logical_bytes_written += p->io_logical_bytes_written;
1861
+ w->fix_io_read_calls += p->io_read_calls;
1862
+ w->fix_io_write_calls += p->io_write_calls;
1863
+ w->fix_io_storage_bytes_read += p->io_storage_bytes_read;
1864
+ w->fix_io_storage_bytes_written += p->io_storage_bytes_written;
1865
+ w->fix_io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1866
+ }
1867
1583
-// fprintf(stderr, "\n");
1584
- // cleanup all un-updated processed (exited, killed, etc)
1585
- for(p = root_of_pids; p ;) {
1586
- if(!p->updated) {
1587
-// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1868
+}
1869
1589
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
1590
- file_descriptor_not_used(p->fds[c]);
1591
- p->fds[c] = 0;
1592
- }
1870
+void count_targets_fds(struct target *root) {
1871
+ int c;
1872
+ struct target *w;
1873
1594
- pid_t r = p->pid;
1595
- p = p->next;
1596
- del_pid_entry(r);
1597
- }
1598
- else p = p->next;
1599
- }
1874
+ for (w = root; w ; w = w->next) {
1875
+ if(!w->fds) continue;
1876
1601
- for (w = target_root; w ; w = w->next) {
1877
w->openfiles = 0;
1878
w->openpipes = 0;
1879
w->opensockets = 0;
@@ -1610,7 +1885,8 @@ void update_statistics(void)
1885
w->openother = 0;
1886
1887
for(c = 1; c < all_files_size ;c++) {
1613
- if(w->fds && w->fds[c] > 0) switch(all_files[c].type) {
1888
+ if(w->fds[c] > 0)
1889
+ switch(all_files[c].type) {
1890
case FILETYPE_FILE:
1891
w->openfiles++;
1892
break;
@@ -1653,15 +1929,90 @@ void update_statistics(void)
1929
}
1930
}
1931
1932
+void calculate_netdata_statistics(void)
1933
+{
1934
+ link_all_processes_to_their_parents();
1935
+ apply_apps_groups_targets_inheritance();
1936
+
1937
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1938
+ aggregate_children_to_parents();
1939
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1940
+
1941
+ zero_all_targets(users_root_target);
1942
+ zero_all_targets(groups_root_target);
1943
+ apps_groups_targets = zero_all_targets(apps_groups_root_target);
1944
+
1945
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
1946
+ if(debug)
1947
+ debug_childrens_aggregations(0, 1);
1948
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
1949
+
1950
+ // this has to be done, before the cleanup
1951
+ struct pid_stat *p = NULL;
1952
+ struct target *w = NULL, *o = NULL;
1953
+
1954
+ // concentrate everything on the apps_groups_targets
1955
+ for(p = root_of_pids; p ; p = p->next) {
1956
+
1957
+ // --------------------------------------------------------------------
1958
+ // apps_groups targets
1959
+ if(likely(p->target))
1960
+ aggregate_pid_on_target(p->target, p, NULL);
1961
+ else
1962
+ error("pid %d %s was left without a target!", p->pid, p->comm);
1963
+
1964
+
1965
+ // --------------------------------------------------------------------
1966
+ // user targets
1967
+ o = p->user_target;
1968
+ if(likely(p->user_target && p->user_target->uid == p->uid))
1969
+ w = p->user_target;
1970
+ else {
1971
+ if(unlikely(debug && p->user_target))
1972
+ fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched user from %d (%s) to %d.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
1973
+
1974
+ w = p->user_target = get_users_target(p->uid);
1975
+ }
1976
+
1977
+ if(likely(w))
1978
+ aggregate_pid_on_target(w, p, o);
1979
+ else
1980
+ error("pid %d %s was left without a user target!", p->pid, p->comm);
1981
+
1982
+
1983
+ // --------------------------------------------------------------------
1984
+ // group targets
1985
+ o = p->group_target;
1986
+ if(likely(p->group_target && p->group_target->gid == p->gid))
1987
+ w = p->group_target;
1988
+ else {
1989
+ if(unlikely(debug && p->group_target))
1990
+ fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched group from %d (%s) to %d.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
1991
+
1992
+ w = p->group_target = get_groups_target(p->gid);
1993
+ }
1994
+
1995
+ if(likely(w))
1996
+ aggregate_pid_on_target(w, p, o);
1997
+ else
1998
+ error("pid %d %s was left without a group target!", p->pid, p->comm);
1999
+
2000
+ }
2001
+
2002
+ count_targets_fds(apps_groups_root_target);
2003
+ count_targets_fds(users_root_target);
2004
+ count_targets_fds(groups_root_target);
2005
+
2006
+ cleanup_non_existing_pids();
2007
+}
2008
+
2009
// ----------------------------------------------------------------------------
2010
// update chart dimensions
2011
1659
-void show_dimensions(void)
1660
-{
2012
+unsigned long long send_resource_usage_to_netdata() {
2013
static struct timeval last = { 0, 0 };
2014
static struct rusage me_last;
2015
1664
- struct target *w;
2016
struct timeval now;
2017
struct rusage me;
2018
@@ -1692,138 +2043,145 @@ void show_dimensions(void)
2043
bcopy(&me, &me_last, sizeof(struct rusage));
2044
}
2045
1695
- fprintf(stdout, "BEGIN apps.cpu %llu\n", usec);
1696
- for (w = target_root; w ; w = w->next) {
2046
+ fprintf(stdout, "BEGIN netdata.apps_cpu %llu\n", usec);
2047
+ fprintf(stdout, "SET user = %llu\n", cpuuser);
2048
+ fprintf(stdout, "SET system = %llu\n", cpusyst);
2049
+ fprintf(stdout, "END\n");
2050
+
2051
+ fprintf(stdout, "BEGIN netdata.apps_files %llu\n", usec);
2052
+ fprintf(stdout, "SET files = %llu\n", file_counter);
2053
+ fprintf(stdout, "SET pids = %ld\n", all_pids_count);
2054
+ fprintf(stdout, "SET fds = %d\n", all_files_len);
2055
+ fprintf(stdout, "SET targets = %ld\n", apps_groups_targets);
2056
+ fprintf(stdout, "END\n");
2057
+
2058
+ return usec;
2059
+}
2060
+
2061
+void send_collected_data_to_netdata(struct target *root, const char *type, unsigned long long usec)
2062
+{
2063
+ struct target *w;
2064
+
2065
+ fprintf(stdout, "BEGIN %s.cpu %llu\n", type, usec);
2066
+ for (w = root; w ; w = w->next) {
2067
if(w->target || (!w->processes && !w->exposed)) continue;
2068
2069
fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + w->fix_utime + w->fix_stime);
2070
}
2071
fprintf(stdout, "END\n");
2072
1703
- fprintf(stdout, "BEGIN apps.cpu_user %llu\n", usec);
1704
- for (w = target_root; w ; w = w->next) {
2073
+ fprintf(stdout, "BEGIN %s.cpu_user %llu\n", type, usec);
2074
+ for (w = root; w ; w = w->next) {
2075
if(w->target || (!w->processes && !w->exposed)) continue;
2076
2077
fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->fix_utime);
2078
}
2079
fprintf(stdout, "END\n");
2080
1711
- fprintf(stdout, "BEGIN apps.cpu_system %llu\n", usec);
1712
- for (w = target_root; w ; w = w->next) {
2081
+ fprintf(stdout, "BEGIN %s.cpu_system %llu\n", type, usec);
2082
+ for (w = root; w ; w = w->next) {
2083
if(w->target || (!w->processes && !w->exposed)) continue;
2084
2085
fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + w->fix_stime);
2086
}
2087
fprintf(stdout, "END\n");
2088
1719
- fprintf(stdout, "BEGIN apps.threads %llu\n", usec);
1720
- for (w = target_root; w ; w = w->next) {
2089
+ fprintf(stdout, "BEGIN %s.threads %llu\n", type, usec);
2090
+ for (w = root; w ; w = w->next) {
2091
if(w->target || (!w->processes && !w->exposed)) continue;
2092
2093
fprintf(stdout, "SET %s = %llu\n", w->name, w->num_threads);
2094
}
2095
fprintf(stdout, "END\n");
2096
1727
- fprintf(stdout, "BEGIN apps.processes %llu\n", usec);
1728
- for (w = target_root; w ; w = w->next) {
2097
+ fprintf(stdout, "BEGIN %s.processes %llu\n", type, usec);
2098
+ for (w = root; w ; w = w->next) {
2099
if(w->target || (!w->processes && !w->exposed)) continue;
2100
2101
fprintf(stdout, "SET %s = %lu\n", w->name, w->processes);
2102
}
2103
fprintf(stdout, "END\n");
2104
1735
- fprintf(stdout, "BEGIN apps.mem %llu\n", usec);
1736
- for (w = target_root; w ; w = w->next) {
2105
+ fprintf(stdout, "BEGIN %s.mem %llu\n", type, usec);
2106
+ for (w = root; w ; w = w->next) {
2107
if(w->target || (!w->processes && !w->exposed)) continue;
2108
2109
fprintf(stdout, "SET %s = %lld\n", w->name, (long long)w->statm_resident - (long long)w->statm_share);
2110
}
2111
fprintf(stdout, "END\n");
2112
1743
- fprintf(stdout, "BEGIN apps.minor_faults %llu\n", usec);
1744
- for (w = target_root; w ; w = w->next) {
2113
+ fprintf(stdout, "BEGIN %s.minor_faults %llu\n", type, usec);
2114
+ for (w = root; w ; w = w->next) {
2115
if(w->target || (!w->processes && !w->exposed)) continue;
2116
2117
fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + w->fix_minflt);
2118
}
2119
fprintf(stdout, "END\n");
2120
1751
- fprintf(stdout, "BEGIN apps.major_faults %llu\n", usec);
1752
- for (w = target_root; w ; w = w->next) {
2121
+ fprintf(stdout, "BEGIN %s.major_faults %llu\n", type, usec);
2122
+ for (w = root; w ; w = w->next) {
2123
if(w->target || (!w->processes && !w->exposed)) continue;
2124
2125
fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + w->fix_majflt);
2126
}
2127
fprintf(stdout, "END\n");
2128
1759
- fprintf(stdout, "BEGIN apps.lreads %llu\n", usec);
1760
- for (w = target_root; w ; w = w->next) {
2129
+ fprintf(stdout, "BEGIN %s.lreads %llu\n", type, usec);
2130
+ for (w = root; w ; w = w->next) {
2131
if(w->target || (!w->processes && !w->exposed)) continue;
2132
1763
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read);
2133
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read + w->fix_io_logical_bytes_read);
2134
}
2135
fprintf(stdout, "END\n");
2136
1767
- fprintf(stdout, "BEGIN apps.lwrites %llu\n", usec);
1768
- for (w = target_root; w ; w = w->next) {
2137
+ fprintf(stdout, "BEGIN %s.lwrites %llu\n", type, usec);
2138
+ for (w = root; w ; w = w->next) {
2139
if(w->target || (!w->processes && !w->exposed)) continue;
2140
1771
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written);
2141
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written + w->fix_io_logical_bytes_written);
2142
}
2143
fprintf(stdout, "END\n");
2144
1775
- fprintf(stdout, "BEGIN apps.preads %llu\n", usec);
1776
- for (w = target_root; w ; w = w->next) {
2145
+ fprintf(stdout, "BEGIN %s.preads %llu\n", type, usec);
2146
+ for (w = root; w ; w = w->next) {
2147
if(w->target || (!w->processes && !w->exposed)) continue;
2148
1779
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read);
2149
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read + w->fix_io_storage_bytes_read);
2150
}
2151
fprintf(stdout, "END\n");
2152
1783
- fprintf(stdout, "BEGIN apps.pwrites %llu\n", usec);
1784
- for (w = target_root; w ; w = w->next) {
2153
+ fprintf(stdout, "BEGIN %s.pwrites %llu\n", type, usec);
2154
+ for (w = root; w ; w = w->next) {
2155
if(w->target || (!w->processes && !w->exposed)) continue;
2156
1787
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written);
2157
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written + w->fix_io_storage_bytes_written);
2158
}
2159
fprintf(stdout, "END\n");
2160
1791
- fprintf(stdout, "BEGIN apps.files %llu\n", usec);
1792
- for (w = target_root; w ; w = w->next) {
2161
+ fprintf(stdout, "BEGIN %s.files %llu\n", type, usec);
2162
+ for (w = root; w ; w = w->next) {
2163
if(w->target || (!w->processes && !w->exposed)) continue;
2164
2165
fprintf(stdout, "SET %s = %llu\n", w->name, w->openfiles);
2166
}
2167
fprintf(stdout, "END\n");
2168
1799
- fprintf(stdout, "BEGIN apps.sockets %llu\n", usec);
1800
- for (w = target_root; w ; w = w->next) {
2169
+ fprintf(stdout, "BEGIN %s.sockets %llu\n", type, usec);
2170
+ for (w = root; w ; w = w->next) {
2171
if(w->target || (!w->processes && !w->exposed)) continue;
2172
2173
fprintf(stdout, "SET %s = %llu\n", w->name, w->opensockets);
2174
}
2175
fprintf(stdout, "END\n");
2176
1807
- fprintf(stdout, "BEGIN apps.pipes %llu\n", usec);
1808
- for (w = target_root; w ; w = w->next) {
2177
+ fprintf(stdout, "BEGIN %s.pipes %llu\n", type, usec);
2178
+ for (w = root; w ; w = w->next) {
2179
if(w->target || (!w->processes && !w->exposed)) continue;
2180
2181
fprintf(stdout, "SET %s = %llu\n", w->name, w->openpipes);
2182
}
2183
fprintf(stdout, "END\n");
2184
1815
- fprintf(stdout, "BEGIN netdata.apps_cpu %llu\n", usec);
1816
- fprintf(stdout, "SET user = %llu\n", cpuuser);
1817
- fprintf(stdout, "SET system = %llu\n", cpusyst);
1818
- fprintf(stdout, "END\n");
1819
-
1820
- fprintf(stdout, "BEGIN netdata.apps_files %llu\n", usec);
1821
- fprintf(stdout, "SET files = %llu\n", file_counter);
1822
- fprintf(stdout, "SET pids = %ld\n", all_pids_count);
1823
- fprintf(stdout, "SET fds = %d\n", all_files_len);
1824
- fprintf(stdout, "SET targets = %ld\n", targets);
1825
- fprintf(stdout, "END\n");
1826
-
2185
fflush(stdout);
2186
}
2187
@@ -1831,12 +2189,12 @@ void show_dimensions(void)
2189
// ----------------------------------------------------------------------------
2190
// generate the charts
2191
1834
-void show_charts(void)
2192
+void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title)
2193
{
2194
struct target *w;
2195
int newly_added = 0;
2196
1839
- for(w = target_root ; w ; w = w->next)
2197
+ for(w = root ; w ; w = w->next)
2198
if(!w->exposed && w->processes) {
2199
newly_added++;
2200
w->exposed = 1;
@@ -1848,122 +2206,110 @@ void show_charts(void)
2206
2207
// we have something new to show
2208
// update the charts
1851
- fprintf(stdout, "CHART apps.cpu '' 'Apps CPU Time (%ld%% = %ld core%s)' 'cpu time %%' cpu apps.cpu stacked 20001 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
1852
- for (w = target_root; w ; w = w->next) {
2209
+ 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);
2210
+ for (w = root; w ; w = w->next) {
2211
if(w->target || (!w->processes && !w->exposed)) continue;
2212
2213
fprintf(stdout, "DIMENSION %s '' incremental 100 %llu %s\n", w->name, Hertz, w->hidden ? "hidden,noreset" : "noreset");
2214
}
2215
1858
- fprintf(stdout, "CHART apps.mem '' 'Apps Dedicated Memory (w/o shared)' 'MB' mem apps.mem stacked 20003 %d\n", update_every);
1859
- for (w = target_root; w ; w = w->next) {
2216
+ fprintf(stdout, "CHART %s.mem '' '%s Dedicated Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
2217
+ for (w = root; w ; w = w->next) {
2218
if(w->target || (!w->processes && !w->exposed)) continue;
2219
2220
fprintf(stdout, "DIMENSION %s '' absolute %ld %ld noreset\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
2221
}
2222
1865
- fprintf(stdout, "CHART apps.threads '' 'Apps Threads' 'threads' processes apps.threads stacked 20005 %d\n", update_every);
1866
- for (w = target_root; w ; w = w->next) {
2223
+ fprintf(stdout, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20005 %d\n", type, title, type, update_every);
2224
+ for (w = root; w ; w = w->next) {
2225
if(w->target || (!w->processes && !w->exposed)) continue;
2226
2227
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
2228
}
2229
1872
- fprintf(stdout, "CHART apps.processes '' 'Apps Processes' 'processes' processes apps.processes stacked 20004 %d\n", update_every);
1873
- for (w = target_root; w ; w = w->next) {
2230
+ fprintf(stdout, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes stacked 20004 %d\n", type, title, type, update_every);
2231
+ for (w = root; w ; w = w->next) {
2232
if(w->target || (!w->processes && !w->exposed)) continue;
2233
2234
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
2235
}
2236
1879
- fprintf(stdout, "CHART apps.cpu_user '' 'Apps CPU User Time (%ld%% = %ld core%s)' 'cpu time %%' cpu apps.cpu_user stacked 20020 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
1880
- for (w = target_root; w ; w = w->next) {
2237
+ 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);
2238
+ for (w = root; w ; w = w->next) {
2239
if(w->target || (!w->processes && !w->exposed)) continue;
2240
2241
fprintf(stdout, "DIMENSION %s '' incremental 100 %llu noreset\n", w->name, Hertz * processors);
2242
}
2243
1886
- fprintf(stdout, "CHART apps.cpu_system '' 'Apps CPU System Time (%ld%% = %ld core%s)' 'cpu time %%' cpu apps.cpu_system stacked 20021 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
1887
- for (w = target_root; w ; w = w->next) {
2244
+ 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);
2245
+ for (w = root; w ; w = w->next) {
2246
if(w->target || (!w->processes && !w->exposed)) continue;
2247
2248
fprintf(stdout, "DIMENSION %s '' incremental 100 %llu noreset\n", w->name, Hertz * processors);
2249
}
2250
1893
- fprintf(stdout, "CHART apps.major_faults '' 'Apps Major Page Faults (swap read)' 'page faults/s' swap apps.major_faults stacked 20010 %d\n", update_every);
1894
- for (w = target_root; w ; w = w->next) {
2251
+ 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);
2252
+ for (w = root; w ; w = w->next) {
2253
if(w->target || (!w->processes && !w->exposed)) continue;
2254
2255
fprintf(stdout, "DIMENSION %s '' incremental 1 1 noreset\n", w->name);
2256
}
2257
1900
- fprintf(stdout, "CHART apps.minor_faults '' 'Apps Minor Page Faults' 'page faults/s' mem apps.minor_faults stacked 20011 %d\n", update_every);
1901
- for (w = target_root; w ; w = w->next) {
2258
+ 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);
2259
+ for (w = root; w ; w = w->next) {
2260
if(w->target || (!w->processes && !w->exposed)) continue;
2261
2262
fprintf(stdout, "DIMENSION %s '' incremental 1 1 noreset\n", w->name);
2263
}
2264
1907
- fprintf(stdout, "CHART apps.lreads '' 'Apps Disk Logical Reads' 'kilobytes/s' disk apps.lreads stacked 20042 %d\n", update_every);
1908
- for (w = target_root; w ; w = w->next) {
2265
+ fprintf(stdout, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
2266
+ for (w = root; w ; w = w->next) {
2267
if(w->target || (!w->processes && !w->exposed)) continue;
2268
2269
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2270
}
2271
1914
- fprintf(stdout, "CHART apps.lwrites '' 'Apps I/O Logical Writes' 'kilobytes/s' disk apps.lwrites stacked 20042 %d\n", update_every);
1915
- for (w = target_root; w ; w = w->next) {
2272
+ fprintf(stdout, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
2273
+ for (w = root; w ; w = w->next) {
2274
if(w->target || (!w->processes && !w->exposed)) continue;
2275
2276
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2277
}
2278
1921
- fprintf(stdout, "CHART apps.preads '' 'Apps Disk Reads' 'kilobytes/s' disk apps.preads stacked 20002 %d\n", update_every);
1922
- for (w = target_root; w ; w = w->next) {
2279
+ fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
2280
+ for (w = root; w ; w = w->next) {
2281
if(w->target || (!w->processes && !w->exposed)) continue;
2282
2283
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2284
}
2285
1928
- fprintf(stdout, "CHART apps.pwrites '' 'Apps Disk Writes' 'kilobytes/s' disk apps.pwrites stacked 20002 %d\n", update_every);
1929
- for (w = target_root; w ; w = w->next) {
2286
+ fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
2287
+ for (w = root; w ; w = w->next) {
2288
if(w->target || (!w->processes && !w->exposed)) continue;
2289
2290
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2291
}
2292
1935
- fprintf(stdout, "CHART apps.files '' 'Apps Open Files' 'open files' disk apps.files stacked 20050 %d\n", update_every);
1936
- for (w = target_root; w ; w = w->next) {
2293
+ fprintf(stdout, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type, title, type, update_every);
2294
+ for (w = root; w ; w = w->next) {
2295
if(w->target || (!w->processes && !w->exposed)) continue;
2296
2297
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
2298
}
2299
1942
- fprintf(stdout, "CHART apps.sockets '' 'Apps Open Sockets' 'open sockets' net apps.sockets stacked 20051 %d\n", update_every);
1943
- for (w = target_root; w ; w = w->next) {
2300
+ fprintf(stdout, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n", type, title, type, update_every);
2301
+ for (w = root; w ; w = w->next) {
2302
if(w->target || (!w->processes && !w->exposed)) continue;
2303
2304
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
2305
}
2306
1949
- fprintf(stdout, "CHART apps.pipes '' 'Apps Pipes' 'open pipes' processes apps.pipes stacked 20053 %d\n", update_every);
1950
- for (w = target_root; w ; w = w->next) {
2307
+ fprintf(stdout, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type, title, type, update_every);
2308
+ for (w = root; w ; w = w->next) {
2309
if(w->target || (!w->processes && !w->exposed)) continue;
2310
2311
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
2312
}
1955
-
1956
- fprintf(stdout, "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %d\n", update_every);
1957
- fprintf(stdout, "DIMENSION user '' incremental 1 %d\n", 1000);
1958
- fprintf(stdout, "DIMENSION system '' incremental 1 %d\n", 1000);
1959
-
1960
- fprintf(stdout, "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %d\n", update_every);
1961
- fprintf(stdout, "DIMENSION files '' incremental 1 1\n");
1962
- fprintf(stdout, "DIMENSION pids '' absolute 1 1\n");
1963
- fprintf(stdout, "DIMENSION fds '' absolute 1 1\n");
1964
- fprintf(stdout, "DIMENSION targets '' absolute 1 1\n");
1965
-
1966
- fflush(stdout);
2313
}
2314
2315
@@ -2002,12 +2348,18 @@ void parse_args(int argc, char **argv)
2348
if(freq > 0) update_every = freq;
2349
if(!name) name = "groups";
2350
2005
- if(read_process_groups(name)) {
2351
+ if(read_apps_groups_conf(name)) {
2352
error("Cannot read process groups %s", name);
2353
exit(1);
2354
}
2355
}
2356
2357
+unsigned long long sutime() {
2358
+ struct timeval now;
2359
+ gettimeofday(&now, NULL);
2360
+ return now.tv_sec * 1000000ULL + now.tv_usec;
2361
+}
2362
+
2363
int main(int argc, char **argv)
2364
{
2365
// debug_flags = D_PROCFILE;
@@ -2035,9 +2387,9 @@ int main(int argc, char **argv)
2387
2388
time_t started_t = time(NULL);
2389
time_t current_t;
2038
- Hertz = get_hertz();
2039
- pid_max = get_pid_max();
2040
- processors = get_processors();
2390
+ Hertz = get_system_hertz();
2391
+ pid_max = get_system_pid_max();
2392
+ processors = get_system_cpus();
2393
2394
parse_args(argc, argv);
2395
@@ -2048,39 +2400,63 @@ int main(int argc, char **argv)
2400
exit(1);
2401
}
2402
2051
- unsigned long long counter = 1;
2052
- unsigned long long usec = 0, susec = 0;
2053
- struct timeval last, now;
2054
- gettimeofday(&last, NULL);
2403
+ fprintf(stdout, "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %d\n", update_every);
2404
+ fprintf(stdout, "DIMENSION user '' incremental 1 %d\n", 1000);
2405
+ fprintf(stdout, "DIMENSION system '' incremental 1 %d\n", 1000);
2406
2407
+ fprintf(stdout, "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %d\n", update_every);
2408
+ fprintf(stdout, "DIMENSION files '' incremental 1 1\n");
2409
+ fprintf(stdout, "DIMENSION pids '' absolute 1 1\n");
2410
+ fprintf(stdout, "DIMENSION fds '' absolute 1 1\n");
2411
+ fprintf(stdout, "DIMENSION targets '' absolute 1 1\n");
2412
+
2413
+
2414
+#ifndef PROFILING_MODE
2415
+ unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL;
2416
+ unsigned long long sunow;
2417
+#endif /* PROFILING_MODE */
2418
+
2419
+ unsigned long long counter = 1;
2420
for(;1; counter++) {
2057
- if(!update_from_proc()) {
2058
- error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
2421
+#ifndef PROFILING_MODE
2422
+ // delay until it is our time to run
2423
+ while((sunow = sutime()) < sunext)
2424
+ usleep((useconds_t)(sunext - sunow));
2425
+
2426
+ // find the next time we need to run
2427
+ while(sutime() > sunext)
2428
+ sunext += update_every * 1000000ULL;
2429
+#endif /* PROFILING_MODE */
2430
+
2431
+ if(!collect_data_for_all_processes_from_proc()) {
2432
+ error("Cannot collect /proc data for running processes. Disabling apps.plugin...");
2433
printf("DISABLE\n");
2434
exit(1);
2435
}
2436
2063
- update_statistics();
2064
- show_charts(); // this is smart enough to show only newly added apps, when needed
2065
- show_dimensions();
2437
+ calculate_netdata_statistics();
2438
2067
- if(debug) fprintf(stderr, "apps.plugin: done Loop No %llu\n", counter);
2068
- fflush(NULL);
2439
+ unsigned long long dt = send_resource_usage_to_netdata();
2440
2070
- gettimeofday(&now, NULL);
2071
- usec = usecdiff(&now, &last) - susec;
2072
- if(debug) fprintf(stderr, "apps.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).\n", usec + susec, usec, susec);
2441
+ // this is smart enough to show only newly added apps, when needed
2442
+ send_charts_updates_to_netdata(apps_groups_root_target, "apps", "Apps");
2443
+ send_charts_updates_to_netdata(users_root_target, "users", "Users");
2444
+ send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups");
2445
2074
- // if the last loop took less than half the time
2075
- // wait the rest of the time
2076
- if(usec < (update_every * 1000000ULL / 2)) susec = (update_every * 1000000ULL) - usec;
2077
- else susec = update_every * 1000000ULL / 2;
2446
+ send_collected_data_to_netdata(apps_groups_root_target, "apps", dt);
2447
+ send_collected_data_to_netdata(users_root_target, "users", dt);
2448
+ send_collected_data_to_netdata(groups_root_target, "groups", dt);
2449
2079
- usleep((useconds_t) susec);
2080
- bcopy(&now, &last, sizeof(struct timeval));
2450
+ if(debug) fprintf(stderr, "apps.plugin: done Loop No %llu\n", counter);
2451
+ fflush(NULL);
2452
2082
- // restart once per day (14400 seconds)
2453
current_t = time(NULL);
2454
+
2455
+#ifndef PROFILING_MODE
2456
+ // restart check (14400 seconds)
2457
if(current_t - started_t > 14400) exit(0);
2458
+#else
2459
+ if(current_t - started_t > 10) exit(0);
2460
+#endif /* PROFILING_MODE */
2461
}
2462
}
src/avl.c
+21
@@ -145,19 +145,23 @@ int _avl_insert(avl_tree* t, avl* a) {
145
}
146
}
147
int avl_insert(avl_tree* t, avl* a) {
148
+#ifndef AVL_WITHOUT_PTHREADS
149
#ifdef AVL_LOCK_WITH_MUTEX
150
pthread_mutex_lock(&t->mutex);
151
#else
152
pthread_rwlock_wrlock(&t->rwlock);
153
#endif
154
+#endif /* AVL_WITHOUT_PTHREADS */
155
156
int ret = _avl_insert(t, a);
157
158
+#ifndef AVL_WITHOUT_PTHREADS
159
#ifdef AVL_LOCK_WITH_MUTEX
160
pthread_mutex_unlock(&t->mutex);
161
#else
162
pthread_rwlock_unlock(&t->rwlock);
163
#endif
164
+#endif /* AVL_WITHOUT_PTHREADS */
165
return ret;
166
}
167
@@ -243,19 +247,23 @@ int _avl_remove(avl_tree* t, avl* a) {
247
}
248
249
int avl_remove(avl_tree* t, avl* a) {
250
+#ifndef AVL_WITHOUT_PTHREADS
251
#ifdef AVL_LOCK_WITH_MUTEX
252
pthread_mutex_lock(&t->mutex);
253
#else
254
pthread_rwlock_wrlock(&t->rwlock);
255
#endif
256
+#endif /* AVL_WITHOUT_PTHREADS */
257
258
int ret = _avl_remove(t, a);
259
260
+#ifndef AVL_WITHOUT_PTHREADS
261
#ifdef AVL_LOCK_WITH_MUTEX
262
pthread_mutex_unlock(&t->mutex);
263
#else
264
pthread_rwlock_unlock(&t->rwlock);
265
#endif
266
+#endif /* AVL_WITHOUT_PTHREADS */
267
return ret;
268
}
269
@@ -299,19 +307,23 @@ int _avl_removeroot(avl_tree* t) {
307
}
308
309
int avl_removeroot(avl_tree* t) {
310
+#ifndef AVL_WITHOUT_PTHREADS
311
#ifdef AVL_LOCK_WITH_MUTEX
312
pthread_mutex_lock(&t->mutex);
313
#else
314
pthread_rwlock_wrlock(&t->rwlock);
315
#endif
316
+#endif /* AVL_WITHOUT_PTHREADS */
317
318
int ret = _avl_removeroot(t);
319
320
+#ifndef AVL_WITHOUT_PTHREADS
321
#ifdef AVL_LOCK_WITH_MUTEX
322
pthread_mutex_unlock(&t->mutex);
323
#else
324
pthread_rwlock_unlock(&t->rwlock);
325
#endif
326
+#endif /* AVL_WITHOUT_PTHREADS */
327
return ret;
328
}
329
@@ -363,19 +375,23 @@ int _avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl*), avl** ret) {
375
}
376
377
int avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl*), avl** ret) {
378
+#ifndef AVL_WITHOUT_PTHREADS
379
#ifdef AVL_LOCK_WITH_MUTEX
380
pthread_mutex_lock(&t->mutex);
381
#else
382
pthread_rwlock_wrlock(&t->rwlock);
383
#endif
384
+#endif /* AVL_WITHOUT_PTHREADS */
385
386
int ret2 = _avl_range(t, a, b, iter, ret);
387
388
+#ifndef AVL_WITHOUT_PTHREADS
389
#ifdef AVL_LOCK_WITH_MUTEX
390
pthread_mutex_unlock(&t->mutex);
391
#else
392
pthread_rwlock_unlock(&t->rwlock);
393
#endif
394
+#endif /* AVL_WITHOUT_PTHREADS */
395
396
return ret2;
397
}
@@ -392,7 +408,9 @@ void avl_init(avl_tree* t, int (*compar)(void* a, void* b)) {
408
t->root = NULL;
409
t->compar = compar;
410
411
+#ifndef AVL_WITHOUT_PTHREADS
412
int lock;
413
+
414
#ifdef AVL_LOCK_WITH_MUTEX
415
lock = pthread_mutex_init(&t->mutex, NULL);
416
#else
@@ -401,4 +419,7 @@ void avl_init(avl_tree* t, int (*compar)(void* a, void* b)) {
419
420
if(lock != 0)
421
fatal("Failed to initialize AVL mutex/rwlock, error: %d", lock);
422
+
423
+#endif /* AVL_WITHOUT_PTHREADS */
424
+
425
}
src/avl.h
+6
-2
@@ -15,7 +15,9 @@
15
#ifndef _AVL_H
16
#define _AVL_H 1
17
18
+#ifndef AVL_WITHOUT_PTHREADS
19
#include <pthread.h>
20
+#endif /* AVL_WITHOUT_PTHREADS */
21
22
// #define AVL_LOCK_WITH_MUTEX 1
23
@@ -33,11 +35,13 @@ typedef struct avl_tree {
35
avl* root;
36
int (*compar)(void* a, void* b);
37
38
+#ifndef AVL_WITHOUT_PTHREADS
39
#ifdef AVL_LOCK_WITH_MUTEX
40
pthread_mutex_t mutex;
38
-#else
41
+#else /* AVL_LOCK_WITH_MUTEX */
42
pthread_rwlock_t rwlock;
40
-#endif
43
+#endif /* AVL_LOCK_WITH_MUTEX */
44
+#endif /* AVL_WITHOUT_PTHREADS */
45
} avl_tree;
46
47
/* Public methods */
src/log.c
-2
@@ -143,9 +143,7 @@ void log_access( const char *fmt, ... )
143
vfprintf( stdaccess, fmt, args );
144
va_end( args );
145
fprintf( stdaccess, "\n");
146
-#ifdef NETDATA_INTERNAL_CHECKS
146
fflush( stdaccess );
148
-#endif
147
}
148
149
if(access_log_syslog) {
web/index.html
+37
-1
@@ -939,6 +939,18 @@ var menuData = {
939
height: 1.5
940
},
941
942
+ 'users': {
943
+ title: 'Users',
944
+ 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 childs continiously, 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 childs 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 unrealisting utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
945
+ height: 1.5
946
+ },
947
+
948
+ 'groups': {
949
+ title: 'User Groups',
950
+ 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 childs continiously, 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 childs 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 unrealisting utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
951
+ height: 1.5
952
+ },
953
+
954
'netdata': {
955
title: 'Netdata Monitoring',
956
info: undefined
@@ -1075,6 +1087,30 @@ var chartData = {
1087
height: 2.0
1088
},
1089
1090
+ 'users.cpu': {
1091
+ height: 2.0
1092
+ },
1093
+
1094
+ 'users.preads': {
1095
+ height: 2.0
1096
+ },
1097
+
1098
+ 'users.pwrites': {
1099
+ height: 2.0
1100
+ },
1101
+
1102
+ 'groups.cpu': {
1103
+ height: 2.0
1104
+ },
1105
+
1106
+ 'groups.preads': {
1107
+ height: 2.0
1108
+ },
1109
+
1110
+ 'groups.pwrites': {
1111
+ height: 2.0
1112
+ },
1113
+
1114
'tc.qos': {
1115
heads: [
1116
function(id) {
@@ -1224,7 +1260,7 @@ function menuTitle(menu) {
1260
}
1261
1262
function menuInfo(menu) {
1227
- return anyAttribute(menuData, 'title', menu, null);
1263
+ return anyAttribute(menuData, 'info', menu, null);
1264
}
1265
1266
function menuHeight(menu, relative) {