Fastgrind
GitHub: https://github.com/adny-code/fastgrind
引言
在高性能計(jì)算場(chǎng)景下,常使用perf工具進(jìn)行函數(shù)級(jí)別的時(shí)間分析、使用valgrind工具進(jìn)行內(nèi)存泄漏和內(nèi)存分配異常檢測(cè)。
valgrind功能非常強(qiáng)大,能追蹤每一段內(nèi)存申請(qǐng)和釋放的棧幀。但是valgrind使用相對(duì)復(fù)雜,最重要的是valgrind效率極其低下,通常為原始程序運(yùn)行時(shí)間長的10倍以上。對(duì)于多線程程序,valgrind無法跑滿線程,性能退化能到幾十甚至上百倍。
大部分場(chǎng)景下,即使精簡(jiǎn)case后,valgrind依然難以快速定位內(nèi)存異常問題。
對(duì)于上述問題,fastgrind開源庫提供一個(gè)輕量級(jí)的、函數(shù)級(jí)別監(jiān)控、可視化的、高效C++內(nèi)存監(jiān)控方案。在64核服務(wù)器上測(cè)試,64個(gè)線程能完全跑滿。簡(jiǎn)單case (調(diào)用棧深度10以內(nèi)),性能幾乎無退化;復(fù)雜case (調(diào)用棧深度30+),性能退化4倍以內(nèi)。

fastgrind倉庫的testcase中,提供了一個(gè)包含bin query、分組算法的box grouping測(cè)例,調(diào)整線程數(shù)量,測(cè)試得到的benchmark如上圖所示。
簡(jiǎn)介
fastgrind 是一個(gè)僅單一頭文件、輕量級(jí)、快速、線程安全、類似 Valgrind 的內(nèi)存分析器,旨在跟蹤 C++ 應(yīng)用程序中的運(yùn)行時(shí)內(nèi)存分配并分析調(diào)用堆棧。Fastgrind 通過自動(dòng)和手動(dòng)插樁兩種檢測(cè)方法提供全面的內(nèi)存使用情況分析。
fastgrind 兼容C++11以上版本,集成到工程中不影響原始倉庫中其它第三方內(nèi)存管理庫或glibc內(nèi)存管理的正常運(yùn)行。
倉庫結(jié)構(gòu)
fastgrind/
├── include/fastgrind.h
|
├── demo/
│ ├── manual_instrument/
│ ├── auto_instrument/
| └── build_all_demo.sh
|
├── testcase/
│ ├── benchmark_box_grouping/
│ ├── cpp_feature_test/
│ ├── glibc_je_tc_availabe/
│ ├── multi_pkg_compile/
| ├── thirdparty_leveldb_test/
| └── thirdparty_zlib_test
|
├── doc/
| ├── compile.md
| ├── demo.md
| ├── feature_list.md
| ├── querstion_list.md
| └── testcase.md
|
├── tools/fastgrind.py
|
├── CMakeList.txt
├── Doxyfile
└── README.md
快速開始
編譯 testcase
mkdir build && cd build
cmake ..
make -j$(nproc)
運(yùn)行 testcase
cd build/testcase/benchmark_box_grouping
./benchmark_raw
./benchmark_fastgrind
./run_valgrind.sh
cd build/testcase/cpp_feature_test
./cpp_feature_test
...
cd build/testcase/multi_pkg_compile
./multi_pkg_main
調(diào)用堆棧 Report
程序退出時(shí)會(huì)生成兩個(gè)報(bào)告文件
[FASTGRIND] Start summary memory info
[FASTGRIND] saved: fastgrind.text (size=2335 bytes)
[FASTGRIND] saved: fastgrind.json (size=65952 bytes)
更多細(xì)節(jié)請(qǐng)看本文段落: fastgrind 輸出與分析
如何在你的項(xiàng)目中使用
手動(dòng)和自動(dòng)插樁都需要額外的編譯標(biāo)志
有關(guān)詳細(xì)編譯和鏈接選項(xiàng),請(qǐng)看本文段落: fastgrind 編譯選項(xiàng)
手動(dòng)插樁的使用方法
通過顯示的插入__FASTGRIND__::FAST_GRIND宏,選擇要監(jiān)控的函數(shù)。
#include "fastgrind.h"
using namespace __FASTGRIND__;
void processData() {
FAST_GRIND;
int* data = new int[1000];
delete[] data;
}
int main() {
FAST_GRIND;
processData();
return 0;
}
自動(dòng)插樁的使用方法
在任何一個(gè).cpp中包含 fastgrind.h,并通過編譯選項(xiàng),使得目標(biāo)外的所有函數(shù)都會(huì)自動(dòng)監(jiān)控。
fastgrind 輸出與分析
當(dāng)集成 fastgrind 的應(yīng)用程序退出時(shí),會(huì)自動(dòng)生成兩個(gè)文件:fastgrind.text和fastgrind.json
fastgrind.text
fastgrind.text 是類似于 Linux 下 perf report 格式的輸出。有函數(shù)級(jí)別的調(diào)用棧內(nèi)存申請(qǐng)/釋放統(tǒng)計(jì),在vscode等editor下可以進(jìn)行子調(diào)用棧折疊。

