Learn runqlat in 5 minutes

内容预告

learn X in 5 系列第一篇. 本篇主要介绍进程时延统计方式和 rawtracepoint.

runqlat

"高负载场景下应用为何卡顿", "进程 A 为什么得不到调度". 当我们在工作生活中产生这样的疑问, 目标进程的调度时延是一个不错的观测切入点. runqlat 可以帮我们完成这项统计, 以下是父子线程通过 pipe 通信, 通过 runqlat.bt 统计得到双方的时延信息:

我们做了些手脚, 让线程 524785 运行条件更为恶劣, 通过上图可以发现双方调度时延有着显著的区别. 采集数据使用的 runqlat.bt 是使用 bpftrace 重写的 bcc/tools/runqlat, bpftrace 语法参考上篇文章:

$ wget -qO - https://raw.githubusercontent.com/lilstaz/perf-tool-examples/main/bpftrace/runqlat.bt
BEGIN
{if (!$1) // 1{printf("Specify the pid of the task first\n");exit();}@pid = $1;printf("Tracing latency of task %d. Hit Ctrl-C to end.\n", @pid);
}rt:sched_wakeup, // 2
rt:sched_wakeup_new
{$wakee = (struct task_struct*)arg0;if ($wakee->tgid == @pid) // 3{@qt[$wakee->pid] = nsecs;}
}rt:sched_switch // 4
{$prev = (struct task_struct*)arg1;$next = (struct task_struct*)arg2;if ($prev->tgid == @pid && $prev->state == TASK_RUNNING) // 5{@qt[$prev->pid] = nsecs;}if ($next->tgid == @pid && @qt[$next->pid]) // 6{@[@pid] = hist((nsecs - @qt[$next->pid]) / 1000);delete(@qt[$next->pid]);}
}
# 运行效果
$ wget -qO - https://raw.githubusercontent.com/lilstaz/perf-tool-examples/main/bpftrace/runqlat.bt| bpftrace - // 7
Attaching 5 probes...
Tracing latency of task 524783. Hit Ctrl-C to end.@[524783]: 
[128, 256)             2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|@[524785]: 
[8K, 16K)             79 |@@@@@@@@@@@@@                                       |
[16K, 32K)           307 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[32K, 64K)            28 |@@@@                                                |

该脚本实现统计指定进程中所有线程的调度时延(从加入运行队列进程实际运行), 其中:

  1. 强制用户输入待观测的进程号, 将用户输入的进程号赋值给全局变量 @pid;

  2. 通过 , 分隔挂载点, 可以将该段代码段挂在多个挂载点上. 这里 rtrawtracepoint 的缩写, 会在下一节介绍;

  3. 该挂载点第一个参数是被唤醒进程的 PCB, 该结构体保存了进程的 tgid(对应用户态的进程 ID), pid(对应用户态的线程 ID), comm 进程名等信息. 当满足条件 $wakee->tgid == @pid, 则说明目标进程的某线程进入了唤醒逻辑, 即将被放置在运行队列上, 我们使用线程号作为 @qt 哈希表的键, 将此时系统纳秒数保存下来;

  4. 进程发生切换时会执行以下代码段;

  5. 我们使用 $prev 标志被剥夺运行权的进程, 使用 $next 标志即将获得运行权的进程. 在 linux 中, 运行中以及在队列等待的进程状态都为 TASK_RUNNING. 若 $prev 进程状态为 TASK_RUNNING, 说明它将重新入队. 我们需要更新它的入队时间为当前时间;

  6. $next 线程终于在运行队列熬到头, 即将拥有 CPU 的运行权, 通过计算当前时间和入队时间之间的差值, 我们就可以得到该线程的调度时延. 通过 hist() 函数, bpftrace 可以帮忙把数据统计成直方图;

  7. 如果无法运行请下载最新版本的 bpftrace.

rawtracepoint

tracepoints 是内核内置静态的事件源, 接口稳定, 且包含了大部分子系统, 是优质的信息来源, 例如对于调度子系统有以下可用的 tracepoint:

$ grep sched: /sys/kernel/debug/tracing/available_events
...
sched:sched_migrate_task
sched:sched_switch
...

tracepoint 本质是内核中的打印语句, 它们以固定的格式被打印, 可以通过 /sys/kernel/debug/tracing/events/<子系统>/<名称>/format 文件查看打印格式. 以 sched:sched_switch 为例:

