-
Notifications
You must be signed in to change notification settings - Fork 173
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #758 from vvzxy/develop
cpu_watcher:添加readme文档
- Loading branch information
Showing
1 changed file
with
225 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
# cpu_watcher:动态CPU指标实时监测 | ||
|
||
## 一、项目简介 | ||
|
||
`CPU_Watcher`是一项基于`eBPF(Extended Berkeley Packet Filter)`技术的项目,旨在实现对`CPU`各项指标的实时动态监测和分析,可以清晰且直观的了解CPU资源利用率以及事件的发生的速率。 | ||
|
||
本工具使用ebpf工具进行实现,`eBPF`是`Linux`内核中的一种强大的工具,它允许在内核空间执行小型程序,用于在运行时过滤、转发和监控系统事件。 | ||
|
||
`CPU_Watcher`利用`eBPF`的这一特性,通过在内核空间执行精简的程序来捕获`CPU`相关的事件和指标,从而实现对`CPU`性能的实时监测和分析。 | ||
|
||
## 二、使用方法 | ||
|
||
### 1.使用环境 | ||
|
||
- OS:Ubuntu 22.04 | ||
- kernel:Linux 6.2 | ||
|
||
### 2.编译运行 | ||
|
||
```shell | ||
make 编译 | ||
sudo ./cpu_watcher -[options] 运行 | ||
make clean 清除生成文件 | ||
``` | ||
|
||
## 三、功能介绍 | ||
|
||
`cpu_watcher`是一个用于监视系统 CPU 使用情况的工具,它可以帮助用户了解系统在不同负载下的性能表现,并提供详细的统计数据。该工具分为以下几个部分,通过不同的参数控制相关的`ebpf`捕获程序是否加载到内核中: | ||
|
||
| 参数 | 描述 | | ||
| :----------------: | :----------------------------------------: | | ||
| -s :SAR | 实时采集SAR的各项指标,每秒输出一次 | | ||
| -p:preempt_time | 实时采集当前系统的每次抢占调度详细信息 | | ||
| -d:schedule_delay | 实时采集当前系统的调度时延 | | ||
| -S:syscall_delay | 实时采集当前系统调用时间 | | ||
| -m:mq_delay | 实时采集当前消息队列通信时延 | | ||
| -c:cs_delay | 实时对内核函数schedule()的执行时长进行测试 | | ||
|
||
### 1.SAR 统计功能(每秒输出一次): | ||
|
||
#### 输出效果: | ||
|
||
``` | ||
time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms | ||
16:18:03 29 1216 1 1277 19394 1087 2908 662 747 665 | ||
16:18:04 43 2036 2 1262 24823 1432 3981 72 171 76 | ||
16:18:05 0 1371 2 4927 16949 1152 2489 538 636 541 | ||
16:18:06 11 2569 4 10900 9085 518 2967 941 1121 944 | ||
16:18:07 3 5166 4 9929 15864 469 10778 482 1020 493 | ||
16:18:08 30 2426 2 2436 17877 1435 5086 90 262 96 | ||
16:18:09 43 1257 1 351 20457 1713 3040 8 40 11 | ||
16:18:10 0 813 1 20071 30563 1727 117472 41 0 159 | ||
16:18:11 0 751 1 748 14532 1855 3935 16 50 20 | ||
16:18:12 0 1118 1 1115 20750 1733 1956 1 50 3 | ||
16:18:13 29 1083 1 286 18081 1698 3861 50 10 54 | ||
16:18:14 43 1032 1 577 19513 1704 3919 26 10 30 | ||
``` | ||
|
||
对上述参数的解释: | ||
|
||
- `proc/s`: 每秒创建的进程数,此数值是通过fork数来统计的。 | ||
- `cswch/s`: 每秒上下文切换数。 | ||
- `runqlen`:此时CPU的运行队列的长度。 | ||
- `irqTime/us`:CPU响应`irq`中断所占用的时间,是所有CPU时间的叠加。 | ||
- `softirq/us`: CPU执行`softirq`所占用的时间,是所有CPU时间的叠加。 | ||
- `idle/ms`: CPU处于空闲状态的时间,是所有CPU时间的叠加。 | ||
- `kthread/us`: CPU执行内核线程所占用的时间,是所有CPU的叠加。不包括IDLE-0进程,因为此进程只执行空闲指令使CPU闲置。 | ||
- `sysc/ms`: CPU执行用户程序系统调用(`syscall`)所占用的时间,是所有CPU的叠加。 | ||
- ` utime/ms`:CPU执行普通用户进程时,花在用户态的时间,是所有CPU的叠加。 | ||
|
||
### **2.统计抢占调度时间:** | ||
|
||
统计系统中发生抢占调度的情况,包括抢占进程的`pid`与进程名,以及被强占进程的`pid`,和本次抢占时间,单位纳秒。 | ||
|
||
#### 输出效果: | ||
|
||
``` | ||
COMM prev_pid next_pid duration_ns | ||
node 14221 2589 3014 | ||
kworker/u256:1 15144 13516 1277 | ||
node 14221 2589 3115 | ||
kworker/u256:1 15144 13516 1125 | ||
kworker/u256:1 15144 13516 974 | ||
node 14221 2589 2560 | ||
kworker/u256:1 15144 13516 1132 | ||
node 14221 2589 2717 | ||
kworker/u256:1 15144 13516 1206 | ||
kworker/u256:1 15144 13516 1131 | ||
node 14221 2589 3355 | ||
``` | ||
|
||
### 3.**统计调度延迟:** | ||
|
||
分析系统中进程调度的延迟情况,提供相关统计数据,输出包括当前系统的最大调度延迟、最小调度延迟、平均调度延迟。 | ||
|
||
#### 输出效果: | ||
|
||
``` | ||
TIME avg_delay/μs max_delay/μs min_delay/μs | ||
17:31:28 35.005000 97.663000 9.399000 | ||
17:31:29 326.518000 12618.465000 7.994000 | ||
17:31:30 455.837000 217053.545000 6.462000 | ||
17:31:31 422.582000 217053.545000 6.462000 | ||
17:31:32 382.627000 217053.545000 6.462000 | ||
17:31:33 360.499000 217053.545000 6.462000 | ||
17:31:34 364.805000 217053.545000 6.462000 | ||
17:31:35 362.039000 217053.545000 6.462000 | ||
17:31:36 373.751000 217053.545000 6.462000 | ||
``` | ||
|
||
### 4.**统计系统调用响应时间:** | ||
|
||
记录系统调用的响应时间,帮助用户评估系统对外部请求的处理效率, 其输出包括发起本次系统调用的进程的进程名、pid、系统调用号以及响应时间。 | ||
|
||
#### 输出效果: | ||
|
||
``` | ||
Time Pid comm syscall_id delay/us | ||
21:28:07 276073 cpu_watcher 1 21 | ||
21:28:07 2579 node 0 7 | ||
21:28:07 276073 cpu_watcher 4 8 | ||
21:28:07 2579 node 232 6 | ||
21:28:07 2579 node 0 6 | ||
21:28:07 276073 cpu_watcher 1 22 | ||
21:28:07 276073 cpu_watcher 4 8 | ||
``` | ||
|
||
### 5.**统计消息队列延迟:** | ||
|
||
统计进程间通过消息队列通信时,消息块从发送到接收的延迟情况,以便用户了解系统中进程间通信的效率和延迟,其输出内容包括发消息动作(mq_send)的延迟、接收消息动作(mq_receive)的延迟、消息块从发送到接收过程的延迟。 | ||
|
||
#### 输出效果: | ||
|
||
```c | ||
Time Mqdes SND_PID RCV_PID SND_Delay/ms RCV_Delay/ms Delay/ms | ||
21:40:36 3 281101 281167 0.02 0.02 2161.58542 | ||
21:40:46 3 281432 281493 0.02 0.03 1373.68176 | ||
21:40:52 3 281680 281741 0.03 0.05 1494.31408 | ||
21:40:58 3 281909 281945 0.03 0.02 1434.06373 | ||
21:41:01 3 282019 282088 0.03 0.02 1401.26321 | ||
``` | ||
|
||
原理介绍: | ||
|
||
[lmp/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/docs/mq_delay功能介绍.md at develop · albertxu216/lmp (github.com)](https://github.com/albertxu216/lmp/blob/develop/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/docs/mq_delay功能介绍.md) | ||
|
||
### 6.对内核函数schedule()的执行时长进行测试 | ||
|
||
统计每次调度的执行时间,可以输出本次调度的时间,单位为微秒,并用直方图展示汇总结果: | ||
|
||
#### 输出效果: | ||
|
||
``` | ||
t1:4817139183 t2:4817139248 delay:65 | ||
t1:4817139255 t2:4817139319 delay:64 | ||
t1:4817139454 t2:4817139505 delay:51 | ||
t1:4817139512 t2:4817139557 delay:45 | ||
t1:4817139675 t2:4817139735 delay:60 | ||
t1:4817139742 t2:4817139800 delay:58 | ||
t1:4817139936 t2:4817139998 delay:62 | ||
t1:4817140005 t2:4817140065 delay:60 | ||
t1:4817140488 t2:4817140552 delay:64 | ||
t1:4817140559 t2:4817140621 delay:62 | ||
t1:4817140816 t2:4817140878 delay:62 | ||
t1:4817141241 t2:4817141303 delay:62 | ||
``` | ||
|
||
```c | ||
Time : 21:46:45 | ||
cs_delay Count Distribution | ||
0 => 1 585 | | ||
2 => 3 856 | | ||
4 => 7 2271 |** | ||
8 => 15 5792 |***** | ||
16 => 31 8641 |******** | ||
32 => 63 9762 |********* | ||
64 => 127 2041 |** | ||
128 => 255 2158 |** | ||
256 => 511 2075 |** | ||
512 => 1023 751 | | ||
1024 => 2047 301 | | ||
2048 => 4095 112 | | ||
4096 => 8191 36 | | ||
8192 => 16383 0 | | ||
16384 => 32767 0 | | ||
32768 => 65535 0 | | ||
65536 => 131071 0 | | ||
131072 => 262143 0 | | ||
262144 => 524287 0 | | ||
524288 => 1048575 0 | | ||
per_len = 1000 | ||
``` | ||
|
||
|
||
|
||
## 四、实现方式 | ||
|
||
### 1.使用kprobe捕获内核函数的参数 | ||
|
||
使用kprobe、kretprobe捕获挂载的内核函数的参数,从参数中提取有效的数据。比如从finish_task_switch.isra.0内核函数的参数中拿取关于prev进程的相关信息。 | ||
|
||
### 2.使用内核提供的tracepoint捕获特定时间 | ||
|
||
使用tracepoint捕获特定状态的开始和结束,计算持续时间。比如softirq运行时间就是通过内核提供的tracepoint计算的。 | ||
|
||
### 3.获取内核全局变量 | ||
|
||
获取内核全局变量,直接从内核全局变量读取信息。如proc/s就是通过直接读取total_forks内核全局变量来计算每秒产生进程数的。 | ||
|
||
|
||
|
||
## 五、未来展望 | ||
|
||
目前`cpu_watcher`工具的总体框架已经完成,工具所能满足的功能已覆盖CPU所涉及的大部分性能指标。下一阶段,本工具将从以下几个方向进行开发和优化: | ||
|
||
* 完善工具可视化; | ||
* 功能模块化; | ||
* 更细粒度的提取CPU相关指标; | ||
* 完善工具,使其适配更多场景; | ||
|
||
|
||
|
||
如果你也对cpu_watcher或ebpf感兴趣,欢迎加入我们一起开发cpu_watcher工具,希望我们可以共同成长。 | ||
|
||
**cpu_watcher负责人:**[email protected] [email protected] [email protected] |