2026年7月28日 1 分钟阅读

CPU 利用率很高却不一定慢:用 swift-topomap 把 NUMA、IPC 与进程调度放到同一张终端图里

tinyash 0 条评论

排查 Linux 服务主机的性能问题时,tophtop 和监控平台通常会告诉我们:某个进程占满了 CPU。但这是“忙”的信号,不等于解释了“为什么慢”。同样是 100% 的 CPU 使用率,一个线程可能持续完成有效计算,另一个线程则可能频繁等待内存;在多 NUMA 节点机器上,进程运行的核心与内存所在节点不匹配,也会让普通 CPU 百分比失去解释力。

swift-topomap 是 SwiftLogic Systems 发布的 Apache-2.0 开源终端工具。它将 Linux sysfs 的硬件拓扑、硬件性能计数器和 eBPF 的调度信息放进 Ratatui TUI:既显示 CPU 核心、L3 缓存边界与 NUMA 内存,也呈现 IPC、缓存未命中相关信号以及运行在核心上的进程/PID。它适合用作“性能调查的第一屏”,而不是替代持续监控系统。

先把“CPU 很忙”拆成三个问题

传统仪表盘擅长回答“哪台机器、哪个进程、哪个核忙”。需要进一步归因时,至少还要区分三层。

  1. 拓扑层:核心属于哪个 NUMA 节点,哪些核心共享 L3 缓存;线程和内存是否可能跨节点访问。
  2. 执行质量层:IPC(每周期完成的指令数)可以辅助判断核心是在高效执行,还是受访存、分支等微架构因素制约。它不是业务吞吐量,更不能脱离工作负载给出绝对的“好/坏”。
  3. 调度归因层:在异常核心上究竟是哪一个 PID 在运行。仅有 CPU 曲线时,工程师常要在多个命令和时间窗口之间手工对齐;调度归因把这一步前移到同一界面。

swift-topomap 的定位就是关联这些信息。项目 README 描述它通过 sysfs 按物理 L3 缓存边界组织核心,而不是依赖 libhwloc;eBPF 的 sched_switch hook 用于显示正在特定物理核心上运行的进程名称与 PID。对怀疑存在 NUMA 放置不当、缓存压力或局部热点的服务,这个组合比只看平均 CPU 使用率更有用。

最小启动方式

项目当前 README 给出的发布二进制安装方式如下。命令会下载 v0.2.3-beta 的 Linux 二进制,将其设为可执行文件,再以管理员权限启动:

curl -L -o topomap https://github.com/swiftlogicsystems/swifttopology/releases/download/v0.2.3-beta/swift-topomap \
  && chmod +x topomap \
  && sudo ./topomap

这里的 sudo 不是装饰:工具需要读取系统拓扑并加载 eBPF 相关能力。上线前应先在测试或低风险主机运行,确认组织对 eBPF、性能计数器访问和管理员权限的安全策略;不要把从未审查的二进制直接放进生产自动化流程。

启动后,建议先在没有压测的基线状态下观察一遍,再在问题复现期间对照变化。不要从单个数值得出结论:先找出高负载核心所在的 NUMA/L3 分组,再看 IPC 与进程归因是否同步变化,最后回到应用线程、绑定策略和内存分配行为验证假设。

一个可复现的排查路径

假设某个推理或编译服务在高并发时 P99 延迟升高,监控显示整机 CPU 尚未打满。可以采用下面的调查顺序:

  • 在基线和异常窗口各记录一次 TUI 中的核心分布:热点是否集中在少数物理核心,是否跨越多个 NUMA 节点。
  • 对照异常核心的 IPC:如果 CPU 占用很高但 IPC 低,不要马上增加 worker;先把它当成“需要验证的内存或微架构瓶颈”线索。
  • 查看该核心上出现的进程名与 PID,把线索带回应用侧。检查线程池、CPU affinity、容器 CPU 集、批处理并发和内存分配策略是否让关键线程长期聚集。
  • 做一次小范围变更,例如调整并发或线程绑定,然后重复同一负载和观察窗口。只有延迟、吞吐和拓扑/执行信号一起改善,才把假设视为成立。

