bpf: clang format the bpf codes.
Signed-off-by: Tonghao Zhang <tonghao@bamaicloud.com>
This commit is contained in:
parent
e6b9b84e24
commit
43964c0387
287
bpf/dropwatch.c
287
bpf/dropwatch.c
|
@ -1,195 +1,202 @@
|
|||
#include "vmlinux.h"
|
||||
#include "vmlinux_net.h"
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "bpf_ratelimit.h"
|
||||
#include "vmlinux_net.h"
|
||||
|
||||
#define TYPE_TCP_COMMON_DROP 1
|
||||
#define TYPE_TCP_SYN_FLOOD 2
|
||||
#define TYPE_TCP_LISTEN_OVERFLOW_HANDSHAKE1 3
|
||||
#define TYPE_TCP_LISTEN_OVERFLOW_HANDSHAKE3 4
|
||||
#define TYPE_TCP_COMMON_DROP 1
|
||||
#define TYPE_TCP_SYN_FLOOD 2
|
||||
#define TYPE_TCP_LISTEN_OVERFLOW_HANDSHAKE1 3
|
||||
#define TYPE_TCP_LISTEN_OVERFLOW_HANDSHAKE3 4
|
||||
|
||||
#define SK_FL_PROTO_SHIFT 8
|
||||
#define SK_FL_PROTO_MASK 0x0000ff00
|
||||
#define SK_FL_TYPE_SHIFT 16
|
||||
#define SK_FL_TYPE_MASK 0xffff0000
|
||||
#define SK_FL_PROTO_SHIFT 8
|
||||
#define SK_FL_PROTO_MASK 0x0000ff00
|
||||
#define SK_FL_TYPE_SHIFT 16
|
||||
#define SK_FL_TYPE_MASK 0xffff0000
|
||||
|
||||
struct perf_event_t {
|
||||
u64 tgid_pid;
|
||||
u32 saddr;
|
||||
u32 daddr;
|
||||
u16 sport;
|
||||
u16 dport;
|
||||
u32 seq;
|
||||
u32 ack_seq;
|
||||
u32 queue_mapping;
|
||||
u64 pkt_len;
|
||||
s64 stack_size;
|
||||
u64 stack[PERF_MAX_STACK_DEPTH];
|
||||
u32 sk_max_ack_backlog;
|
||||
u8 state;
|
||||
u8 type;
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
u64 tgid_pid;
|
||||
u32 saddr;
|
||||
u32 daddr;
|
||||
u16 sport;
|
||||
u16 dport;
|
||||
u32 seq;
|
||||
u32 ack_seq;
|
||||
u32 queue_mapping;
|
||||
u64 pkt_len;
|
||||
s64 stack_size;
|
||||
u64 stack[PERF_MAX_STACK_DEPTH];
|
||||
u32 sk_max_ack_backlog;
|
||||
u8 state;
|
||||
u8 type;
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
};
|
||||
|
||||
/* format: /sys/kernel/debug/tracing/events/skb/kfree_skb/format */
|
||||
struct kfree_skb_args {
|
||||
unsigned long long pad;
|
||||
unsigned long long pad;
|
||||
|
||||
void *skbaddr;
|
||||
void *location;
|
||||
u16 protocol;
|
||||
void *skbaddr;
|
||||
void *location;
|
||||
u16 protocol;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
} perf_events SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(key_size, sizeof(u32));
|
||||
__uint(value_size, sizeof(struct perf_event_t));
|
||||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(key_size, sizeof(u32));
|
||||
__uint(value_size, sizeof(struct perf_event_t));
|
||||
} dropwatch_stackmap SEC(".maps");
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
||||
static const struct perf_event_t zero_data = {};
|
||||
static const u32 stackmap_key = 0;
|
||||
static const u32 stackmap_key = 0;
|
||||
|
||||
BPF_RATELIMIT(rate, 1, 100); // 100/s
|
||||
|
||||
struct sock___5_10 {
|
||||
u16 sk_type;
|
||||
u16 sk_protocol;
|
||||
}__attribute__((preserve_access_index));
|
||||
u16 sk_type;
|
||||
u16 sk_protocol;
|
||||
} __attribute__((preserve_access_index));
|
||||
|
||||
static void sk_get_type_and_protocol(struct sock *sk, u16 *protocol, u16 *type)
|
||||
{
|
||||
// kernel version <= 4.18
|
||||
//
|
||||
// struct sock {
|
||||
// unsigned int __sk_flags_offset[0];
|
||||
// #ifdef __BIG_ENDIAN_BITFIELD
|
||||
// #define SK_FL_PROTO_SHIFT 16
|
||||
// #define SK_FL_PROTO_MASK 0x00ff0000
|
||||
// #
|
||||
// #define SK_FL_TYPE_SHIFT 0
|
||||
// #define SK_FL_TYPE_MASK 0x0000ffff
|
||||
// #else
|
||||
// #define SK_FL_PROTO_SHIFT 8
|
||||
// #define SK_FL_PROTO_MASK 0x0000ff00
|
||||
// #
|
||||
// #define SK_FL_TYPE_SHIFT 16
|
||||
// #define SK_FL_TYPE_MASK 0xffff0000
|
||||
// #endif
|
||||
//
|
||||
// unsigned int sk_padding : 1,
|
||||
// sk_kern_sock : 1,
|
||||
// sk_no_check_tx : 1,
|
||||
// sk_no_check_rx : 1,
|
||||
// sk_userlocks : 4,
|
||||
// sk_protocol : 8,
|
||||
// sk_type : 16;
|
||||
// }
|
||||
if (bpf_core_field_exists(sk->__sk_flags_offset)) {
|
||||
u32 sk_flags;
|
||||
// kernel version <= 4.18
|
||||
//
|
||||
// struct sock {
|
||||
// unsigned int __sk_flags_offset[0];
|
||||
// #ifdef __BIG_ENDIAN_BITFIELD
|
||||
// #define SK_FL_PROTO_SHIFT 16
|
||||
// #define SK_FL_PROTO_MASK 0x00ff0000
|
||||
// #
|
||||
// #define SK_FL_TYPE_SHIFT 0
|
||||
// #define SK_FL_TYPE_MASK 0x0000ffff
|
||||
// #else
|
||||
// #define SK_FL_PROTO_SHIFT 8
|
||||
// #define SK_FL_PROTO_MASK 0x0000ff00
|
||||
// #
|
||||
// #define SK_FL_TYPE_SHIFT 16
|
||||
// #define SK_FL_TYPE_MASK 0xffff0000
|
||||
// #endif
|
||||
//
|
||||
// unsigned int sk_padding : 1,
|
||||
// sk_kern_sock : 1,
|
||||
// sk_no_check_tx : 1,
|
||||
// sk_no_check_rx : 1,
|
||||
// sk_userlocks : 4,
|
||||
// sk_protocol : 8,
|
||||
// sk_type : 16;
|
||||
// }
|
||||
if (bpf_core_field_exists(sk->__sk_flags_offset)) {
|
||||
u32 sk_flags;
|
||||
|
||||
bpf_probe_read(&sk_flags, sizeof(sk_flags), &sk->__sk_flags_offset);
|
||||
*protocol = sk_flags >> SK_FL_PROTO_SHIFT;
|
||||
*type = sk_flags >> SK_FL_TYPE_SHIFT;
|
||||
return;
|
||||
}
|
||||
bpf_probe_read(&sk_flags, sizeof(sk_flags),
|
||||
&sk->__sk_flags_offset);
|
||||
*protocol = sk_flags >> SK_FL_PROTO_SHIFT;
|
||||
*type = sk_flags >> SK_FL_TYPE_SHIFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// kernel version >= 5.10
|
||||
//
|
||||
// struct sock {
|
||||
// u16 sk_type;
|
||||
// u16 sk_protocol;
|
||||
// }
|
||||
struct sock___5_10 *sk_new = (struct sock___5_10 *)sk;
|
||||
// kernel version >= 5.10
|
||||
//
|
||||
// struct sock {
|
||||
// u16 sk_type;
|
||||
// u16 sk_protocol;
|
||||
// }
|
||||
struct sock___5_10 *sk_new = (struct sock___5_10 *)sk;
|
||||
|
||||
*protocol = BPF_CORE_READ(sk_new, sk_protocol);
|
||||
*type = BPF_CORE_READ(sk_new, sk_type);
|
||||
return;
|
||||
*protocol = BPF_CORE_READ(sk_new, sk_protocol);
|
||||
*type = BPF_CORE_READ(sk_new, sk_type);
|
||||
return;
|
||||
}
|
||||
|
||||
SEC("tracepoint/skb/kfree_skb")
|
||||
int bpf_kfree_skb_prog(struct kfree_skb_args *ctx)
|
||||
{
|
||||
struct sk_buff *skb = ctx->skbaddr;
|
||||
struct perf_event_t *data = NULL;
|
||||
struct sock_common *sk_common;
|
||||
struct tcphdr tcphdr;
|
||||
struct iphdr iphdr;
|
||||
struct sock *sk;
|
||||
u16 protocol = 0;
|
||||
u16 type = 0;
|
||||
u8 state = 0;
|
||||
struct sk_buff *skb = ctx->skbaddr;
|
||||
struct perf_event_t *data = NULL;
|
||||
struct sock_common *sk_common;
|
||||
struct tcphdr tcphdr;
|
||||
struct iphdr iphdr;
|
||||
struct sock *sk;
|
||||
u16 protocol = 0;
|
||||
u16 type = 0;
|
||||
u8 state = 0;
|
||||
|
||||
/* only for IP && TCP */
|
||||
if (ctx->protocol != ETH_P_IP)
|
||||
return 0;
|
||||
/* only for IP && TCP */
|
||||
if (ctx->protocol != ETH_P_IP)
|
||||
return 0;
|
||||
|
||||
bpf_probe_read(&iphdr, sizeof(iphdr), skb_network_header(skb));
|
||||
if (iphdr.protocol != IPPROTO_TCP)
|
||||
return 0;
|
||||
bpf_probe_read(&iphdr, sizeof(iphdr), skb_network_header(skb));
|
||||
if (iphdr.protocol != IPPROTO_TCP)
|
||||
return 0;
|
||||
|
||||
sk = BPF_CORE_READ(skb, sk);
|
||||
if (!sk)
|
||||
return 0;
|
||||
sk_common = (struct sock_common *)sk;
|
||||
sk = BPF_CORE_READ(skb, sk);
|
||||
if (!sk)
|
||||
return 0;
|
||||
sk_common = (struct sock_common *)sk;
|
||||
|
||||
// filter the sock by AF_INET, SOCK_STREAM, IPPROTO_TCP
|
||||
if (BPF_CORE_READ(sk_common, skc_family) != AF_INET)
|
||||
return 0;
|
||||
// filter the sock by AF_INET, SOCK_STREAM, IPPROTO_TCP
|
||||
if (BPF_CORE_READ(sk_common, skc_family) != AF_INET)
|
||||
return 0;
|
||||
|
||||
sk_get_type_and_protocol(sk, &protocol, &type);
|
||||
if ((u8)protocol != IPPROTO_TCP || type != SOCK_STREAM)
|
||||
return 0;
|
||||
sk_get_type_and_protocol(sk, &protocol, &type);
|
||||
if ((u8)protocol != IPPROTO_TCP || type != SOCK_STREAM)
|
||||
return 0;
|
||||
|
||||
// filter not CLOSE
|
||||
state = BPF_CORE_READ(sk_common, skc_state);
|
||||
if (state == TCP_CLOSE || state == 0)
|
||||
return 0;
|
||||
// filter not CLOSE
|
||||
state = BPF_CORE_READ(sk_common, skc_state);
|
||||
if (state == TCP_CLOSE || state == 0)
|
||||
return 0;
|
||||
|
||||
// ratelimit
|
||||
if (bpf_ratelimited(&rate))
|
||||
return 0;
|
||||
// ratelimit
|
||||
if (bpf_ratelimited(&rate))
|
||||
return 0;
|
||||
|
||||
data = bpf_map_lookup_elem(&dropwatch_stackmap, &stackmap_key);
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
data = bpf_map_lookup_elem(&dropwatch_stackmap, &stackmap_key);
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bpf_probe_read(&tcphdr, sizeof(tcphdr), skb_transport_header(skb));
|
||||
bpf_probe_read(&tcphdr, sizeof(tcphdr), skb_transport_header(skb));
|
||||
|
||||
/* event */
|
||||
data->tgid_pid = bpf_get_current_pid_tgid();
|
||||
bpf_get_current_comm(&data->comm, sizeof(data->comm));
|
||||
data->type = TYPE_TCP_COMMON_DROP;
|
||||
data->state = state;
|
||||
data->saddr = iphdr.saddr;
|
||||
data->daddr = iphdr.daddr;
|
||||
data->sport = tcphdr.source;
|
||||
data->dport = tcphdr.dest;
|
||||
data->seq = tcphdr.seq;
|
||||
data->ack_seq = tcphdr.ack_seq;
|
||||
data->pkt_len = BPF_CORE_READ(skb, len);
|
||||
data->queue_mapping = BPF_CORE_READ(skb, queue_mapping);
|
||||
data->stack_size = bpf_get_stack(ctx, data->stack, sizeof(data->stack), 0);
|
||||
data->sk_max_ack_backlog = 0; // ignore sk_max_ack_backlog in dropwatch case.
|
||||
/* event */
|
||||
data->tgid_pid = bpf_get_current_pid_tgid();
|
||||
bpf_get_current_comm(&data->comm, sizeof(data->comm));
|
||||
data->type = TYPE_TCP_COMMON_DROP;
|
||||
data->state = state;
|
||||
data->saddr = iphdr.saddr;
|
||||
data->daddr = iphdr.daddr;
|
||||
data->sport = tcphdr.source;
|
||||
data->dport = tcphdr.dest;
|
||||
data->seq = tcphdr.seq;
|
||||
data->ack_seq = tcphdr.ack_seq;
|
||||
data->pkt_len = BPF_CORE_READ(skb, len);
|
||||
data->queue_mapping = BPF_CORE_READ(skb, queue_mapping);
|
||||
data->stack_size =
|
||||
bpf_get_stack(ctx, data->stack, sizeof(data->stack), 0);
|
||||
data->sk_max_ack_backlog =
|
||||
0; // ignore sk_max_ack_backlog in dropwatch case.
|
||||
|
||||
// output
|
||||
bpf_perf_event_output(ctx, &perf_events, COMPAT_BPF_F_CURRENT_CPU, data, sizeof(*data));
|
||||
// output
|
||||
bpf_perf_event_output(ctx, &perf_events, COMPAT_BPF_F_CURRENT_CPU, data,
|
||||
sizeof(*data));
|
||||
|
||||
// clean
|
||||
bpf_map_update_elem(&dropwatch_stackmap, &stackmap_key, &zero_data, COMPAT_BPF_EXIST);
|
||||
return 0;
|
||||
// clean
|
||||
bpf_map_update_elem(&dropwatch_stackmap, &stackmap_key, &zero_data,
|
||||
COMPAT_BPF_EXIST);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The current kernel does not support kprobe+offset very well, waiting for kpatch to come online.
|
||||
// The current kernel does not support kprobe+offset very well, waiting for
|
||||
// kpatch to come online.
|
||||
#if 0
|
||||
static int fill_overflow_event(void *ctx, u8 type, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "vmlinux.h"
|
||||
#include "bpf_common.h"
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "bpf_ratelimit.h"
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
@ -10,16 +12,15 @@ char __license[] SEC("license") = "Dual MIT/GPL";
|
|||
#define CPU_NUM 128
|
||||
BPF_RATELIMIT_IN_MAP(rate, 1, CPU_NUM * 10000, 0);
|
||||
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
} hungtask_perf_events SEC(".maps");
|
||||
|
||||
struct hungtask_info {
|
||||
int32_t pid;
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
int32_t pid;
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
};
|
||||
|
||||
struct tracepoint_args {
|
||||
|
@ -31,13 +32,14 @@ struct tracepoint_args {
|
|||
SEC("tracepoint/sched/sched_process_hang")
|
||||
int tracepoint_sched_process_hang(struct tracepoint_args *ctx)
|
||||
{
|
||||
struct hungtask_info info = {};
|
||||
struct hungtask_info info = {};
|
||||
|
||||
if (bpf_ratelimited_in_map(ctx, rate))
|
||||
return 0;
|
||||
info.pid = ctx->pid;
|
||||
// custom defined struct can't use BPF_CORE_READ_STR_INTO()
|
||||
if (bpf_ratelimited_in_map(ctx, rate))
|
||||
return 0;
|
||||
|
||||
info.pid = ctx->pid;
|
||||
bpf_probe_read_str(&info.comm, COMPAT_TASK_COMM_LEN, ctx->comm);
|
||||
bpf_perf_event_output(ctx, &hungtask_perf_events, COMPAT_BPF_F_CURRENT_CPU, &info, sizeof(info));
|
||||
return 0;
|
||||
bpf_perf_event_output(ctx, &hungtask_perf_events,
|
||||
COMPAT_BPF_F_CURRENT_CPU, &info, sizeof(info));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ int ad_disable(struct pt_regs *ctx)
|
|||
// ko module and CO-RE relocation is not supported directly at old
|
||||
// kernel
|
||||
u64 nothing = 0;
|
||||
bpf_perf_event_output(ctx, &ad_event_map, COMPAT_BPF_F_CURRENT_CPU, ¬hing,
|
||||
sizeof(nothing));
|
||||
bpf_perf_event_output(ctx, &ad_event_map, COMPAT_BPF_F_CURRENT_CPU,
|
||||
¬hing, sizeof(nothing));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include "bpf_common.h"
|
||||
#include "vmlinux.h"
|
||||
#include "vmlinux_sched.h"
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "vmlinux_sched.h"
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
||||
struct mem_cgroup_metric {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "vmlinux.h"
|
||||
#include "bpf_common.h"
|
||||
#include "bpf_func_trace.h"
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "bpf_func_trace.h"
|
||||
|
||||
struct mm_free_compact_entry {
|
||||
/* host: compaction latency */
|
||||
unsigned long compaction_stat;
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
#include "vmlinux.h"
|
||||
#include "bpf_common.h"
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
|
||||
#define NSEC_PER_MSEC 1000000UL
|
||||
#define NSEC_PER_USEC 1000UL
|
||||
#define NR_SOFTIRQS_MAX 16 // must be 2^order
|
||||
#include "bpf_common.h"
|
||||
|
||||
#define NSEC_PER_MSEC 1000000UL
|
||||
#define NSEC_PER_USEC 1000UL
|
||||
#define NR_SOFTIRQS_MAX 16 // must be 2^order
|
||||
|
||||
enum lat_zone {
|
||||
LAT_ZONE0=0, // 0 ~ 10us
|
||||
LAT_ZONE1, // 10us ~ 100us
|
||||
LAT_ZONE2, // 100us ~ 1ms
|
||||
LAT_ZONE3, // 1ms ~ inf
|
||||
LAT_ZONE0 = 0, // 0 ~ 10us
|
||||
LAT_ZONE1, // 10us ~ 100us
|
||||
LAT_ZONE2, // 100us ~ 1ms
|
||||
LAT_ZONE3, // 1ms ~ inf
|
||||
LAT_ZONE_MAX,
|
||||
};
|
||||
|
||||
|
@ -31,12 +33,12 @@ struct softirq_lat {
|
|||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||
//key -> NR_SOFTIRQS
|
||||
// key -> NR_SOFTIRQS
|
||||
__type(key, u32);
|
||||
// value -> ts, record softirq_raise start time
|
||||
__type(value, u64);
|
||||
__uint(max_entries, NR_SOFTIRQS);
|
||||
} silat_map SEC(".maps");//softirq latency map
|
||||
} silat_map SEC(".maps"); // softirq latency map
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
|
@ -56,8 +58,7 @@ void probe_softirq_raise(struct tp_softirq *ctx)
|
|||
bpf_map_update_elem(&silat_map, &nr, &now, COMPAT_BPF_ANY);
|
||||
}
|
||||
|
||||
static void
|
||||
calc_softirq_latency(struct softirq_lat *lat_mc, u32 nr, u64 now)
|
||||
static void calc_softirq_latency(struct softirq_lat *lat_mc, u32 nr, u64 now)
|
||||
{
|
||||
u64 lat, *ts;
|
||||
|
||||
|
@ -67,15 +68,19 @@ calc_softirq_latency(struct softirq_lat *lat_mc, u32 nr, u64 now)
|
|||
|
||||
lat = now - *ts;
|
||||
|
||||
//update to metrics
|
||||
if (lat < 10 * NSEC_PER_USEC) { //10us
|
||||
__sync_fetch_and_add(&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE0], 1);
|
||||
} else if (lat < 100 * NSEC_PER_USEC) {//100us
|
||||
__sync_fetch_and_add(&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE1], 1);
|
||||
} else if (lat < 1 * NSEC_PER_MSEC) {//1ms
|
||||
__sync_fetch_and_add(&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE2], 1);
|
||||
} else {//1ms+
|
||||
__sync_fetch_and_add(&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE3], 1);
|
||||
// update to metrics
|
||||
if (lat < 10 * NSEC_PER_USEC) { // 10us
|
||||
__sync_fetch_and_add(
|
||||
&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE0], 1);
|
||||
} else if (lat < 100 * NSEC_PER_USEC) { // 100us
|
||||
__sync_fetch_and_add(
|
||||
&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE1], 1);
|
||||
} else if (lat < 1 * NSEC_PER_MSEC) { // 1ms
|
||||
__sync_fetch_and_add(
|
||||
&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE2], 1);
|
||||
} else { // 1ms+
|
||||
__sync_fetch_and_add(
|
||||
&lat_mc->silat[nr & (NR_SOFTIRQS_MAX - 1)][LAT_ZONE3], 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
183
bpf/netrecvlat.c
183
bpf/netrecvlat.c
|
@ -1,112 +1,117 @@
|
|||
//go:build ignore
|
||||
// go:build ignore
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "vmlinux_net.h"
|
||||
#include "bpf_ratelimit.h"
|
||||
#include "vmlinux_net.h"
|
||||
|
||||
volatile const long long mono_wall_offset = 0;
|
||||
volatile const long long to_netif = 5 * 1000 * 1000; // 5ms
|
||||
volatile const long long to_tcpv4 = 10 * 1000 * 1000; // 10ms
|
||||
volatile const long long to_user_copy = 115 * 1000 * 1000; // 115ms
|
||||
volatile const long long to_netif = 5 * 1000 * 1000; // 5ms
|
||||
volatile const long long to_tcpv4 = 10 * 1000 * 1000; // 10ms
|
||||
volatile const long long to_user_copy = 115 * 1000 * 1000; // 115ms
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
BPF_RATELIMIT(rate, 1, 100);
|
||||
|
||||
struct netif_receive_skb_args {
|
||||
struct trace_entry entry;
|
||||
struct sk_buff *skb;
|
||||
struct trace_entry entry;
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
|
||||
struct skb_copy_datagram_iovec_args {
|
||||
struct trace_entry entry;
|
||||
struct sk_buff *skb;
|
||||
struct trace_entry entry;
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
|
||||
struct perf_event_t {
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
u64 latency;
|
||||
u64 tgid_pid;
|
||||
u64 pkt_len;
|
||||
u16 sport;
|
||||
u16 dport;
|
||||
u32 saddr;
|
||||
u32 daddr;
|
||||
u32 seq;
|
||||
u32 ack_seq;
|
||||
u8 state;
|
||||
u8 where;
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
u64 latency;
|
||||
u64 tgid_pid;
|
||||
u64 pkt_len;
|
||||
u16 sport;
|
||||
u16 dport;
|
||||
u32 saddr;
|
||||
u32 daddr;
|
||||
u32 seq;
|
||||
u32 ack_seq;
|
||||
u8 state;
|
||||
u8 where;
|
||||
};
|
||||
|
||||
enum skb_rcv_where {
|
||||
TO_NETIF_RCV,
|
||||
TO_TCPV4_RCV,
|
||||
TO_USER_COPY,
|
||||
TO_NETIF_RCV,
|
||||
TO_TCPV4_RCV,
|
||||
TO_USER_COPY,
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
} net_recv_lat_event_map SEC(".maps");
|
||||
|
||||
struct mix {
|
||||
struct iphdr *ip_hdr;
|
||||
u64 lat;
|
||||
u8 state;
|
||||
u8 where;
|
||||
struct iphdr *ip_hdr;
|
||||
u64 lat;
|
||||
u8 state;
|
||||
u8 where;
|
||||
};
|
||||
|
||||
static inline u64 delta_now_skb_tstamp(struct sk_buff *skb)
|
||||
{
|
||||
u64 tstamp = BPF_CORE_READ(skb, tstamp);
|
||||
// although the skb->tstamp record is opened in user space by SOF_TIMESTAMPING_RX_SOFTWARE,
|
||||
// it is still 0 in the following cases:
|
||||
// unix recv, netlink recv, few virtual dev(e.g. tun dev, napi dsabled)
|
||||
if (!tstamp)
|
||||
return 0;
|
||||
// although the skb->tstamp record is opened in user space by
|
||||
// SOF_TIMESTAMPING_RX_SOFTWARE, it is still 0 in the following cases:
|
||||
// unix recv, netlink recv, few virtual dev(e.g. tun dev, napi dsabled)
|
||||
if (!tstamp)
|
||||
return 0;
|
||||
|
||||
return bpf_ktime_get_ns() + mono_wall_offset - tstamp;
|
||||
return bpf_ktime_get_ns() + mono_wall_offset - tstamp;
|
||||
}
|
||||
|
||||
static inline u8 get_state(struct sk_buff *skb)
|
||||
{
|
||||
return BPF_CORE_READ(skb, sk, __sk_common.skc_state);
|
||||
return BPF_CORE_READ(skb, sk, __sk_common.skc_state);
|
||||
}
|
||||
|
||||
static inline void fill_and_output_event(void *ctx, struct sk_buff *skb, struct mix *_mix)
|
||||
static inline void
|
||||
fill_and_output_event(void *ctx, struct sk_buff *skb, struct mix *_mix)
|
||||
{
|
||||
struct perf_event_t event = {};
|
||||
struct tcphdr tcp_hdr;
|
||||
struct tcphdr tcp_hdr;
|
||||
|
||||
// ratelimit
|
||||
if (bpf_ratelimited(&rate))
|
||||
return;
|
||||
// ratelimit
|
||||
if (bpf_ratelimited(&rate))
|
||||
return;
|
||||
|
||||
if (likely(_mix->where == TO_USER_COPY)) {
|
||||
event.tgid_pid = bpf_get_current_pid_tgid();
|
||||
bpf_get_current_comm(&event.comm, sizeof(event.comm));
|
||||
}
|
||||
|
||||
bpf_probe_read(&tcp_hdr, sizeof(tcp_hdr), skb_transport_header(skb));
|
||||
event.latency = _mix->lat;
|
||||
event.saddr = _mix->ip_hdr->saddr;
|
||||
event.daddr = _mix->ip_hdr->daddr;
|
||||
event.sport = tcp_hdr.source;
|
||||
event.dport = tcp_hdr.dest;
|
||||
event.seq = tcp_hdr.seq;
|
||||
event.ack_seq = tcp_hdr.ack_seq;
|
||||
event.pkt_len = BPF_CORE_READ(skb, len);
|
||||
event.state = _mix->state;
|
||||
event.where = _mix->where;
|
||||
if (likely(_mix->where == TO_USER_COPY)) {
|
||||
event.tgid_pid = bpf_get_current_pid_tgid();
|
||||
bpf_get_current_comm(&event.comm, sizeof(event.comm));
|
||||
}
|
||||
|
||||
bpf_perf_event_output(ctx, &net_recv_lat_event_map, COMPAT_BPF_F_CURRENT_CPU, &event, sizeof(struct perf_event_t));
|
||||
bpf_probe_read(&tcp_hdr, sizeof(tcp_hdr), skb_transport_header(skb));
|
||||
event.latency = _mix->lat;
|
||||
event.saddr = _mix->ip_hdr->saddr;
|
||||
event.daddr = _mix->ip_hdr->daddr;
|
||||
event.sport = tcp_hdr.source;
|
||||
event.dport = tcp_hdr.dest;
|
||||
event.seq = tcp_hdr.seq;
|
||||
event.ack_seq = tcp_hdr.ack_seq;
|
||||
event.pkt_len = BPF_CORE_READ(skb, len);
|
||||
event.state = _mix->state;
|
||||
event.where = _mix->where;
|
||||
|
||||
bpf_perf_event_output(ctx, &net_recv_lat_event_map,
|
||||
COMPAT_BPF_F_CURRENT_CPU, &event,
|
||||
sizeof(struct perf_event_t));
|
||||
}
|
||||
|
||||
SEC("tracepoint/net/netif_receive_skb")
|
||||
|
@ -114,39 +119,43 @@ int netif_receive_skb_prog(struct netif_receive_skb_args *args)
|
|||
{
|
||||
struct sk_buff *skb = args->skb;
|
||||
struct iphdr ip_hdr;
|
||||
u64 delta;
|
||||
u64 delta;
|
||||
|
||||
if (unlikely(BPF_CORE_READ(skb, protocol) != bpf_ntohs(ETH_P_IP))) // IPv4
|
||||
if (unlikely(BPF_CORE_READ(skb, protocol) !=
|
||||
bpf_ntohs(ETH_P_IP))) // IPv4
|
||||
return 0;
|
||||
|
||||
bpf_probe_read(&ip_hdr, sizeof(ip_hdr), skb_network_header(skb));
|
||||
if (ip_hdr.protocol != IPPROTO_TCP)
|
||||
return 0;
|
||||
if (ip_hdr.protocol != IPPROTO_TCP)
|
||||
return 0;
|
||||
|
||||
delta = delta_now_skb_tstamp(skb);
|
||||
if (delta < to_netif)
|
||||
return 0;
|
||||
delta = delta_now_skb_tstamp(skb);
|
||||
if (delta < to_netif)
|
||||
return 0;
|
||||
|
||||
fill_and_output_event(args, skb, &(struct mix){&ip_hdr, delta, 0, TO_NETIF_RCV});
|
||||
fill_and_output_event(args, skb,
|
||||
&(struct mix){&ip_hdr, delta, 0, TO_NETIF_RCV});
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("kprobe/tcp_v4_rcv")
|
||||
int tcp_v4_rcv_prog(struct pt_regs *ctx)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff*)PT_REGS_PARM1_CORE(ctx);
|
||||
struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1_CORE(ctx);
|
||||
struct iphdr ip_hdr;
|
||||
u64 delta;
|
||||
u64 delta;
|
||||
|
||||
delta = delta_now_skb_tstamp(skb);
|
||||
delta = delta_now_skb_tstamp(skb);
|
||||
if (delta < to_tcpv4)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
bpf_probe_read(&ip_hdr, sizeof(ip_hdr), skb_network_header(skb));
|
||||
fill_and_output_event(ctx, skb, &(struct mix){&ip_hdr, delta, get_state(skb), TO_TCPV4_RCV});
|
||||
bpf_probe_read(&ip_hdr, sizeof(ip_hdr), skb_network_header(skb));
|
||||
fill_and_output_event(
|
||||
ctx, skb,
|
||||
&(struct mix){&ip_hdr, delta, get_state(skb), TO_TCPV4_RCV});
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tracepoint/skb/skb_copy_datagram_iovec")
|
||||
|
@ -154,20 +163,22 @@ int skb_copy_datagram_iovec_prog(struct skb_copy_datagram_iovec_args *args)
|
|||
{
|
||||
struct sk_buff *skb = args->skb;
|
||||
struct iphdr ip_hdr;
|
||||
u64 delta;
|
||||
u64 delta;
|
||||
|
||||
if (unlikely(BPF_CORE_READ(skb, protocol) != bpf_ntohs(ETH_P_IP))) // IPv4
|
||||
if (unlikely(BPF_CORE_READ(skb, protocol) != bpf_ntohs(ETH_P_IP)))
|
||||
return 0;
|
||||
|
||||
bpf_probe_read(&ip_hdr, sizeof(ip_hdr), skb_network_header(skb));
|
||||
if (ip_hdr.protocol != IPPROTO_TCP)
|
||||
return 0;
|
||||
if (ip_hdr.protocol != IPPROTO_TCP)
|
||||
return 0;
|
||||
|
||||
delta = delta_now_skb_tstamp(skb);
|
||||
delta = delta_now_skb_tstamp(skb);
|
||||
if (delta < to_user_copy)
|
||||
return 0;
|
||||
|
||||
fill_and_output_event(args, skb, &(struct mix){&ip_hdr, delta, get_state(skb), TO_USER_COPY});
|
||||
|
||||
fill_and_output_event(
|
||||
args, skb,
|
||||
&(struct mix){&ip_hdr, delta, get_state(skb), TO_USER_COPY});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
70
bpf/oom.c
70
bpf/oom.c
|
@ -1,8 +1,10 @@
|
|||
#include "vmlinux.h"
|
||||
#include "bpf_common.h"
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "bpf_ratelimit.h"
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
@ -11,44 +13,48 @@ char __license[] SEC("license") = "Dual MIT/GPL";
|
|||
BPF_RATELIMIT_IN_MAP(rate, 1, CPU_NUM * 10000, 0);
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
} oom_perf_events SEC(".maps");
|
||||
|
||||
struct oom_info {
|
||||
char trigger_comm[COMPAT_TASK_COMM_LEN];
|
||||
char victim_comm[COMPAT_TASK_COMM_LEN];
|
||||
u32 trigger_pid;
|
||||
u32 victim_pid;
|
||||
u64 trigger_memcg_css;
|
||||
u64 victim_memcg_css;
|
||||
char trigger_comm[COMPAT_TASK_COMM_LEN];
|
||||
char victim_comm[COMPAT_TASK_COMM_LEN];
|
||||
u32 trigger_pid;
|
||||
u32 victim_pid;
|
||||
u64 trigger_memcg_css;
|
||||
u64 victim_memcg_css;
|
||||
};
|
||||
|
||||
SEC("kprobe/oom_kill_process")
|
||||
int kprobe_oom_kill_process(struct pt_regs *ctx)
|
||||
{
|
||||
struct oom_control *oc;
|
||||
struct oom_info info = {};
|
||||
struct task_struct *trigger_task, *victim_task;
|
||||
struct oom_control *oc;
|
||||
struct oom_info info = {};
|
||||
struct task_struct *trigger_task, *victim_task;
|
||||
|
||||
if (bpf_ratelimited_in_map(ctx, rate))
|
||||
return 0;
|
||||
if (bpf_ratelimited_in_map(ctx, rate))
|
||||
return 0;
|
||||
|
||||
oc = (void *)ctx->di;
|
||||
oc = (void *)ctx->di;
|
||||
|
||||
if (!oc)
|
||||
return 0;
|
||||
trigger_task = (struct task_struct *)bpf_get_current_task();
|
||||
victim_task = BPF_CORE_READ(oc, chosen);
|
||||
info.trigger_pid = BPF_CORE_READ(trigger_task, pid);
|
||||
info.victim_pid = BPF_CORE_READ(victim_task, pid);
|
||||
BPF_CORE_READ_STR_INTO(&info.trigger_comm, trigger_task, comm);
|
||||
BPF_CORE_READ_STR_INTO(&info.victim_comm, victim_task, comm);
|
||||
|
||||
info.victim_memcg_css = (u64)BPF_CORE_READ(victim_task, cgroups, subsys[4]);
|
||||
info.trigger_memcg_css = (u64)BPF_CORE_READ(trigger_task, cgroups, subsys[4]);
|
||||
|
||||
bpf_perf_event_output(ctx, &oom_perf_events, COMPAT_BPF_F_CURRENT_CPU, &info, sizeof(info));
|
||||
return 0;
|
||||
if (!oc)
|
||||
return 0;
|
||||
|
||||
trigger_task = (struct task_struct *)bpf_get_current_task();
|
||||
victim_task = BPF_CORE_READ(oc, chosen);
|
||||
info.trigger_pid = BPF_CORE_READ(trigger_task, pid);
|
||||
info.victim_pid = BPF_CORE_READ(victim_task, pid);
|
||||
BPF_CORE_READ_STR_INTO(&info.trigger_comm, trigger_task, comm);
|
||||
BPF_CORE_READ_STR_INTO(&info.victim_comm, victim_task, comm);
|
||||
|
||||
info.victim_memcg_css =
|
||||
(u64)BPF_CORE_READ(victim_task, cgroups, subsys[4]);
|
||||
info.trigger_memcg_css =
|
||||
(u64)BPF_CORE_READ(trigger_task, cgroups, subsys[4]);
|
||||
|
||||
bpf_perf_event_output(ctx, &oom_perf_events, COMPAT_BPF_F_CURRENT_CPU,
|
||||
&info, sizeof(info));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,84 +1,94 @@
|
|||
#include "vmlinux.h"
|
||||
#include "bpf_common.h"
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
|
||||
// defaultly, we use task_group address as key to operate map.
|
||||
#define TG_ADDR_KEY
|
||||
|
||||
#define TASK_RUNNING 0
|
||||
#define TASK_ON_RQ_QUEUED 1
|
||||
#define TASK_RUNNING 0
|
||||
#define TASK_ON_RQ_QUEUED 1
|
||||
|
||||
#define _(P) \
|
||||
({ \
|
||||
typeof(P) val = 0; \
|
||||
bpf_probe_read(&val, sizeof(val), &(P)); \
|
||||
val; \
|
||||
})
|
||||
#define _(P) \
|
||||
({ \
|
||||
typeof(P) val = 0; \
|
||||
bpf_probe_read(&val, sizeof(val), &(P)); \
|
||||
val; \
|
||||
})
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
||||
struct stat_t {
|
||||
unsigned long nvcsw; // task_group counts of voluntary context switch
|
||||
unsigned long nivcsw; // task_group counts of involuntary context switch
|
||||
unsigned long nlat_01; // task_group counts of sched latency range [0, 10)ms
|
||||
unsigned long nlat_02; // task_group counts of sched latency range [10, 20)ms
|
||||
unsigned long nlat_03; // task_group counts of sched latency range [20, 50)ms
|
||||
unsigned long nlat_04; // task_group counts of sched latency range [50, inf)ms
|
||||
unsigned long nvcsw; // task_group counts of voluntary context switch
|
||||
unsigned long nivcsw; // task_group counts of involuntary context switch
|
||||
unsigned long
|
||||
nlat_01; // task_group counts of sched latency range [0, 10)ms
|
||||
unsigned long
|
||||
nlat_02; // task_group counts of sched latency range [10, 20)ms
|
||||
unsigned long
|
||||
nlat_03; // task_group counts of sched latency range [20, 50)ms
|
||||
unsigned long
|
||||
nlat_04; // task_group counts of sched latency range [50, inf)ms
|
||||
};
|
||||
|
||||
struct g_stat_t {
|
||||
unsigned long g_nvcsw; // global counts of voluntary context switch
|
||||
unsigned long g_nvcsw; // global counts of voluntary context switch
|
||||
unsigned long g_nivcsw; // global counts of involuntary context switch
|
||||
unsigned long g_nlat_01; // global counts of sched latency range [0, 10)ms
|
||||
unsigned long g_nlat_02; // global counts of sched latency range [10, 20)ms
|
||||
unsigned long g_nlat_03; // global counts of sched latency range [20, 50)ms
|
||||
unsigned long g_nlat_04; // global counts of sched latency range [50, inf)ms
|
||||
unsigned long
|
||||
g_nlat_01; // global counts of sched latency range [0, 10)ms
|
||||
unsigned long
|
||||
g_nlat_02; // global counts of sched latency range [10, 20)ms
|
||||
unsigned long
|
||||
g_nlat_03; // global counts of sched latency range [20, 50)ms
|
||||
unsigned long
|
||||
g_nlat_04; // global counts of sched latency range [50, inf)ms
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__type(key, u32);
|
||||
__type(value, u64);
|
||||
// FIXME: is 10000 enough or too large?
|
||||
__uint(max_entries, 10000);
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__type(key, u32);
|
||||
__type(value, u64);
|
||||
// FIXME: is 10000 enough or too large?
|
||||
__uint(max_entries, 10000);
|
||||
} latency SEC(".maps");
|
||||
|
||||
struct stat_t;
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
#ifdef TG_ADDR_KEY
|
||||
__type(key, u64);
|
||||
__type(key, u64);
|
||||
#else
|
||||
__type(key, u32);
|
||||
__type(key, u32);
|
||||
#endif
|
||||
__type(value, struct stat_t);
|
||||
__uint(max_entries, 10000);
|
||||
__type(value, struct stat_t);
|
||||
__uint(max_entries, 10000);
|
||||
} cpu_tg_metric SEC(".maps");
|
||||
|
||||
struct g_stat_t;
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__type(key, u32);
|
||||
__type(value, struct g_stat_t);
|
||||
// all global counts are integrated in one g_stat_t struct
|
||||
__uint(max_entries, 1);
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__type(key, u32);
|
||||
__type(value, struct g_stat_t);
|
||||
// all global counts are integrated in one g_stat_t struct
|
||||
__uint(max_entries, 1);
|
||||
} cpu_host_metric SEC(".maps");
|
||||
|
||||
// record enqueue timestamp
|
||||
static int trace_enqueue(u32 pid)
|
||||
{
|
||||
//u64 *valp;
|
||||
u64 ts;
|
||||
// u64 *valp;
|
||||
u64 ts;
|
||||
|
||||
if (pid == 0)
|
||||
return 0;
|
||||
if (pid == 0)
|
||||
return 0;
|
||||
|
||||
ts = bpf_ktime_get_ns();
|
||||
bpf_map_update_elem(&latency, &pid, &ts, COMPAT_BPF_ANY);
|
||||
ts = bpf_ktime_get_ns();
|
||||
bpf_map_update_elem(&latency, &pid, &ts, COMPAT_BPF_ANY);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sched_wakeup_new_args {
|
||||
|
@ -93,7 +103,7 @@ struct sched_wakeup_new_args {
|
|||
SEC("tracepoint/sched/sched_wakeup_new")
|
||||
int sched_wakeup_new_entry(struct sched_wakeup_new_args *ctx)
|
||||
{
|
||||
return trace_enqueue(ctx->pid);
|
||||
return trace_enqueue(ctx->pid);
|
||||
}
|
||||
|
||||
struct sched_wakeup_args {
|
||||
|
@ -108,174 +118,180 @@ struct sched_wakeup_args {
|
|||
SEC("tracepoint/sched/sched_wakeup")
|
||||
int sched_wakeup_entry(struct sched_wakeup_new_args *ctx)
|
||||
{
|
||||
return trace_enqueue(ctx->pid);
|
||||
return trace_enqueue(ctx->pid);
|
||||
}
|
||||
|
||||
#define NSEC_PER_MSEC 1000000L
|
||||
SEC("raw_tracepoint/sched_switch")
|
||||
int sched_switch_entry(struct bpf_raw_tracepoint_args *ctx)
|
||||
{
|
||||
u32 prev_pid, next_pid, g_key = 0;
|
||||
u64 now, *tsp, delta;
|
||||
bool is_voluntary;
|
||||
struct stat_t *entry;
|
||||
struct g_stat_t *g_entry;
|
||||
u32 prev_pid, next_pid, g_key = 0;
|
||||
u64 now, *tsp, delta;
|
||||
bool is_voluntary;
|
||||
struct stat_t *entry;
|
||||
struct g_stat_t *g_entry;
|
||||
|
||||
// TP_PROTO(bool preempt, struct task_struct *prev, struct task_struct *next)
|
||||
struct task_struct *prev = (struct task_struct *)ctx->args[1];
|
||||
struct task_struct *next = (struct task_struct *)ctx->args[2];
|
||||
// TP_PROTO(bool preempt, struct task_struct *prev, struct task_struct
|
||||
// *next)
|
||||
struct task_struct *prev = (struct task_struct *)ctx->args[1];
|
||||
struct task_struct *next = (struct task_struct *)ctx->args[2];
|
||||
|
||||
#ifdef TG_ADDR_KEY
|
||||
// get task_group addr: task_struct->sched_task_group
|
||||
u64 key = (u64)_(prev->sched_task_group);
|
||||
// get task_group addr: task_struct->sched_task_group
|
||||
u64 key = (u64)_(prev->sched_task_group);
|
||||
#else
|
||||
// get pid ns id: task_struct->nsproxy->pid_ns_for_children->ns.inum
|
||||
u32 key = BPF_CORE_READ(prev, nsproxy, pid_ns_for_children, ns.inum);
|
||||
// get pid ns id: task_struct->nsproxy->pid_ns_for_children->ns.inum
|
||||
u32 key = BPF_CORE_READ(prev, nsproxy, pid_ns_for_children, ns.inum);
|
||||
#endif
|
||||
|
||||
long state;
|
||||
// to avoid compilation warning, use raw interface instead of macro _()
|
||||
bpf_probe_read(&state, sizeof(long), (void *)&(prev->state));
|
||||
long state;
|
||||
// to avoid compilation warning, use raw interface instead of macro _()
|
||||
bpf_probe_read(&state, sizeof(long), (void *)&(prev->state));
|
||||
|
||||
// ivcsw: treat like an enqueue event and store timestamp
|
||||
prev_pid = _(prev->pid);
|
||||
if (state == TASK_RUNNING) {
|
||||
if (prev_pid != 0) {
|
||||
now = bpf_ktime_get_ns();
|
||||
bpf_map_update_elem(&latency, &prev_pid, &now, COMPAT_BPF_ANY);
|
||||
}
|
||||
is_voluntary = 0;
|
||||
} else {
|
||||
is_voluntary = 1;
|
||||
}
|
||||
|
||||
g_entry = bpf_map_lookup_elem(&cpu_host_metric, &g_key);
|
||||
if (!g_entry) {
|
||||
// init global counts map
|
||||
struct g_stat_t g_new_stat = {
|
||||
.g_nvcsw = 0,
|
||||
.g_nivcsw = 0,
|
||||
.g_nlat_01 = 0,
|
||||
.g_nlat_02 = 0,
|
||||
.g_nlat_03 = 0,
|
||||
.g_nlat_04 = 0,
|
||||
};
|
||||
bpf_map_update_elem(&cpu_host_metric, &g_key, &g_new_stat, COMPAT_BPF_NOEXIST);
|
||||
g_entry = bpf_map_lookup_elem(&cpu_host_metric, &g_key);
|
||||
if (!g_entry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// When use pid namespace id as key, sometimes we would encounter
|
||||
// null id because task->nsproxy is freed, usually means that this
|
||||
// task is almost dead (zombie), so ignore it.
|
||||
if (key && prev_pid) {
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry) {
|
||||
struct stat_t new_stat = {
|
||||
.nvcsw = 0,
|
||||
.nivcsw = 0,
|
||||
.nlat_01 = 0,
|
||||
.nlat_02 = 0,
|
||||
.nlat_03 = 0,
|
||||
.nlat_04 = 0,
|
||||
};
|
||||
bpf_map_update_elem(&cpu_tg_metric, &key, &new_stat, COMPAT_BPF_NOEXIST);
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_voluntary) {
|
||||
__sync_fetch_and_add(&entry->nvcsw, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nvcsw, 1);
|
||||
// ivcsw: treat like an enqueue event and store timestamp
|
||||
prev_pid = _(prev->pid);
|
||||
if (state == TASK_RUNNING) {
|
||||
if (prev_pid != 0) {
|
||||
now = bpf_ktime_get_ns();
|
||||
bpf_map_update_elem(&latency, &prev_pid, &now,
|
||||
COMPAT_BPF_ANY);
|
||||
}
|
||||
is_voluntary = 0;
|
||||
} else {
|
||||
__sync_fetch_and_add(&entry->nivcsw, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nivcsw, 1);
|
||||
is_voluntary = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//trace_sched_switch is called under prev != next, no need to check again.
|
||||
g_entry = bpf_map_lookup_elem(&cpu_host_metric, &g_key);
|
||||
if (!g_entry) {
|
||||
// init global counts map
|
||||
struct g_stat_t g_new_stat = {
|
||||
.g_nvcsw = 0,
|
||||
.g_nivcsw = 0,
|
||||
.g_nlat_01 = 0,
|
||||
.g_nlat_02 = 0,
|
||||
.g_nlat_03 = 0,
|
||||
.g_nlat_04 = 0,
|
||||
};
|
||||
bpf_map_update_elem(&cpu_host_metric, &g_key, &g_new_stat,
|
||||
COMPAT_BPF_NOEXIST);
|
||||
g_entry = bpf_map_lookup_elem(&cpu_host_metric, &g_key);
|
||||
if (!g_entry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_pid = _(next->pid);
|
||||
// ignore idle
|
||||
if (next_pid == 0)
|
||||
return 0;
|
||||
// When use pid namespace id as key, sometimes we would encounter
|
||||
// null id because task->nsproxy is freed, usually means that this
|
||||
// task is almost dead (zombie), so ignore it.
|
||||
if (key && prev_pid) {
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry) {
|
||||
struct stat_t new_stat = {
|
||||
.nvcsw = 0,
|
||||
.nivcsw = 0,
|
||||
.nlat_01 = 0,
|
||||
.nlat_02 = 0,
|
||||
.nlat_03 = 0,
|
||||
.nlat_04 = 0,
|
||||
};
|
||||
bpf_map_update_elem(&cpu_tg_metric, &key, &new_stat,
|
||||
COMPAT_BPF_NOEXIST);
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fetch timestamp and calculate delta
|
||||
tsp = bpf_map_lookup_elem(&latency, &next_pid);
|
||||
if (tsp == 0 || *tsp == 0) {
|
||||
return 0; // missed enqueue
|
||||
}
|
||||
if (is_voluntary) {
|
||||
__sync_fetch_and_add(&entry->nvcsw, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nvcsw, 1);
|
||||
} else {
|
||||
__sync_fetch_and_add(&entry->nivcsw, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nivcsw, 1);
|
||||
}
|
||||
}
|
||||
|
||||
now = bpf_ktime_get_ns();
|
||||
delta = now - *tsp;
|
||||
bpf_map_delete_elem(&latency, &next_pid);
|
||||
// trace_sched_switch is called under prev != next, no need to check
|
||||
// again.
|
||||
|
||||
next_pid = _(next->pid);
|
||||
// ignore idle
|
||||
if (next_pid == 0)
|
||||
return 0;
|
||||
|
||||
// fetch timestamp and calculate delta
|
||||
tsp = bpf_map_lookup_elem(&latency, &next_pid);
|
||||
if (tsp == 0 || *tsp == 0) {
|
||||
return 0; // missed enqueue
|
||||
}
|
||||
|
||||
now = bpf_ktime_get_ns();
|
||||
delta = now - *tsp;
|
||||
bpf_map_delete_elem(&latency, &next_pid);
|
||||
|
||||
#ifdef TG_ADDR_KEY
|
||||
key = (u64)_(next->sched_task_group);
|
||||
key = (u64)_(next->sched_task_group);
|
||||
#else
|
||||
key = BPF_CORE_READ(next, nsproxy, pid_ns_for_children, ns.inum);
|
||||
key = BPF_CORE_READ(next, nsproxy, pid_ns_for_children, ns.inum);
|
||||
#endif
|
||||
|
||||
if (key) {
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry) {
|
||||
struct stat_t new_stat = {
|
||||
.nvcsw = 0,
|
||||
.nivcsw = 0,
|
||||
.nlat_01 = 0,
|
||||
.nlat_02 = 0,
|
||||
.nlat_03 = 0,
|
||||
.nlat_04 = 0,
|
||||
};
|
||||
bpf_map_update_elem(&cpu_tg_metric, &key, &new_stat, COMPAT_BPF_NOEXIST);
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry)
|
||||
return 0;
|
||||
}
|
||||
if (key) {
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry) {
|
||||
struct stat_t new_stat = {
|
||||
.nvcsw = 0,
|
||||
.nivcsw = 0,
|
||||
.nlat_01 = 0,
|
||||
.nlat_02 = 0,
|
||||
.nlat_03 = 0,
|
||||
.nlat_04 = 0,
|
||||
};
|
||||
bpf_map_update_elem(&cpu_tg_metric, &key, &new_stat,
|
||||
COMPAT_BPF_NOEXIST);
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &key);
|
||||
if (!entry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delta < 10 * NSEC_PER_MSEC) {
|
||||
__sync_fetch_and_add(&entry->nlat_01, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_01, 1);
|
||||
} else if (delta < 20 * NSEC_PER_MSEC) {
|
||||
__sync_fetch_and_add(&entry->nlat_02, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_02, 1);
|
||||
} else if (delta < 50 * NSEC_PER_MSEC) {
|
||||
__sync_fetch_and_add(&entry->nlat_03, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_03, 1);
|
||||
} else {
|
||||
__sync_fetch_and_add(&entry->nlat_04, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_04, 1);
|
||||
}
|
||||
}
|
||||
if (delta < 10 * NSEC_PER_MSEC) {
|
||||
__sync_fetch_and_add(&entry->nlat_01, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_01, 1);
|
||||
} else if (delta < 20 * NSEC_PER_MSEC) {
|
||||
__sync_fetch_and_add(&entry->nlat_02, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_02, 1);
|
||||
} else if (delta < 50 * NSEC_PER_MSEC) {
|
||||
__sync_fetch_and_add(&entry->nlat_03, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_03, 1);
|
||||
} else {
|
||||
__sync_fetch_and_add(&entry->nlat_04, 1);
|
||||
__sync_fetch_and_add(&g_entry->g_nlat_04, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("raw_tracepoint/sched_process_exit")
|
||||
int sched_process_exit_entry(struct bpf_raw_tracepoint_args *ctx)
|
||||
{
|
||||
u32 pid;
|
||||
u32 pid;
|
||||
|
||||
// TP_PROTO(struct task_struct *tsk)
|
||||
struct task_struct *p = (struct task_struct *)ctx->args[0];
|
||||
// TP_PROTO(struct task_struct *tsk)
|
||||
struct task_struct *p = (struct task_struct *)ctx->args[0];
|
||||
|
||||
pid = _(p->pid);
|
||||
/*
|
||||
* check latency table to fix latency table overflow in below scenario:
|
||||
* when wake up the target task, but the target task always running in
|
||||
* the other cpu, the target cpu will never be the next pid, because the
|
||||
* target task will be exiting, the latency item never delete.
|
||||
* To avoid latency table overflow, we should delete the latency item in
|
||||
* exit process.
|
||||
*/
|
||||
pid = _(p->pid);
|
||||
/*
|
||||
* check latency table to fix latency table overflow in below scenario:
|
||||
* when wake up the target task, but the target task always running in
|
||||
* the other cpu, the target cpu will never be the next pid, because the
|
||||
* target task will be exiting, the latency item never delete.
|
||||
* To avoid latency table overflow, we should delete the latency item in
|
||||
* exit process.
|
||||
*/
|
||||
|
||||
if (bpf_map_lookup_elem(&latency, &pid)) {
|
||||
bpf_map_delete_elem(&latency, &pid);
|
||||
}
|
||||
if (bpf_map_lookup_elem(&latency, &pid)) {
|
||||
bpf_map_delete_elem(&latency, &pid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TG_ADDR_KEY
|
||||
|
@ -283,29 +299,29 @@ int sched_process_exit_entry(struct bpf_raw_tracepoint_args *ctx)
|
|||
SEC("kprobe/sched_free_group")
|
||||
int sched_free_group_entry(struct pt_regs *ctx)
|
||||
{
|
||||
struct task_group *tg = (void *) PT_REGS_PARM1(ctx);
|
||||
struct stat_t *entry;
|
||||
struct task_group *tg = (void *)PT_REGS_PARM1(ctx);
|
||||
struct stat_t *entry;
|
||||
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &tg);
|
||||
if (entry)
|
||||
bpf_map_delete_elem(&cpu_tg_metric, &tg);
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &tg);
|
||||
if (entry)
|
||||
bpf_map_delete_elem(&cpu_tg_metric, &tg);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
// When pid namespace is destroyed, the record should be deleted.
|
||||
SEC("kprobe/destroy_pid_namespace")
|
||||
int destroy_pid_namespace_entry(struct pt_regs *ctx)
|
||||
{
|
||||
struct pid_namespace *ns = (void *) PT_REGS_PARM1(ctx);
|
||||
struct stat_t *entry;
|
||||
struct pid_namespace *ns = (void *)PT_REGS_PARM1(ctx);
|
||||
struct stat_t *entry;
|
||||
|
||||
// ns->ns.inum
|
||||
u32 pidns = BPF_CORE_READ(ns, ns.inum);
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &pidns);
|
||||
if (entry)
|
||||
bpf_map_delete_elem(&cpu_tg_metric, &pidns);
|
||||
// ns->ns.inum
|
||||
u32 pidns = BPF_CORE_READ(ns, ns.inum);
|
||||
entry = bpf_map_lookup_elem(&cpu_tg_metric, &pidns);
|
||||
if (entry)
|
||||
bpf_map_delete_elem(&cpu_tg_metric, &pidns);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
#include "vmlinux.h"
|
||||
#include "bpf_common.h"
|
||||
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "bpf_ratelimit.h"
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
||||
#define NR_STACK_TRACE_MAX 0x4000
|
||||
#define MSEC_PER_NSEC 1000000UL
|
||||
#define TICK_DEP_MASK_NONE 0
|
||||
#define SOFTIRQ_THRESH 5000000UL
|
||||
#define NR_STACK_TRACE_MAX 0x4000
|
||||
#define MSEC_PER_NSEC 1000000UL
|
||||
#define TICK_DEP_MASK_NONE 0
|
||||
#define SOFTIRQ_THRESH 5000000UL
|
||||
|
||||
volatile const u64 softirq_thresh = SOFTIRQ_THRESH;
|
||||
|
||||
#define CPU_NUM 128
|
||||
#define TICK 1000
|
||||
BPF_RATELIMIT(rate, 1, CPU_NUM * TICK * 1000);
|
||||
BPF_RATELIMIT(rate, 1, CPU_NUM *TICK * 1000);
|
||||
|
||||
struct timer_softirq_run_ts {
|
||||
u32 start_trace;
|
||||
|
@ -63,10 +65,10 @@ void probe_scheduler_tick(struct pt_regs *ctx)
|
|||
if (bpf_ratelimited(&rate))
|
||||
return;
|
||||
|
||||
//update soft timer timestamps
|
||||
// update soft timer timestamps
|
||||
int key = 0;
|
||||
struct timer_softirq_run_ts *ts;
|
||||
//struct thresh_data *tdata;
|
||||
// struct thresh_data *tdata;
|
||||
struct report_event *event;
|
||||
u64 now;
|
||||
u64 delta;
|
||||
|
@ -78,7 +80,7 @@ void probe_scheduler_tick(struct pt_regs *ctx)
|
|||
if (!ts->start_trace)
|
||||
return;
|
||||
|
||||
//update soft timer timestamps
|
||||
// update soft timer timestamps
|
||||
if (!ts->soft_ts) {
|
||||
ts->soft_ts = bpf_ktime_get_ns();
|
||||
return;
|
||||
|
@ -90,26 +92,28 @@ void probe_scheduler_tick(struct pt_regs *ctx)
|
|||
|
||||
if (ts->restarting_tick) {
|
||||
ts->restarting_tick = 0;
|
||||
ts->soft_ts = bpf_ktime_get_ns();
|
||||
ts->soft_ts = bpf_ktime_get_ns();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
now = bpf_ktime_get_ns();
|
||||
now = bpf_ktime_get_ns();
|
||||
delta = now - ts->soft_ts;
|
||||
|
||||
// if delta over threshold, dump important info to user
|
||||
if (delta >= softirq_thresh) {
|
||||
event->now = now;
|
||||
event->now = now;
|
||||
event->stall_time = delta;
|
||||
__builtin_memset(event->comm, 0, sizeof(event->comm));
|
||||
bpf_get_current_comm(&event->comm, sizeof(event->comm));
|
||||
event->pid = (u32)bpf_get_current_pid_tgid();
|
||||
event->cpu = bpf_get_smp_processor_id();
|
||||
event->stack_size = bpf_get_stack(ctx, event->stack, sizeof(event->stack), 0);
|
||||
event->stack_size =
|
||||
bpf_get_stack(ctx, event->stack, sizeof(event->stack), 0);
|
||||
|
||||
bpf_perf_event_output(ctx, &irqoff_event_map, COMPAT_BPF_F_CURRENT_CPU,
|
||||
event, sizeof(struct report_event));
|
||||
bpf_perf_event_output(ctx, &irqoff_event_map,
|
||||
COMPAT_BPF_F_CURRENT_CPU, event,
|
||||
sizeof(struct report_event));
|
||||
}
|
||||
|
||||
// update soft_ts, use for next trace
|
||||
|
@ -152,7 +156,7 @@ void probe_tick_nohz_restart_sched_tick(struct pt_regs *ctx)
|
|||
|
||||
now = bpf_ktime_get_ns();
|
||||
|
||||
ts->soft_ts = now;
|
||||
ts->start_trace = 1;
|
||||
ts->soft_ts = now;
|
||||
ts->start_trace = 1;
|
||||
ts->restarting_tick = 1;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "vmlinux.h"
|
||||
#include "bpf_common.h"
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#include "bpf_common.h"
|
||||
#include "bpf_ratelimit.h"
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
@ -10,31 +12,32 @@ char __license[] SEC("license") = "Dual MIT/GPL";
|
|||
#define CPU_NUM 128
|
||||
BPF_RATELIMIT_IN_MAP(rate, 1, CPU_NUM * 10000, 0);
|
||||
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(u32));
|
||||
} softlockup_perf_events SEC(".maps");
|
||||
|
||||
struct softlockup_info {
|
||||
u32 cpu;
|
||||
u32 pid;
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
u32 pid;
|
||||
char comm[COMPAT_TASK_COMM_LEN];
|
||||
};
|
||||
|
||||
SEC("kprobe/watchdog_timer_fn+442")
|
||||
int kprobe_watchdog_timer_fn(struct pt_regs *ctx)
|
||||
{
|
||||
struct softlockup_info info = {};
|
||||
struct task_struct *task;
|
||||
struct softlockup_info info = {};
|
||||
struct task_struct *task;
|
||||
|
||||
if (bpf_ratelimited_in_map(ctx, rate))
|
||||
return 0;
|
||||
info.cpu = bpf_get_smp_processor_id();
|
||||
task = (struct task_struct *)bpf_get_current_task();
|
||||
info.pid = bpf_get_current_pid_tgid() & 0xffffffffUL;
|
||||
BPF_CORE_READ_STR_INTO(&info.comm, task, comm);
|
||||
bpf_perf_event_output(ctx, &softlockup_perf_events, COMPAT_BPF_F_CURRENT_CPU, &info, sizeof(info));
|
||||
return 0;
|
||||
if (bpf_ratelimited_in_map(ctx, rate))
|
||||
return 0;
|
||||
|
||||
info.cpu = bpf_get_smp_processor_id();
|
||||
task = (struct task_struct *)bpf_get_current_task();
|
||||
info.pid = bpf_get_current_pid_tgid() & 0xffffffffUL;
|
||||
BPF_CORE_READ_STR_INTO(&info.comm, task, comm);
|
||||
bpf_perf_event_output(ctx, &softlockup_perf_events,
|
||||
COMPAT_BPF_F_CURRENT_CPU, &info, sizeof(info));
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue