当前位置:首页 > 文章列表 > 文章 > linux > Linux bpftrace profile怎样按函数聚合CPU样本

Linux bpftrace profile怎样按函数聚合CPU样本

来源:17golang原创 2026-11-15 16:51:31 0浏览 收藏

想用 Linux 上的 bpftrace 找 CPU 热点时,profile 探针适合做按固定时间间隔抽样:每个 CPU 到达采样点就记录当前调用栈,再把相同函数或调用栈的样本累加。按函数聚合的关键不是把采样次数当成精确 CPU 秒数,而是先选好采样频率、栈类型和过滤条件,再用样本数量比较热点。

官方地址:https://bpftrace.org/

最小可用思路是:用 profile:hz:99 触发采样,用 ustack() 或 kstack() 作为聚合键,再用 PID、线程名或进程名收窄范围。样本越多只表示在采样窗口内越常出现在采样点,不等同于一次精确的函数耗时测量。

先分清 profile 采样到底统计什么

bpftrace 官方语言文档把 profile 定义为定时采样探针。它可以写成 profile:hz:99、profile:ms:10 或 profile:s:1 等形式;profile 探针按每个 CPU 的指定间隔触发,底层使用 Linux 的 perf events。这里的 99 Hz 是采样节奏,不是目标函数每秒被调用 99 次。

表达式含义适合场景
profile:hz:99按频率触发采样全局热点观察
profile:ms:10每 10 毫秒触发直观控制采样周期
profile:s:1每秒触发低成本长时间观察
interval:s:10每 10 秒执行一次 interval 代码输出或退出控制

因此,按函数聚合更接近采样型 profiling:在固定窗口里,某函数出现在栈顶或调用栈中的次数越多,说明它更可能是 CPU 热点。短函数、睡眠间隙、符号缺失和采样频率都会影响观察结果。

用 ustack 或 kstack 建立函数聚合键

最小的用户态聚合写法,是把当前用户态调用栈作为 map 的 key,把每次采样计为 1。下面是静态示例;代码只表达写法,不声称已经在本机执行。

profile:hz:99
{
    // 把用户态调用栈作为聚合键,每次采样增加一个样本
    @[ustack()] = count();
}

如果更关心内核路径,可以把聚合键换成 kstack();如果只想先看进程级分布,则可以按 comm 聚合:

profile:hz:49
{
    // 先按进程名聚合,低频率用于快速找出可疑进程
    @[comm] = count();
}

ustack() 回答用户程序从哪里消耗了采样点,kstack() 回答内核路径从哪里消耗了采样点,而 comm 只回答哪个进程名更常出现在采样点。排查时通常先从 comm 找范围,再切换到用户态或内核态栈。

bpftrace profile按时间采样并以用户态或内核态调用栈聚合的静态结构图
图1:结构图说明 profile 采样点如何进入 ustack、kstack 或 comm 聚合 map;这是原创静态说明图,不是截图或运行证据。

用 PID 过滤,再观察目标进程的调用栈

全机采样很容易被后台服务和内核线程淹没。已知目标进程 PID 时,可以在 probe 后面加条件,只保留该进程的样本:

profile:hz:99 /pid == 1234/
{
    // 只统计目标 PID 的用户态栈,避免其他进程污染结果
    @[ustack()] = count();
}

如果要按线程观察,可以使用 tid 作为一层 key,再配合用户态栈:

profile:hz:49 /pid == 1234/
{
    // 第一层区分线程,第二层保留用户态调用栈
    @[tid, ustack()] = count();
}

PID 过滤只限制采样事件中的当前进程,不会自动把子进程纳入统计;线程很多时把 tid 放进 key 会增加 map 基数;输出出现地址或 unknown 也不代表 profile 没有触发。

采样频率和运行窗口怎么选

频率越高,单位时间内样本越多,但观测成本、map 更新压力和输出体积也会增大。可以按这个顺序收敛:先用 49 Hz 左右摸底,再用 PID 或进程过滤,只有需要观察短函数或瞬时尖峰时才提高频率并缩短窗口。

