基于ebpf的性能工具 您所在的位置:网站首页 bpftrace三 基于ebpf的性能工具

基于ebpf的性能工具

2024-05-19 01:47| 来源: 网络整理| 查看: 265

在实际的软件开发过程中,内存问题常常是耗费大量时间进行分析的挑战之一。为了更有效地定位和解决与内存相关的难题,一系列辅助工具应运而生,其中备受赞誉的Valgrind工具便是其中之一。事实上,笔者本人曾利用Valgrind工具成功地发现并解决了一个隐藏在软件中的bug,这充分体现了工具在开发过程中的重要性。

然而,同样强大的bpftrace工具同样具备简洁而直观的特点,能够协助我们高效地追踪内存泄漏问题。在这方面,bpftrace提供了一种更加精细的、实时的分析方式,帮助开发人员准确地定位代码中可能存在的内存泄漏情况。

构建样例我们编写一个程序--mem_check.c,代码中包含正确的申请内存和释放内存的逻辑,同时包含存在内存泄露的代码代码。。代码语言:javascript复制#include #include int main(){ char *p1 = NULL; char *p2 = NULL; for(int i = 0; i < 5; i++) { p1 = malloc(16); } for(int i = 0; i < 5; i++) { p2 = malloc(32); free(p2); } getchar(); return 0; } 上面的代码非常简单,我们申请了5次16个字节的内存,没有释放,存在内存泄露。申请5次32个字节的内存,有释放,没存在内存泄露。那么我们如何通过bpftrace定位呢?我们通过bpftrace对mem_check.c进行动态的统计内存的申请和释放,定位内存泄露的问题。我们需要对关键的两个接口进行probe--malloc和free,这两个接口的实现在libc中。编译mem_check.c文件,生成可执行文件:代码语言:javascript复制gcc mem_check.c -o mem_check 探测mem_ckeck可执行文件bpftrace可以对内核态进行探测也可以对用户态进行探测,其中探针如下:内核态探针:kprobe/kretprobe用户态探针:uprobe/uretprobemem_check.c是一个应用程序,显然我们需要使用用户态探针:uprobe/uretprobe通过uprobe探测mem_check.c中的malloc函数,我们单行指令验证,参数格式是 uprobe:可执行文件:函数名:理论是没有没有问题,但实际发生错误:No probes to attach。原因:可执行文件mem_check中找不到符号:malloc,我们可以通过nm命令确定一下:我们发现malloc是一个链接自GLIBC_2.2.5的符号,并不是mem_ckeck自身的符号,所以我们探测的符号修改libc库中malloc符号,系统中可能存在多个c库,我们需要找到mem_ckeck程序使用的C库,通过ldd命令查看:mem_check可执行文件使用的C库为:/lib/x86_64-linux-gnu/libc.so.6,我们将可以执行文件替换为/lib/x86_64-linux-gnu/libc.so.6。再次执行,会出现大量内容,显然是其他进程调用了malloc引起的,而我们的mem_ckeck还没有运行,显然还没有探测我们的可执行程序。代码语言:javascript复制bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc {printf("malloc call\n")}' 我们需要进行过滤,增加filter只保留我们关心的应用程序的调用探测。bpftrace提供了系统变量comm表示可执行文件名 (进程名),只需要在上述指令中增加 filter,只处理comm=="mem_check"的malloc调用事件。左边终端执行探测,右边终端执行可执行文件。每调用一次malloc函数,就能探测到一次:使用bpftrace脚本进一步探测将上面的单行命令变为bpftrace脚本--bpf_test.bt代码语言:javascript复制BEGIN { printf("start probe\n"); } uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("malloc call\n"); } END { printf("end probe\n"); } 探测mem_check中malloc的内存空间大小。malloc的原型:代码语言:javascript复制void *malloc(size_t size); bpftrace的uprobe和kprobe可以通过内置变量arg0、arg1 ··· ··· 访问函数参数,对bpf_test.bt修改就可以打印malloc申请内存的大小:代码语言:javascript复制BEGIN { printf("start probe\n"); } uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("malloc size: %d\n", arg0); } END { printf("end probe\n"); } 如下图可以看到mem_check中申请内存的情况,最后一个malloc size 1024是mem_check自动创建输出缓冲区申请的内存,不用理会。探测mem_check中malloc的返回值malloc的返回值是地址,需借助uretprobe进行探测,函数返回值可通过内置变量retval访问。uretprobe的filter与malloc参数探测时类似,脚本修改为:代码语言:javascript复制BEGIN { printf("start probe\n"); } uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("malloc size: %d\n", arg0); } uretprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("addr = %p\n", retval); } END { printf("end probe\n"); } 运行结果:探测mem_check中free我们已经探测到mem_check的malloc的内存大小,内存的地址,我们通过探测free,然后匹配malloc和free的情况就可以查找内存的泄漏点。脚本修改为:代码语言:javascript复制BEGIN { printf("start probe\n"); } uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("malloc size: %d\n", arg0); } uretprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("addr = %p\n", retval); } uprobe:/lib/x86_64-linux-gnu/libc.so.6:free /comm == "mem_check"/{ printf("free addr = %p\n", arg0); } END { printf("end probe\n"); } 运行结果:探测内存泄露上面我们已经探测到了mem_check中的malloc,free情况。我们可以通过malloc和free的地址集合差,就可以得到内存泄露的地址位置。bpftrace底层使用的是eBPF的map作为存储结构,可以简单的看作K-V存储,我们可以利用map来统计地址集合差,步骤如下:定义一个map变量@mem:保存malloc返回的内存地址。当探测到free调用时,将@mem对应地址删除。最后@mem剩下的就是内存泄露的地址。内存泄露检测脚本如下:代码语言:javascript复制BEGIN { printf("start probe\n"); } uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("malloc size: %d\n", arg0); @size = arg0; } uretprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{ printf("addr = %p\n", retval); @mem[retval] = @size; } uprobe:/lib/x86_64-linux-gnu/libc.so.6:free /comm == "mem_check"/{ printf("free addr = %p\n", arg0); delete(@mem[arg0]); } END { printf("end probe\n"); } 运行结果:如上图,红色框中就是没有释放的内存和内存大小。总结

通过编写一些简单的bpftrace脚本,我们就可以监视应用程序的内存分配和释放事件,捕获内存泄漏的迹象。这种直接的实时监控方式,使得开发者能够在问题出现时即刻获得反馈,从而更加迅速地解决潜在的内存问题,提升软件的稳定性和性能。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有