Hical 性能优化全记录

优化背景 Hical 是我写的 C++20/26 Web 框架,跑 Hello World 压测时起初只有 27K QPS,而同类框架(Cinatra 165K、Drogon 170K)差了将近一个数量级。目标很明确:追平 Cinatra/Drogon 的水平。 整个优化过程分 6 个阶段,不是拍脑袋乱改,每一步都是 perf + 火焰图定位瓶颈 → 想方案 → 写代码 → 跑压测验证 的循环。能看到数字变化才算数。 阶段 1:协程帧削减(v2.5.1-v2.5.2) 发现问题 perf 火焰图第一个大头:14.5% CPU 在 scheduler::wake_one_thread_and_unlock + pthread_cond_signal。 一开始以为是跨线程调度问题,仔细一看不是——是 Boost.Asio scheduler 每次 co_await resume 都要走的内部调度流程太重了。一个 Hello World 请求居然走了 4 个协程帧: 1 2 3 4 5 handleSession: co_await async_read → 帧 1(必需,I/O 等待) co_await router_.dispatch() → 帧 2(Router 本身是协程) co_await handler(req) → 帧 3(同步 handler 被包装成协程,不必要!) co_await async_write → 帧 4(必需,I/O 等待) 帧 1 和 4 是真正的 I/O 等待不可消除,但帧 2 和 3 完全是浪费——一个同步的 return HttpResponse("Hello") 被裹了两层协程。 ...

May 22, 2026 · 9 min · 1794 words

Linux 性能分析与优化实战指南:perf / 火焰图 / Heaptrack 全流程

Linux 性能分析与优化实战指南 基于 Hical 项目的 Ubuntu 24.04 VM 环境(VirtualBox,8 CPU / 16GB RAM)。 前置条件:已完成 Hical-Linux开发环境 和 VM编译运行Hical-Benchmark流程 的环境搭建。 目录 零、工具安装 一、perf stat:硬件计数器分析 二、perf record + 火焰图:CPU 热点定位 三、Heaptrack:内存分配分析 四、缓存层次与 cache line 五、实战:Hical 性能分析全流程 六、速查卡 零、工具安装 0.1 一键安装所有性能工具 1 2 3 4 5 6 7 8 9 10 11 # perf(必须匹配内核版本) sudo apt install -y linux-tools-$(uname -r) linux-tools-generic # heaptrack(内存分配分析) sudo apt install -y heaptrack heaptrack-gui # FlameGraph(火焰图生成脚本) git clone --depth 1 https://github.com/brendangregg/FlameGraph.git ~/FlameGraph # 辅助工具 sudo apt install -y valgrind strace sysstat hwloc 0.2 内核参数调整(perf / heaptrack 权限) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # ── perf 权限 ── # 查看当前值(默认通常是 4,限制很严) cat /proc/sys/kernel/perf_event_paranoid # 临时放开(重启失效) sudo sysctl -w kernel.perf_event_paranoid=-1 sudo sysctl -w kernel.kptr_restrict=0 # ── ptrace 权限(heaptrack --pid 运行时附着需要) ── # 查看当前值(默认 1,禁止非父进程 ptrace) cat /proc/sys/kernel/yama/ptrace_scope # 临时放开(重启失效) sudo sysctl -w kernel.yama.ptrace_scope=0 # ── 永久生效(写入配置文件) ── cat << 'EOF' | sudo tee /etc/sysctl.d/99-perf.conf kernel.perf_event_paranoid = -1 kernel.kptr_restrict = 0 kernel.yama.ptrace_scope = 0 EOF sudo sysctl --system 各级别含义: ...

May 15, 2026 · 25 min · 5176 words

perf + 火焰图:5 分钟定位 C++ 程序的 CPU 瓶颈

