master
c 1,057 lines 38.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "apps_plugin.h"
4 #include <limits.h>
5 #include <unistd.h>
6
7 #if defined(OS_LINUX)
8
9 #define MAX_PROC_PID_LIMITS 8192
10 #define PROC_PID_LIMITS_MAX_OPEN_FILES_KEY "\nMax open files "
11
12 int max_fds_cache_seconds = 60;
13 kernel_uint_t system_uptime_secs;
14
15 void apps_os_init_linux(void) {
16 ;
17 }
18
19 // --------------------------------------------------------------------------------------------------------------------
20 // /proc/pid/fd
21
22 struct arl_callback_ptr {
23 struct pid_stat *p;
24 procfile *ff;
25 size_t line;
26 };
27
28 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
29
30 struct arl_callback_smaps_ptr {
31 struct pid_stat *p;
32 procfile *ff;
33 size_t line;
34 };
35
36 static procfile *smaps_rollup_ff = NULL;
37 static struct arl_callback_smaps_ptr smaps_rollup_ctx;
38 static bool smaps_rollup_checked = false;
39 static bool smaps_rollup_available = false;
40 static bool smaps_rollup_warned = false;
41
42 struct smaps_candidate {
43 struct pid_stat *p;
44 kernel_uint_t delta; // for delta-based refresh strategy
45 size_t age; // for age-based refresh strategy
46 kernel_uint_t vmshared; // for age-based refresh strategy (tiebreaker)
47 };
48
49 static int compare_smaps_delta_desc(const void *a, const void *b) {
50 const struct smaps_candidate *A = (const struct smaps_candidate *)a;
51 const struct smaps_candidate *B = (const struct smaps_candidate *)b;
52 if(A->delta < B->delta) return 1;
53 if(A->delta > B->delta) return -1;
54 return 0;
55 }
56
57 static int compare_smaps_age_desc(const void *a, const void *b) {
58 const struct smaps_candidate *A = (const struct smaps_candidate *)a;
59 const struct smaps_candidate *B = (const struct smaps_candidate *)b;
60 if(A->age < B->age) return 1;
61 if(A->age > B->age) return -1;
62 if(A->vmshared < B->vmshared) return 1;
63 if(A->vmshared > B->vmshared) return -1;
64 return 0;
65 }
66
67 static inline void pid_update_estimated_memory(struct pid_stat *p) {
68 kernel_uint_t vmrss = p->values[PDF_VMRSS];
69 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
70 p->values[PDF_PSS] = p->pss_bytes;
71 #endif
72 if(vmrss == 0) {
73 p->values[PDF_MEM_ESTIMATED] = 0;
74 return;
75 }
76
77 NETDATA_DOUBLE ratio = p->pss_total_ratio;
78 if(unlikely(ratio < 0.0)) ratio = 0.0;
79 if(unlikely(ratio > 1.0)) ratio = 1.0;
80
81 NETDATA_DOUBLE scaled = (NETDATA_DOUBLE)vmrss * ratio;
82 if(unlikely(scaled > (NETDATA_DOUBLE)UINT64_MAX))
83 p->values[PDF_MEM_ESTIMATED] = vmrss;
84 else
85 p->values[PDF_MEM_ESTIMATED] = (kernel_uint_t)(scaled + 0.5);
86 }
87
88 static inline kernel_uint_t smaps_value_to_bytes(const char *value) {
89 return str2kernel_uint_t(value) * 1024ULL;
90 }
91
92 static void arl_callback_smaps_pss(const char *name __maybe_unused, uint32_t hash __maybe_unused, const char *value __maybe_unused, void *dst) {
93 struct arl_callback_smaps_ptr *ctx = (struct arl_callback_smaps_ptr *)dst;
94 if(unlikely(procfile_linewords(ctx->ff, ctx->line) < 2))
95 return;
96
97 ctx->p->values[PDF_PSS] = smaps_value_to_bytes(procfile_lineword(ctx->ff, ctx->line, 1));
98 }
99
100 bool apps_os_have_smaps_rollup_linux(void) {
101 if(likely(smaps_rollup_checked))
102 return smaps_rollup_available;
103
104 char filename[FILENAME_MAX + 1];
105 snprintfz(filename, FILENAME_MAX, "%s/proc/self/smaps_rollup", netdata_configured_host_prefix);
106
107 if(access(filename, R_OK) == 0) {
108 smaps_rollup_available = true;
109 }
110 else {
111 if(!smaps_rollup_warned) {
112 netdata_log_info("apps.plugin: /proc/*/smaps_rollup is not available on this kernel. PSS metrics will be disabled.");
113 smaps_rollup_warned = true;
114 }
115 smaps_rollup_available = false;
116 }
117
118 smaps_rollup_checked = true;
119 return smaps_rollup_available;
120 }
121
122 bool apps_os_read_pid_smaps_rollup_linux(struct pid_stat *p, void *ptr __maybe_unused) {
123 if(unlikely(!apps_os_have_smaps_rollup_linux()))
124 return false;
125
126 if(unlikely(!p->smaps_rollup_arl)) {
127 p->smaps_rollup_arl = arl_create("/proc/pid/smaps_rollup", NULL, 60);
128 arl_expect_custom(p->smaps_rollup_arl, "Pss", arl_callback_smaps_pss, &smaps_rollup_ctx);
129 }
130
131 if(unlikely(!p->smaps_rollup_filename)) {
132 char filename[FILENAME_MAX + 1];
133 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/smaps_rollup", netdata_configured_host_prefix, p->pid);
134 p->smaps_rollup_filename = strdupz(filename);
135 }
136
137 smaps_rollup_ff = procfile_reopen(smaps_rollup_ff, p->smaps_rollup_filename, (!smaps_rollup_ff) ? " \t:" : NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
138 if(unlikely(!smaps_rollup_ff)) {
139 if(errno == EINVAL)
140 errno = ENOENT;
141 return false;
142 }
143
144 smaps_rollup_ff = procfile_readall(smaps_rollup_ff);
145 if(unlikely(!smaps_rollup_ff)) {
146 if(errno == EINVAL)
147 errno = ENOENT;
148 return false;
149 }
150
151 calls_counter++;
152
153 smaps_rollup_ctx.p = p;
154 smaps_rollup_ctx.ff = smaps_rollup_ff;
155
156 size_t lines = procfile_lines(smaps_rollup_ff);
157 arl_begin(p->smaps_rollup_arl);
158
159 for(size_t l = 0; l < lines; l++) {
160 smaps_rollup_ctx.line = l;
161 if(unlikely(arl_check(p->smaps_rollup_arl,
162 procfile_lineword(smaps_rollup_ff, l, 0),
163 procfile_lineword(smaps_rollup_ff, l, 1))))
164 break;
165 }
166
167 kernel_uint_t vmrss = p->values[PDF_VMRSS];
168 kernel_uint_t pss = p->values[PDF_PSS];
169 NETDATA_DOUBLE ratio = 1.0;
170 if(vmrss > 0)
171 ratio = (NETDATA_DOUBLE)pss / (NETDATA_DOUBLE)vmrss;
172
173 if(ratio < 0.0) ratio = 0.0;
174 if(ratio > 1.0) ratio = 1.0;
175
176 p->pss_total_ratio = ratio;
177 p->pss_bytes = pss;
178 pid_update_estimated_memory(p);
179 p->vmshared_delta = 0;
180 p->last_pss_iteration = global_iterations_counter;
181
182 return true;
183 }
184
185 #define PSS_REFRESH_MIN 1
186
187 static void apps_handle_smaps_updates(void) {
188 if(pss_refresh_period <= 0)
189 return;
190
191 if(unlikely(!apps_os_have_smaps_rollup()))
192 return;
193
194 struct pid_stat *p;
195
196 // On first iteration, scan all processes to get accurate initial estimates
197 if(unlikely(global_iterations_counter == 1)) {
198 for(p = root_of_pids(); p ; p = p->next) {
199 if(p->values[PDF_VMSHARED] > 0)
200 OS_FUNCTION(apps_os_read_pid_smaps_rollup)(p, NULL);
201 }
202 return;
203 }
204
205 // Alternate between delta-based and age-based refresh strategies
206 static bool refresh_by_delta = true;
207
208 size_t total_pids = 0;
209
210 for(p = root_of_pids(); p ; p = p->next)
211 total_pids++;
212
213 if(unlikely(total_pids == 0))
214 return;
215
216 int divisor = pss_refresh_period / update_every;
217 if(divisor < 1)
218 divisor = 1;
219
220 size_t budget = total_pids / (size_t)divisor;
221 if(budget < PSS_REFRESH_MIN)
222 budget = PSS_REFRESH_MIN;
223
224 struct smaps_candidate *candidates = mallocz(sizeof(*candidates) * total_pids);
225 size_t candidate_count = 0;
226
227 // Populate candidates based on current strategy
228 if(refresh_by_delta) {
229 // Delta-based: prioritize processes with largest memory changes
230 for(p = root_of_pids(); p ; p = p->next) {
231 kernel_uint_t vmshared = p->values[PDF_VMSHARED];
232
233 if(vmshared > 0 && p->vmshared_delta > 0) {
234 candidates[candidate_count].p = p;
235 candidates[candidate_count].delta = p->vmshared_delta;
236 candidate_count++;
237 }
238 }
239
240 // Sort by delta (descending)
241 if(candidate_count > 1)
242 qsort(candidates, candidate_count, sizeof(*candidates), compare_smaps_delta_desc);
243 }
244 else {
245 // Age-based: prioritize processes that haven't been updated longest
246 for(p = root_of_pids(); p ; p = p->next) {
247 kernel_uint_t vmshared = p->values[PDF_VMSHARED];
248
249 if(vmshared == 0)
250 continue;
251
252 size_t age;
253 if(p->last_pss_iteration == 0)
254 age = SIZE_MAX;
255 else if(global_iterations_counter >= p->last_pss_iteration)
256 age = global_iterations_counter - p->last_pss_iteration;
257 else
258 age = SIZE_MAX;
259
260 candidates[candidate_count].p = p;
261 candidates[candidate_count].age = age;
262 candidates[candidate_count].vmshared = vmshared;
263 candidate_count++;
264 }
265
266 // Sort by age (descending), with vmshared as tiebreaker
267 if(candidate_count > 1)
268 qsort(candidates, candidate_count, sizeof(*candidates), compare_smaps_age_desc);
269 }
270
271 // Refresh top priority processes within budget
272 size_t to_refresh = candidate_count;
273 if(to_refresh > budget)
274 to_refresh = budget;
275
276 for(size_t i = 0; i < to_refresh; i++) {
277 struct pid_stat *pid_entry = candidates[i].p;
278 if(!pid_entry)
279 continue;
280 OS_FUNCTION(apps_os_read_pid_smaps_rollup)(pid_entry, NULL);
281 }
282
283 freez(candidates);
284
285 // Toggle strategy for next iteration
286 refresh_by_delta = !refresh_by_delta;
287 }
288
289 #endif // PROCESSES_HAVE_SMAPS_ROLLUP
290
291 bool apps_os_read_pid_fds_linux(struct pid_stat *p, void *ptr __maybe_unused) {
292 if(unlikely(!p->fds_dirname)) {
293 char dirname[FILENAME_MAX+1];
294 snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", netdata_configured_host_prefix, p->pid);
295 p->fds_dirname = strdupz(dirname);
296 }
297
298 DIR *fds = opendir(p->fds_dirname);
299 if(unlikely(!fds)) return false;
300
301 struct dirent *de;
302 char linkname[FILENAME_MAX + 1];
303
304 // we make all pid fds negative, so that
305 // we can detect unused file descriptors
306 // at the end, to free them
307 make_all_pid_fds_negative(p);
308
309 while((de = readdir(fds))) {
310 // we need only files with numeric names
311
312 if(unlikely(de->d_name[0] < '0' || de->d_name[0] > '9'))
313 continue;
314
315 // get its number
316 int fdid = (int) str2l(de->d_name);
317 if(unlikely(fdid < 0)) continue;
318
319 // check if the fds array is small
320 if(unlikely((size_t)fdid >= p->fds_size)) {
321 // it is small, extend it
322
323 uint32_t new_size = fds_new_size(p->fds_size, fdid);
324
325 debug_log("extending fd memory slots for %s from %u to %u",
326 pid_stat_comm(p), p->fds_size, new_size);
327
328 p->fds = reallocz(p->fds, new_size * sizeof(struct pid_fd));
329
330 // and initialize it
331 init_pid_fds(p, p->fds_size, new_size - p->fds_size);
332 p->fds_size = new_size;
333 }
334
335 if(unlikely(p->fds[fdid].fd < 0 && de->d_ino != p->fds[fdid].inode)) {
336 // inodes do not match, clear the previous entry
337 inodes_changed_counter++;
338 file_descriptor_not_used(-p->fds[fdid].fd);
339 clear_pid_fd(&p->fds[fdid]);
340 }
341
342 if(p->fds[fdid].fd < 0 && p->fds[fdid].cache_iterations_counter > 0) {
343 p->fds[fdid].fd = -p->fds[fdid].fd;
344 p->fds[fdid].cache_iterations_counter--;
345 continue;
346 }
347
348 if(unlikely(!p->fds[fdid].filename)) {
349 filenames_allocated_counter++;
350 char fdname[FILENAME_MAX + 1];
351 snprintfz(fdname, FILENAME_MAX, "%s/proc/%d/fd/%s", netdata_configured_host_prefix, p->pid, de->d_name);
352 p->fds[fdid].filename = strdupz(fdname);
353 }
354
355 file_counter++;
356 ssize_t l = readlink(p->fds[fdid].filename, linkname, FILENAME_MAX);
357 if(unlikely(l == -1)) {
358 // cannot read the link
359
360 if(debug_enabled)
361 netdata_log_error("Cannot read link %s", p->fds[fdid].filename);
362
363 if(unlikely(p->fds[fdid].fd < 0)) {
364 file_descriptor_not_used(-p->fds[fdid].fd);
365 clear_pid_fd(&p->fds[fdid]);
366 }
367
368 continue;
369 }
370 else
371 linkname[l] = '\0';
372
373 uint32_t link_hash = simple_hash(linkname);
374
375 if(unlikely(p->fds[fdid].fd < 0 && p->fds[fdid].link_hash != link_hash)) {
376 // the link changed
377 links_changed_counter++;
378 file_descriptor_not_used(-p->fds[fdid].fd);
379 clear_pid_fd(&p->fds[fdid]);
380 }
381
382 if(unlikely(p->fds[fdid].fd == 0)) {
383 // we don't know this fd, get it
384
385 // if another process already has this, we will get
386 // the same id
387 p->fds[fdid].fd = (int)file_descriptor_find_or_add(linkname, link_hash);
388 p->fds[fdid].inode = de->d_ino;
389 p->fds[fdid].link_hash = link_hash;
390 }
391 else {
392 // else make it positive again, we need it
393 p->fds[fdid].fd = -p->fds[fdid].fd;
394 }
395
396 // caching control
397 // without this we read all the files on every iteration
398 if(max_fds_cache_seconds > 0) {
399 size_t spread = ((size_t)max_fds_cache_seconds > 10) ? 10 : (size_t)max_fds_cache_seconds;
400
401 // cache it for a few iterations
402 size_t max = ((size_t) max_fds_cache_seconds + (fdid % spread)) / (size_t) update_every;
403 p->fds[fdid].cache_iterations_reset++;
404
405 if(unlikely(p->fds[fdid].cache_iterations_reset % spread == (size_t) fdid % spread))
406 p->fds[fdid].cache_iterations_reset++;
407
408 if(unlikely((fdid <= 2 && p->fds[fdid].cache_iterations_reset > 5) ||
409 p->fds[fdid].cache_iterations_reset > max)) {
410 // for stdin, stdout, stderr (fdid <= 2) we have checked a few times, or if it goes above the max, goto max
411 p->fds[fdid].cache_iterations_reset = max;
412 }
413
414 p->fds[fdid].cache_iterations_counter = p->fds[fdid].cache_iterations_reset;
415 }
416 }
417
418 closedir(fds);
419
420 return true;
421 }
422
423 // --------------------------------------------------------------------------------------------------------------------
424 // /proc/meminfo
425
426 uint64_t apps_os_get_total_memory_linux(void) {
427 uint64_t ret = 0;
428
429 char filename[FILENAME_MAX + 1];
430 snprintfz(filename, FILENAME_MAX, "%s/proc/meminfo", netdata_configured_host_prefix);
431
432 procfile *ff = procfile_open(filename, ": \t", PROCFILE_FLAG_DEFAULT);
433 if(!ff)
434 return ret;
435
436 ff = procfile_readall(ff);
437 if(!ff)
438 return ret;
439
440 size_t line, lines = procfile_lines(ff);
441
442 for(line = 0; line < lines ;line++) {
443 size_t words = procfile_linewords(ff, line);
444 if(words == 3 && strcmp(procfile_lineword(ff, line, 0), "MemTotal") == 0 && strcmp(procfile_lineword(ff, line, 2), "kB") == 0) {
445 ret = str2ull(procfile_lineword(ff, line, 1), NULL) * 1024;
446 break;
447 }
448 }
449
450 procfile_close(ff);
451
452 return ret;
453 }
454
455 // --------------------------------------------------------------------------------------------------------------------
456 // /proc/pid/cmdline
457
458 bool apps_os_get_pid_cmdline_linux(struct pid_stat *p, char *cmdline, size_t bytes) {
459 if(unlikely(!p->cmdline_filename)) {
460 char filename[FILENAME_MAX];
461 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
462 p->cmdline_filename = strdupz(filename);
463 }
464
465 int fd = open(p->cmdline_filename, procfile_open_flags, 0666);
466 if(unlikely(fd == -1))
467 return false;
468
469 ssize_t i, b = read(fd, cmdline, bytes - 1);
470 close(fd);
471
472 if(unlikely(b < 0))
473 return false;
474
475 cmdline[b] = '\0';
476 for(i = 0; i < b ; i++)
477 if(unlikely(!cmdline[i])) cmdline[i] = ' ';
478
479 // remove trailing spaces
480 while(b > 0 && cmdline[b - 1] == ' ')
481 cmdline[--b] = '\0';
482
483 return true;
484 }
485
486 // --------------------------------------------------------------------------------------------------------------------
487 // /proc/pid/io
488
489 bool apps_os_read_pid_io_linux(struct pid_stat *p, void *ptr __maybe_unused) {
490 static procfile *ff = NULL;
491
492 if(unlikely(!p->io_filename)) {
493 char filename[FILENAME_MAX + 1];
494 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", netdata_configured_host_prefix, p->pid);
495 p->io_filename = strdupz(filename);
496 }
497
498 // open the file
499 ff = procfile_reopen(ff, p->io_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
500 if(unlikely(!ff)) goto cleanup;
501
502 ff = procfile_readall(ff);
503 if(unlikely(!ff)) goto cleanup;
504
505 pid_incremental_rate(io, PDF_LREAD, str2kernel_uint_t(procfile_lineword(ff, 0, 1)));
506 pid_incremental_rate(io, PDF_LWRITE, str2kernel_uint_t(procfile_lineword(ff, 1, 1)));
507 pid_incremental_rate(io, PDF_OREAD, str2kernel_uint_t(procfile_lineword(ff, 2, 1)));
508 pid_incremental_rate(io, PDF_OWRITE, str2kernel_uint_t(procfile_lineword(ff, 3, 1)));
509 pid_incremental_rate(io, PDF_PREAD, str2kernel_uint_t(procfile_lineword(ff, 4, 1)));
510 pid_incremental_rate(io, PDF_PWRITE, str2kernel_uint_t(procfile_lineword(ff, 5, 1)));
511
512 return true;
513
514 cleanup:
515 return false;
516 }
517
518 // --------------------------------------------------------------------------------------------------------------------
519 // /proc/pid/limits
520
521 static inline kernel_uint_t get_proc_pid_limits_limit(char *buf, const char *key, size_t key_len, kernel_uint_t def) {
522 char *line = strstr(buf, key);
523 if(!line)
524 return def;
525
526 char *v = &line[key_len];
527 while(isspace((uint8_t)*v)) v++;
528
529 if(strcmp(v, "unlimited") == 0)
530 return 0;
531
532 return str2ull(v, NULL);
533 }
534
535 bool apps_os_read_pid_limits_linux(struct pid_stat *p, void *ptr __maybe_unused) {
536 static char proc_pid_limits_buffer[MAX_PROC_PID_LIMITS + 1];
537 bool ret = false;
538 bool read_limits = false;
539
540 errno_clear();
541 proc_pid_limits_buffer[0] = '\0';
542
543 kernel_uint_t all_fds = pid_openfds_sum(p);
544 if(all_fds < p->limits.max_open_files / 2 && p->io_collected_usec > p->last_limits_collected_usec && p->io_collected_usec - p->last_limits_collected_usec <= 60 * USEC_PER_SEC) {
545 // too frequent, we want to collect limits once per minute
546 ret = true;
547 goto cleanup;
548 }
549
550 if(unlikely(!p->limits_filename)) {
551 char filename[FILENAME_MAX + 1];
552 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/limits", netdata_configured_host_prefix, p->pid);
553 p->limits_filename = strdupz(filename);
554 }
555
556 int fd = open(p->limits_filename, procfile_open_flags, 0666);
557 if(unlikely(fd == -1)) goto cleanup;
558
559 ssize_t bytes = read(fd, proc_pid_limits_buffer, MAX_PROC_PID_LIMITS);
560 close(fd);
561
562 if(bytes <= 0)
563 goto cleanup;
564
565 // make it '\0' terminated
566 if(bytes < MAX_PROC_PID_LIMITS)
567 proc_pid_limits_buffer[bytes] = '\0';
568 else
569 proc_pid_limits_buffer[MAX_PROC_PID_LIMITS - 1] = '\0';
570
571 p->limits.max_open_files = get_proc_pid_limits_limit(proc_pid_limits_buffer, PROC_PID_LIMITS_MAX_OPEN_FILES_KEY, sizeof(PROC_PID_LIMITS_MAX_OPEN_FILES_KEY) - 1, 0);
572 if(p->limits.max_open_files == 1) {
573 // it seems a bug in the kernel or something similar
574 // it sets max open files to 1 but the number of files
575 // the process has open are more than 1...
576 // https://github.com/netdata/netdata/issues/15443
577 p->limits.max_open_files = 0;
578 ret = true;
579 goto cleanup;
580 }
581
582 p->last_limits_collected_usec = p->io_collected_usec;
583 read_limits = true;
584
585 ret = true;
586
587 cleanup:
588 if(p->limits.max_open_files)
589 p->openfds_limits_percent = (NETDATA_DOUBLE)all_fds * 100.0 / (NETDATA_DOUBLE)p->limits.max_open_files;
590 else
591 p->openfds_limits_percent = 0.0;
592
593 if(p->openfds_limits_percent > 100.0) {
594 if(!(p->log_thrown & PID_LOG_LIMITS_DETAIL)) {
595 char *line;
596
597 if(!read_limits) {
598 proc_pid_limits_buffer[0] = '\0';
599 line = "NOT READ";
600 }
601 else {
602 line = strstr(proc_pid_limits_buffer, PROC_PID_LIMITS_MAX_OPEN_FILES_KEY);
603 if (line) {
604 line++; // skip the initial newline
605
606 char *end = strchr(line, '\n');
607 if (end)
608 *end = '\0';
609 }
610 }
611
612 netdata_log_info(
613 "FDS_LIMITS: PID %d (%s) is using "
614 "%0.2f %% of its fds limits, "
615 "open fds = %"PRIu64 "("
616 "files = %"PRIu64 ", "
617 "pipes = %"PRIu64 ", "
618 "sockets = %"PRIu64", "
619 "inotifies = %"PRIu64", "
620 "eventfds = %"PRIu64", "
621 "timerfds = %"PRIu64", "
622 "signalfds = %"PRIu64", "
623 "eventpolls = %"PRIu64" "
624 "other = %"PRIu64" "
625 "), open fds limit = %"PRIu64", "
626 "%s, "
627 "original line [%s]",
628 p->pid, pid_stat_comm(p), p->openfds_limits_percent, all_fds,
629 p->openfds.files,
630 p->openfds.pipes,
631 p->openfds.sockets,
632 p->openfds.inotifies,
633 p->openfds.eventfds,
634 p->openfds.timerfds,
635 p->openfds.signalfds,
636 p->openfds.eventpolls,
637 p->openfds.other,
638 p->limits.max_open_files,
639 read_limits ? "and we have read the limits AFTER counting the fds"
640 : "but we have read the limits BEFORE counting the fds",
641 line);
642
643 p->log_thrown |= PID_LOG_LIMITS_DETAIL;
644 }
645 }
646 else
647 p->log_thrown &= ~PID_LOG_LIMITS_DETAIL;
648
649 return ret;
650 }
651
652 // --------------------------------------------------------------------------------------------------------------------
653 // /proc/pid/status
654
655 void arl_callback_status_uid(const char *name, uint32_t hash, const char *value, void *dst) {
656 (void)name; (void)hash; (void)value;
657 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
658 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 5)) return;
659
660 //const char *real_uid = procfile_lineword(aptr->ff, aptr->line, 1);
661 const char *effective_uid = procfile_lineword(aptr->ff, aptr->line, 2);
662 //const char *saved_uid = procfile_lineword(aptr->ff, aptr->line, 3);
663 //const char *filesystem_uid = procfile_lineword(aptr->ff, aptr->line, 4);
664
665 if(likely(effective_uid && *effective_uid))
666 aptr->p->uid = (uid_t)str2l(effective_uid);
667 }
668
669 void arl_callback_status_gid(const char *name, uint32_t hash, const char *value, void *dst) {
670 (void)name; (void)hash; (void)value;
671 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
672 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 5)) return;
673
674 //const char *real_gid = procfile_lineword(aptr->ff, aptr->line, 1);
675 const char *effective_gid = procfile_lineword(aptr->ff, aptr->line, 2);
676 //const char *saved_gid = procfile_lineword(aptr->ff, aptr->line, 3);
677 //const char *filesystem_gid = procfile_lineword(aptr->ff, aptr->line, 4);
678
679 if(likely(effective_gid && *effective_gid))
680 aptr->p->gid = (uid_t)str2l(effective_gid);
681 }
682
683 void arl_callback_status_vmsize(const char *name, uint32_t hash, const char *value, void *dst) {
684 (void)name; (void)hash; (void)value;
685 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
686 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return;
687
688 aptr->p->values[PDF_VMSIZE] = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)) * 1024;
689 }
690
691 void arl_callback_status_vmswap(const char *name, uint32_t hash, const char *value, void *dst) {
692 (void)name; (void)hash; (void)value;
693 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
694 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return;
695
696 aptr->p->values[PDF_VMSWAP] = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)) * 1024;
697 }
698
699 void arl_callback_status_vmrss(const char *name, uint32_t hash, const char *value, void *dst) {
700 (void)name; (void)hash; (void)value;
701 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
702 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return;
703
704 aptr->p->values[PDF_VMRSS] = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)) * 1024;
705 }
706
707 void arl_callback_status_rssfile(const char *name, uint32_t hash, const char *value, void *dst) {
708 (void)name; (void)hash; (void)value;
709 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
710 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return;
711
712 aptr->p->values[PDF_RSSFILE] = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)) * 1024;
713 }
714
715 void arl_callback_status_rssshmem(const char *name, uint32_t hash, const char *value, void *dst) {
716 (void)name; (void)hash; (void)value;
717 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
718 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return;
719
720 struct pid_stat *p = aptr->p;
721 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
722 kernel_uint_t old_shared = p->values[PDF_VMSHARED];
723 #endif
724
725 p->values[PDF_RSSSHMEM] = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)) * 1024;
726 p->values[PDF_VMSHARED] = p->values[PDF_RSSFILE] + p->values[PDF_RSSSHMEM];
727
728 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
729 if(old_shared > p->values[PDF_VMSHARED])
730 p->vmshared_delta += old_shared - p->values[PDF_VMSHARED];
731 else
732 p->vmshared_delta += p->values[PDF_VMSHARED] - old_shared;
733
734 p->values[PDF_PSS] = p->pss_bytes;
735
736 pid_update_estimated_memory(p);
737 #endif
738 }
739
740 void arl_callback_status_voluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) {
741 (void)name; (void)hash; (void)value;
742 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
743 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
744
745 struct pid_stat *p = aptr->p;
746 pid_incremental_rate(stat, PDF_VOLCTX, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
747 }
748
749 void arl_callback_status_nonvoluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) {
750 (void)name; (void)hash; (void)value;
751 struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
752 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
753
754 struct pid_stat *p = aptr->p;
755 pid_incremental_rate(stat, PDF_NVOLCTX, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
756 }
757
758 bool apps_os_read_pid_status_linux(struct pid_stat *p, void *ptr __maybe_unused) {
759 static struct arl_callback_ptr arl_ptr;
760 static procfile *ff = NULL;
761
762 if(unlikely(!p->status_arl)) {
763 p->status_arl = arl_create("/proc/pid/status", NULL, 60);
764 arl_expect_custom(p->status_arl, "Uid", arl_callback_status_uid, &arl_ptr);
765 arl_expect_custom(p->status_arl, "Gid", arl_callback_status_gid, &arl_ptr);
766 arl_expect_custom(p->status_arl, "VmSize", arl_callback_status_vmsize, &arl_ptr);
767 arl_expect_custom(p->status_arl, "VmRSS", arl_callback_status_vmrss, &arl_ptr);
768 arl_expect_custom(p->status_arl, "RssFile", arl_callback_status_rssfile, &arl_ptr);
769 arl_expect_custom(p->status_arl, "RssShmem", arl_callback_status_rssshmem, &arl_ptr);
770 arl_expect_custom(p->status_arl, "VmSwap", arl_callback_status_vmswap, &arl_ptr);
771 arl_expect_custom(p->status_arl, "voluntary_ctxt_switches", arl_callback_status_voluntary_ctxt_switches, &arl_ptr);
772 arl_expect_custom(p->status_arl, "nonvoluntary_ctxt_switches", arl_callback_status_nonvoluntary_ctxt_switches, &arl_ptr);
773 }
774
775 if(unlikely(!p->status_filename)) {
776 char filename[FILENAME_MAX + 1];
777 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/status", netdata_configured_host_prefix, p->pid);
778 p->status_filename = strdupz(filename);
779 }
780
781 ff = procfile_reopen(ff, p->status_filename, (!ff)?" \t:,-()/":NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
782 if(unlikely(!ff)) return false;
783
784 ff = procfile_readall(ff);
785 if(unlikely(!ff)) return false;
786
787 calls_counter++;
788
789 // let ARL use this pid
790 arl_ptr.p = p;
791 arl_ptr.ff = ff;
792
793 size_t lines = procfile_lines(ff), l;
794 arl_begin(p->status_arl);
795
796 for(l = 0; l < lines ;l++) {
797 // debug_log("CHECK: line %zu of %zu, key '%s' = '%s'", l, lines, procfile_lineword(ff, l, 0), procfile_lineword(ff, l, 1));
798 arl_ptr.line = l;
799 if(unlikely(arl_check(p->status_arl,
800 procfile_lineword(ff, l, 0),
801 procfile_lineword(ff, l, 1)))) break;
802 }
803
804 p->values[PDF_VMSHARED] = p->values[PDF_RSSFILE] + p->values[PDF_RSSSHMEM];
805 return true;
806 }
807
808 // --------------------------------------------------------------------------------------------------------------------
809 // global CPU utilization
810
811 bool apps_os_read_global_cpu_utilization_linux(void) {
812 static char filename[FILENAME_MAX + 1] = "";
813 static procfile *ff = NULL;
814 static kernel_uint_t utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0;
815 static usec_t collected_usec = 0, last_collected_usec = 0;
816
817 if(unlikely(!ff)) {
818 snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix);
819 ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
820 if(unlikely(!ff)) goto cleanup;
821 }
822
823 ff = procfile_readall(ff);
824 if(unlikely(!ff)) goto cleanup;
825
826 last_collected_usec = collected_usec;
827 collected_usec = now_monotonic_usec();
828
829 calls_counter++;
830
831 // temporary - it is added global_ntime;
832 kernel_uint_t global_ntime = 0;
833
834 incremental_rate(global_utime, utime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 1)), collected_usec, last_collected_usec, CPU_TO_NANOSECONDCORES);
835 incremental_rate(global_ntime, ntime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 2)), collected_usec, last_collected_usec, CPU_TO_NANOSECONDCORES);
836 incremental_rate(global_stime, stime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 3)), collected_usec, last_collected_usec, CPU_TO_NANOSECONDCORES);
837 incremental_rate(global_gtime, gtime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 10)), collected_usec, last_collected_usec, CPU_TO_NANOSECONDCORES);
838
839 global_utime += global_ntime;
840
841 if(enable_guest_charts) {
842 // temporary - it is added global_ntime;
843 kernel_uint_t global_gntime = 0;
844
845 // guest nice time, on guest time
846 incremental_rate(global_gntime, gntime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 11)), collected_usec, last_collected_usec, 1);
847
848 global_gtime += global_gntime;
849
850 // remove guest time from user time
851 global_utime -= (global_utime > global_gtime) ? global_gtime : global_utime;
852 }
853
854 if(unlikely(global_iterations_counter == 1)) {
855 global_utime = 0;
856 global_stime = 0;
857 global_gtime = 0;
858 }
859
860 return true;
861
862 cleanup:
863 global_utime = 0;
864 global_stime = 0;
865 global_gtime = 0;
866 return false;
867 }
868
869 // --------------------------------------------------------------------------------------------------------------------
870 // /proc/pid/stat
871
872 static inline void update_proc_state_count(char proc_stt) {
873 switch (proc_stt) {
874 case 'S':
875 proc_state_count[PROC_STATUS_SLEEPING] += 1;
876 break;
877 case 'R':
878 proc_state_count[PROC_STATUS_RUNNING] += 1;
879 break;
880 case 'D':
881 proc_state_count[PROC_STATUS_SLEEPING_D] += 1;
882 break;
883 case 'Z':
884 proc_state_count[PROC_STATUS_ZOMBIE] += 1;
885 break;
886 case 'T':
887 proc_state_count[PROC_STATUS_STOPPED] += 1;
888 break;
889 default:
890 break;
891 }
892 }
893
894 bool apps_os_read_pid_stat_linux(struct pid_stat *p, void *ptr __maybe_unused) {
895 static procfile *ff = NULL;
896
897 if(unlikely(!p->stat_filename)) {
898 char filename[FILENAME_MAX + 1];
899 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", netdata_configured_host_prefix, p->pid);
900 p->stat_filename = strdupz(filename);
901 }
902
903 bool set_quotes = (!ff) ? true : false;
904
905 ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
906 if(unlikely(!ff)) goto cleanup;
907
908 // if(set_quotes) procfile_set_quotes(ff, "()");
909 if(unlikely(set_quotes))
910 procfile_set_open_close(ff, "(", ")");
911
912 ff = procfile_readall(ff);
913 if(unlikely(!ff)) goto cleanup;
914
915 // p->pid = str2pid_t(procfile_lineword(ff, 0, 0));
916 char *comm = procfile_lineword(ff, 0, 1);
917 p->state = *(procfile_lineword(ff, 0, 2));
918 p->ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
919 // p->pgrp = (int32_t)str2pid_t(procfile_lineword(ff, 0, 4));
920 // p->session = (int32_t)str2pid_t(procfile_lineword(ff, 0, 5));
921 // p->tty_nr = (int32_t)str2pid_t(procfile_lineword(ff, 0, 6));
922 // p->tpgid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 7));
923 // p->flags = str2uint64_t(procfile_lineword(ff, 0, 8));
924
925 update_pid_comm(p, comm);
926
927 pid_incremental_rate(stat, PDF_MINFLT, str2kernel_uint_t(procfile_lineword(ff, 0, 9)));
928 pid_incremental_rate(stat, PDF_CMINFLT, str2kernel_uint_t(procfile_lineword(ff, 0, 10)));
929 pid_incremental_rate(stat, PDF_MAJFLT, str2kernel_uint_t(procfile_lineword(ff, 0, 11)));
930 pid_incremental_rate(stat, PDF_CMAJFLT, str2kernel_uint_t(procfile_lineword(ff, 0, 12)));
931 pid_incremental_cpu(stat, PDF_UTIME, str2kernel_uint_t(procfile_lineword(ff, 0, 13)));
932 pid_incremental_cpu(stat, PDF_STIME, str2kernel_uint_t(procfile_lineword(ff, 0, 14)));
933 pid_incremental_cpu(stat, PDF_CUTIME, str2kernel_uint_t(procfile_lineword(ff, 0, 15)));
934 pid_incremental_cpu(stat, PDF_CSTIME, str2kernel_uint_t(procfile_lineword(ff, 0, 16)));
935 // p->priority = str2kernel_uint_t(procfile_lineword(ff, 0, 17));
936 // p->nice = str2kernel_uint_t(procfile_lineword(ff, 0, 18));
937 p->values[PDF_THREADS] = (int32_t) str2uint32_t(procfile_lineword(ff, 0, 19), NULL);
938 // p->itrealvalue = str2kernel_uint_t(procfile_lineword(ff, 0, 20));
939 kernel_uint_t collected_starttime = str2kernel_uint_t(procfile_lineword(ff, 0, 21)) / system_hz;
940 p->values[PDF_UPTIME] = (system_uptime_secs > collected_starttime)?(system_uptime_secs - collected_starttime):0;
941 // p->vsize = str2kernel_uint_t(procfile_lineword(ff, 0, 22));
942 // p->rss = str2kernel_uint_t(procfile_lineword(ff, 0, 23));
943 // p->rsslim = str2kernel_uint_t(procfile_lineword(ff, 0, 24));
944 // p->starcode = str2kernel_uint_t(procfile_lineword(ff, 0, 25));
945 // p->endcode = str2kernel_uint_t(procfile_lineword(ff, 0, 26));
946 // p->startstack = str2kernel_uint_t(procfile_lineword(ff, 0, 27));
947 // p->kstkesp = str2kernel_uint_t(procfile_lineword(ff, 0, 28));
948 // p->kstkeip = str2kernel_uint_t(procfile_lineword(ff, 0, 29));
949 // p->signal = str2kernel_uint_t(procfile_lineword(ff, 0, 30));
950 // p->blocked = str2kernel_uint_t(procfile_lineword(ff, 0, 31));
951 // p->sigignore = str2kernel_uint_t(procfile_lineword(ff, 0, 32));
952 // p->sigcatch = str2kernel_uint_t(procfile_lineword(ff, 0, 33));
953 // p->wchan = str2kernel_uint_t(procfile_lineword(ff, 0, 34));
954 // p->nswap = str2kernel_uint_t(procfile_lineword(ff, 0, 35));
955 // p->cnswap = str2kernel_uint_t(procfile_lineword(ff, 0, 36));
956 // p->exit_signal = str2kernel_uint_t(procfile_lineword(ff, 0, 37));
957 // p->processor = str2kernel_uint_t(procfile_lineword(ff, 0, 38));
958 // p->rt_priority = str2kernel_uint_t(procfile_lineword(ff, 0, 39));
959 // p->policy = str2kernel_uint_t(procfile_lineword(ff, 0, 40));
960 // p->delayacct_blkio_ticks = str2kernel_uint_t(procfile_lineword(ff, 0, 41));
961
962 if(enable_guest_charts) {
963 pid_incremental_cpu(stat, PDF_GTIME, str2kernel_uint_t(procfile_lineword(ff, 0, 42)));
964 pid_incremental_cpu(stat, PDF_CGTIME, str2kernel_uint_t(procfile_lineword(ff, 0, 43)));
965
966 if (show_guest_time || p->values[PDF_GTIME] || p->values[PDF_CGTIME]) {
967 p->values[PDF_UTIME] -= (p->values[PDF_UTIME] >= p->values[PDF_GTIME]) ? p->values[PDF_GTIME] : p->values[PDF_UTIME];
968 p->values[PDF_CUTIME] -= (p->values[PDF_CUTIME] >= p->values[PDF_CGTIME]) ? p->values[PDF_CGTIME] : p->values[PDF_CUTIME];
969 show_guest_time = true;
970 }
971 }
972
973 if(unlikely(debug_enabled))
974 debug_log_int("READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT ", threads=" KERNEL_UINT_FORMAT,
975 netdata_configured_host_prefix, p->pid, pid_stat_comm(p), (p->target)?string2str(p->target->name):"UNSET", p->stat_collected_usec - p->last_stat_collected_usec,
976 p->values[PDF_UTIME],
977 p->values[PDF_STIME],
978 p->values[PDF_CUTIME],
979 p->values[PDF_CSTIME],
980 p->values[PDF_MINFLT],
981 p->values[PDF_MAJFLT],
982 p->values[PDF_CMINFLT],
983 p->values[PDF_CMAJFLT],
984 p->values[PDF_THREADS]);
985
986 update_proc_state_count(p->state);
987 return true;
988
989 cleanup:
990 return false;
991 }
992
993 // ----------------------------------------------------------------------------
994
995 // 1. read all files in /proc
996 // 2. for each numeric directory:
997 // i. read /proc/pid/stat
998 // ii. read /proc/pid/status
999 // iii. read /proc/pid/io (requires root access)
1000 // iii. read the entries in directory /proc/pid/fd (requires root access)
1001 // for each entry:
1002 // a. find or create a struct file_descriptor
1003 // b. cleanup any old/unused file_descriptors
1004
1005 // after all these, some pids may be linked to targets, while others may not
1006
1007 // in case of errors, only 1 every 1000 errors is printed
1008 // to avoid filling up all disk space
1009 // if debug is enabled, all errors are printed
1010
1011 bool apps_os_collect_all_pids_linux(void) {
1012 #if (PROCESSES_HAVE_STATE == 1)
1013 // clear process state counter
1014 memset(proc_state_count, 0, sizeof proc_state_count);
1015 #endif
1016
1017 // preload the parents and then their children
1018 collect_parents_before_children();
1019
1020 static char uptime_filename[FILENAME_MAX + 1] = "";
1021 if(*uptime_filename == '\0')
1022 snprintfz(uptime_filename, FILENAME_MAX, "%s/proc/uptime", netdata_configured_host_prefix);
1023
1024 system_uptime_secs = (kernel_uint_t)(uptime_msec(uptime_filename) / MSEC_PER_SEC);
1025
1026 char dirname[FILENAME_MAX + 1];
1027
1028 snprintfz(dirname, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
1029 DIR *dir = opendir(dirname);
1030 if(!dir) return false;
1031
1032 struct dirent *de = NULL;
1033
1034 while((de = readdir(dir))) {
1035 char *endptr = de->d_name;
1036
1037 if(unlikely(de->d_type != DT_DIR || de->d_name[0] < '0' || de->d_name[0] > '9'))
1038 continue;
1039
1040 pid_t pid = (pid_t) strtoul(de->d_name, &endptr, 10);
1041
1042 // make sure we read a valid number
1043 if(unlikely(endptr == de->d_name || *endptr != '\0'))
1044 continue;
1045
1046 incrementally_collect_data_for_pid(pid, NULL);
1047 }
1048 closedir(dir);
1049
1050 #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1)
1051 apps_handle_smaps_updates();
1052 #endif
1053
1054 return true;
1055 }
1056
1057 #endif