apps.plugin detects in-place process changes; fixes #1698
Costa Tsaousis (ktsaou) committed
Feb 1, 2017 at 23:02 UTC
6ee4780546b133905f488296747f915a5fbb9de1
4 files changed
+150
-149
src/apps_plugin.c
+137
-136
@@ -293,7 +293,6 @@ struct pid_stat {
293
int keeploops; // increases by 1 every time keep is 1 and updated 0
294
char updated:1; // 1 when the process is currently running
295
char merged:1; // 1 when it has been merged to its parent
296
- char new_entry:1; // 1 when this is a new process, just saw for the first time
296
char read:1; // 1 when we have already read this process for this iteration
297
298
int sortlist; // higher numbers = top on the process tree
@@ -627,56 +626,132 @@ static int read_apps_groups_conf(const char *file)
626
// struct pid_stat management
627
628
static inline struct pid_stat *get_pid_entry(pid_t pid) {
630
- if(unlikely(all_pids[pid])) {
631
- all_pids[pid]->new_entry = 0;
629
+ if(unlikely(all_pids[pid]))
630
return all_pids[pid];
633
- }
631
635
- all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
636
- all_pids[pid]->fds = callocz(sizeof(int), MAX_SPARE_FDS);
637
- all_pids[pid]->fds_size = MAX_SPARE_FDS;
632
+ struct pid_stat *p = callocz(sizeof(struct pid_stat), 1);
633
+ p->fds = callocz(sizeof(int), MAX_SPARE_FDS);
634
+ p->fds_size = MAX_SPARE_FDS;
635
636
if(likely(root_of_pids))
640
- root_of_pids->prev = all_pids[pid];
637
+ root_of_pids->prev = p;
638
642
- all_pids[pid]->next = root_of_pids;
643
- root_of_pids = all_pids[pid];
639
+ p->next = root_of_pids;
640
+ root_of_pids = p;
641
645
- all_pids[pid]->pid = pid;
646
- all_pids[pid]->new_entry = 1;
642
+ p->pid = pid;
643
644
+ all_pids[pid] = p;
645
all_pids_count++;
646
650
- return all_pids[pid];
647
+ return p;
648
}
649
650
static inline void del_pid_entry(pid_t pid) {
654
- if(unlikely(!all_pids[pid])) {
651
+ struct pid_stat *p = all_pids[pid];
652
+
653
+ if(unlikely(!p)) {
654
error("attempted to free pid %d that is not allocated.", pid);
655
return;
656
}
657
658
if(unlikely(debug))
660
- fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
659
+ fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, p->comm);
660
662
- if(root_of_pids == all_pids[pid])
663
- root_of_pids = all_pids[pid]->next;
661
+ if(root_of_pids == p)
662
+ root_of_pids = p->next;
663
665
- if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
666
- if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
664
+ if(p->next) p->next->prev = p->prev;
665
+ if(p->prev) p->prev->next = p->next;
666
668
- freez(all_pids[pid]->fds);
669
- freez(all_pids[pid]->fds_dirname);
670
- freez(all_pids[pid]->stat_filename);
671
- freez(all_pids[pid]->statm_filename);
672
- freez(all_pids[pid]->io_filename);
673
- freez(all_pids[pid]->cmdline_filename);
674
- freez(all_pids[pid]);
667
+ freez(p->fds);
668
+ freez(p->fds_dirname);
669
+ freez(p->stat_filename);
670
+ freez(p->statm_filename);
671
+ freez(p->io_filename);
672
+ freez(p->cmdline_filename);
673
+ freez(p);
674
675
all_pids[pid] = NULL;
676
all_pids_count--;
677
}
678
679
+// ----------------------------------------------------------------------------
680
+
681
+static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
682
+ if(unlikely(!status)) {
683
+ // error("command failed log %u, errno %d", log, errno);
684
+
685
+ if(unlikely(debug || errno != ENOENT)) {
686
+ if(unlikely(debug || !(p->log_thrown & log))) {
687
+ p->log_thrown |= log;
688
+ switch(log) {
689
+ case PID_LOG_IO:
690
+ error("Cannot process %s/proc/%d/io (command '%s')", global_host_prefix, p->pid, p->comm);
691
+ break;
692
+
693
+ case PID_LOG_STATM:
694
+ error("Cannot process %s/proc/%d/statm (command '%s')", global_host_prefix, p->pid, p->comm);
695
+ break;
696
+
697
+ case PID_LOG_CMDLINE:
698
+ error("Cannot process %s/proc/%d/cmdline (command '%s')", global_host_prefix, p->pid, p->comm);
699
+ break;
700
+
701
+ case PID_LOG_FDS:
702
+ error("Cannot process entries in %s/proc/%d/fd (command '%s')", global_host_prefix, p->pid, p->comm);
703
+ break;
704
+
705
+ case PID_LOG_STAT:
706
+ break;
707
+
708
+ default:
709
+ error("unhandled error for pid %d, command '%s'", p->pid, p->comm);
710
+ break;
711
+ }
712
+ }
713
+ }
714
+ errno = 0;
715
+ }
716
+ else if(unlikely(p->log_thrown & log)) {
717
+ // error("unsetting log %u on pid %d", log, p->pid);
718
+ p->log_thrown &= ~log;
719
+ }
720
+
721
+ return status;
722
+}
723
+
724
+static inline void assign_target_to_pid(struct pid_stat *p) {
725
+ uint32_t hash = simple_hash(p->comm);
726
+ size_t pclen = strlen(p->comm);
727
+
728
+ struct target *w;
729
+ for(w = apps_groups_root_target; w ; w = w->next) {
730
+ // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
731
+
732
+ // find it - 4 cases:
733
+ // 1. the target is not a pattern
734
+ // 2. the target has the prefix
735
+ // 3. the target has the suffix
736
+ // 4. the target is something inside cmdline
737
+
738
+ if(unlikely(( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
739
+ || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
740
+ || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
741
+ || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
742
+ ))) {
743
+
744
+ if(w->target) p->target = w->target;
745
+ else p->target = w;
746
+
747
+ if(debug || (p->target && p->target->debug))
748
+ fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
749
+
750
+ break;
751
+ }
752
+ }
753
+}
754
+
755
756
// ----------------------------------------------------------------------------
757
// update pids from proc
@@ -758,11 +833,8 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
833
p->stat_collected_usec = now_monotonic_usec();
834
file_counter++;
835
761
- // p->pid = str2pid_t(procfile_lineword(ff, 0, 0+i));
762
-
763
- if(unlikely(!p->comm[0]))
764
- strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
765
-
836
+ // p->pid = str2pid_t(procfile_lineword(ff, 0, 0));
837
+ char *comm = procfile_lineword(ff, 0, 1);
838
// p->state = *(procfile_lineword(ff, 0, 2));
839
p->ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
840
// p->pgrp = (int32_t)str2pid_t(procfile_lineword(ff, 0, 4));
@@ -771,9 +843,24 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
843
// p->tpgid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 7));
844
// p->flags = str2uint64_t(procfile_lineword(ff, 0, 8));
845
774
- kernel_uint_t last;
846
+ if(strcmp(p->comm, comm)) {
847
+ if(unlikely(debug)) {
848
+ if(p->comm[0])
849
+ fprintf(stderr, "apps.plugin: \tpid %d (%s) changed name to '%s'\n", p->pid, p->comm, comm);
850
+ else
851
+ fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", p->pid, p->comm);
852
+ }
853
+
854
+ strncpyz(p->comm, comm, MAX_COMPARE_NAME);
855
+
856
+ // /proc/<pid>/cmdline
857
+ if(likely(proc_pid_cmdline_is_needed))
858
+ managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
859
+
860
+ assign_target_to_pid(p);
861
+ }
862
776
- last = p->minflt_raw;
863
+ kernel_uint_t last = p->minflt_raw;
864
p->minflt_raw = str2kernel_uint_t(procfile_lineword(ff, 0, 9));
865
p->minflt = (p->minflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
866
@@ -1262,20 +1349,25 @@ static inline int file_descriptor_find_or_add(const char *name)
1349
// not found
1350
1351
FD_FILETYPE type;
1265
- if(name[0] == '/') type = FILETYPE_FILE;
1266
- else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
1267
- else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
1268
- else if(strcmp(name, "anon_inode:inotify") == 0 || strcmp(name, "inotify") == 0) type = FILETYPE_INOTIFY;
1269
- else if(strcmp(name, "anon_inode:[eventfd]") == 0) type = FILETYPE_EVENTFD;
1270
- else if(strcmp(name, "anon_inode:[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
1271
- else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
1272
- else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
1273
- else if(strncmp(name, "anon_inode:", 11) == 0) {
1274
- if(unlikely(debug))
1275
- fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
1352
+ if(likely(name[0] == '/')) type = FILETYPE_FILE;
1353
+ else if(likely(strncmp(name, "pipe:", 5) == 0)) type = FILETYPE_PIPE;
1354
+ else if(likely(strncmp(name, "socket:", 7) == 0)) type = FILETYPE_SOCKET;
1355
+ else if(likely(strncmp(name, "anon_inode:", 11) == 0)) {
1356
+ const char *t = &name[11];
1357
+
1358
+ if(strcmp(t, "inotify") == 0) type = FILETYPE_INOTIFY;
1359
+ else if(strcmp(t, "[eventfd]") == 0) type = FILETYPE_EVENTFD;
1360
+ else if(strcmp(t, "[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
1361
+ else if(strcmp(t, "[timerfd]") == 0) type = FILETYPE_TIMERFD;
1362
+ else if(strcmp(t, "[signalfd]") == 0) type = FILETYPE_SIGNALFD;
1363
+ else {
1364
+ if(unlikely(debug))
1365
+ fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
1366
1277
- type = FILETYPE_OTHER;
1367
+ type = FILETYPE_OTHER;
1368
+ }
1369
}
1370
+ else if(likely(strcmp(name, "inotify") == 0)) type = FILETYPE_INOTIFY;
1371
else {
1372
if(unlikely(debug))
1373
fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
@@ -1696,80 +1788,6 @@ static int compar_pid(const void *pid1, const void *pid2) {
1788
return 1;
1789
}
1790
1699
-static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
1700
- if(unlikely(!status)) {
1701
- // error("command failed log %u, errno %d", log, errno);
1702
-
1703
- if(unlikely(debug || errno != ENOENT)) {
1704
- if(unlikely(debug || !(p->log_thrown & log))) {
1705
- p->log_thrown |= log;
1706
- switch(log) {
1707
- case PID_LOG_IO:
1708
- error("Cannot process %s/proc/%d/io (command '%s')", global_host_prefix, p->pid, p->comm);
1709
- break;
1710
-
1711
- case PID_LOG_STATM:
1712
- error("Cannot process %s/proc/%d/statm (command '%s')", global_host_prefix, p->pid, p->comm);
1713
- break;
1714
-
1715
- case PID_LOG_CMDLINE:
1716
- error("Cannot process %s/proc/%d/cmdline (command '%s')", global_host_prefix, p->pid, p->comm);
1717
- break;
1718
-
1719
- case PID_LOG_FDS:
1720
- error("Cannot process entries in %s/proc/%d/fd (command '%s')", global_host_prefix, p->pid, p->comm);
1721
- break;
1722
-
1723
- case PID_LOG_STAT:
1724
- break;
1725
-
1726
- default:
1727
- error("unhandled error for pid %d, command '%s'", p->pid, p->comm);
1728
- break;
1729
- }
1730
- }
1731
- }
1732
- errno = 0;
1733
- }
1734
- else if(unlikely(p->log_thrown & log)) {
1735
- // error("unsetting log %u on pid %d", log, p->pid);
1736
- p->log_thrown &= ~log;
1737
- }
1738
-
1739
- return status;
1740
-}
1741
-
1742
-static inline void assign_target_to_pid(struct pid_stat *p) {
1743
- uint32_t hash = simple_hash(p->comm);
1744
- size_t pclen = strlen(p->comm);
1745
-
1746
- struct target *w;
1747
- for(w = apps_groups_root_target; w ; w = w->next) {
1748
- // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1749
-
1750
- // find it - 4 cases:
1751
- // 1. the target is not a pattern
1752
- // 2. the target has the prefix
1753
- // 3. the target has the suffix
1754
- // 4. the target is something inside cmdline
1755
-
1756
- if(unlikely(( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
1757
- || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
1758
- || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
1759
- || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
1760
- ))) {
1761
-
1762
- if(w->target) p->target = w->target;
1763
- else p->target = w;
1764
-
1765
- if(debug || (p->target && p->target->debug))
1766
- fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1767
-
1768
- break;
1769
- }
1770
- }
1771
-}
1772
-
1791
static inline int collect_data_for_pid(pid_t pid) {
1792
if(unlikely(pid <= 0 || pid > pid_max)) {
1793
error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
@@ -1809,22 +1827,6 @@ static inline int collect_data_for_pid(pid_t pid) {
1827
// there is no reason to proceed if we cannot get its memory status
1828
return 0;
1829
1812
- // --------------------------------------------------------------------
1813
- // link it
1814
-
1815
- // check if it is target
1816
- // we do this only once, the first time this pid is loaded
1817
- if(unlikely(p->new_entry)) {
1818
- // /proc/<pid>/cmdline
1819
- if(likely(proc_pid_cmdline_is_needed))
1820
- managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
1821
-
1822
- if(unlikely(debug))
1823
- fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
1824
-
1825
- assign_target_to_pid(p);
1826
- }
1827
-
1830
// --------------------------------------------------------------------
1831
// /proc/<pid>/fd
1832
@@ -1853,7 +1855,6 @@ static int collect_data_for_all_processes(void) {
1855
for(p = root_of_pids; p ; p = p->next) {
1856
p->read = 0; // mark it as not read, so that collect_data_for_pid() will read it
1857
p->updated = 0;
1856
- p->new_entry = 0;
1858
p->merged = 0;
1859
p->children_count = 0;
1860
p->parent = NULL;
src/common.c
-11
@@ -1060,17 +1060,6 @@ char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
1060
return s;
1061
}
1062
1063
-char *strncpyz(char *dst, const char *src, size_t n) {
1064
- char *p = dst;
1065
-
1066
- while (*src && n--)
1067
- *dst++ = *src++;
1068
-
1069
- *dst = '\0';
1070
-
1071
- return p;
1072
-}
1073
-
1063
int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
1064
int size = vsnprintf(dst, n, fmt, args);
1065
src/common.h
-1
@@ -221,7 +221,6 @@ extern void strreverse(char* begin, char* end);
221
extern char *mystrsep(char **ptr, char *s);
222
extern char *trim(char *s);
223
224
-extern char *strncpyz(char *dst, const char *src, size_t n);
224
extern int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args);
225
extern int snprintfz(char *dst, size_t n, const char *fmt, ...) PRINTFLIKE(3, 4);
226
src/inlined.h
+13
-1
@@ -128,12 +128,24 @@ static inline unsigned long long str2ull(const char *s) {
128
#undef strcmp
129
#endif
130
#define strcmp(a, b) strsame(a, b)
131
+#endif // NETDATA_STRCMP_OVERRIDE
132
+
133
static inline int strsame(const char *a, const char *b) {
134
if(unlikely(a == b)) return 0;
135
while(*a && *a == *b) { a++; b++; }
136
return *a - *b;
137
}
136
-#endif // NETDATA_STRSAME
138
+
139
+static inline char *strncpyz(char *dst, const char *src, size_t n) {
140
+ char *p = dst;
141
+
142
+ while (*src && n--)
143
+ *dst++ = *src++;
144
+
145
+ *dst = '\0';
146
+
147
+ return p;
148
+}
149
150
static inline int read_single_number_file(const char *filename, unsigned long long *result) {
151
char buffer[30 + 1];