Skip to content

Commit

Permalink
Software IRQ latency tracking (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
UmanShahzad authored Aug 23, 2021
1 parent d099cdc commit bc6e88e
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 7 deletions.
1 change: 1 addition & 0 deletions includes/netdata_ebpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
30 changes: 30 additions & 0 deletions includes/netdata_softirq.h
Original file line number Diff line number Diff line change
@@ -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_ */
3 changes: 2 additions & 1 deletion kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ NETDATA_APPS= btrfs \
mount \
msync \
nfs \
socket \
process \
socket \
softirq \
sync \
sync_file_range \
syncfs \
Expand Down
1 change: 1 addition & 0 deletions kernel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
14 changes: 8 additions & 6 deletions kernel/hardirq_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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; \
}
Expand Down
72 changes: 72 additions & 0 deletions kernel/softirq_kern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#define KBUILD_MODNAME "softirq_netdata"
#include <linux/bpf.h>
#include <linux/ptrace.h>
#include <linux/genhd.h>

#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";

0 comments on commit bc6e88e

Please sign in to comment.