$ cat /sys/kernel/debug/tracing/events/sched/sched_switch/format
name: sched_switch
ID: 313
format:field:unsigned short common_type;       offset:0;       size:2; signed:0;field:unsigned char common_flags;       offset:2;       size:1; signed:0;field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;field:int common_pid;   offset:4;       size:4; signed:1;field:char prev_comm[16];       offset:8;       size:16;        signed:1;field:pid_t prev_pid;   offset:24;      size:4; signed:1;field:int prev_prio;    offset:28;      size:4; signed:1;field:long prev_state;  offset:32;      size:8; signed:1;field:char next_comm[16];       offset:40;      size:16;        signed:1;  // 1field:pid_t next_pid;   offset:56;      size:4; signed:1;field:int next_prio;    offset:60;      size:4; signed:1;print fmt: "prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s%s ==> next_comm=%s next_pid=%d next_prio=%d", ...) : 

假设我们对即将获得运行权的进程名感兴趣, 我们可以用以下语句打印标号 1 处定义的信息:

$ bpftrace -e 't:sched:sched_switch {printf("%s\n", args->next_comm)}'
swapper/5
pthread_pipe
pthread_pipe
...

tracepoint 很完美, 它总是在代码关键路径出现. 对于理解内核代码, 抑或调试都非常好用. 但在以下场景:

  1. 对观测脚本的性能有要求;

  2. 希望从原数据结构获取更丰富的信息. 使用 rawtracepoint 或许是更合适的.

那么 rawtracepoint 是什么? 它可以理解为 tracepoint 的另一面, /sys/kernel/debug/tracing/available_events 中可用的事件, rawtracepoint 都可以使用, 但相对 tracepoint 提供特定的值, rawtracepoint 直接提供内核数据结构. 即更接近内核的 '第一手数据'. 再次以 sched:sched_switch 为例, 相关代码(include/trace/events/sched.h)如下:

TRACE_EVENT(sched_switch,TP_PROTO(bool preempt, struct task_struct *prev, struct task_struct *next), // 1TP_fast_assign(memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);__entry->prev_pid = prev->pid;   // 2__entry->prev_prio = prev->prio;__entry->prev_state = __trace_sched_switch_state(preempt, prev);memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);__entry->next_pid = next->pid;   // 3__entry->next_prio = next->prio;),TP_printk("prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s%s ==> next_comm=%s next_pid=%d next_prio=%d", ...)
);

根据标号 1 的定义, 该 tracepoint 接受调度子系统给它传递的三个参数 preempt, prev, next, 并通过 TP_printk() 打印到环形缓冲区. 在第一节 runqlat 中, 为了过滤特定进程的调度时延, 我们需要获取进程切换时两个进程的 tgid 以及 pid. 但根据标号 2 和 3, tracepoint 只能获取到 pid. 为了直接使用 preempt, prev, next 三个变量, 我们可以使用 rawtracepoint, 在 bpftrace 中简写为 rt. 回顾第一节的代码:

