master
c 357 lines 10.5 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "apps_plugin.h"
4
5 // ----------------------------------------------------------------------------
6 // update statistics on the targets
7
8 static size_t zero_all_targets(struct target *root) {
9 struct target *w;
10 size_t count = 0;
11
12 for (w = root; w ; w = w->next) {
13 count++;
14
15 for(size_t f = 0; f < PDF_MAX ;f++)
16 w->values[f] = 0;
17
18 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
19 w->needs_smaps_update = false;
20 #endif
21
22 w->uptime_min = 0;
23 w->uptime_max = 0;
24
25 #if (PROCESSES_HAVE_FDS == 1)
26 // zero file counters
27 if(w->target_fds) {
28 memset(w->target_fds, 0, sizeof(int) * w->target_fds_size);
29 w->openfds.files = 0;
30 w->openfds.pipes = 0;
31 w->openfds.sockets = 0;
32 w->openfds.inotifies = 0;
33 w->openfds.eventfds = 0;
34 w->openfds.timerfds = 0;
35 w->openfds.signalfds = 0;
36 w->openfds.eventpolls = 0;
37 w->openfds.other = 0;
38
39 w->max_open_files_percent = 0.0;
40 }
41 #endif
42
43 if(unlikely(w->root_pid)) {
44 struct pid_on_target *pid_on_target = w->root_pid;
45
46 while(pid_on_target) {
47 struct pid_on_target *pid_on_target_to_free = pid_on_target;
48 pid_on_target = pid_on_target->next;
49 freez(pid_on_target_to_free);
50 }
51
52 w->root_pid = NULL;
53 }
54 }
55
56 return count;
57 }
58
59 static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o __maybe_unused) {
60 if(unlikely(!p->updated)) {
61 // the process is not running
62 return;
63 }
64
65 if(unlikely(!w)) {
66 netdata_log_error("pid %d %s was left without a target!", p->pid, pid_stat_comm(p));
67 return;
68 }
69
70 #if (PROCESSES_HAVE_FDS == 1) && (PROCESSES_HAVE_PID_LIMITS == 1)
71 if(p->openfds_limits_percent > w->max_open_files_percent)
72 w->max_open_files_percent = p->openfds_limits_percent;
73 #endif
74
75 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
76 kernel_uint_t shared = p->values[PDF_VMSHARED];
77 if(shared > 0) {
78 if(o && o != w)
79 o->needs_smaps_update = true;
80 if(!o || o != w)
81 w->needs_smaps_update = true;
82 }
83 #endif
84
85 for(size_t f = 0; f < PDF_MAX ;f++)
86 w->values[f] += p->values[f];
87
88 if(!w->uptime_min || p->values[PDF_UPTIME] < w->uptime_min) w->uptime_min = p->values[PDF_UPTIME];
89 if(!w->uptime_max || w->uptime_max < p->values[PDF_UPTIME]) w->uptime_max = p->values[PDF_UPTIME];
90
91 if(unlikely(debug_enabled)) {
92 struct pid_on_target *pid_on_target = mallocz(sizeof(struct pid_on_target));
93 pid_on_target->pid = p->pid;
94 pid_on_target->next = w->root_pid;
95 w->root_pid = pid_on_target;
96 }
97 }
98
99 static inline void cleanup_exited_pids(void) {
100 struct pid_stat *p = NULL;
101
102 for(p = root_of_pids(); p ;) {
103 if(!p->updated && (!p->keep || p->keeploops > 0)) {
104 if(unlikely(debug_enabled && (p->keep || p->keeploops)))
105 debug_log(" > CLEANUP cannot keep exited process %d (%s) anymore - removing it.", p->pid, pid_stat_comm(p));
106
107 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
108 if(p->values[PDF_VMSHARED] > 0) {
109 if(p->target)
110 p->target->needs_smaps_update = true;
111 }
112 #endif
113
114 #if (PROCESSES_HAVE_FDS == 1)
115 for(size_t c = 0; c < p->fds_size; c++)
116 if(p->fds[c].fd > 0) {
117 file_descriptor_not_used(p->fds[c].fd);
118 clear_pid_fd(&p->fds[c]);
119 }
120 #endif
121
122 const pid_t r = p->pid;
123 p = p->next;
124 del_pid_entry(r);
125 }
126 else {
127 if(unlikely(p->keep)) p->keeploops++;
128 p->keep = false;
129 p = p->next;
130 }
131 }
132 }
133
134 static struct target *get_apps_groups_target_for_pid(struct pid_stat *p) {
135 targets_assignment_counter++;
136
137 for(struct target *w = apps_groups_root_target; w ; w = w->next) {
138 if(w->type != TARGET_TYPE_APP_GROUP) continue;
139
140 if(pid_match_check(p, &w->match)) {
141 if(p->is_manager)
142 return NULL;
143
144 p->matched_by_config = true;
145 return w->target ? w->target : w;
146 }
147 }
148
149 return NULL;
150 }
151
152 static void assign_a_target_to_all_processes(void) {
153 // assign targets from app_groups.conf
154 for(struct pid_stat *p = root_of_pids(); p ; p = p->next) {
155 if(!p->target)
156 p->target = get_apps_groups_target_for_pid(p);
157 }
158
159 // assign targets from their parents, if they have
160 for(struct pid_stat *p = root_of_pids(); p ; p = p->next) {
161 if(!p->target) {
162 if(!p->is_manager) {
163 for (struct pid_stat *pp = p->parent; pp; pp = pp->parent) {
164 if(pp->is_manager) break;
165
166 if (pp->target) {
167 p->target = pp->target;
168 break;
169 }
170 }
171 }
172
173 if(!p->target) {
174 // there is no target, get it from the tree
175 p->target = get_tree_target(p);
176 }
177 }
178
179 fatal_assert(p->target != NULL);
180 }
181 }
182
183 #if (PROCESSES_HAVE_SERVICE == 1)
184 static STRING *other_service_name = NULL;
185
186 static void assign_service_to_all_processes(void) {
187 if(!other_service_name)
188 other_service_name = string_strdupz("not-services");
189
190 // Clear walk-up assigned service_names from previous iteration.
191 // Direct matches (got_service) are kept — they persist per process lifetime.
192 for(struct pid_stat *p = root_of_pids(); p ; p = p->next) {
193 if(!p->got_service && p->service_name) {
194 string_freez(p->service_name);
195 p->service_name = NULL;
196 }
197 }
198
199 // Phase 1: direct match — GetServiceNames() already tagged service root PIDs
200 // with p->service_name during data collection.
201
202 // Phase 2: untagged processes walk up to find a service-tagged ancestor
203 for(struct pid_stat *p = root_of_pids(); p ; p = p->next) {
204 if(!p->service_name) {
205 if(!p->is_manager) {
206 for(struct pid_stat *pp = p->parent; pp ; pp = pp->parent) {
207 if(pp->is_manager) break;
208
209 if(pp->service_name) {
210 p->service_name = string_dup(pp->service_name);
211 break;
212 }
213 }
214 }
215
216 // Phase 3: fallback — no service ancestor found
217 if(!p->service_name)
218 p->service_name = string_dup(other_service_name);
219 }
220 }
221 }
222 #endif
223
224 void aggregate_processes_to_targets(void) {
225 assign_a_target_to_all_processes();
226
227 #if (PROCESSES_HAVE_SERVICE == 1)
228 if(enable_services_charts)
229 assign_service_to_all_processes();
230 #endif
231 apps_groups_targets_count = zero_all_targets(apps_groups_root_target);
232
233 #if (PROCESSES_HAVE_UID == 1)
234 zero_all_targets(users_root_target);
235 #endif
236 #if (PROCESSES_HAVE_GID == 1)
237 zero_all_targets(groups_root_target);
238 #endif
239 #if (PROCESSES_HAVE_SID == 1)
240 zero_all_targets(sids_root_target);
241 #endif
242 #if (PROCESSES_HAVE_SERVICE == 1)
243 if(enable_services_charts)
244 zero_all_targets(services_root_target);
245 #endif
246
247 // this has to be done, before the cleanup
248 struct target *w = NULL, *o = NULL;
249 (void)w; (void)o;
250
251 #if (PROCESSES_HAVE_UID == 1)
252 update_cached_host_users();
253 #endif
254 #if (PROCESSES_HAVE_GID == 1)
255 update_cached_host_groups();
256 #endif
257
258 // concentrate everything on the targets
259 for(struct pid_stat *p = root_of_pids(); p ; p = p->next) {
260
261 // --------------------------------------------------------------------
262 // apps_groups and tree target
263
264 aggregate_pid_on_target(p->target, p,
265 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
266 p->prev_target
267 #else
268 NULL
269 #endif
270 );
271
272
273 // --------------------------------------------------------------------
274 // user target
275
276 #if (PROCESSES_HAVE_UID == 1)
277 o = p->uid_target;
278 if(likely(p->uid_target && p->uid_target->uid == p->uid))
279 w = p->uid_target;
280 else {
281 if(unlikely(debug_enabled && p->uid_target))
282 debug_log("pid %d (%s) switched user from %u (%s) to %u.", p->pid, pid_stat_comm(p), p->uid_target->uid, p->uid_target->name, p->uid);
283
284 w = p->uid_target = get_uid_target(p->uid);
285 }
286
287 aggregate_pid_on_target(w, p, o);
288 #endif
289
290 // --------------------------------------------------------------------
291 // user group target
292
293 #if (PROCESSES_HAVE_GID == 1)
294
295 o = p->gid_target;
296 if(likely(p->gid_target && p->gid_target->gid == p->gid))
297 w = p->gid_target;
298 else {
299 if(unlikely(debug_enabled && p->gid_target))
300 debug_log("pid %d (%s) switched group from %u (%s) to %u.", p->pid, pid_stat_comm(p), p->gid_target->gid, p->gid_target->name, p->gid);
301
302 w = p->gid_target = get_gid_target(p->gid);
303 }
304
305 aggregate_pid_on_target(w, p, o);
306 #endif
307
308 // --------------------------------------------------------------------
309 // sid target
310
311 #if (PROCESSES_HAVE_SID == 1)
312 o = p->sid_target;
313 if(likely(p->sid_target && p->sid_target->sid_name == p->sid_name))
314 w = p->sid_target;
315 else
316 w = p->sid_target = get_sid_target(p->sid_name);
317
318 aggregate_pid_on_target(w, p, o);
319 #endif
320
321 // --------------------------------------------------------------------
322 // service target
323
324 #if (PROCESSES_HAVE_SERVICE == 1)
325 if(enable_services_charts) {
326 o = p->service_target;
327 if(likely(p->service_target && p->service_target->service_name == p->service_name))
328 w = p->service_target;
329 else
330 w = p->service_target = get_service_target(p->service_name);
331
332 aggregate_pid_on_target(w, p, o);
333 }
334 #endif
335
336 // --------------------------------------------------------------------
337 // aggregate all file descriptors
338
339 #if (PROCESSES_HAVE_FDS == 1)
340 if(enable_file_charts)
341 aggregate_pid_fds_on_targets(p);
342 #endif
343
344 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
345 p->prev_target = p->target;
346 #endif
347 }
348
349 cleanup_exited_pids();
350
351 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
352 for(struct pid_stat *p = root_of_pids(); p ; p = p->next) {
353 if(p->target && p->target->needs_smaps_update && p->values[PDF_VMSHARED] > 0)
354 p->vmshared_delta = p->values[PDF_VMSHARED];
355 }
356 #endif
357 }