From bc6e88e617421d531f7cfa63dbb1cf332540bee1 Mon Sep 17 00:00:00 2001 From: Uman Shahzad Date: Tue, 24 Aug 2021 01:23:56 +0500 Subject: [PATCH] Software IRQ latency tracking (#251) --- includes/netdata_ebpf.h | 1 + includes/netdata_softirq.h | 30 ++++++++++++++++ kernel/Makefile | 3 +- kernel/README.md | 1 + kernel/hardirq_kern.c | 14 ++++---- kernel/softirq_kern.c | 72 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 includes/netdata_softirq.h create mode 100644 kernel/softirq_kern.c diff --git a/includes/netdata_ebpf.h b/includes/netdata_ebpf.h index 221f6f46..4f5706cc 100644 --- a/includes/netdata_ebpf.h +++ b/includes/netdata_ebpf.h @@ -21,6 +21,7 @@ This header has the common definitions for all `.c` files. #include "netdata_mount.h" #include "netdata_process.h" #include "netdata_socket.h" +#include "netdata_softirq.h" #include "netdata_sync.h" #include "netdata_swap.h" #include "netdata_vfs.h" diff --git a/includes/netdata_softirq.h b/includes/netdata_softirq.h new file mode 100644 index 00000000..14bd6689 --- /dev/null +++ b/includes/netdata_softirq.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef _NETDATA_SOFTIRQ_H_ +#define _NETDATA_SOFTIRQ_H_ 1 + +#define NETDATA_SOFTIRQ_MAX_IRQS 10 + +// /sys/kernel/debug/tracing/events/irq/softirq_entry +struct netdata_softirq_entry { + u64 pad; // This is not used with eBPF + u32 vec; // offset:8; size:4; signed:0; +}; + +// /sys/kernel/debug/tracing/events/irq/softirq_exit +struct netdata_softirq_exit { + u64 pad; // This is not used with eBPF + u32 vec; // offset:8; size:4; signed:0; +}; + +typedef struct softirq_val { + // incremental counter storing the total latency so far. + u64 latency; + + // temporary timestamp stored at the entry handler, to be diff'd with a + // timestamp at the exit handler, to get the latency to add to the + // `latency` field. + u64 ts; +} softirq_val_t; + +#endif /* _NETDATA_SOFTIRQ_H_ */ diff --git a/kernel/Makefile b/kernel/Makefile index 650bc8b0..cff026b7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -44,8 +44,9 @@ NETDATA_APPS= btrfs \ mount \ msync \ nfs \ - socket \ process \ + socket \ + softirq \ sync \ sync_file_range \ syncfs \ diff --git a/kernel/README.md b/kernel/README.md index f3f66825..6321b33c 100644 --- a/kernel/README.md +++ b/kernel/README.md @@ -28,6 +28,7 @@ Right now we have the following `eBPF` program collectors: - `nfs_kern.c` : provides nfs monitoring. - `process_kern.c` : provides process, file and VFS stats. - `socket_kern.c` : provides network stats; +- `softirq_kern.c` : provides software interrupt (soft IRQ) latency monitoring. - `swap_kern.c` : provides swap stats; - `sync_file_range_kern.c`: monitor calls for syscall `sync_file_range`. - `sync_kern.c` : monitor calls for syscall `sync`. diff --git a/kernel/hardirq_kern.c b/kernel/hardirq_kern.c index 7c9b9c28..22cca878 100644 --- a/kernel/hardirq_kern.c +++ b/kernel/hardirq_kern.c @@ -42,13 +42,14 @@ int netdata_irq_handler_entry(struct netdata_irq_handler_entry *ptr) key.irq = ptr->irq; valp = bpf_map_lookup_elem(&tbl_hardirq, &key); if (!valp) { - valp = &val; val.latency = 0; TP_DATA_LOC_READ_CONST(val.name, ptr, ptr->data_loc_name, NETDATA_HARDIRQ_NAME_LEN); + } else { + val.latency = valp->latency; } - valp->ts = bpf_ktime_get_ns(); - bpf_map_update_elem(&tbl_hardirq, &key, valp, BPF_ANY); + val.ts = bpf_ktime_get_ns(); + bpf_map_update_elem(&tbl_hardirq, &key, &val, BPF_ANY); return 0; } @@ -85,12 +86,13 @@ int netdata_irq_ ##__type(struct netdata_irq_vectors_entry *ptr) \ idx = __enum_idx; \ valp = bpf_map_lookup_elem(&tbl_hardirq_static, &idx); \ if (!valp) { \ - valp = &val; \ val.latency = 0; \ + } else { \ + val.latency = valp->latency; \ } \ \ - valp->ts = bpf_ktime_get_ns(); \ - bpf_map_update_elem(&tbl_hardirq_static, &idx, valp, BPF_ANY); \ + val.ts = bpf_ktime_get_ns(); \ + bpf_map_update_elem(&tbl_hardirq_static, &idx, &val, BPF_ANY); \ \ return 0; \ } diff --git a/kernel/softirq_kern.c b/kernel/softirq_kern.c new file mode 100644 index 00000000..58bec19d --- /dev/null +++ b/kernel/softirq_kern.c @@ -0,0 +1,72 @@ +#define KBUILD_MODNAME "softirq_netdata" +#include +#include +#include + +#include "bpf_helpers.h" +#include "netdata_ebpf.h" + +/************************************************************************************ + * MAPS + ***********************************************************************************/ + +// maps from irq index to latency. +struct bpf_map_def SEC("maps") tbl_softirq = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(softirq_val_t), + .max_entries = NETDATA_SOFTIRQ_MAX_IRQS +}; + +/************************************************************************************ + * SOFTIRQ SECTION + ***********************************************************************************/ + +SEC("tracepoint/irq/softirq_entry") +int netdata_softirq_entry(struct netdata_softirq_entry *ptr) +{ + softirq_val_t *valp, val = {}; + u32 vec = ptr->vec; + + // out-of-range index. + if (vec > NETDATA_SOFTIRQ_MAX_IRQS-1) { + return 0; + } + + valp = bpf_map_lookup_elem(&tbl_softirq, &vec); + if (!valp) { + val.latency = 0; + } else { + val.latency = valp->latency; + } + + val.ts = bpf_ktime_get_ns(); + bpf_map_update_elem(&tbl_softirq, &vec, &val, BPF_ANY); + + return 0; +} + +SEC("tracepoint/irq/softirq_exit") +int netdata_softirq_exit(struct netdata_softirq_exit *ptr) +{ + softirq_val_t *valp; + u32 vec = ptr->vec; + + // out-of-range index. + if (vec > NETDATA_SOFTIRQ_MAX_IRQS-1) { + return 0; + } + + valp = bpf_map_lookup_elem(&tbl_softirq, &vec); + if (!valp) { + return 0; + } + + // get time diff and convert to microseconds. + u64 latency = (bpf_ktime_get_ns() - valp->ts) / 1000; + libnetdata_update_u64(&valp->latency, latency); + + return 0; +} + +char _license[] SEC("license") = "GPL";