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