rt:sched_switch
{$prev = (struct task_struct*)arg1;$next = (struct task_struct*)arg2;
...

这里 $prev $next 其实是获取了该 tracepoint 中 TP_PROTO 定义的第 2 和第 3 个参数. 因为只获取参数, 不需要构建 context 结构体, 使得 rawtracepoint 比 tracepoint 的效率更高.

后记

在 bpftrace git 仓库其实有另一个版本的 runqlat.bt , 但没有提供追踪特定进程的功能. 当年用它查问题写了相当绕且丑的逻辑. 知道有 rawtracepoint 之后, 对调度子系统的追踪观测明显方便了几个数量级.

在 tracepoint 无法满足你的场景, 记得翻代码看看它 TP_PROTO, rawtracepoint 总能给你惊喜.

ref

  1. Frequently asked questions about using raw tracepoint with ebpf/libbpf programs[1]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/168472.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【网络编程】网络层——IP协议

文章目录 基本概念路径选择主机和路由器 IP协议格式分片与组装网段划分IP地址的数量限制私网IP地址和公网IP地址深入认识局域网路由 基本概念 TCP作为传输层控制协议&#xff0c;其保证的是数据传输的可靠性和传输效率&#xff0c;但TCP提供的仅仅是数据传输的策略&#xff0c…

C语言 每日一题 PTA 11.7 day13

1.求e的近似值 自然常数 e 可以用级数 1 1 / 1! 1 / 2! ⋯ 1 / n! ⋯ 来近似计算。 本题要求对给定的非负整数 n&#xff0c;求该级数的前 n 1 项和。 代码实现 #include<stdio.h> void main() {int a, i, j; double b 1; double c 1;printf("请输入一个数\n…

考研数据结构单链表的增删改查看这一篇就够了

目录 一. 单链表的特点 1.1 解引用拓展 &#x1f916; 二. 单链表的操作 2.1不带头节点的操作 2.1.1 打印 2.1.1.1 创建结点 2.1.2 尾插&#xff08;需要二级指针&#xff09; 注意形参的值不改变实参&#xff1a;&#xff08;精髓部分&#xff09; 2.1.3 头插 2.1.4…

苹果手机安装未上架APP应用测试教程

STEP 2&#xff1a;找到下载的描述文件&#xff08;如果没有找到&#xff0c;请到 设置 - 通用 - 描述文件 中查看&#xff09; STEP 3&#xff1a;安装描述文件 STEP 4&#xff1a;输入解锁密码安装描述文件 STEP 5&#xff1a;同意免责声明&#xff0c;安装描述文件 STEP 6…

单词规律问题

给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 示例1: 输入: pattern “abba”, s “dog cat cat d…

一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?

目录 1解题思路&#xff1a; 2代码如下&#xff1a; 3运行结果&#xff1a; 4总结&#xff1a; 5介绍&#xff1a; 1解题思路&#xff1a; 利用循环&#xff08;穷举法&#xff09;来 对 所 需要的数 进行确定 2代码如下&#xff1a; #include <stdio.h>int main() …

[蓝桥杯复盘] 第 3 场双周赛20231111

[蓝桥杯复盘] 第 3 场双周赛20231111 总结深秋的苹果1. 题目描述2. 思路分析3. 代码实现 鲜花之海1. 题目描述2. 思路分析3. 代码实现 斐波拉契跳跃2. 思路分析3. 代码实现 星石传送阵2. 思路分析3. 代码实现 六、参考链接 总结 做了后4题。https://www.lanqiao.cn/oj-contes…

react+星火大模型,构建上下文ai问答页面(可扩展)

前言 最近写的开源项目核心功能跑通了&#xff0c;前两天突发奇想。关于项目可否介入大模型来辅助用户使用平台&#xff0c;就跑去研究了最近比较活火的国内大模型–讯飞星火大模型。 大模型api获取 控制台登录 地址&#xff1a;https://console.xfyun.cn/app/myapp 新建应…

ceph-deploy bclinux aarch64 ceph 14.2.10

ssh-copy-id&#xff0c;部署机免密登录其他三台主机 所有机器硬盘配置参考如下&#xff0c;计划采用vdb作为ceph数据盘 下载ceph-deploy pip install ceph-deploy 免密登录设置主机名 hostnamectl --static set-hostname ceph-0 .. 3 配置hosts 172.17.163.105 ceph-0 172.…

火星加载WMTS服务

这是正常的加载瓦片 http://192.168.1.23:8008/geoserver/mars3d/gwc/service/wmts?tilematrixEPSG%3A4326%3A7&layermars3d%3Abuffer&style&tilerow46&tilecol197&tilematrixsetEPSG%3A4326&formatimage%2Fpng&serviceWMTS&version1.0.0&…

商越科技:渗透测试保障平台安全,推动线上采购高效运转

商越科技是数字化采购解决方案提供商&#xff0c;在同赛道企业中始终保持前列。商越科技通过自主研发的智能采购中台、SaaS应用及运营服务等为企业搭建专属的互联网采购平台&#xff0c;帮助企业实现采购数字化以及智能化转型&#xff0c;提高工作效率、降低采购成本。 打造数字…

【扩散模型】万字长文全面理解与应用Stable Diffusion

万字长文全面理解与应用Stable Diffusion 1. Stable Diffusion简介1.1 基本概念1.2 主体结构1.3 训练细节1.4 模型评测1.5 模型应用1.6 模型版本1.7 其他类型的条件生成模型1.8 使用DreamBooth进行微调 2. 实战Stable Diffusion2.1 环境准备2.2 从文本生成图像2.3 Stable Diffu…