fastgrind.json
fastgrind.json 文件中包含:
- 時(shí)間片內(nèi)存使用統(tǒng)計(jì)
- 每線程內(nèi)存分配詳細(xì)信息
- 完整的調(diào)用堆棧信息
- 函數(shù)級(jí)分配明細(xì)
每時(shí)間片、每線程、每函數(shù)記錄器:
單線程記錄如下

多線程記錄如下

可視化
使用tools/fastgrind.py生成交互式可視化折線圖
它將調(diào)用 matplotlib 繪制折線圖,并生成 fastgrind.html以防用戶環(huán)境中沒有 matplotlib,使用瀏覽器打開fastgrind.html可以得到與matplotlib相同的折線圖
用法
python fastgrind.py fastgrind.json
or
python fastgrind.py
以第三方開源庫 leveldb 為例,監(jiān)控其內(nèi)存分配:
matplot結(jié)果

html結(jié)果

fastgrind 編譯選項(xiàng)
手動(dòng)插樁的編譯選項(xiàng)
描述: 手動(dòng)檢測(cè)要求開發(fā)人員在源代碼中顯式添加__FASTGRIND__::FAST_GRIND到需要監(jiān)控的函數(shù),但只需要更簡(jiǎn)單的編譯配置
編譯選項(xiàng):
g++ -O3 -Wall -Wextra -std=c++11 \
-I/path/to/fastgrind/include \
source_files...
鏈接選項(xiàng):
Wrap flags: 內(nèi)存分配器的符號(hào)包裝(下面列出了所有支持的)
WRAP_FLAGS=(
-Wl,--wrap=malloc
-Wl,--wrap=calloc
-Wl,--wrap=realloc
-Wl,--wrap=free
-Wl,--wrap=_Znwm
-Wl,--wrap=_Znam
-Wl,--wrap=_ZdlPv
-Wl,--wrap=_ZdaPv
-Wl,--wrap=_ZnwmRKSt9nothrow_t
-Wl,--wrap=_ZnamRKSt9nothrow_t
-Wl,--wrap=_ZdlPvRKSt9nothrow_t
-Wl,--wrap=_ZdaPvRKSt9nothrow_t
-Wl,--wrap=valloc
-Wl,--wrap=pvalloc
-Wl,--wrap=memalign
-Wl,--wrap=posix_memalign
-Wl,--wrap=reallocarray
-Wl,--wrap=aligned_alloc
-Wl,--wrap=_ZdaPvm
-Wl,--wrap=_ZdlPvm
-Wl,--wrap=_ZnwmSt11align_val_t
-Wl,--wrap=_ZnamSt11align_val_t
-Wl,--wrap=_ZdlPvSt11align_val_t
-Wl,--wrap=_ZdaPvSt11align_val_t
-Wl,--wrap=_ZdlPvmSt11align_val_t
-Wl,--wrap=_ZdaPvmSt11align_val_t
-Wl,--wrap=_ZdlPvmRKSt9nothrow_t
-Wl,--wrap=_ZdaPvmRKSt9nothrow_t
-Wl,--wrap=_ZnwmSt11align_val_tRKSt9nothrow_t
-Wl,--wrap=_ZnamSt11align_val_tRKSt9nothrow_t
-Wl,--wrap=_ZdlPvSt11align_val_tRKSt9nothrow_t
-Wl,--wrap=_ZdaPvSt11align_val_tRKSt9nothrow_t
-Wl,--wrap=_ZdlPvmSt11align_val_tRKSt9nothrow_t
-Wl,--wrap=_ZdaPvmSt11align_val_tRKSt9nothrow_t
)
具體示例可看原倉庫中demo/manual_instrument
自動(dòng)插樁的編譯選項(xiàng)
描述: 自動(dòng)插樁能監(jiān)控所有非排除函數(shù),但需要更復(fù)雜的編譯配置
編譯選項(xiàng):
EXCLUDE_FILE_LISTS=(
/usr/include/
/usr/lib/
/usr/local/
fastgrind.h
)
EXCLUDE_FILE_LISTS=$(IFS=,; echo "${EXCLUDE_FILE_LISTS[*]}")
INSTRUMENT_FLAGS=(
-finstrument-functions
-finstrument-functions-exclude-file-list=${EXCLUDE_FILE_LISTS}
)
g++ -O3 -Wall -Wextra -std=c++11 \
"${INSTRUMENT_FLAGS[@]}" \
-DFASTGRIND_INSTRUMENT \
-Wl,--export-dynamic \
-I/path/to/fastgrind/include \
source_files...
鏈接選項(xiàng):
同 手動(dòng)插樁 一致
具體示例可看原倉庫中demo/auto_instrument
限制和注意事項(xiàng)
- 跨函數(shù)棧幀分配: 在一個(gè)函數(shù)中分配并在另一個(gè)函數(shù)中釋放的內(nèi)存將被如實(shí)記錄,導(dǎo)致這些函數(shù)堆棧幀記錄釋放的數(shù)量少于或超過分配的數(shù)量,在另一些則相反.
- 模板復(fù)雜性支持: 復(fù)雜的模板元編程可能會(huì)在報(bào)告中顯示通用名稱
- 文件覆蓋: 每次運(yùn)行時(shí)輸出文件都會(huì)覆蓋以前的內(nèi)容
- GUN依賴: 需要 GNU ld 來實(shí)現(xiàn)
--wrap 功能
原作者
?轉(zhuǎn)自https://www.cnblogs.com/ZhongQianwen/p/19147719
該文章在 2025/11/3 10:01:51 編輯過