# 先确认 bpftrace 版本;发行版文档应与实际版本对应
bpftrace --version

# 运行示例脚本并以短窗口观察;按 Ctrl-C 结束并输出 map
# ./cpu-profile.bt 只是示例脚本路径,不是固定系统路径
sudo bpftrace ./cpu-profile.bt

不要把采样频率机械地换算成函数占用百分比。均匀采样时,样本占比可以作为 CPU 热点的近似比较;调度、阻塞、符号化失败、CPU 亲和性和多进程竞争都会改变解释。对比两次采样时,应保持频率、窗口、过滤条件和负载一致。

bpftrace采样频率、目标过滤、运行窗口与样本解释边界的静态关系图
图2:说明图展示采样频率、过滤条件、窗口长度与样本解释之间的关系;图中是方法示意,不代表某次真实输出。

读懂 map 输出和符号化限制

脚本结束时,bpftrace 会打印非空 map。对 @[ustack()] = count() 来说,每组调用栈后的数字是该栈被采到的次数;对 @[comm] = count() 来说,数字是进程名对应的采样次数。它们都应被称为样本数,而不是函数调用次数或精确 CPU 时间。

现象优先解释下一步
某个栈样本数高该栈在窗口更常出现保持条件重复或延长窗口
只看到地址或 unknown符号表、权限或栈展开不足检查符号包、构建选项和版本
map 项很多聚合键过细或窗口过大先按 comm、PID 收敛
用户态栈为空用户栈无法展开或过滤不匹配分别检查过滤与符号条件

如果需要控制输出频率,可以把观测和输出控制分开:profile 负责累加样本,interval 负责周期性打印或清理 map。不要在每个采样点直接打印文本,否则大量输出会改变被观测程序的行为。

一套可复用的排障顺序

  1. 确认探针触发:先用 comm 或简单计数确认 profile 事件能产生数据。
  2. 确认范围:检查 PID、线程和 CPU 范围,没有把后台任务误当目标。
  3. 匹配栈类型:用户态问题用 ustack,内核路径用 kstack。
  4. 处理符号:地址解析失败时先处理符号和权限,再讨论函数热点。
  5. 重复采样:用相同负载和参数重复采样,避免只依赖一次短窗口。

一个函数样本数高,可能是它本身慢,也可能是它被许多路径共同调用;需要结合调用栈上下文、输入负载和阻塞状态继续分析。

常见问题

profile 统计的是函数调用次数吗?

不是。它按时间点采样当前执行上下文,聚合的是样本出现次数。调用很多但执行极短的函数,未必比少量但执行较久的调用得到更多样本。

为什么 99 Hz 不是每秒恰好 99 个样本?

profile 按每个 CPU 的节奏触发,CPU 数、调度状态、目标过滤和系统能力都会影响实际可见样本;99 Hz 只是请求的采样频率。

ustack 和 kstack 能放在同一个 map key 里吗?

不建议直接混用。两者描述的地址空间和符号解析边界不同,分开聚合更容易解释;需要对照时分别输出,再按同一窗口比较。

什么时候应该换用 perf 或专用 profiler?

需要成熟调用图、长期采样、复杂用户态符号处理或跨平台分析时,应评估 perf、语言运行时 profiler 或持续观测方案;bpftrace 更适合快速提出清晰的内核或用户态观测问题。

总结

Linux bpftrace 的 profile 探针提供按时间抽样的 CPU 观察入口。以 ustack()、kstack() 或 comm 为聚合键,把样本集中到 map 中,再通过 PID、线程和运行窗口逐层收敛,就能快速找出值得继续分析的函数路径。记住样本数是近似信号,不是精确 CPU 时间;频率、符号、过滤条件和重复窗口决定结论是否可信。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Linux systemd socket激活服务Linux systemd socket激活服务
上一篇
Linux systemd socket激活服务
nftables list ruleset怎样按地址族导出配置
下一篇
nftables list ruleset怎样按地址族导出配置
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    1039次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    1038次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1181次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1143次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    987次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码