perf + 火焰图:5 分钟定位 C++ 程序的 CPU 瓶颈 你的服务器 CPU 跑满了,QPS 却上不去。top 告诉你"忙",但不告诉你忙在哪。怎么办? 故事:从 27K 到 136K QPS 我开发了一个 C++20/26 Web 框架(Hical),第一次压测只有 27K QPS,而同场景下 Drogon 和 Cinatra 都在 160K+。CPU 使用率 100%,top 没用,gdb 打断点太慢。 最终靠 perf record + 火焰图,5 分钟定位到瓶颈不在我的框架代码(仅占 2% CPU),而在 Boost.Asio 的调度层——跨线程 epoll_ctl 和 per-request timer 合计吃了 27% CPU。 优化后 QPS 从 27K → 136K。 这篇文章把我整套分析流程分享出来。不需要你用过 Hical,任何 C++ 服务器程序都适用。 一、工具安装(2 分钟搞定) 1 2 3 4 5 6 7 8 9 # perf(必须匹配内核版本) sudo apt install -y linux-tools-$(uname -r) linux-tools-generic # FlameGraph 脚本(Brendan Gregg 出品) git clone --depth 1 https://github.com/brendangregg/FlameGraph.git ~/FlameGraph # 放开 perf 权限(否则只能看到自己的进程) sudo sysctl -w kernel.perf_event_paranoid=-1 sudo sysctl -w kernel.kptr_restrict=0 验证: ...

May 15, 2026 · 5 min · 971 words

C++ 性能分析全景指南:从工具链到方法论

C++ 性能分析全景指南:从工具链到方法论 不要凭直觉猜瓶颈——人的直觉在性能问题上错误率极高。先量测,再优化。 写在前面 性能优化是 C++ 程序员的核心竞争力之一。但"性能优化"这四个字太大了——从微架构级的 cache line 对齐,到宏观的算法复杂度选择,中间跨越了多个抽象层次。 这篇文章不是某个工具的使用教程,而是试图建立一套完整的性能分析知识框架:遇到性能问题时,你该用什么工具、看什么指标、按什么思路排查。全文分为九个部分: 核心思维 CPU Profiling 内存分析 编译优化分析 Benchmark 编写 并发与锁分析 Sanitizer 全家桶 优化决策方法论 工具选择与学习路线 一、核心思维 1.1 性能问题的三种类型 所有性能问题,本质上只有三类: 类型 表现 典型原因 CPU-bound CPU 利用率高,但吞吐上不去 算法复杂度高、分支预测失败、指令级并行度低 Memory-bound CPU 利用率不高(在等数据),IPC 低 缓存未命中、TLB miss、false sharing、频繁堆分配 I/O-bound CPU 几乎空闲,程序却很慢 磁盘读写、网络等待、锁竞争(广义 I/O) 判断当前程序属于哪一类,是性能分析的第一步。用错了工具,你会在错误的方向上浪费大量时间。 1.2 Amdahl 定律的启示 优化一个占总耗时 5% 的函数,即使你把它优化到 0,整体也只快 5%。但优化一个占 60% 的函数,哪怕只快 20%,整体就快 12%。 永远先找大头。这就是为什么 profiling 必须走在优化前面。 1.3 量测的四条铁律 在接近生产环境的条件下量测——Debug 模式的热点分布和 Release 完全不同 量测时关闭无关进程——CPU 频率调节(turbo boost / power saving)会干扰结果 多次量测取统计值——单次运行的噪声太大,至少跑 3 次取中位数 量测前后只改一个变量——否则你不知道是哪个改动起了作用 二、CPU Profiling CPU 剖析是性能分析的基础。根据实现方式不同,分为采样式和插桩式两大类。 ...

May 12, 2026 · 16 min · 3208 words

火焰图对比分析:自研 HTTP 栈 vs Beast HTTP 栈

火焰图对比分析:自研 HTTP 栈 vs Beast HTTP 栈 Hical v2.6.0 完成了从 Beast HTTP 到自研零拷贝 HTTP 栈的迁移。本文通过两份火焰图的逐项对比,用数据量化"去 Beast"到底省了什么、省了多少,以及当前性能瓶颈到底在哪里。 目录 火焰图对比分析:自研 HTTP 栈 vs Beast HTTP 栈 目录 1. 测试环境与采集方式 2. 总体热度分布对比 flame.svg(自研路径)— 总计 ~299 亿 samples flame1.svg(Beast 路径)— 总计 ~411 亿 samples 3. HTTP 解析:picohttpparser vs Beast parser 4. Header 存储:栈数组 vs 链表堆分配 5. 响应序列化:FixedBuffer vs Beast serializer 自研路径 Beast 路径 6. 发送路径:sendto vs sendmsg 7. 协程与调度开销 8. 内核瓶颈:loopback softirq 的天花板 epoll_ctl 已不是瓶颈 9. strace 佐证:系统调用频率 10. 结论与下一步 量化收益:去 Beast 到底省了多少 当前性能分布总结 下一步优化方向 最终结论 1. 测试环境与采集方式 项目 配置 环境 Ubuntu VM (Docker 内),GCC 14,-O2 -g 压测工具 wrk,4 线程,keep-alive 采集 perf record -F 99 -g -p <pid> → FlameGraph 生成 SVG 辅助 strace -c -f -p <pid> 统计系统调用频率 对比目标 flame.svg(自研路径 v2.6.0)vs flame1.svg(Beast 路径) 两份火焰图采集条件一致,唯一区别是 HTTP 处理栈的实现路径。 ...

