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.rhkb.cn/news/188589.html

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

相关文章

2022最新版-李宏毅机器学习深度学习课程-P50 BERT的预训练和微调

模型输入无标签文本&#xff08;Text without annotation&#xff09;&#xff0c;通过消耗大量计算资源预训练&#xff08;Pre-train&#xff09;得到一个可以读懂文本的模型&#xff0c;在遇到有监督的任务是微调&#xff08;Fine-tune&#xff09;即可。 最具代表性是BERT&…

在线生成二维码--支持彩色二维码和包含Logo

具体请前往&#xff1a;在线二维码生成工具--可将网址等内容生成为指定大小&#xff0c;指定颜色的彩色二维码,同时支持添加Logo

数据结构:Map和Set(2):相关OJ题目

目录 136. 只出现一次的数字 - 力扣&#xff08;LeetCode&#xff09; 771. 宝石与石头 - 力扣&#xff08;LeetCode&#xff09; 旧键盘 (20)__牛客网 (nowcoder.com) 138. 随机链表的复制 - 力扣&#xff08;LeetCode&#xff09; 692. 前K个高频单词 - 力扣&#xff08…

linux_day02

1、链接&#xff1a;LN 一个点表示当前工作目录&#xff0c;两个点表示上一层工作目录&#xff1b; 目录的本质&#xff1a;文件&#xff08;该文件储存目录项&#xff0c;以链表的形式链接&#xff0c;每个结点都是目录项&#xff0c;创建文件相当于把目录项添加到链表中&…

【Unity之UI编程】编写一个面板交互界面需要注意的细节

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

devops完整搭建教程(gitlab、jenkins、harbor、docker)

devops完整搭建教程&#xff08;gitlab、jenkins、harbor、docker&#xff09; 文章目录 devops完整搭建教程&#xff08;gitlab、jenkins、harbor、docker&#xff09;1.简介&#xff1a;2.工作流程&#xff1a;3.优缺点4.环境说明5.部署前准备工作5.1.所有主机永久关闭防火墙…

[PHP]Kodexplorer可道云 v4.47

KodExplorer可道云&#xff0c;原名芒果云&#xff0c;是基于Web技术的私有云和在线文件管理系统&#xff0c;由上海岱牧网络有限公司开发&#xff0c;发布于2012年6月。致力于为用户提供安全可控、可靠易用、高扩展性的私有云解决方案。 用户只需通过简单环境搭建&#xff0c;…

数据库安全:Hadoop 未授权访问-命令执行漏洞.

数据库安全&#xff1a;Hadoop 未授权访问-命令执行漏洞. Hadoop 未授权访问主要是因为 Hadoop YARN 资源管理系统配置不当&#xff0c;导致可以未经授权进行访问&#xff0c;从而被攻击者恶意利用。攻击者无需认证即可通过 RESTAPI 部署任务来执行任意指令&#xff0c;最终完…

SQL SELECT INTO 语句

SQL SELECT INTO 语句 使用 SQL&#xff0c;您可以将信息从一个表中复制到另一个表中。 SELECT INTO 语句从一个表中复制数据&#xff0c;然后将数据插入到另一个新表中。 SQL SELECT INTO 语法 我们可以把所有的列都复制到新表中&#xff1a; SELECT * INTO newtable [IN ex…

【Git】说说Git中开发测试的使用Git分支Git标签的使用场景

一、Git的使用场景 1、四个环境以及各自的功能特点 dev环境&#xff1a;开发环境&#xff0c;外部用户无法访问&#xff0c;开发人员使用&#xff0c;版本变动很大。test环境&#xff1a;测试环境&#xff0c;外部用户无法访问&#xff0c;专门给测试人员使用的&#xff0c;版本…

Spring Boot (三)

1、热部署 热部署可以替我们节省大把花在重启项目本身上的时间。热部署原理上&#xff0c;一个springboot项目在运行时实际上是分两个过程进行的&#xff0c;根据加载的东西不同&#xff0c;划分成base类加载器与restart类加载器。 base类加载器&#xff1a;用来加载jar包中的类…

如何在苹果iOS系统ipa应用中获取当前版本号和Bundle ID

在iOS应用开发过程中&#xff0c;了解如何获取和使用应用的当前版本号、Bundle ID和其他相关信息是至关重要的。无论是在应用内显示这些信息&#xff0c;还是在编写一些版本依赖的逻辑时&#xff0c;掌握这些知识点都将帮助开发者进行更有效的管理和维护。本文将详细介绍如何在…

【探索Linux】—— 强大的命令行工具 P.14(进程间通信 | 匿名管道 | |进程池 | pipe() 函数 | mkfifo() 函数)

阅读导航 引言一、进程间通信概念二、进程间通信目的三、进程间通信分类四、管道1. 什么是管道2. 匿名管道&#xff08;1&#xff09;创建和关闭⭕pipe() 函数⭕创建匿名管道⭕关闭匿名管道 &#xff08;2&#xff09;通信方式&#xff08;3&#xff09;用法示例&#xff08;4&…

腾讯云3年期轻量应用服务器优惠(薅羊毛教程)

腾讯云轻量应用服务器特价是有新用户限制的&#xff0c;所以阿腾云建议大家选择3年期轻量应用服务器&#xff0c;一劳永逸&#xff0c;免去续费困扰。腾讯云轻量应用服务器3年优惠可以选择2核2G4M和2核4G5M带宽&#xff0c;3年轻量2核2G4M服务器540元&#xff0c;2核4G5M轻量应…

Vatee万腾科技决策力的未来展望:开创数字化创新的新高度

随着科技不断演进&#xff0c;Vatee万腾的科技决策力在数字化创新领域展现出了强大的潜力和前瞻性。 Vatee万腾的科技决策力被视为数字化创新的引擎&#xff0c;为未来创新注入了新的动力。通过深刻的市场洞察和科学决策&#xff0c;Vatee万腾致力于推动数字化创新走向新的高度…

SW如何显示样条曲线的控标

刚刚学习隔壁老王的sw画图时&#xff0c;怎么点都点不出样条曲线的控标&#xff0c;于是果断查询了一下解决方法&#xff0c;其实很简单&#xff0c;只不过是培训机构故意不说&#xff0c;叫你还解决不了&#xff0c;难受了就会花钱买他们的课了。毕竟如果学会了怎么解决问题了…

【Linux C IO多路复用】多用户聊天系统

目录 Server-Client mutiplexingServer mutiplexingClient mutiplexing Server-Client 在Linux系统中&#xff0c;IO多路复用是一种机制&#xff0c;它允许一个进程能够监视多个文件描述符&#xff08;sockets、pipes等&#xff09;的可读、可写和异常等事件。这样&#xf…

计算机毕业设计 基于SpringBoot的驾校管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

win10虚机扩容C盘

需求&#xff1a; 在虚机管理平台上&#xff0c;将win10虚机的C盘空间扩容至200G&#xff0c;当前空间为100G 操作步骤 1.在虚机平台上&#xff0c;将硬盘1的大小增加至200G 如下图 点击保存&#xff1b; 查看win10虚机&#xff0c;发现C盘空间还是100G&#xff0c;如下图…

C++学习---信号处理机制、中断、异步环境

文章目录 前言信号处理signal()函数关于异步环境 信号处理函数示例raise()函数 前言 信号处理 关于信号&#xff0c;信号是一种进程间通信的机制&#xff0c;用于在程序执行过程中通知进程发生了一些事件。在Unix和类Unix系统中&#xff0c;信号是一种异步通知机制&#xff0c…