11# C++ Remote Profiler
22
3- 类似 Go pprof 和 brpc pprof service 的 C++ 远程性能分析工具,基于 gperftools 和 Drogon 框架实现。
3+ 类似 Go pprof 和 brpc pprof service 的 C++ 远程性能分析工具,基于 gperftools 和 Drogon 框架(可选)实现。
4+
5+ ## 目录
6+
7+ - [ 版本说明] ( #-版本说明 )
8+ - [ 功能特性] ( #-功能特性 )
9+ - [ 设计理念] ( #-设计理念 )
10+ - [ 快速开始] ( #-快速开始 )
11+ - [ 使用方法] ( #-使用方法 )
12+ - [ 如何查看火焰图] ( #-如何查看火焰图 )
13+ - [ API 端点] ( #-api-端点 )
14+ - [ 项目结构] ( #-项目结构 )
15+ - [ 运行测试] ( #-运行测试 )
16+ - [ 代码格式检查] ( #-代码格式检查 )
17+ - [ 集成到你的项目] ( #-集成到你的项目 )
18+ - [ 配置说明] ( #-配置说明 )
19+ - [ 注意事项] ( #-注意事项 )
20+ - [ 与其他工具的对比] ( #-与其他工具的对比 )
21+ - [ 许可证] ( #-许可证 )
422
523** 当前版本** : v0.1.0 (开发阶段)
624
3957
4058- ✅ ** CPU Profiling** : 使用 gperftools 进行 CPU 性能分析
4159- ✅ ** Heap Profiling** : 内存使用分析和内存泄漏检测(调用 tcmalloc sample)
60+ - ✅ ** Heap Growth Profiling** : 堆增长分析,无需 TCMALLOC_SAMPLE_PARAMETER 环境变量
4261- ✅ ** 线程堆栈捕获** : 获取所有线程的调用堆栈,支持动态线程数
4362- ✅ ** 标准 pprof 接口** : 支持 Go pprof 工具直接访问
4463- ✅ ** Web 界面** : 美观的 Web 控制面板,支持一键式火焰图分析
64+ - ✅ ** 框架无关** : ProfilerHttpHandlers 提供框架无关的 handler,可集成任意 Web 框架
65+ - ✅ ** Drogon 可选** : Web 界面依赖 Drogon,但核心 profiling 功能完全独立
66+ - ✅ ** 可配置日志系统** : 支持自定义 LogSink,集成到应用日志系统
4567- ✅ ** RESTful API** : 完整的 HTTP API 接口
4668- ✅ ** 依赖管理** : 使用 vcpkg 管理所有依赖
4769- ✅ ** 信号处理器安全** : 保存并恢复用户程序的信号处理器
53751 . ** 标准 pprof 模式** : 提供 ` /pprof/profile ` 、` /pprof/heap ` 接口,返回原始 profile 文件,兼容 Go pprof 工具
54762 . ** 一键分析模式** : 提供 ` /api/cpu/analyze ` 等接口,直接返回 SVG,适合浏览器查看
5577
78+ ** 架构特点** :
79+ - ** 核心库与 Web 解耦** : ` profiler_core ` 不依赖任何 Web 框架,` profiler_web ` 是可选的 Drogon 适配层
80+ - ** 框架无关的 Handler** : ` ProfilerHttpHandlers ` 返回 ` HandlerResponse ` 结构体,可与任意 Web 框架集成
81+ - ** 非单例设计** : ` ProfilerManager ` 是普通类,用户自行管理生命周期
82+
5683** 接口命名规则** :
5784- ` /pprof/* ` - 标准 Go pprof 接口
5885- ` /api/* ` - 自定义分析接口(浏览器直接查看)
@@ -116,11 +143,14 @@ cd vcpkg
116143```
117144
118145这将自动安装以下依赖:
119- - drogon (Web 框架)
146+ - drogon (Web 框架,可选 )
120147- gtest (测试框架)
121148- nlohmann-json (JSON 库)
122149- openssl
123150- zlib
151+ - protobuf
152+ - backward-cpp (栈回溯)
153+ - gperftools (CPU/Heap 性能分析)
124154
125155### 4. 编译项目
126156
@@ -290,24 +320,34 @@ cpp-remote-profiler/
290320├── build.sh # 构建脚本
291321├── start.sh # 启动脚本
292322├── include/
293- │ ├── profiler_manager.h # Profiler 管理器
294- │ ├── symbolize.h # 符号化引擎
295- │ ├── web_resources.h # Web 资源(嵌入的 HTML)
296- │ ├── web_server.h # HTTP 服务器
297- │ └── version.h # 版本信息
323+ │ ├── profiler_manager.h # Profiler 管理器(非单例)
324+ │ ├── profiler_version.h.in # 版本信息模板(CMake 生成)
325+ │ ├── version.h # 版本宏(向后兼容)
326+ │ └── profiler/
327+ │ ├── http_handlers.h # 框架无关的 HTTP 处理器
328+ │ ├── drogon_adapter.h # Drogon 适配层(可选)
329+ │ ├── log_sink.h # 日志 Sink 接口
330+ │ └── logger.h # 日志配置接口
298331├── src/
299- │ ├── profiler_manager.cpp
300- │ ├── symbolize.cpp
332+ │ ├── profiler_manager.cpp # Profiler 管理器实现
333+ │ ├── symbolize.cpp # 符号化引擎
334+ │ ├── http_handlers.cpp # HTTP 处理器实现(框架无关)
335+ │ ├── drogon_adapter.cpp # Drogon 适配层实现(可选)
301336│ ├── web_resources.cpp # 嵌入的 Web 资源
302- │ └── web_server.cpp # HTTP 路由处理
337+ │ └── internal/ # 内部实现(不对外暴露)
338+ │ ├── log_manager.h/cpp # 日志管理器
339+ │ ├── default_log_sink.h/cpp # 默认日志实现(std::cout/cerr)
340+ │ ├── log_macros.h # 内部日志宏
341+ │ └── ... # 其他内部头文件
303342├── example/
304343│ ├── main.cpp # 示例程序主入口
305344│ ├── workload.cpp # 工作负载示例
306345│ ├── workload.h
307346│ └── custom_signal.cpp # 自定义信号示例
308347├── tests/
309- │ ├── test_cpu_profile.cpp
310- │ └── test_full_flow.cpp
348+ │ ├── test_cpu_profile.cpp # CPU profiling 测试
349+ │ ├── test_full_flow.cpp # 完整流程测试
350+ │ └── test_logger.cpp # 日志系统测试
311351├── docs/ # 用户文档
312352│ ├── README.md # 文档索引
313353│ └── user_guide/ # 用户指南
@@ -317,15 +357,20 @@ cpp-remote-profiler/
317357│ ├── 04_troubleshooting.md
318358│ ├── 05_installation.md
319359│ └── 06_using_find_package.md
360+ ├── scripts/
361+ │ └── check-format.sh # 代码格式检查脚本
320362└── vcpkg/ # vcpkg 包管理器
321363```
322364
323365## 🧪 运行测试
324366
325367``` bash
326368cd build
369+ ctest --output-on-failure
370+ # 或单独运行:
327371./test_cpu_profile
328372./test_full_flow
373+ ./test_logger
329374```
330375
331376运行完整的火焰图测试:
@@ -377,49 +422,70 @@ http://localhost:8080
377422
378423## 💡 集成到你的项目
379424
380- ### 选项 1: 作为 HTTP 服务集成(推荐)
425+ ### 选项 1: 仅使用核心 profiling 功能(无 Web 依赖)
426+
427+ 只需链接 ` profiler_core ` ,不需要 Drogon:
381428
382- 将 profiler 作为一个独立的 HTTP 服务运行:
429+ ``` cmake
430+ find_package(cpp-remote-profiler REQUIRED)
431+ target_link_libraries(my_app cpp-remote-profiler::profiler_core)
432+ ```
383433
384434``` cpp
385- #include < drogon/drogon.h >
435+ #include " profiler_manager.h "
386436
387437int main () {
388- // 启动 profiler HTTP 服务
389- // 监听 8080 端口,提供 /prof 和 /heap 接口
390- // 你的主程序可以在其他端口运行
391- // 通过 HTTP 请求获取 profile 数据
438+ profiler::ProfilerManager profiler;
439+
440+ // 启动 CPU profiling
441+ profiler.startCPUProfiler("cpu.prof");
442+
443+ // ... 运行你的代码 ...
444+
445+ profiler.stopCPUProfiler();
446+ return 0;
392447}
393448```
394449
395- ### 选项 2: 使用 gperftools 直接集成
450+ ### 选项 2: 使用 Drogon Web 界面(推荐)
451+
452+ 链接 ` profiler_web ` 即可获得完整的 Web 控制面板:
453+
454+ ``` cmake
455+ find_package(cpp-remote-profiler REQUIRED)
456+ find_package(Drogon CONFIG REQUIRED)
457+ target_link_libraries(my_app
458+ cpp-remote-profiler::profiler_web
459+ Drogon::Drogon
460+ )
461+ ```
396462
397463``` cpp
398- #include < gperftools/profiler.h>
464+ #include " profiler_manager.h"
465+ #include " profiler/drogon_adapter.h"
466+ #include < drogon/drogon.h>
399467
400468int main () {
401- // 启动 CPU profiler
402- ProfilerStart ("/tmp/my_app.prof");
469+ profiler::ProfilerManager profiler;
470+ profiler::registerDrogonHandlers (profiler);
471+ drogon::app().addListener("0.0.0.0", 8080).run();
472+ }
473+ ```
403474
404- // 运行需要分析的代码
405- yourCodeToProfile ();
475+ ### 选项 3: 与任意 Web 框架集成
406476
407- // 停止 CPU profiler
408- ProfilerStop ();
477+ 使用框架无关的 ` ProfilerHttpHandlers ` ,只链接 ` profiler_core ` :
409478
410- // 使用 pprof 工具分析
411- // go tool pprof /tmp/my_app.prof
412- return 0;
413- }
414- ```
479+ ``` cpp
480+ #include " profiler_manager.h"
481+ #include " profiler/http_handlers.h"
415482
416- ### 编译你的程序
483+ profiler::ProfilerManager profiler;
484+ profiler::ProfilerHttpHandlers handlers (profiler);
417485
418- ``` bash
419- g++ -o your_app your_app.cpp \
420- -ltcmalloc_and_profiler \
421- -lprofiler \
422- -lpthread
486+ // 调用 handler,获得框架无关的响应
487+ auto resp = handlers.handleCpuAnalyze(10, "flamegraph");
488+ // resp.status, resp.content_type, resp.body → 用你的框架包装
423489```
424490
425491### 配置信号(可选)
@@ -430,10 +496,10 @@ g++ -o your_app your_app.cpp \
430496#include "profiler_manager.h"
431497
432498int main() {
433- // 在使用 Profiler 之前设置信号
499+ // 在创建 ProfilerManager 之前设置信号
434500 profiler::ProfilerManager::setStackCaptureSignal(SIGRTMIN + 5);
435501
436- auto& profiler = profiler ::ProfilerManager::getInstance() ;
502+ profiler::ProfilerManager profiler ;
437503
438504 // ... 正常使用 profiler ...
439505}
@@ -446,6 +512,32 @@ int main() {
446512
447513** 示例程序** :参考 ` example/custom_signal.cpp ` 查看详细用法。
448514
515+ ### 配置日志(可选)
516+
517+ 可以自定义日志输出,集成到你的应用日志系统:
518+
519+ ``` cpp
520+ #include " profiler_manager.h"
521+ #include " profiler/log_sink.h"
522+
523+ class MyAppLogSink : public profiler ::LogSink {
524+ public:
525+ void log(profiler::LogLevel level, const char* file, int line,
526+ const char* function, const char* message) override {
527+ // 转发到你的日志系统
528+ MY_APP_LOG("[ Profiler] {}:{} - {}", file, line, message);
529+ }
530+ };
531+
532+ int main() {
533+ profiler::ProfilerManager profiler;
534+ profiler.setLogSink(std::make_shared<MyAppLogSink >());
535+ profiler.setLogLevel(profiler::LogLevel::Debug);
536+
537+ // ... 正常使用 profiler ...
538+ }
539+ ```
540+
449541## ⚙️ 配置说明
450542
451543### 环境变量
@@ -485,11 +577,11 @@ cd vcpkg
4855771 . ** 编译选项** : 使用 ` -g ` 编译选项保留调试符号,以便正确显示函数名
4865782 . ** 性能开销** : CPU profiler 会有 1-5% 的性能开销
4875793 . ** Heap Profiler** : 需要 tcmalloc 内存分配器和 ` TCMALLOC_SAMPLE_PARAMETER ` 环境变量
488- 4 . ** 生产环境 ** : 谨慎使用,建议在开发/测试环境中使用
489- 5 . ** 并发限制 ** : 同一时间只能有一个 CPU profiling 请求
490- 6 . ** 环境变量 ** : 使用 heap profiling 前必须设置 ` TCMALLOC_SAMPLE_PARAMETER `
580+ 4 . ** Heap Growth ** : 无需 ` TCMALLOC_SAMPLE_PARAMETER ` ,可即时获取堆增长数据
581+ 5 . ** 生产环境 ** : 谨慎使用,建议在开发/测试环境中使用
582+ 6 . ** 并发限制 ** : 同一时间只能有一个 CPU profiling 请求
4915837 . ** 信号冲突** : 默认使用 SIGUSR1,如与你的程序冲突,请使用 ` setStackCaptureSignal() ` 配置其他信号
492- 8 . ** 线程安全** : 线程堆栈捕获使用信号处理器,确保程序正确处理 SIGUSR1(或配置的信号)
584+ 8 . ** 线程安全** : 所有公共 API 都是线程安全的
493585
494586## 🎨 与其他工具的对比
495587
0 commit comments