流程的价值不在于 TUI 自动给出结论,而在于它将“核心—缓存/NUMA 边界—执行信号—运行进程”放在同一个时间点,减少在 topnumactl、性能分析器和日志之间来回猜测的成本。

从现象到验证:不要把拓扑图当作结论

性能排障最昂贵的部分,往往不是缺少指标,而是团队把相关性当成了因果关系。比如某个核心显示较低 IPC,可能是等待内存,也可能只是该线程执行了不同类型的指令;某个 PID 持续出现在热点核心,也可能是采样瞬间恰好被调度到那里。swift-topomap 应该帮助你设计下一步实验,而不是让你跳过实验。

一个稳妥的做法是先固定三件事:请求集或压测脚本、并发度、观察时长。随后每次只改变一个变量。例如,将 worker 数从 16 改为 12 后,除了看 P99 延迟,也记录热点核心是否更分散、异常核心的 IPC 是否回升、对应 PID 的运行位置是否改变。如果结果没有稳定复现,不应把这次 TUI 观察写成架构判断。

在容器环境中,还要补充核对 CPU 配额与 CPU 集。应用看到的逻辑 CPU、容器允许使用的 CPU,以及宿主机的物理核心和 NUMA 边界并非同一个视角。工具显示的物理布局能提醒工程师继续检查运行时配置,但不能自动推导 Kubernetes 的调度策略、cgroup 限制或内存策略。把这一层信息与部署清单、容器运行参数以及应用线程模型放在一起看,才有可能找出真正的错配。

对于需要长期保留证据的事故,建议把 TUI 作为交互式定位工具:先在现场缩小范围,再使用团队现有的 metrics、profile、火焰图或 trace 保存可比较的数据。这样既保留了终端工具的即时性,也避免把一次视觉观察误当成可审计的性能报告。

读数时最容易犯的错误

第一,不能把 IPC 当成跨应用、跨 CPU 型号的绝对评分。不同指令组合和处理器架构本来就会产生不同 IPC;它更适合比较同一工作负载变更前后的趋势,或比较同一台机器上同时出现异常的核心。

第二,看到核心与某个 NUMA 节点相邻,并不能证明应用内存一定分配在该节点。拓扑图提供的是调查入口,内存亲和性和实际页分布仍需要用系统工具与应用数据继续验证。

第三,eBPF 调度归因展示的是观测时刻的调度信息。短生命周期线程、高频上下文切换和容器运行时都可能让画面快速变化;需要在可重复的负载窗口中观察,而不是截一次图就下结论。

swift-topomap 是 README 所称的单个静态链接二进制,体积约 3.5MB、没有额外安装器;这降低了临时诊断的部署摩擦,但不意味着它已经覆盖告警、长期存储、跨节点聚合或业务指标关联。更实际的用法是:让它与现有 Prometheus、日志和 profiling 流程互补,负责缩小“性能到底卡在机器哪一层”的搜索范围。

一次排查可以留下什么记录

为了让下一位值班工程师能够复核判断,建议在事件记录中写清楚观察条件,而不只贴一张终端截图:主机型号和内核版本、是否裸金属或容器、负载开始与结束时间、异常核心所在的 NUMA/L3 分组、出现过的进程 PID,以及对照实验修改了什么。若使用的是下载的发布二进制,也记录其 release 版本和校验流程。这样,后续即使换了机器或升级内核,团队仍能区分“负载变化”与“观测环境变化”。

还应把工具的边界写进结论。项目使用 eBPF 和硬件计数器带来的优势是能靠近内核调度与物理拓扑;代价是不同 CPU、内核配置和权限模型下可见的数据可能不同。对于多租户生产集群,先与平台和安全团队确认权限范围,再把它用于临时诊断,比把管理员权限常态化交给应用容器更稳妥。

适合谁用

如果你维护单机性能敏感服务、裸金属工作负载,或需要理解容器背后实际 CPU/NUMA 位置的 SRE 与系统工程团队,swift-topomap 值得放进排障工具箱。它最适合回答“这台机器的热点在哪里、在怎样的硬件边界内、此刻是谁在跑”;随后仍应由基准、profile 与业务指标完成因果验证。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。