1 前言
在系统性能运维监控的一些场景中我们往往需要对系统进行"采样"分析,最场景的例子就是perf top/record;在使用ebpf+perf event的情况下,ebpf中使用SEC("perf_event")这个名字的section来作为perf event的prog程序。 这类程序有着固定的参数类型:struct bpf_perf_event_data,如下所示:
SEC("perf_event")
int perf_event_foo(struct bpf_perf_event_data *ctx)
这个参数是什么含义呢?里面有什么成员呢?这些问题都是本文要讲究的内容。
2 结构体的构成
这里的参数ctx是struct bpf_perf_event_data结构:
struct bpf_perf_event_data { bpf_user_pt_regs_t regs; __u64 sample_period; __u64 addr; };
可以看到这个结构的第一个参数是bpf_user_pt_regs_t结构,这个结构对于不同的架构,定义不同。这里仅举x86和arm64为例进行说明(其他架构大部分都和x86或者arm64类似)。
2.1 x86架构
typedef struct pt_regs bpf_user_pt_regs_t;
对于x86架构而言bpf_user_pt_regs_t就等价于struct pt_regs结构,也就是Linux中存放寄存器上下文的结构。
2) arm64架构
typedef struct user_pt_regs bpf_user_pt_regs_t;
对于arm64架构而言,user_pt_regs的定义,以及与上下文寄存器struct pt_regs的关联如下:
/* user_pt_regs中包含了上下文切换所需要的绝大部分信息 */ truct user_pt_regs { __u64 regs[31]; __u64 sp; __u64 pc; __u64 pstate; }; struct pt_regs { union { /* user_pt_regs作为第一个成员放到pt_regs中 */ struct user_pt_regs user_regs; struct { u64 regs[31]; u64 sp; u64 pc; u64 pstate; }; }; u64 orig_x0; #ifdef __AARCH64EB__ u32 unused2; s32 syscallno; #else s32 syscallno; u32 unused2; #endif u64 orig_addr_limit; /* Only valid when ARM64_HAS_IRQ_PRIO_MASKING is enabled. */ u64 pmr_save; u64 stackframe[2]; /* Only valid for some EL1 exceptions. */ u64 lockdep_hardirqs; u64 exit_rcu; };
3 总结
我们了解了struct bpf_perf_event_data结构的构成,知道了它与struct pt_regs的关系,这对于我们对系统的探测、监控更加方便。