共计 3586 个字符,预计需要花费 9 分钟才能阅读完成。
Perf Buffer 惯例用法:
struct addrinfo // 须要上传给应用层的数据结构
{
int ai_flags; /* Input flags. */
int ai_family; /* Protocol family for socket. */
int ai_socktype; /* Socket type. */
int ai_protocol; /* Protocol for socket. */
u32 ai_addrlen; /* Length of socket address. */ // CHANGED from socklen_t
struct sockaddr *ai_addr; /* Socket address for socket. */
char *ai_canonname; /* Canonical name for service location. */
struct addrinfo *ai_next; /* Pointer to next in list. */
};
struct //Perf Map 申明
{__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int)); // 这里不是 struct addrinfo 大小,这里指的是 key 对应的 fd 的大小 *****
__uint(max_entries, 1024); // 最大 fd 数量,这里能够不设置,在应用层设置,会笼罩这里的值,尽量保障一个 cpu 对应一个 buffer
// https://github.com/cilium/ebpf/pull/300
// https://github.com/cilium/ebpf/issues/209
// https://github.com/cilium/ebpf/blob/02ebf28c2b0cd7c2c6aaf56031bc54f4684c5850/map.go 的函数 clampPerfEventArraySize() 外面} events SEC(".maps");
SEC("uretprobe/getaddrinfo")
int getaddrinfo_return(struct pt_regs *ctx) {
...
struct data_t data = {}; // 创立栈上构造体,第一次内存拷贝
data.xxx = xxx; // 获取须要的数据
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &data, sizeof(data)); // 将栈上构造体复制到 Perf Map 中,第二次内存拷贝
...
return 0;
}
总结:在栈中申请的构造体,此时 ebpf verify 验证器会限度构造体不能超过 512 字节,影响性能开发。
产生了 2 次内存拷贝,耗费性能。
在对构造体成员赋值实现后,调用 bpf_perf_event_output 时,如果 Perf Map 曾经满了。则会产生上传数据失败。
Perf Buffer 高阶用法:
struct addrinfo // 须要上传给应用层的数据结构
{
int ai_flags; /* Input flags. */
int ai_family; /* Protocol family for socket. */
int ai_socktype; /* Socket type. */
int ai_protocol; /* Protocol for socket. */
u32 ai_addrlen; /* Length of socket address. */ // CHANGED from socklen_t
struct sockaddr *ai_addr; /* Socket address for socket. */
char *ai_canonname; /* Canonical name for service location. */
struct addrinfo *ai_next; /* Pointer to next in list. */
};
struct { //Perf Map 申明
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
__uint(max_entries, 1024);
} events SEC(".maps");
struct { // 高阶用法,改为 Map 堆中创立数据结构
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 1);
__type(key, int);
__type(value, struct event);
} heap SEC(".maps");
SEC("uretprobe/getaddrinfo")
int getaddrinfo_return(struct pt_regs *ctx) {
...
struct data_t *data; // 差别点,不创立栈上数据结构
int zero = 0;
data = bpf_map_lookup_elem(&heap, &zero); // 改为创立在 Map 堆中
data.xxx = xxx; // 获取须要的数据
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, data, sizeof(*data)); // 上传数据
...
return 0;
}
总结:内存申请产生在 Map 提供的堆中,躲避栈上申请 512 字节的限度
还是存在调用 bpf_perf_event_output 时,如果 Perf Map 曾经满了。则会产生上传数据失败。
Ring Buffer 用法
struct addrinfo // 须要上传给应用层的数据结构
{
int ai_flags; /* Input flags. */
int ai_family; /* Protocol family for socket. */
int ai_socktype; /* Socket type. */
int ai_protocol; /* Protocol for socket. */
u32 ai_addrlen; /* Length of socket address. */ // CHANGED from socklen_t
struct sockaddr *ai_addr; /* Socket address for socket. */
char *ai_canonname; /* Canonical name for service location. */
struct addrinfo *ai_next; /* Pointer to next in list. */
};
struct { //Ring buffer 申明,留神此时 max_entries 代表的是 buffer 的大小,和 Perf buffer 中该字段的含意有所不同
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024 /* 256 KB */);
} events SEC(".maps");
SEC("uretprobe/getaddrinfo")
int getaddrinfo_return(struct pt_regs *ctx) {
...
struct data_t *data; // 差别点,不创立栈上数据结构
data = bpf_ringbuf_reserve(&events, sizeof(*data), 0); // 间接在 ring buffer 中申请空间
if (!data)
return 0;
data.xxx = xxx; // 获取须要的数据
bpf_ringbuf_submit(data, 0); // 上传数据
return 0;
}
总结:函数一开始间接在 ring buffer 中申请空间,申请失败的话间接就返回了,不会执行后续操作,节省时间,一旦申请胜利,即可保障 bpf_ringbuf_submit 肯定不会因为没有空间失败,且省去 Perf buffer 中拷贝构造体的操作。
差异性
总结:
共同点:
- Perf/Ring Buffer 绝对于其余品种 map(被动轮询) 来说,提供专用 api,告诉应用层事件就绪,缩小 cpu 耗费,进步性能。
- 采纳共享内存,节俭复制数据开销。
- Perf/Ring Buffer 反对传入可变长构造。
差别:
- Perf Buffer 每个 CPU 外围一个缓存区,不保证数据程序 (fork exec exit),会对咱们应用层生产数据造成影响。Ring Buffer 多 CPU 共用一个缓存区且外部实现了自旋锁,保证数据程序。
- Perf Buffer 有着两次数据拷贝动作,当空间有余时,效率低下。Ring Buffer 采纳先申请内存,再操作模式,提高效率。
- Ring Buffer 性能强于 Perf Buffer。参考 patch【ringbuf perfbuf 性能比照】
本文由博客一文多发平台 OpenWrite 公布!
正文完