Files
bpf-developer-tutorial/12-profile/README.md
2022-12-04 19:26:29 +08:00

104 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## eBPF 入门实践教程:编写 eBPF 程序 profile 进行性能分析
### 背景
`profile` 是一款用户追踪程序执行调用流程的工具类似于perf中的 -g 指令。但是相较于perf而言
`profile`的功能更为细化,它可以选择用户需要追踪的层面,比如在用户态层面进行追踪,或是在内核态进行追踪。
### 实现原理
`profile` 的实现依赖于linux中的perf_event。在注入ebpf程序前`profile` 工具会先将 perf_event
注册好。
```c
static int open_and_attach_perf_event(int freq, struct bpf_program *prog,
struct bpf_link *links[])
{
struct perf_event_attr attr = {
.type = PERF_TYPE_SOFTWARE,
.freq = env.freq,
.sample_freq = env.sample_freq,
.config = PERF_COUNT_SW_CPU_CLOCK,
};
int i, fd;
for (i = 0; i < nr_cpus; i++) {
if (env.cpu != -1 && env.cpu != i)
continue;
fd = syscall(__NR_perf_event_open, &attr, -1, i, -1, 0);
if (fd < 0) {
/* Ignore CPU that is offline */
if (errno == ENODEV)
continue;
fprintf(stderr, "failed to init perf sampling: %s\n",
strerror(errno));
return -1;
}
links[i] = bpf_program__attach_perf_event(prog, fd);
if (!links[i]) {
fprintf(stderr, "failed to attach perf event on cpu: "
"%d\n", i);
links[i] = NULL;
close(fd);
return -1;
}
}
return 0;
}
```
其ebpf程序实现逻辑是对程序的堆栈进行定时采样从而捕获程序的执行流程。
```c
SEC("perf_event")
int do_perf_event(struct bpf_perf_event_data *ctx)
{
__u64 id = bpf_get_current_pid_tgid();
__u32 pid = id >> 32;
__u32 tid = id;
__u64 *valp;
static const __u64 zero;
struct key_t key = {};
if (!include_idle && tid == 0)
return 0;
if (targ_pid != -1 && targ_pid != pid)
return 0;
if (targ_tid != -1 && targ_tid != tid)
return 0;
key.pid = pid;
bpf_get_current_comm(&key.name, sizeof(key.name));
if (user_stacks_only)
key.kern_stack_id = -1;
else
key.kern_stack_id = bpf_get_stackid(&ctx->regs, &stackmap, 0);
if (kernel_stacks_only)
key.user_stack_id = -1;
else
key.user_stack_id = bpf_get_stackid(&ctx->regs, &stackmap, BPF_F_USER_STACK);
if (key.kern_stack_id >= 0) {
// populate extras to fix the kernel stack
__u64 ip = PT_REGS_IP(&ctx->regs);
if (is_kernel_addr(ip)) {
key.kernel_ip = ip;
}
}
valp = bpf_map_lookup_or_try_init(&counts, &key, &zero);
if (valp)
__sync_fetch_and_add(valp, 1);
return 0;
}
```
通过这种方式,它可以根据用户指令,简单的决定追踪用户态层面的执行流程或是内核态层面的执行流程。
### Eunomia中使用方式
### 总结
`profile` 实现了对程序执行流程的分析在debug等操作中可以极大的帮助开发者提高效率。