From 3a96325bfa77c4a55a601bf661643fc5a5a6b936 Mon Sep 17 00:00:00 2001 From: IronsDu Date: Wed, 8 Apr 2026 11:32:18 +0800 Subject: [PATCH 1/2] docs: update README to reflect post-refactor project state Sync documentation with the Drogon decoupling and singleton removal refactoring: updated project structure, dependency list, integration examples (non-singleton API, ProfilerHttpHandlers, Drogon optional), and added logging configuration section. Co-Authored-By: Claude Opus 4.6 --- README.md | 160 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 117 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index db8b48c..3490575 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,13 @@ - ✅ **CPU Profiling**: 使用 gperftools 进行 CPU 性能分析 - ✅ **Heap Profiling**: 内存使用分析和内存泄漏检测(调用 tcmalloc sample) +- ✅ **Heap Growth Profiling**: 堆增长分析,无需 TCMALLOC_SAMPLE_PARAMETER 环境变量 - ✅ **线程堆栈捕获**: 获取所有线程的调用堆栈,支持动态线程数 - ✅ **标准 pprof 接口**: 支持 Go pprof 工具直接访问 - ✅ **Web 界面**: 美观的 Web 控制面板,支持一键式火焰图分析 +- ✅ **框架无关**: ProfilerHttpHandlers 提供框架无关的 handler,可集成任意 Web 框架 +- ✅ **Drogon 可选**: Web 界面依赖 Drogon,但核心 profiling 功能完全独立 +- ✅ **可配置日志系统**: 支持自定义 LogSink,集成到应用日志系统 - ✅ **RESTful API**: 完整的 HTTP API 接口 - ✅ **依赖管理**: 使用 vcpkg 管理所有依赖 - ✅ **信号处理器安全**: 保存并恢复用户程序的信号处理器 @@ -53,6 +57,11 @@ 1. **标准 pprof 模式**: 提供 `/pprof/profile`、`/pprof/heap` 接口,返回原始 profile 文件,兼容 Go pprof 工具 2. **一键分析模式**: 提供 `/api/cpu/analyze` 等接口,直接返回 SVG,适合浏览器查看 +**架构特点**: +- **核心库与 Web 解耦**: `profiler_core` 不依赖任何 Web 框架,`profiler_web` 是可选的 Drogon 适配层 +- **框架无关的 Handler**: `ProfilerHttpHandlers` 返回 `HandlerResponse` 结构体,可与任意 Web 框架集成 +- **非单例设计**: `ProfilerManager` 是普通类,用户自行管理生命周期 + **接口命名规则**: - `/pprof/*` - 标准 Go pprof 接口 - `/api/*` - 自定义分析接口(浏览器直接查看) @@ -116,11 +125,14 @@ cd vcpkg ``` 这将自动安装以下依赖: -- drogon (Web 框架) +- drogon (Web 框架,可选) - gtest (测试框架) - nlohmann-json (JSON 库) - openssl - zlib +- protobuf +- backward-cpp (栈回溯) +- gperftools (CPU/Heap 性能分析) ### 4. 编译项目 @@ -290,24 +302,34 @@ cpp-remote-profiler/ ├── build.sh # 构建脚本 ├── start.sh # 启动脚本 ├── include/ -│ ├── profiler_manager.h # Profiler 管理器 -│ ├── symbolize.h # 符号化引擎 -│ ├── web_resources.h # Web 资源(嵌入的 HTML) -│ ├── web_server.h # HTTP 服务器 -│ └── version.h # 版本信息 +│ ├── profiler_manager.h # Profiler 管理器(非单例) +│ ├── profiler_version.h.in # 版本信息模板(CMake 生成) +│ ├── version.h # 版本宏(向后兼容) +│ └── profiler/ +│ ├── http_handlers.h # 框架无关的 HTTP 处理器 +│ ├── drogon_adapter.h # Drogon 适配层(可选) +│ ├── log_sink.h # 日志 Sink 接口 +│ └── logger.h # 日志配置接口 ├── src/ -│ ├── profiler_manager.cpp -│ ├── symbolize.cpp +│ ├── profiler_manager.cpp # Profiler 管理器实现 +│ ├── symbolize.cpp # 符号化引擎 +│ ├── http_handlers.cpp # HTTP 处理器实现(框架无关) +│ ├── drogon_adapter.cpp # Drogon 适配层实现(可选) │ ├── web_resources.cpp # 嵌入的 Web 资源 -│ └── web_server.cpp # HTTP 路由处理 +│ └── internal/ # 内部实现(不对外暴露) +│ ├── log_manager.h/cpp # 日志管理器 +│ ├── default_log_sink.h/cpp # 默认日志实现(std::cout/cerr) +│ ├── log_macros.h # 内部日志宏 +│ └── ... # 其他内部头文件 ├── example/ │ ├── main.cpp # 示例程序主入口 │ ├── workload.cpp # 工作负载示例 │ ├── workload.h │ └── custom_signal.cpp # 自定义信号示例 ├── tests/ -│ ├── test_cpu_profile.cpp -│ └── test_full_flow.cpp +│ ├── test_cpu_profile.cpp # CPU profiling 测试 +│ ├── test_full_flow.cpp # 完整流程测试 +│ └── test_logger.cpp # 日志系统测试 ├── docs/ # 用户文档 │ ├── README.md # 文档索引 │ └── user_guide/ # 用户指南 @@ -317,6 +339,8 @@ cpp-remote-profiler/ │ ├── 04_troubleshooting.md │ ├── 05_installation.md │ └── 06_using_find_package.md +├── scripts/ +│ └── check-format.sh # 代码格式检查脚本 └── vcpkg/ # vcpkg 包管理器 ``` @@ -324,8 +348,11 @@ cpp-remote-profiler/ ```bash cd build +ctest --output-on-failure +# 或单独运行: ./test_cpu_profile ./test_full_flow +./test_logger ``` 运行完整的火焰图测试: @@ -377,49 +404,70 @@ http://localhost:8080 ## 💡 集成到你的项目 -### 选项 1: 作为 HTTP 服务集成(推荐) +### 选项 1: 仅使用核心 profiling 功能(无 Web 依赖) + +只需链接 `profiler_core`,不需要 Drogon: -将 profiler 作为一个独立的 HTTP 服务运行: +```cmake +find_package(cpp-remote-profiler REQUIRED) +target_link_libraries(my_app cpp-remote-profiler::profiler_core) +``` ```cpp -#include +#include "profiler_manager.h" int main() { - // 启动 profiler HTTP 服务 - // 监听 8080 端口,提供 /prof 和 /heap 接口 - // 你的主程序可以在其他端口运行 - // 通过 HTTP 请求获取 profile 数据 + profiler::ProfilerManager profiler; + + // 启动 CPU profiling + profiler.startCPUProfiler("cpu.prof"); + + // ... 运行你的代码 ... + + profiler.stopCPUProfiler(); + return 0; } ``` -### 选项 2: 使用 gperftools 直接集成 +### 选项 2: 使用 Drogon Web 界面(推荐) + +链接 `profiler_web` 即可获得完整的 Web 控制面板: + +```cmake +find_package(cpp-remote-profiler REQUIRED) +find_package(Drogon CONFIG REQUIRED) +target_link_libraries(my_app + cpp-remote-profiler::profiler_web + Drogon::Drogon +) +``` ```cpp -#include +#include "profiler_manager.h" +#include "profiler/drogon_adapter.h" +#include int main() { - // 启动 CPU profiler - ProfilerStart("/tmp/my_app.prof"); + profiler::ProfilerManager profiler; + profiler::registerDrogonHandlers(profiler); + drogon::app().addListener("0.0.0.0", 8080).run(); +} +``` - // 运行需要分析的代码 - yourCodeToProfile(); +### 选项 3: 与任意 Web 框架集成 - // 停止 CPU profiler - ProfilerStop(); +使用框架无关的 `ProfilerHttpHandlers`,只链接 `profiler_core`: - // 使用 pprof 工具分析 - // go tool pprof /tmp/my_app.prof - return 0; -} -``` +```cpp +#include "profiler_manager.h" +#include "profiler/http_handlers.h" -### 编译你的程序 +profiler::ProfilerManager profiler; +profiler::ProfilerHttpHandlers handlers(profiler); -```bash -g++ -o your_app your_app.cpp \ - -ltcmalloc_and_profiler \ - -lprofiler \ - -lpthread +// 调用 handler,获得框架无关的响应 +auto resp = handlers.handleCpuAnalyze(10, "flamegraph"); +// resp.status, resp.content_type, resp.body → 用你的框架包装 ``` ### 配置信号(可选) @@ -430,10 +478,10 @@ g++ -o your_app your_app.cpp \ #include "profiler_manager.h" int main() { - // 在使用 Profiler 之前设置信号 + // 在创建 ProfilerManager 之前设置信号 profiler::ProfilerManager::setStackCaptureSignal(SIGRTMIN + 5); - auto& profiler = profiler::ProfilerManager::getInstance(); + profiler::ProfilerManager profiler; // ... 正常使用 profiler ... } @@ -446,6 +494,32 @@ int main() { **示例程序**:参考 `example/custom_signal.cpp` 查看详细用法。 +### 配置日志(可选) + +可以自定义日志输出,集成到你的应用日志系统: + +```cpp +#include "profiler_manager.h" +#include "profiler/log_sink.h" + +class MyAppLogSink : public profiler::LogSink { +public: + void log(profiler::LogLevel level, const char* file, int line, + const char* function, const char* message) override { + // 转发到你的日志系统 + MY_APP_LOG("[Profiler] {}:{} - {}", file, line, message); + } +}; + +int main() { + profiler::ProfilerManager profiler; + profiler.setLogSink(std::make_shared()); + profiler.setLogLevel(profiler::LogLevel::Debug); + + // ... 正常使用 profiler ... +} +``` + ## ⚙️ 配置说明 ### 环境变量 @@ -485,11 +559,11 @@ cd vcpkg 1. **编译选项**: 使用 `-g` 编译选项保留调试符号,以便正确显示函数名 2. **性能开销**: CPU profiler 会有 1-5% 的性能开销 3. **Heap Profiler**: 需要 tcmalloc 内存分配器和 `TCMALLOC_SAMPLE_PARAMETER` 环境变量 -4. **生产环境**: 谨慎使用,建议在开发/测试环境中使用 -5. **并发限制**: 同一时间只能有一个 CPU profiling 请求 -6. **环境变量**: 使用 heap profiling 前必须设置 `TCMALLOC_SAMPLE_PARAMETER` +4. **Heap Growth**: 无需 `TCMALLOC_SAMPLE_PARAMETER`,可即时获取堆增长数据 +5. **生产环境**: 谨慎使用,建议在开发/测试环境中使用 +6. **并发限制**: 同一时间只能有一个 CPU profiling 请求 7. **信号冲突**: 默认使用 SIGUSR1,如与你的程序冲突,请使用 `setStackCaptureSignal()` 配置其他信号 -8. **线程安全**: 线程堆栈捕获使用信号处理器,确保程序正确处理 SIGUSR1(或配置的信号) +8. **线程安全**: 所有公共 API 都是线程安全的 ## 🎨 与其他工具的对比 From 5ee0f5931f58cb3406d57d3ba285a6a094dcbe45 Mon Sep 17 00:00:00 2001 From: IronsDu Date: Wed, 8 Apr 2026 11:55:38 +0800 Subject: [PATCH 2/2] docs: fix outdated references and add README TOC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix profiler_lib → profiler_core/profiler_web across docs and cmake examples - Fix mainpage.dox: remove singleton pattern, update includes and features - Fix docs/README.md: update broken library API links - Fix 06_using_find_package.md: update file structure, link targets - Add navigation TOC to README.md Co-Authored-By: Claude Opus 4.6 --- README.md | 20 +++++++++++++++++++- cmake/examples/CMakeLists.txt | 7 +++---- cmake/examples/FetchContent_example.cmake | 2 +- docs/README.md | 4 ++-- docs/mainpage.dox | 15 +++++++-------- docs/user_guide/04_troubleshooting.md | 14 +++++++------- docs/user_guide/05_installation.md | 8 ++++---- docs/user_guide/06_using_find_package.md | 23 ++++++++++++----------- 8 files changed, 55 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 3490575..b502bdc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,24 @@ # C++ Remote Profiler -类似 Go pprof 和 brpc pprof service 的 C++ 远程性能分析工具,基于 gperftools 和 Drogon 框架实现。 +类似 Go pprof 和 brpc pprof service 的 C++ 远程性能分析工具,基于 gperftools 和 Drogon 框架(可选)实现。 + +## 目录 + +- [版本说明](#-版本说明) +- [功能特性](#-功能特性) +- [设计理念](#-设计理念) +- [快速开始](#-快速开始) +- [使用方法](#-使用方法) +- [如何查看火焰图](#-如何查看火焰图) +- [API 端点](#-api-端点) +- [项目结构](#-项目结构) +- [运行测试](#-运行测试) +- [代码格式检查](#-代码格式检查) +- [集成到你的项目](#-集成到你的项目) +- [配置说明](#-配置说明) +- [注意事项](#-注意事项) +- [与其他工具的对比](#-与其他工具的对比) +- [许可证](#-许可证) **当前版本**: v0.1.0 (开发阶段) diff --git a/cmake/examples/CMakeLists.txt b/cmake/examples/CMakeLists.txt index 42a48e4..5eae46f 100644 --- a/cmake/examples/CMakeLists.txt +++ b/cmake/examples/CMakeLists.txt @@ -29,7 +29,7 @@ FetchContent_MakeAvailable(cpp-remote-profiler) # Find dependencies (manual - since we're not using vcpkg here) find_package(PkgConfig REQUIRED) pkg_check_modules(GPERFTOOLS REQUIRED libprofiler libtcmalloc) -find_package(Drogon REQUIRED) +# Drogon is pulled in automatically by profiler_web target # ============================================================================ # Build example executable @@ -38,8 +38,7 @@ find_package(Drogon REQUIRED) add_executable(fetch_content_example FetchContent_integration_example.cpp) target_link_libraries(fetch_content_example - profiler_lib - Drogon::Drogon + cpp-remote-profiler::profiler_web ${GPERFTOOLS_LIBRARIES} ) @@ -51,4 +50,4 @@ target_link_libraries(fetch_content_example # add_subdirectory(/path/to/cpp-remote-profiler) # Then link: -# target_link_libraries(your_app profiler_lib) +# target_link_libraries(your_app cpp-remote-profiler::profiler_core) diff --git a/cmake/examples/FetchContent_example.cmake b/cmake/examples/FetchContent_example.cmake index 32dc5c8..136805f 100644 --- a/cmake/examples/FetchContent_example.cmake +++ b/cmake/examples/FetchContent_example.cmake @@ -48,6 +48,6 @@ FetchContent_MakeAvailable(cpp-remote-profiler) # Link to your target # target_link_libraries(your_target -# cpp-remote-profiler::profiler_lib +# cpp-remote-profiler::profiler_web # Drogon::Drogon # Required if using web features # ) diff --git a/docs/README.md b/docs/README.md index a396614..f0d6369 100644 --- a/docs/README.md +++ b/docs/README.md @@ -54,8 +54,8 @@ 详细的 API 文档(待完善)。 - [ProfilerManager API](library_api/profiler_manager.md) -- [Symbolize API](library_api/symbolize.md) -- [Web Server API](library_api/web_server.md) +- [HTTP Handlers API](library_api/http_handlers.md) +- [Log Sink API](library_api/log_sink.md) ### 开发者指南 贡献者和维护者文档。 diff --git a/docs/mainpage.dox b/docs/mainpage.dox index 3919ac6..8d78320 100644 --- a/docs/mainpage.dox +++ b/docs/mainpage.dox @@ -10,27 +10,26 @@ * * - @b CPU @b Profiling: CPU performance analysis using gperftools * - @b Heap @b Profiling: Memory usage analysis and leak detection + * - @b Heap @b Growth @b Profiling: Heap growth analysis (no env var needed) * - @b Thread @b Stack @b Capture: Get call stacks of all threads * - @b Standard @b pprof @b Interface: Compatible with Go pprof tools + * - @b Framework @b Agnostic: ProfilerHttpHandlers work with any web framework * - @b Web @b Interface: Beautiful web control panel with one-click flame graph * - @b RESTful @b API: Complete HTTP API endpoints + * - @b Configurable @b Logging: Custom LogSink integration * * @section getting_started Getting Started * * @subsection quick_example Quick Example * * @code{.cpp} - * #include * #include "profiler_manager.h" - * #include "web_server.h" + * #include "profiler/drogon_adapter.h" + * #include * * int main() { - * auto& profiler = profiler::ProfilerManager::getInstance(); - * - * // Register HTTP handlers - * profiler::registerHttpHandlers(profiler); - * - * // Start HTTP server + * profiler::ProfilerManager profiler; + * profiler::registerDrogonHandlers(profiler); * drogon::app().addListener("0.0.0.0", 8080).run(); * return 0; * } diff --git a/docs/user_guide/04_troubleshooting.md b/docs/user_guide/04_troubleshooting.md index e793909..d34a621 100644 --- a/docs/user_guide/04_troubleshooting.md +++ b/docs/user_guide/04_troubleshooting.md @@ -133,13 +133,13 @@ target_link_libraries(your_app ) ``` -链接顺序很重要: +确保使用正确的 CMake 目标名: ```cmake -# 错误的顺序 -target_link_libraries(your_app pthread profiler_lib) +# 核心功能 +target_link_libraries(your_app cpp-remote-profiler::profiler_core) -# 正确的顺序 -target_link_libraries(your_app profiler_lib pthread) +# 如果需要 Web 界面 +target_link_libraries(your_app cpp-remote-profiler::profiler_web) ``` --- @@ -465,7 +465,7 @@ setenv("TCMALLOC_SAMPLE_PARAMETER", "524288", 1); 2. **确保链接 tcmalloc**: ```cmake target_link_libraries(your_app - profiler_lib + cpp-remote-profiler::profiler_core tcmalloc # 或 ${GPERFTOOLS_LIBRARIES} pthread ) @@ -626,7 +626,7 @@ profiler::ProfilerManager::setStackCaptureSignal(SIGUSR2); 1. ✅ 编译时使用了 `-g` 选项 2. ✅ 设置了 `TCMALLOC_SAMPLE_PARAMETER` (用于 heap profiling) -3. ✅ 链接了所有必需的库(profiler_lib, tcmalloc, pthread) +3. ✅ 链接了所有必需的库(profiler_core, tcmalloc, pthread) 4. ✅ 服务器端口未被占用 5. ✅ 有足够的磁盘空间存储 profile 文件 6. ✅ 使用了支持的操作系统(Linux) diff --git a/docs/user_guide/05_installation.md b/docs/user_guide/05_installation.md index d114649..945cffd 100644 --- a/docs/user_guide/05_installation.md +++ b/docs/user_guide/05_installation.md @@ -224,7 +224,7 @@ add_executable(my_app main.cpp) # 链接库 target_link_libraries(my_app - profiler_lib + cpp-remote-profiler::profiler_core Drogon::Drogon # 如果使用 Web 功能 ) ``` @@ -349,7 +349,7 @@ project(MyApp) add_subdirectory(/path/to/cpp-remote-profiler build/cpp-remote-profiler) add_executable(my_app main.cpp) -target_link_libraries(my_app profiler_lib) +target_link_libraries(my_app cpp-remote-profiler::profiler_core) ``` --- @@ -388,7 +388,7 @@ sudo dnf install cpp-remote-profiler-devel ```bash # 检查动态库 -ldconfig -p | grep profiler_lib +ldconfig -p | grep profiler_core # 或检查特定路径 ls -l /usr/local/lib/libprofiler_core.* @@ -426,7 +426,7 @@ int main() { 编译并运行: ```bash -g++ -std=c++20 test_install.cpp -lprofiler_lib -o test_install +g++ -std=c++20 test_install.cpp -lprofiler_core -o test_install ./test_install ``` diff --git a/docs/user_guide/06_using_find_package.md b/docs/user_guide/06_using_find_package.md index 2c10ef2..ec97c7e 100644 --- a/docs/user_guide/06_using_find_package.md +++ b/docs/user_guide/06_using_find_package.md @@ -45,11 +45,13 @@ sudo make install DESTDIR=/opt/cpp-remote-profiler └── include/ └── cpp-remote-profiler/ ├── profiler_manager.h - ├── symbolize.h + ├── profiler_version.h + ├── version.h ├── profiler/ -│ ├── drogon_adapter.h -│ ├── http_handlers.h - ├── web_resources.h + │ ├── drogon_adapter.h + │ ├── http_handlers.h + │ ├── log_sink.h + │ └── logger.h └── version.h ``` @@ -126,10 +128,9 @@ find_package(cpp-remote-profiler REQUIRED) # 创建可执行文件 add_executable(my_app main.cpp) -# 链接库(需要同时链接 Drogon) +# 链接库(使用 profiler_web 自动带上 Drogon) target_link_libraries(my_app - cpp-remote-profiler::profiler_core - Drogon::Drogon + cpp-remote-profiler::profiler_web ) ``` @@ -213,8 +214,7 @@ find_package(cpp-remote-profiler REQUIRED) add_executable(web_app main.cpp) target_link_libraries(web_app - cpp-remote-profiler::profiler_core - Drogon::Drogon + cpp-remote-profiler::profiler_web ) ``` @@ -326,7 +326,7 @@ cmake .. undefined reference to `drogon::...` ``` -**原因**: profiler_lib 包含 Web 功能,需要链接 Drogon +**原因**: profiler_web 依赖 Drogon,需要链接 Drogon **解决方案**: @@ -456,7 +456,8 @@ make ```bash # 删除安装的文件 sudo rm -rf /usr/local/include/cpp-remote-profiler -sudo rm -f /usr/local/lib/libprofiler_lib.* +sudo rm -f /usr/local/lib/libprofiler_core.* +sudo rm -f /usr/local/lib/libprofiler_web.* sudo rm -rf /usr/local/lib/cmake/cpp-remote-profiler # 更新动态链接库缓存