Linux下追踪mimalloc动态库内部函数调用的方法咨询
Ubuntu下mimalloc动态库内部行为追踪方案
需求背景
- 环境:Linux(Ubuntu)
- 分析对象:动态库
/home/user/mimalloc-2.1.7/out/release/libmimalloc.so.2,对应源码路径/home/user/mimalloc-2.1.7/src/ - 测试程序:链接mimalloc的简单C程序,调用
mi_malloc、mi_free等函数 - 核心目标:追踪库内部函数调用关系(如
mi_malloc依赖的辅助函数)、调用次数、传递参数
现有工具局限
- ltrace:仅能捕获测试程序到库的顶层函数调用(如
mi_malloc),无法深入库内部调用链 - GDB:调试速度过慢,不适合全流程性能敏感型追踪
可行解决方案
方法1:perf + 调试符号追踪内部调用
利用perf的事件追踪能力,结合带调试符号的mimalloc库,实现轻量高效的调用链分析:
- 重新编译带调试符号的mimalloc:
cd /home/user/mimalloc-2.1.7 mkdir -p out/debug && cd out/debug cmake -DCMAKE_BUILD_TYPE=Debug -DMI_BUILD_SHARED=ON .. make -j$(nproc)
- 加载调试版库运行测试程序:
LD_PRELOAD=/home/user/mimalloc-2.1.7/out/debug/libmimalloc.so.2 ./your_test_program
- 记录函数调用事件:
perf record -g -e 'libmimalloc.so.2:*' ./your_test_program
- 分析调用链与次数:
# 可视化调用链 perf report -g graph,0.5 # 统计mimalloc相关函数调用次数 perf script | awk '{print $5}' | grep -E 'mi_' | sort | uniq -c
方法2:SystemTap动态插桩追踪
通过SystemTap动态插入探针,精准捕获函数调用与参数,无需修改源码:
- 安装依赖:
sudo apt-get install systemtap gcc linux-headers-$(uname -r)
- 编写追踪脚本(
mimalloc_trace.stp):
# 追踪顶层函数参数 probe process("/home/user/mimalloc-2.1.7/out/debug/libmimalloc.so.2").function("mi_malloc") { printf("mi_malloc called with size: %d\n", $size) } probe process("/home/user/mimalloc-2.1.7/out/debug/libmimalloc.so.2").function("mi_free") { printf("mi_free called with ptr: %p\n", $ptr) } # 追踪内部辅助函数 probe process("/home/user/mimalloc-2.1.7/out/debug/libmimalloc.so.2").function("mi_page_alloc") { printf("mi_page_alloc called with size: %d, flags: %x\n", $size, $flags) } # 统计所有mi_前缀函数的调用次数 global call_counts probe process("/home/user/mimalloc-2.1.7/out/debug/libmimalloc.so.2").function("*mi_*").call { call_counts[probefunc()]++ } probe end { printf("\nCall counts:\n") foreach (func in call_counts+) { printf("%s: %d\n", func, call_counts[func]) } }
- 运行脚本:
sudo stap mimalloc_trace.stp -c ./your_test_program
方法3:编译时插桩自定义追踪
利用编译器插桩或源码修改,实现高度自定义的追踪逻辑:
- 编译器插桩方案:
编译mimalloc时添加-finstrument-functions选项生成函数钩子:
cd /home/user/mimalloc-2.1.7/out/debug cmake -DCMAKE_BUILD_TYPE=Debug -DMI_BUILD_SHARED=ON -DCMAKE_C_FLAGS="-finstrument-functions" .. make -j$(nproc)
编写钩子函数(trace.c):
#include <stdio.h> #include <dlfcn.h> void __cyg_profile_func_enter(void* func, void* caller) { Dl_info info; if (dladdr(func, &info) && info.dli_sname != NULL) { printf("Enter: %s\n", info.dli_sname); // 如需捕获参数,需手动解析栈帧(复杂度较高) } }
编译钩子为动态库并运行:
gcc -shared -fPIC trace.c -o libtrace.so -ldl LD_PRELOAD=/home/user/mimalloc-2.1.7/out/debug/libmimalloc.so.2:./libtrace.so ./your_test_program
- 源码修改方案:
直接在mimalloc关键函数入口添加日志代码(如printf或文件写入),适合需精准控制追踪点的场景,注意避免过度日志影响性能。
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| perf | 轻量高效,无需额外依赖 | 参数追踪需额外处理 |
| SystemTap | 灵活精准,支持参数捕获 | 需要root权限,依赖内核头文件 |
| 编译时插桩 | 高度自定义,可追踪任意细节 | 需修改编译配置或源码,性能影响略大 |
内容的提问来源于stack exchange,提问作者sveerrr
相关产品推荐
相关产品推荐