May 12, 2026 · 5 min · 918 words

Hical v2.6.0 性能优化心得:从 27K 到 159K QPS 的完整旅程

Hical v2.6.0 性能优化心得:从 27K 到 159K QPS 的完整旅程 这篇文章记录了 Hical 从 v2.5.2 到 v2.6.0 的完整性能优化历程。不是罗列"我做了什么改动",而是分享怎么发现问题、怎么思考方案、怎么验证效果——以及那些"看起来应该有用但实际没用"的弯路。希望对做 C++ 高性能服务器开发的同学有参考价值。 目录 Hical v2.6.0 性能优化心得:从 27K 到 159K QPS 的完整旅程 目录 1. 起点:27K QPS,差距 6 倍 2. 第一个教训:不要猜,要量 3. 找对方向:火焰图告诉你真相 4. 三阶段优化路线 5. 阶段一:调度模型重构(27K → 132K) 5.1 SO_REUSEPORT:消除跨线程调度 5.2 连接级 Timer + atomic 时间戳 5.3 结果 6. 阶段二:去 Beast,自研 HTTP/WS 栈(132K → 140K) 6.1 四个 Phase 6.2 零拷贝请求解析 6.3 结果 7. 阶段三:热路径微优化(140K → 159K) 7.1 修复 readBuf 残留数据丢弃(功能 BUG + 性能) 7.2 scatter-gather I/O 替代单 buffer 合并 7.3 其他微优化(含后续延迟分配优化) 7.4 结果 8. 最终火焰图:确认优化到位 9. 走过的弯路 弯路 1:优化不是瓶颈的代码 弯路 2:FixedBuffer 栈缓冲区太大 弯路 3:过早放弃 10. 总结:性能优化的方法论 原则一:Profiling 驱动,不靠直觉 原则二:按占比排序,从大到小 原则三:每步验证,不要积累 原则四:知道何时停手 最终成绩单 1. 起点:27K QPS,差距 6 倍 v2.5.1 的 Hical 在 Docker 环境(Ubuntu 24.04, GCC 14, 4 线程)下跑 Hello World benchmark,wrk 报出 ~27K QPS。 ...

May 11, 2026 · 6 min · 1235 words

Hical 性能剖析实战:perf + 火焰图定位 QPS 瓶颈

Hical 性能剖析实战:perf + 火焰图定位 QPS 瓶颈 在 C++ 框架性能实测中,Hical 的 Hello World QPS(~27K)远低于 Cinatra(165K)和 Drogon(161K)。静态链接 + strip 验证后确认瓶颈不在链接方式。本文记录用 perf record + 火焰图精确定位 CPU 热点的全过程。 目录 1. 背景与动机 2. Profiling 环境搭建 3. 数据采集 4. 火焰图分析 5. 优化方向 6. 复现指南 1. 背景与动机 1.1 已排除的因素 在本次 profiling 之前,已经通过对照实验排除了以下因素: 假设 验证方式 结论 动态链接 Boost 有性能损耗 改为 Boost 静态链接,重跑压测 QPS 无显著变化(27K → 27K) strip 影响性能 strip vs 不 strip 对比 无影响(符号表不参与运行时) 二进制体积(icache 压力) 7.8M(strip) vs 9.3M(不strip) QPS 在噪声范围内,非瓶颈 排除结论:性能瓶颈在框架运行时架构,需要 profiling 定位具体热点函数。 ...

May 9, 2026 · 4 min · 687 words