Skip to content

Commit

Permalink
hardirq: add tracepoints for statically known hardware IRQs.
Browse files Browse the repository at this point in the history
  • Loading branch information
UmanShahzad committed Aug 12, 2021
1 parent 98698bd commit 9341f0b
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 5 deletions.
45 changes: 44 additions & 1 deletion includes/netdata_hardirq.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ struct netdata_irq_handler_entry {
};

// /sys/kernel/debug/tracing/events/irq/irq_handler_exit/
// https://elixir.bootlin.com/linux/latest/source/include/trace/events/block.h
struct netdata_irq_handler_exit {
u64 pad; // This is not used with eBPF
int irq; // offset:8; size:4; signed:1;
Expand All @@ -39,4 +38,48 @@ typedef struct hardirq_val {
char name[NETDATA_HARDIRQ_NAME_LEN];
} hardirq_val_t;

/************************************************************************************
* HARDIRQ STATIC
***********************************************************************************/

// all of the `irq_vectors` events, except `vector_*`, have the same format.
// cat /sys/kernel/debug/tracing/available_events | grep 'irq_vectors' | grep -v ':vector_'
struct netdata_irq_vectors_entry {
u64 pad; // This is not used with eBPF
int vector; // offset:8; size:4; signed:1;
};
struct netdata_irq_vectors_exit {
u64 pad; // This is not used with eBPF
int vector; // offset:8; size:4; signed:1;
};

// these represent static IRQs that aren't given an IRQ ID like the ones above.
// they each require separate entry/exit tracepoints to track.
enum netdata_hardirq_static {
NETDATA_HARDIRQ_STATIC_APIC_THERMAL,
NETDATA_HARDIRQ_STATIC_APIC_DEFERRED_ERROR,
NETDATA_HARDIRQ_STATIC_APIC_THRESHOLD,
NETDATA_HARDIRQ_STATIC_APIC_ERROR,
NETDATA_HARDIRQ_STATIC_APIC_SPURIOUS,
NETDATA_HARDIRQ_STATIC_FUNC_CALL,
NETDATA_HARDIRQ_STATIC_FUNC_CALL_SINGLE,
NETDATA_HARDIRQ_STATIC_RESCHEDULE,
NETDATA_HARDIRQ_STATIC_LOCAL_TIMER,
NETDATA_HARDIRQ_STATIC_IRQ_WORK,
NETDATA_HARDIRQ_STATIC_X86_PLATFORM_IPI,

// must be last; used as counter.
NETDATA_HARDIRQ_STATIC_END
};

typedef struct hardirq_static_val {
// incremental counter storing the total latency so far.
u64 latency;

// temporary timestamp stored at the IRQ entry handler, to be diff'd with a
// timestamp at the IRQ exit handler, to get the latency to add to the
// `latency` field.
u64 ts;
} hardirq_static_val_t;

#endif /* _NETDATA_HARDIRQ_H_ */
175 changes: 171 additions & 4 deletions kernel/hardirq_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
#include "netdata_ebpf.h"

/************************************************************************************
*
* MAPS
*
***********************************************************************************/

struct bpf_map_def SEC("maps") tbl_hardirq = {
Expand All @@ -23,10 +21,16 @@ struct bpf_map_def SEC("maps") tbl_hardirq = {
.max_entries = NETDATA_HARDIRQ_MAX_IRQS
};

// maps from enum index to latency.
struct bpf_map_def SEC("maps") tbl_hardirq_static = {
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(hardirq_static_val_t),
.max_entries = NETDATA_HARDIRQ_STATIC_END
};

/************************************************************************************
*
* HARDIRQ SECTION
*
***********************************************************************************/

SEC("tracepoint/irq/irq_handler_entry")
Expand Down Expand Up @@ -68,4 +72,167 @@ int netdata_irq_handler_exit(struct netdata_irq_handler_exit *ptr)
return 0;
}

/************************************************************************************
* HARDIRQ STATIC
***********************************************************************************/

#define HARDIRQ_STATIC_GEN_ENTRY(__type, __enum_idx) \
int netdata_irq_ ##__type(struct netdata_irq_vectors_entry *ptr) \
{ \
u32 idx; \
hardirq_static_val_t *valp, val = {}; \
\
idx = __enum_idx; \
valp = bpf_map_lookup_elem(&tbl_hardirq_static, &idx); \
if (!valp) { \
valp = &val; \
val.latency = 0; \
} \
\
valp->ts = bpf_ktime_get_ns(); \
bpf_map_update_elem(&tbl_hardirq_static, &idx, valp, BPF_ANY); \
\
return 0; \
}

#define HARDIRQ_STATIC_GEN_EXIT(__type, __enum_idx) \
int netdata_irq_ ##__type(struct netdata_irq_vectors_exit *ptr) \
{ \
u32 idx; \
hardirq_static_val_t *valp; \
\
idx = __enum_idx; \
valp = bpf_map_lookup_elem(&tbl_hardirq_static, &idx); \
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; \
}

SEC("tracepoint/irq_vectors/thermal_apic_entry")
HARDIRQ_STATIC_GEN_ENTRY(
thermal_apic_entry,
NETDATA_HARDIRQ_STATIC_APIC_THERMAL
)
SEC("tracepoint/irq_vectors/thermal_apic_exit")
HARDIRQ_STATIC_GEN_EXIT(
thermal_apic_exit,
NETDATA_HARDIRQ_STATIC_APIC_THERMAL
)

SEC("tracepoint/irq_vectors/threshold_apic_entry")
HARDIRQ_STATIC_GEN_ENTRY(
threshold_apic_entry,
NETDATA_HARDIRQ_STATIC_APIC_THRESHOLD
)
SEC("tracepoint/irq_vectors/threshold_apic_exit")
HARDIRQ_STATIC_GEN_EXIT(
threshold_apic_exit,
NETDATA_HARDIRQ_STATIC_APIC_THRESHOLD
)

SEC("tracepoint/irq_vectors/error_apic_entry")
HARDIRQ_STATIC_GEN_ENTRY(
error_apic_entry,
NETDATA_HARDIRQ_STATIC_APIC_ERROR
)
SEC("tracepoint/irq_vectors/error_apic_exit")
HARDIRQ_STATIC_GEN_EXIT(
error_apic_exit,
NETDATA_HARDIRQ_STATIC_APIC_ERROR
)

SEC("tracepoint/irq_vectors/deferred_error_apic_entry")
HARDIRQ_STATIC_GEN_ENTRY(
deferred_error_apic_entry,
NETDATA_HARDIRQ_STATIC_APIC_DEFERRED_ERROR
)
SEC("tracepoint/irq_vectors/deferred_error_apic_exit")
HARDIRQ_STATIC_GEN_EXIT(
deferred_error_apic_exit,
NETDATA_HARDIRQ_STATIC_APIC_DEFERRED_ERROR
)

SEC("tracepoint/irq_vectors/spurious_apic_entry")
HARDIRQ_STATIC_GEN_ENTRY(
spurious_apic_entry,
NETDATA_HARDIRQ_STATIC_APIC_SPURIOUS
)
SEC("tracepoint/irq_vectors/spurious_apic_exit")
HARDIRQ_STATIC_GEN_EXIT(
spurious_apic_exit,
NETDATA_HARDIRQ_STATIC_APIC_SPURIOUS
)

SEC("tracepoint/irq_vectors/call_function_entry")
HARDIRQ_STATIC_GEN_ENTRY(
call_function_entry,
NETDATA_HARDIRQ_STATIC_FUNC_CALL
)
SEC("tracepoint/irq_vectors/call_function_exit")
HARDIRQ_STATIC_GEN_EXIT(
call_function_exit,
NETDATA_HARDIRQ_STATIC_FUNC_CALL
)

SEC("tracepoint/irq_vectors/call_function_single_entry")
HARDIRQ_STATIC_GEN_ENTRY(
call_function_single_entry,
NETDATA_HARDIRQ_STATIC_FUNC_CALL_SINGLE
)
SEC("tracepoint/irq_vectors/call_function_single_exit")
HARDIRQ_STATIC_GEN_EXIT(
call_function_single_exit,
NETDATA_HARDIRQ_STATIC_FUNC_CALL_SINGLE
)

SEC("tracepoint/irq_vectors/reschedule_entry")
HARDIRQ_STATIC_GEN_ENTRY(
reschedule_entry,
NETDATA_HARDIRQ_STATIC_RESCHEDULE
)
SEC("tracepoint/irq_vectors/reschedule_exit")
HARDIRQ_STATIC_GEN_EXIT(
reschedule_exit,
NETDATA_HARDIRQ_STATIC_RESCHEDULE
)

SEC("tracepoint/irq_vectors/local_timer_entry")
HARDIRQ_STATIC_GEN_ENTRY(
local_timer_entry,
NETDATA_HARDIRQ_STATIC_LOCAL_TIMER
)
SEC("tracepoint/irq_vectors/local_timer_exit")
HARDIRQ_STATIC_GEN_EXIT(
local_timer_exit,
NETDATA_HARDIRQ_STATIC_LOCAL_TIMER
)

SEC("tracepoint/irq_vectors/irq_work_entry")
HARDIRQ_STATIC_GEN_ENTRY(
irq_work_entry,
NETDATA_HARDIRQ_STATIC_IRQ_WORK
)
SEC("tracepoint/irq_vectors/irq_work_exit")
HARDIRQ_STATIC_GEN_EXIT(
irq_work_exit,
NETDATA_HARDIRQ_STATIC_IRQ_WORK
)

SEC("tracepoint/irq_vectors/x86_platform_ipi_entry")
HARDIRQ_STATIC_GEN_ENTRY(
x86_platform_ipi_entry,
NETDATA_HARDIRQ_STATIC_X86_PLATFORM_IPI
)
SEC("tracepoint/irq_vectors/x86_platform_ipi_exit")
HARDIRQ_STATIC_GEN_EXIT(
x86_platform_ipi_exit,
NETDATA_HARDIRQ_STATIC_X86_PLATFORM_IPI
)

char _license[] SEC("license") = "GPL";

0 comments on commit 9341f0b

Please sign in to comment.