@cryptotaxi247 / netdata-1 / commits / f5b425401

apps.plugin fds limits improvements (#15437)

* apps.plugin fds limits improvements * removal of fdperc * added fds family and moved all fds charts there * added decimal points

Costa Tsaousis committed Jul 18, 2023 at 16:24 UTC f5b4254016a59903c1c4d0190dd3536d68046bbf
1 file changed +153 -53
collectors/apps.plugin/apps_plugin.c
+153 -53
@@ -2,7 +2,7 @@
2
3 /*
4 * netdata apps.plugin
5 - * (C) Copyright 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
5 + * (C) Copyright 2023 Netdata Inc.
6 * Released under GPL v3+
7 */
8
@@ -180,7 +180,7 @@ static size_t
180 // the metrics. This results in utilization that exceeds the total utilization
181 // of the system.
182 //
183 -// With normalization we align the per-process utilization, to the total of
183 +// During normalization, we align the per-process utilization, to the total of
184 // the system. We first consume the exited children utilization and it the
185 // collected values is above the total, we proportionally scale each reported
186 // metric.
@@ -222,6 +222,8 @@ struct openfds {
222 kernel_uint_t other;
223 };
224
225 +#define pid_openfds_sum(p) ((p)->openfds.files + (p)->openfds.pipes + (p)->openfds.sockets + (p)->openfds.inotifies + (p)->openfds.eventfds + (p)->openfds.timerfds + (p)->openfds.signalfds + (p)->openfds.eventpolls + (p)->openfds.other)
226 +
227 struct pid_limits {
228 // kernel_uint_t max_cpu_time;
229 // kernel_uint_t max_file_size;
@@ -454,6 +456,8 @@ struct pid_stat {
456 struct openfds openfds;
457 struct pid_limits limits;
458
459 + NETDATA_DOUBLE openfds_limits_percent;
460 +
461 int sortlist; // higher numbers = top on the process tree
462 // each process gets a unique number
463
@@ -554,8 +558,6 @@ static int
558 all_files_len = 0,
559 all_files_size = 0;
560
557 -long currentmaxfds = 0;
558 -
561 // ----------------------------------------------------------------------------
562 // read users and groups from files
563
@@ -1314,8 +1316,7 @@ void arl_callback_status_voluntary_ctxt_switches(const char *name, uint32_t hash
1316 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
1317
1318 struct pid_stat *p = aptr->p;
1317 - pid_incremental_rate(
1318 - stat, p->status_voluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
1319 + pid_incremental_rate(stat, p->status_voluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
1320 }
1321
1322 void arl_callback_status_nonvoluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) {
@@ -1324,8 +1325,7 @@ void arl_callback_status_nonvoluntary_ctxt_switches(const char *name, uint32_t h
1325 if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
1326
1327 struct pid_stat *p = aptr->p;
1327 - pid_incremental_rate(
1328 - stat, p->status_nonvoluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
1328 + pid_incremental_rate(stat, p->status_nonvoluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
1329 }
1330
1331 static void update_proc_state_count(char proc_state) {
@@ -1371,11 +1371,13 @@ static inline int read_proc_pid_limits(struct pid_stat *p, void *ptr) {
1371 #ifdef __FreeBSD__
1372 return 0;
1373 #else
1374 - static char proc_pid_limits[MAX_PROC_PID_LIMITS + 1];
1374 + static char proc_pid_limits_buffer[MAX_PROC_PID_LIMITS + 1];
1375 + int ret = 0;
1376
1376 - if(p->io_collected_usec > p->last_limits_collected_usec && p->io_collected_usec - p->last_limits_collected_usec <= 60 * USEC_PER_SEC)
1377 + kernel_uint_t all_fds = pid_openfds_sum(p);
1378 + 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)
1379 // too frequent, we want to collect limits once per minute
1378 - return 0;
1380 + goto cleanup;
1381
1382 if(unlikely(!p->limits_filename)) {
1383 char filename[FILENAME_MAX + 1];
@@ -1384,18 +1386,26 @@ static inline int read_proc_pid_limits(struct pid_stat *p, void *ptr) {
1386 }
1387
1388 int fd = open(p->limits_filename, procfile_open_flags, 0666);
1387 - if(unlikely(fd == -1)) return 0;
1389 + if(unlikely(fd == -1)) goto cleanup;
1390
1389 - ssize_t bytes = read(fd, proc_pid_limits, MAX_PROC_PID_LIMITS);
1391 + ssize_t bytes = read(fd, proc_pid_limits_buffer, MAX_PROC_PID_LIMITS);
1392 close(fd);
1393
1394 if(bytes <= 0)
1393 - return 0;
1395 + goto cleanup;
1396
1395 - p->limits.max_open_files = get_proc_pid_limits_limit(proc_pid_limits, PROC_PID_LIMITS_MAX_OPEN_FILES_KEY, sizeof(PROC_PID_LIMITS_MAX_OPEN_FILES_KEY) - 1, 0);
1397 + 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);
1398 p->last_limits_collected_usec = p->io_collected_usec;
1399
1398 - return 1;
1400 + ret = 1;
1401 +
1402 +cleanup:
1403 + if(p->limits.max_open_files)
1404 + p->openfds_limits_percent = (NETDATA_DOUBLE)all_fds * 100.0 / (NETDATA_DOUBLE)p->limits.max_open_files;
1405 + else
1406 + p->openfds_limits_percent = 0.0;
1407 +
1408 + return ret;
1409 #endif
1410 }
1411
@@ -2904,7 +2914,7 @@ static void apply_apps_groups_targets_inheritance(void) {
2914 if(unlikely(debug_enabled)) loops++;
2915 found = 0;
2916 for(p = root_of_pids; p ; p = p->next) {
2907 - // if this process does not have a target
2917 + // if this process does not have a target,
2918 // and it has a parent
2919 // and its parent has a target
2920 // then, set the parent's target to this process
@@ -2971,7 +2981,7 @@ static void apply_apps_groups_targets_inheritance(void) {
2981 if(unlikely(debug_enabled)) loops++;
2982 for(p = root_of_pids; p ; p = p->next) {
2983 // if the process is not merged itself
2974 - // then is is a top level process
2984 + // then it is a top level process
2985 if(unlikely(!p->merged && !p->target))
2986 p->target = apps_groups_default_target;
2987
@@ -3185,9 +3195,6 @@ static inline void aggregate_pid_fds_on_targets(struct pid_stat *p) {
3195 aggregate_fd_on_target(fd, u);
3196 aggregate_fd_on_target(fd, g);
3197 }
3188 -
3189 - if (currentfds >= currentmaxfds)
3190 - currentmaxfds = currentfds;
3198 }
3199
3200 static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
@@ -3203,22 +3210,8 @@ static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p,
3210 return;
3211 }
3212
3206 - if(p->limits.max_open_files > 0) {
3207 - kernel_uint_t all_dfs =
3208 - p->openfds.files +
3209 - p->openfds.pipes +
3210 - p->openfds.sockets +
3211 - p->openfds.inotifies +
3212 - p->openfds.eventfds +
3213 - p->openfds.timerfds +
3214 - p->openfds.signalfds +
3215 - p->openfds.eventpolls +
3216 - p->openfds.other;
3217 -
3218 - NETDATA_DOUBLE percent = (NETDATA_DOUBLE)all_dfs * 100.0 / (NETDATA_DOUBLE)p->limits.max_open_files;
3219 - if(percent > w->max_open_files_percent)
3220 - w->max_open_files_percent = percent;
3221 - }
3213 + if(p->openfds_limits_percent > w->max_open_files_percent)
3214 + w->max_open_files_percent = p->openfds_limits_percent;
3215
3216 w->cutime += p->cutime;
3217 w->cstime += p->cstime;
@@ -3824,38 +3817,82 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
3817 send_END();
3818
3819 if(enable_file_charts) {
3827 - send_BEGIN(type, "files", dt);
3820 + send_BEGIN(type, "fds_open_limit", dt);
3821 for (w = root; w; w = w->next) {
3822 if (unlikely(w->exposed && w->processes))
3830 - send_SET(w->name, w->openfds.files);
3823 + send_SET(w->name, w->max_open_files_percent * 100.0);
3824 }
3832 - if (!strcmp("apps", type)){
3833 - kernel_uint_t usedfdpercentage = (kernel_uint_t) ((currentmaxfds * 100) / sysconf(_SC_OPEN_MAX));
3834 - fprintf(stdout, "VARIABLE fdperc = " KERNEL_UINT_FORMAT "\n", usedfdpercentage);
3825 + send_END();
3826 +
3827 + send_BEGIN(type, "fds_open", dt);
3828 + for (w = root; w; w = w->next) {
3829 + if (unlikely(w->exposed && w->processes))
3830 + send_SET(w->name, pid_openfds_sum(w));
3831 }
3832 send_END();
3833
3838 - send_BEGIN(type, "sockets", dt);
3834 + send_BEGIN(type, "fds_files", dt);
3835 + for (w = root; w; w = w->next) {
3836 + if (unlikely(w->exposed && w->processes))
3837 + send_SET(w->name, w->openfds.files);
3838 + }
3839 + send_END();
3840 +
3841 + send_BEGIN(type, "fds_sockets", dt);
3842 for (w = root; w; w = w->next) {
3843 if (unlikely(w->exposed && w->processes))
3844 send_SET(w->name, w->openfds.sockets);
3845 }
3846 send_END();
3847
3845 - send_BEGIN(type, "pipes", dt);
3848 + send_BEGIN(type, "fds_pipes", dt);
3849 for (w = root; w; w = w->next) {
3850 if (unlikely(w->exposed && w->processes))
3851 send_SET(w->name, w->openfds.pipes);
3852 }
3853 send_END();
3854
3852 - send_BEGIN(type, "fd_limit", dt);
3855 + send_BEGIN(type, "fds_inotifies", dt);
3856 for (w = root; w; w = w->next) {
3857 if (unlikely(w->exposed && w->processes))
3855 - send_SET(w->name, w->max_open_files_percent * 100.0);
3858 + send_SET(w->name, w->openfds.inotifies);
3859 + }
3860 + send_END();
3861 +
3862 + send_BEGIN(type, "fds_eventfds", dt);
3863 + for (w = root; w; w = w->next) {
3864 + if (unlikely(w->exposed && w->processes))
3865 + send_SET(w->name, w->openfds.eventfds);
3866 + }
3867 + send_END();
3868 +
3869 + send_BEGIN(type, "fds_timerfds", dt);
3870 + for (w = root; w; w = w->next) {
3871 + if (unlikely(w->exposed && w->processes))
3872 + send_SET(w->name, w->openfds.timerfds);
3873 }
3874 send_END();
3875
3876 + send_BEGIN(type, "fds_signalfds", dt);
3877 + for (w = root; w; w = w->next) {
3878 + if (unlikely(w->exposed && w->processes))
3879 + send_SET(w->name, w->openfds.signalfds);
3880 + }
3881 + send_END();
3882 +
3883 + send_BEGIN(type, "fds_eventpolls", dt);
3884 + for (w = root; w; w = w->next) {
3885 + if (unlikely(w->exposed && w->processes))
3886 + send_SET(w->name, w->openfds.eventpolls);
3887 + }
3888 + send_END();
3889 +
3890 + send_BEGIN(type, "fds_other", dt);
3891 + for (w = root; w; w = w->next) {
3892 + if (unlikely(w->exposed && w->processes))
3893 + send_SET(w->name, w->openfds.other);
3894 + }
3895 + send_END();
3896 }
3897 }
3898
@@ -4078,7 +4115,23 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
4115 #endif
4116
4117 if(enable_file_charts) {
4081 - fprintf(stdout, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type,
4118 + fprintf(stdout, "CHART %s.fds_open_limit '' '%s Open File Descriptors Limit' '%%' fds %s.fds_open_limit line 20050 %d\n", type,
4119 + title, type, update_every);
4120 + for (w = root; w; w = w->next) {
4121 + if (unlikely(w->exposed))
4122 + fprintf(stdout, "DIMENSION %s '' absolute 1 100\n", w->name);
4123 + }
4124 + APPS_PLUGIN_FUNCTIONS();
4125 +
4126 + fprintf(stdout, "CHART %s.fds_open '' '%s Open File Descriptors' 'fds' fds %s.fds_open stacked 20051 %d\n", type,
4127 + title, type, update_every);
4128 + for (w = root; w; w = w->next) {
4129 + if (unlikely(w->exposed))
4130 + fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
4131 + }
4132 + APPS_PLUGIN_FUNCTIONS();
4133 +
4134 + fprintf(stdout, "CHART %s.fds_files '' '%s Open Files' 'fds' fds %s.fds_files stacked 20052 %d\n", type,
4135 title, type, update_every);
4136 for (w = root; w; w = w->next) {
4137 if (unlikely(w->exposed))
@@ -4086,7 +4139,7 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
4139 }
4140 APPS_PLUGIN_FUNCTIONS();
4141
4089 - fprintf(stdout, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n",
4142 + fprintf(stdout, "CHART %s.fds_sockets '' '%s Open Sockets' 'fds' fds %s.fds_sockets stacked 20053 %d\n",
4143 type, title, type, update_every);
4144 for (w = root; w; w = w->next) {
4145 if (unlikely(w->exposed))
@@ -4094,7 +4147,7 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
4147 }
4148 APPS_PLUGIN_FUNCTIONS();
4149
4097 - fprintf(stdout, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type,
4150 + fprintf(stdout, "CHART %s.fds_pipes '' '%s Pipes' 'fds' fds %s.fds_pipes stacked 20054 %d\n", type,
4151 title, type, update_every);
4152 for (w = root; w; w = w->next) {
4153 if (unlikely(w->exposed))
@@ -4102,11 +4155,51 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
4155 }
4156 APPS_PLUGIN_FUNCTIONS();
4157
4105 - fprintf(stdout, "CHART %s.fd_limit '' '%s File Descriptors Limit' '%%' processes %s.fd_limit line 20054 %d\n", type,
4158 + fprintf(stdout, "CHART %s.fds_inotifies '' '%s iNotify File Descriptors' 'fds' fds %s.fds_inotifies stacked 20055 %d\n", type,
4159 title, type, update_every);
4160 for (w = root; w; w = w->next) {
4161 if (unlikely(w->exposed))
4109 - fprintf(stdout, "DIMENSION %s '' absolute 1 100\n", w->name);
4162 + fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
4163 + }
4164 + APPS_PLUGIN_FUNCTIONS();
4165 +
4166 + fprintf(stdout, "CHART %s.fds_eventfds '' '%s Event File Descriptors' 'fds' fds %s.fds_eventfds stacked 20056 %d\n", type,
4167 + title, type, update_every);
4168 + for (w = root; w; w = w->next) {
4169 + if (unlikely(w->exposed))
4170 + fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
4171 + }
4172 + APPS_PLUGIN_FUNCTIONS();
4173 +
4174 + fprintf(stdout, "CHART %s.fds_timerfds '' '%s Timer File Descriptors' 'fds' fds %s.fds_timerfds stacked 20057 %d\n", type,
4175 + title, type, update_every);
4176 + for (w = root; w; w = w->next) {
4177 + if (unlikely(w->exposed))
4178 + fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
4179 + }
4180 + APPS_PLUGIN_FUNCTIONS();
4181 +
4182 + fprintf(stdout, "CHART %s.fds_signalfds '' '%s Signal File Descriptors' 'fds' fds %s.fds_signalfds stacked 20058 %d\n", type,
4183 + title, type, update_every);
4184 + for (w = root; w; w = w->next) {
4185 + if (unlikely(w->exposed))
4186 + fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
4187 + }
4188 + APPS_PLUGIN_FUNCTIONS();
4189 +
4190 + fprintf(stdout, "CHART %s.fds_eventpolls '' '%s Event Poll File Descriptors' 'fds' fds %s.fds_eventpolls stacked 20059 %d\n", type,
4191 + title, type, update_every);
4192 + for (w = root; w; w = w->next) {
4193 + if (unlikely(w->exposed))
4194 + fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
4195 + }
4196 + APPS_PLUGIN_FUNCTIONS();
4197 +
4198 + fprintf(stdout, "CHART %s.fds_other '' '%s Other File Descriptors' 'fds' fds %s.fds_other stacked 20060 %d\n", type,
4199 + title, type, update_every);
4200 + for (w = root; w; w = w->next) {
4201 + if (unlikely(w->exposed))
4202 + fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
4203 }
4204 APPS_PLUGIN_FUNCTIONS();
4205 }
@@ -4599,6 +4692,7 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4692 , Shared_max = 0.0
4693 , Swap_max = 0.0
4694 , Memory_max = 0.0
4695 + , FDsLimitPercent_max = 0.0
4696 ;
4697
4698 unsigned long long
@@ -4744,7 +4838,8 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4838 add_value_field_llu_with_max(wb, TMajFlt, (p->majflt + p->cmajflt) / RATES_DETAIL);
4839
4840 // open file descriptors
4747 - add_value_field_llu_with_max(wb, FDs, p->openfds.files + p->openfds.pipes + p->openfds.sockets + p->openfds.inotifies + p->openfds.eventfds + p->openfds.timerfds + p->openfds.signalfds + p->openfds.eventpolls + p->openfds.other);
4841 + add_value_field_ndd_with_max(wb, FDsLimitPercent, p->openfds_limits_percent);
4842 + add_value_field_llu_with_max(wb, FDs, pid_openfds_sum(p));
4843 add_value_field_llu_with_max(wb, Files, p->openfds.files);
4844 add_value_field_llu_with_max(wb, Pipes, p->openfds.pipes);
4845 add_value_field_llu_with_max(wb, Sockets, p->openfds.sockets);
@@ -4755,6 +4850,7 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4850 add_value_field_llu_with_max(wb, EvPollFDs, p->openfds.eventpolls);
4851 add_value_field_llu_with_max(wb, OtherFDs, p->openfds.other);
4852
4853 +
4854 // processes, threads, uptime
4855 add_value_field_llu_with_max(wb, Processes, p->children_count);
4856 add_value_field_llu_with_max(wb, Threads, p->num_threads);
@@ -4983,6 +5079,11 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
5079 RRDF_FIELD_OPTS_VISIBLE, NULL);
5080
5081 // open file descriptors
5082 + buffer_rrdf_table_add_field(wb, field_id++, "FDsLimitPercent", "Percentage of Open Descriptors vs Limits",
5083 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR,
5084 + RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", FDsLimitPercent_max, RRDF_FIELD_SORT_DESCENDING, NULL,
5085 + RRDF_FIELD_SUMMARY_MAX, RRDF_FIELD_FILTER_RANGE,
5086 + RRDF_FIELD_OPTS_NONE, NULL);
5087 buffer_rrdf_table_add_field(wb, field_id++, "FDs", "All Open File Descriptors",
5088 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR,
5089 RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", FDs_max, RRDF_FIELD_SORT_DESCENDING, NULL,
@@ -5553,7 +5654,6 @@ int main(int argc, char **argv) {
5654 exit(1);
5655 }
5656
5556 - currentmaxfds = 0;
5657 calculate_netdata_statistics();
5658 normalize_utilization(apps_groups_root_target);
5659