feat(apps.plugin): collect context switches (#15002)
Ilya Mashchenko committed
May 4, 2023 at 17:52 UTC
13b8b1114ec66044d4a3d9f01b5c34cdad8f1999
2 files changed
+95
collectors/apps.plugin/apps_plugin.c
+89
@@ -251,6 +251,8 @@ struct target {
251
kernel_uint_t status_rssfile;
252
kernel_uint_t status_rssshmem;
253
kernel_uint_t status_vmswap;
254
+ kernel_uint_t status_voluntary_ctxt_switches;
255
+ kernel_uint_t status_nonvoluntary_ctxt_switches;
256
257
kernel_uint_t io_logical_bytes_read;
258
kernel_uint_t io_logical_bytes_written;
@@ -381,12 +383,17 @@ struct pid_stat {
383
uid_t uid;
384
gid_t gid;
385
386
+ kernel_uint_t status_voluntary_ctxt_switches_raw;
387
+ kernel_uint_t status_nonvoluntary_ctxt_switches_raw;
388
+
389
kernel_uint_t status_vmsize;
390
kernel_uint_t status_vmrss;
391
kernel_uint_t status_vmshared;
392
kernel_uint_t status_rssfile;
393
kernel_uint_t status_rssshmem;
394
kernel_uint_t status_vmswap;
395
+ kernel_uint_t status_voluntary_ctxt_switches;
396
+ kernel_uint_t status_nonvoluntary_ctxt_switches;
397
#ifndef __FreeBSD__
398
ARL_BASE *status_arl;
399
#endif
@@ -1263,6 +1270,26 @@ void arl_callback_status_rssshmem(const char *name, uint32_t hash, const char *v
1270
aptr->p->status_rssshmem = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1));
1271
}
1272
1273
+void arl_callback_status_voluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) {
1274
+ (void)name; (void)hash; (void)value;
1275
+ struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
1276
+ if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
1277
+
1278
+ struct pid_stat *p = aptr->p;
1279
+ pid_incremental_rate(
1280
+ stat, p->status_voluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
1281
+}
1282
+
1283
+void arl_callback_status_nonvoluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) {
1284
+ (void)name; (void)hash; (void)value;
1285
+ struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
1286
+ if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
1287
+
1288
+ struct pid_stat *p = aptr->p;
1289
+ pid_incremental_rate(
1290
+ stat, p->status_nonvoluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
1291
+}
1292
+
1293
static void update_proc_state_count(char proc_state) {
1294
switch (proc_state) {
1295
case 'S':
@@ -1293,6 +1320,8 @@ static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) {
1320
p->status_rssfile = 0;
1321
p->status_rssshmem = 0;
1322
p->status_vmswap = 0;
1323
+ p->status_voluntary_ctxt_switches = 0;
1324
+ p->status_nonvoluntary_ctxt_switches = 0;
1325
1326
#ifdef __FreeBSD__
1327
struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
@@ -1318,6 +1347,8 @@ static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) {
1347
arl_expect_custom(p->status_arl, "RssFile", arl_callback_status_rssfile, &arl_ptr);
1348
arl_expect_custom(p->status_arl, "RssShmem", arl_callback_status_rssshmem, &arl_ptr);
1349
arl_expect_custom(p->status_arl, "VmSwap", arl_callback_status_vmswap, &arl_ptr);
1350
+ arl_expect_custom(p->status_arl, "voluntary_ctxt_switches", arl_callback_status_voluntary_ctxt_switches, &arl_ptr);
1351
+ arl_expect_custom(p->status_arl, "nonvoluntary_ctxt_switches", arl_callback_status_nonvoluntary_ctxt_switches, &arl_ptr);
1352
}
1353
1354
@@ -2905,6 +2936,8 @@ static size_t zero_all_targets(struct target *root) {
2936
w->status_rssfile = 0;
2937
w->status_rssshmem = 0;
2938
w->status_vmswap = 0;
2939
+ w->status_voluntary_ctxt_switches = 0;
2940
+ w->status_nonvoluntary_ctxt_switches = 0;
2941
2942
w->io_logical_bytes_read = 0;
2943
w->io_logical_bytes_written = 0;
@@ -3095,6 +3128,8 @@ static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p,
3128
w->status_rssfile += p->status_rssfile;
3129
w->status_rssshmem += p->status_rssshmem;
3130
w->status_vmswap += p->status_vmswap;
3131
+ w->status_voluntary_ctxt_switches += p->status_voluntary_ctxt_switches;
3132
+ w->status_nonvoluntary_ctxt_switches += p->status_nonvoluntary_ctxt_switches;
3133
3134
w->io_logical_bytes_read += p->io_logical_bytes_read;
3135
w->io_logical_bytes_written += p->io_logical_bytes_written;
@@ -3540,6 +3575,22 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
3575
send_END();
3576
}
3577
3578
+#ifndef __FreeBSD__
3579
+ send_BEGIN(type, "voluntary_ctxt_switches", dt);
3580
+ for (w = root; w ; w = w->next) {
3581
+ if(unlikely(w->exposed && w->processes))
3582
+ send_SET(w->name, w->status_voluntary_ctxt_switches);
3583
+ }
3584
+ send_END();
3585
+
3586
+ send_BEGIN(type, "involuntary_ctxt_switches", dt);
3587
+ for (w = root; w ; w = w->next) {
3588
+ if(unlikely(w->exposed && w->processes))
3589
+ send_SET(w->name, w->status_nonvoluntary_ctxt_switches);
3590
+ }
3591
+ send_END();
3592
+#endif
3593
+
3594
send_BEGIN(type, "threads", dt);
3595
for (w = root; w ; w = w->next) {
3596
if(unlikely(w->exposed))
@@ -3822,6 +3873,22 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
3873
APPS_PLUGIN_FUNCTIONS();
3874
}
3875
3876
+#ifndef __FreeBSD__
3877
+ fprintf(stdout, "CHART %s.voluntary_ctxt_switches '' '%s Voluntary Context Switches' 'switches/s' cpu %s.voluntary_ctxt_switches stacked 20023 %d\n", type, title, type, update_every);
3878
+ for (w = root; w ; w = w->next) {
3879
+ if(unlikely(w->exposed))
3880
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
3881
+ }
3882
+ APPS_PLUGIN_FUNCTIONS();
3883
+
3884
+ fprintf(stdout, "CHART %s.involuntary_ctxt_switches '' '%s Involuntary Context Switches' 'switches/s' cpu %s.involuntary_ctxt_switches stacked 20024 %d\n", type, title, type, update_every);
3885
+ for (w = root; w ; w = w->next) {
3886
+ if(unlikely(w->exposed))
3887
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
3888
+ }
3889
+ APPS_PLUGIN_FUNCTIONS();
3890
+#endif
3891
+
3892
#ifndef __FreeBSD__
3893
fprintf(stdout, "CHART %s.swap '' '%s Swap Memory' 'MiB' swap %s.swap stacked 20011 %d\n", type, title, type, update_every);
3894
for (w = root; w ; w = w->next) {
@@ -4426,6 +4493,8 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4493
unsigned long long
4494
Processes_max = 0
4495
, Threads_max = 0
4496
+ , VoluntaryCtxtSwitches_max = 0
4497
+ , NonVoluntaryCtxtSwitches_max = 0
4498
, Uptime_max = 0
4499
, MinFlt_max = 0
4500
, CMinFlt_max = 0
@@ -4527,6 +4596,9 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4596
add_value_field_ndd_with_max(wb, CSysCPU, (NETDATA_DOUBLE)(p->cstime) / cpu_divisor);
4597
add_value_field_ndd_with_max(wb, CGuestCPU, (NETDATA_DOUBLE)(p->cgtime) / cpu_divisor);
4598
4599
+ add_value_field_llu_with_max(wb, VoluntaryCtxtSwitches, p->status_voluntary_ctxt_switches / RATES_DETAIL);
4600
+ add_value_field_llu_with_max(wb, NonVoluntaryCtxtSwitches, p->status_nonvoluntary_ctxt_switches / RATES_DETAIL);
4601
+
4602
// memory MiB
4603
if(MemTotal)
4604
add_value_field_ndd_with_max(wb, Memory, (NETDATA_DOUBLE)p->status_vmrss * 100.0 / (NETDATA_DOUBLE)MemTotal);
@@ -4610,6 +4682,10 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4682
add_table_field(wb, "CSysCPU", "Children System CPU Time (100% = 1 core)", false, "bar-with-integer", "bar", "number", 2, "%", CSysCPU_max, "descending", true, false, false, NULL, "sum", true);
4683
add_table_field(wb, "CGuestCPU", "Children Guest CPU Time (100% = 1 core)", false, "bar-with-integer", "bar", "number", 2, "%", CGuestCPU_max, "descending", true, false, false, NULL, "sum", true);
4684
4685
+ // CPU context switches
4686
+ add_table_field(wb, "vCtxSwitch", "Voluntary Context Switches", false, "bar-with-integer", "bar", "number", 2, "switches/s", VoluntaryCtxtSwitches_max, "descending", true, false, false, NULL, "sum", true);
4687
+ add_table_field(wb, "iCtxSwitch", "Involuntary Context Switches", false, "bar-with-integer", "bar", "number", 2, "switches/s", NonVoluntaryCtxtSwitches_max, "descending", true, false, false, NULL, "sum", true);
4688
+
4689
// memory
4690
if(MemTotal)
4691
add_table_field(wb, "Memory", "Memory Percentage", true, "bar-with-integer", "bar", "number", 2, "%", 100.0, "descending", true, false, false, NULL, "sum", true);
@@ -4684,6 +4760,19 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4760
}
4761
buffer_json_object_close(wb);
4762
4763
+ buffer_json_member_add_object(wb, "CPUCtxSwitches");
4764
+ {
4765
+ buffer_json_member_add_string(wb, "name", "CPU Context Switches");
4766
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
4767
+ buffer_json_member_add_array(wb, "columns");
4768
+ {
4769
+ buffer_json_add_array_item_string(wb, "vCtxSwitch");
4770
+ buffer_json_add_array_item_string(wb, "iCtxSwitch");
4771
+ }
4772
+ buffer_json_array_close(wb);
4773
+ }
4774
+ buffer_json_object_close(wb);
4775
+
4776
// Memory chart
4777
buffer_json_member_add_object(wb, "Memory");
4778
{
collectors/apps.plugin/metrics.csv
+6
@@ -16,6 +16,8 @@ apps.lreads,,a dimension per app group,"KiB/s","Apps Disk Logical Reads",stacked
16
apps.lwrites,,a dimension per app group,"KiB/s","Apps I/O Logical Writes",stacked,,apps.plugin,
17
apps.threads,,a dimension per app group,threads,"Apps Threads",stacked,,apps.plugin,
18
apps.processes,,a dimension per app group,processes,"Apps Processes",stacked,,apps.plugin,
19
+apps.voluntary_ctxt_switches,,a dimension per app group,processes,"Apps Voluntary Context Switches",stacked,,apps.plugin,
20
+apps.involuntary_ctxt_switches,,a dimension per app group,processes,"Apps Involuntary Context Switches",stacked,,apps.plugin,
21
apps.uptime,,a dimension per app group,seconds,"Apps Carried Over Uptime",line,,apps.plugin,
22
apps.uptime_min,,a dimension per app group,seconds,"Apps Minimum Uptime",line,,apps.plugin,
23
apps.uptime_avg,,a dimension per app group,seconds,"Apps Average Uptime",line,,apps.plugin,
@@ -39,6 +41,8 @@ groups.lreads,,a dimension per user group,"KiB/s","User Groups Disk Logical Read
41
groups.lwrites,,a dimension per user group,"KiB/s","User Groups I/O Logical Writes",stacked,,apps.plugin,
42
groups.threads,,a dimension per user group,threads,"User Groups Threads",stacked,,apps.plugin,
43
groups.processes,,a dimension per user group,processes,"User Groups Processes",stacked,,apps.plugin,
44
+groups.voluntary_ctxt_switches,,a dimension per app group,processes,"User Groups Voluntary Context Switches",stacked,,apps.plugin,
45
+groups.involuntary_ctxt_switches,,a dimension per app group,processes,"User Groups Involuntary Context Switches",stacked,,apps.plugin,
46
groups.uptime,,a dimension per user group,seconds,"User Groups Carried Over Uptime",line,,apps.plugin,
47
groups.uptime_min,,a dimension per user group,seconds,"User Groups Minimum Uptime",line,,apps.plugin,
48
groups.uptime_avg,,a dimension per user group,seconds,"User Groups Average Uptime",line,,apps.plugin,
@@ -62,6 +66,8 @@ users.lreads,,a dimension per user,"KiB/s","Users Disk Logical Reads",stacked,,a
66
users.lwrites,,a dimension per user,"KiB/s","Users I/O Logical Writes",stacked,,apps.plugin,
67
users.threads,,a dimension per user,threads,"Users Threads",stacked,,apps.plugin,
68
users.processes,,a dimension per user,processes,"Users Processes",stacked,,apps.plugin,
69
+users.voluntary_ctxt_switches,,a dimension per app group,processes,"Users Voluntary Context Switches",stacked,,apps.plugin,
70
+users.involuntary_ctxt_switches,,a dimension per app group,processes,"Users Involuntary Context Switches",stacked,,apps.plugin,
71
users.uptime,,a dimension per user,seconds,"Users Carried Over Uptime",line,,apps.plugin,
72
users.uptime_min,,a dimension per user,seconds,"Users Minimum Uptime",line,,apps.plugin,
73
users.uptime_avg,,a dimension per user,seconds,"Users Average Uptime",line,,apps.plugin,