报文追踪
1 |
top常见问题
前两天社群有个用户用top命令查看进程时,有一个进程100%,以为CPU占满了,其实不然,下面我们就详细聊一下这个top命令。
很多人用 top 用了几年,却一直在错误解读它。
下面,我们就用一张真实的 top 截图,系统性讲清楚 top 的正确使用方式,以及最容易踩的认知坑。

先看截图图
MySQL 为何CPU能跑到 1265% ?
截图中最“刺眼”的一行:
PID USER VIRT RES %CPU %MEM COMMAND 6308 mysql 220.7g 212.7g 1265 84.5 mysqld
很多人第一反应:
“CPU 都 1265% 了?服务器要炸了”
但这恰恰是对 top 的第一个误解。上面截图中,MySQL服务多少有点问题,但业务并没有受影响。
误区 1:%CPU 最大只能是 100%
错误理解:
%CPU是“CPU 使用率”,最大 100%
正确理解:
top 中的 %CPU = 使用的 CPU 核心数 × 100%
我的机器是 16 核:
100% = 1 个核满载
1265% ≈ 12.6 个核被 mysqld 占用,并没有达到上限
结论:这台机器的 MySQL 不是异常显示,而是在多核上疯狂并行执行。
误区 2:load average很高 = CPU 已经打满
截图顶部:
load average: 12.17, 11.71, 10.50
很多人一看到 load > 10,立刻下结论:
“CPU负载太高 快扛不住了!”
但你要先清楚一个问题:
这台机器有多少核?
正确判断方式
| CPU 核数 | load ≈ 核数 | 含义 |
|---|---|---|
| 4 核 | load ≈ 4 | 接近满载 |
| 16 核 | load ≈ 12 | 完全可接受 |
| 32 核 | load ≈ 12 | 偏空闲 |
load average ≠ CPU 使用率它表示的是:正在运行 + 等待 CPU 的进程数
误区 3:id 很低才说明 CPU 有问题
截图中的 CPU 行:
%Cpu(s): 39.9 us, 0.4 sy, 58.6 id
58.6% idle
这说明什么?
CPU 一半以上是空闲的
这时候再结合:
mysqld:1265%
idle:58%
唯一合理的解释是:
多核机器 + 单个进程高并发消耗
误区 4:VIRT 很大 = 内存要炸
VIRT 220.7g RES 212.7g
很多人看到 VIRT 直接慌了:
“虚拟内存 220G?是不是内存泄漏?”
正确理解
| 字段 | 含义 |
|---|---|
| VIRT | 进程可用的虚拟地址空间 |
| RES | 真正占用的物理内存 |
| SHR | 可共享内存 |
MySQL 的 VIRT 很大是正常现象:
InnoDB buffer pool
内存映射文件
malloc 预留
判断内存是否有问题,看 RES + 系统是否 OOM,而不是看 VIRT
误区 5:free 很小 = 内存不够
截图中:
KiB Mem: 263973326 total 8088860 free 28235512 buff/cache 30766036 avail Mem
很多人盯着:
free 只有 8GB,内存要满了!
但 Linux 的内存哲学是:
不用白不用,有些在缓存中
真正要看的字段是:
avail Mem
avail ≈ 30GB
说明:系统仍然有足够内存可用
误区 6:top 能直接定位“根因”
这张图最多能得出结论:
MySQL 正在大量消耗 CPU
但你完全不知道为什么,这个就要进入MySQL数据库查看了,很大可能是慢SQL的问题。
正确使用 top
先确认 CPU 核数
lscpu
load 要和核数对比
load < CPU核数 ≠ 性能问题
%CPU > 100% 是常态
多核时代,不懂这个等于白用 top
内存优先看 avail,不是 free,不是 buff/cache
搬运
qemu cheatsheet
qemu cheatsheet
一、基本虚拟机启动
1. 基本启动虚拟机
启动x86_64虚拟机加载镜像(基本用法)。
1 | qemu-system-x86_64 -drive file=disk.img,if=virtio |
2. 无图形界面启动
无头模式启动VM(-nographic)。
1 | qemu-system-x86_64 -nographic -drive file=disk.img |
3. 指定CPU核心数
指定4核CPU启动(-smp 4)。
1 | qemu-system-x86_64 -smp 4 -drive file=disk.img |
4. 指定内存大小
分配2GB内存启动(-m 2G)。
1 | qemu-system-x86_64 -m 2G -drive file=disk.img |
5. 启用KVM加速
启用KVM硬件加速(-enable-kvm)。
1 | qemu-system-x86_64 -enable-kvm -drive file=disk.img |
6. 指定机器类型
指定q35机器类型启动(-machine q35)。
1 | qemu-system-x86_64 -machine q35 -drive file=disk.img |
7. 引导顺序指定
指定从硬盘引导(-boot order=c)。
1 | qemu-system-x86_64 -boot order=c -drive file=disk.img |
8. CD-ROM镜像启动
附加CD-ROM镜像启动(-cdrom)。
1 | qemu-system-x86_64 -cdrom iso.img -drive file=disk.img |
9. USB设备模拟
模拟USB设备启动(-usb)。
1 | qemu-system-x86_64 -usb -drive file=disk.img |
10. 守护进程模式启动
后台守护进程启动VM(-daemonize)。
1 | qemu-system-x86_64 -daemonize -drive file=disk.img |
二、设备配置与直通
11. VirtIO磁盘配置
使用VirtIO SCSI磁盘(-drive if=virtio)。
1 | qemu-system-x86_64 -drive file=disk.img,if=virtio,format=qcow2 |
12. PCI设备直通
直通主机PCI设备到VM(-device vfio-pci)。
1 | qemu-system-x86_64 -device vfio-pci,host=0000:01:00.0 -drive file=disk.img |
13. USB主机设备直通
直通USB设备(-usbdevice host)。
1 | qemu-system-x86_64 -usb -device usb-host,vendorid=0x1234,productid=0x5678 -drive file=disk.img |
14. 网络设备配置
配置用户模式网络(-netdev user)。
1 | qemu-system-x86_64 -netdev user,id=mynet -device virtio-net,netdev=mynet -drive file=disk.img |
15. 桥接网络配置
桥接主机网络接口(-netdev bridge)。
1 | qemu-system-x86_64 -netdev bridge,id=mynet,br=br0 -device virtio-net,netdev=mynet -drive file=disk.img |
16. TAP网络配置
使用TAP接口网络(-netdev tap)。
1 | qemu-system-x86_64 -netdev tap,id=mynet,ifname=tap0 -device virtio-net,netdev=mynet -drive file=disk.img |
17. VFIO GPU直通
直通GPU设备并配置VGA(-vfio-pci -vga none)。
1 | qemu-system-x86_64 -device vfio-pci,host=0000:01:00.0 -vga none -drive file=disk.img |
18. 多磁盘附加
附加多个磁盘设备(-drive 多行)。
1 | qemu-system-x86_64 -drive file=disk1.img,if=virtio -drive file=disk2.img,if=virtio -drive file=disk.img |
19. 串口设备配置
配置串口重定向到stdio(-serial stdio)。
1 | qemu-system-x86_64 -serial stdio -drive file=disk.img |
20. 块设备缓存模式
指定磁盘缓存模式为none(cache=none)。
1 | qemu-system-x86_64 -drive file=disk.img,cache=none,if=virtio |
三、网络与迁移
21. 多网卡配置
配置多个网卡接口(-netdev 多行)。
1 | qemu-system-x86_64 -netdev user,id=net1 -device virtio-net,netdev=net1 -netdev user,id=net2 -device virtio-net,netdev=net2 -drive file=disk.img |
22. VLAN网络隔离
使用VLAN隔离网卡(-net vlan=1)。
1 | qemu-system-x86_64 -net user,vlan=1 -drive file=disk.img |
23. 实时迁移VM
迁移VM到远程主机(-incoming tcp)。
1 | # 源: qemu-system-x86_64 -drive file=disk.img -incoming tcp:0:4444 (目标先启动)# 目标: migrate -d tcp:remote-host:4444 |
24. 迁移压缩优化
启用迁移压缩加速(-comp xbzrle)。
1 | qemu-system-x86_64 -drive file=disk.img -enable-kvm -comp xbzrle |
25. 多线程迁移
启用多线程迁移(-thread multi)。
1 | qemu-system-x86_64 -drive file=disk.img -thread multi |
26. 网络端口转发
转发主机端口到VM(-net user,hostfwd)。
1 | qemu-system-x86_64 -net user,hostfwd=tcp::8080-:80 -drive file=disk.img |
27. SMB网络共享
配置SMB网络共享到VM(-net user,smb)。
1 | qemu-system-x86_64 -net user,smb=/path/to/share -drive file=disk.img |
28. VDE网络配置
使用VDE交换机网络(-net vde)。
1 | qemu-system-x86_64 -net vde,sock=/tmp/vde.sock -drive file=disk.img |
29. 网络限速配置
限制网络带宽(-net user,throttle)。
1 | qemu-system-x86_64 -net user,throttle=100 -drive file=disk.img |
30. 迁移快照链
迁移时处理快照链(-drive snapshot=on)。
1 | qemu-system-x86_64 -drive file=disk.img,snapshot=on |
四、图形与输入输出
31. VNC图形界面
启用VNC远程桌面(-vnc)。
1 | qemu-system-x86_64 -vnc :0 -drive file=disk.img |
32. SPICE图形加速
使用SPICE协议图形(-spice)。
1 | qemu-system-x86_64 -spice port=5900,disable-ticketing=on -drive file=disk.img |
33. SDL图形界面
使用SDL库图形输出(-sdl)。
1 | qemu-system-x86_64 -sdl -drive file=disk.img |
34. 键盘布局指定
指定键盘布局为en-us(-k en-us)。
1 | qemu-system-x86_64 -k en-us -drive file=disk.img |
35. 鼠标输入配置
配置绝对鼠标输入(-usbdevice tablet)。
1 | qemu-system-x86_64 -usb -device usb-tablet -drive file=disk.img |
36. 图形分辨率设置
设置VGA分辨率(-vga std -full-screen)。
1 | qemu-system-x86_64 -vga std -full-screen -drive file=disk.img |
37. 多监视器配置
配置多个图形输出(-device virtio-gpu)。
1 | qemu-system-x86_64 -device virtio-gpu -drive file=disk.img |
38. 音频设备模拟
模拟音频设备输出(-soundhw ac97)。
1 | qemu-system-x86_64 -soundhw ac97 -drive file=disk.img |
39. 剪贴板共享
启用SPICE剪贴板共享(-spice clipboard=on)。
1 | qemu-system-x86_64 -spice port=5900,clipboard=on -drive file=disk.img |
40. 图形加速Virgl
启用Virgl 3D加速(-device virtio-gpu-virgl)。
1 | qemu-system-x86_64 -device virtio-gpu-virgl -drive file=disk.img |
五、调试与监视
41. GDB调试连接
启用GDB调试服务器(-s -S)。
1 | qemu-system-x86_64 -s -S -drive file=disk.img |
42. 监视器控制台
启用QMP监视器(-monitor stdio)。
1 | qemu-system-x86_64 -monitor stdio -drive file=disk.img |
43. QMP套接字监视
使用UNIX套接字QMP监视(-qmp unix)。
1 | qemu-system-x86_64 -qmp unix:/tmp/qmp.sock,server,nowait -drive file=disk.img |
44. 性能跟踪
启用性能跟踪日志(-d cpu)。
1 | qemu-system-x86_64 -d cpu -drive file=disk.img |
45. 日志文件输出
输出日志到文件(-D logfile)。
1 | qemu-system-x86_64 -D qemu.log -drive file=disk.img |
46. 内核调试模式
调试Linux内核(-kernel -initrd -append)。
1 | qemu-system-x86_64 -kernel bzImage -initrd initrd.img -append "console=ttyS0" -drive file=disk.img |
47. 内存转储
转储VM内存到文件(-mem-path)。
1 | qemu-system-x86_64 -mem-path /tmp/mem.dump -drive file=disk.img |
48. 事件监视脚本
使用脚本监视事件(-trace events=events.txt)。
1 | qemu-system-x86_64 -trace events=events.txt -drive file=disk.img |
49. CPU热插拔监视
启用CPU热插拔并监视(-smp 1,maxcpus=4)。
1 | qemu-system-x86_64 -smp 1,maxcpus=4 -drive file=disk.img |
50. 调试符号加载
加载调试符号启动(-gdb tcp::1234)。
1 | qemu-system-x86_64 -gdb tcp::1234 -drive file=disk.img |
virsh cheatsheet
常用命令
启动与关闭
| 操作 | 命令 | 说明 |
|---|---|---|
| 启动 | virsh start <虚拟机名> |
启动一个处于关闭状态的虚拟机 |
| 正常关机 | virsh shutdown <虚拟机名> |
模拟按下电源键,优雅关机(推荐) |
| 强制关闭 | virsh destroy <虚拟机名> |
相当于直接拔掉电源,仅在卡死时使用 |
| 重启 | virsh reboot <虚拟机名> |
重启虚拟机 |
| 强制重置 | virsh reset <虚拟机名> |
强制硬重启 |
挂起与恢复
| 操作 | 命令 | 说明 |
|---|---|---|
| 挂起 | virsh suspend <虚拟机名> |
暂停虚拟机,内存数据保留在主机 |
| 恢复 | virsh resume <虚拟机名> |
从挂起状态恢复运行 |
自启动配置
- 设置开机自启:
virsh autostart <虚拟机名> - 取消开机自启:
virsh autostart --disable <虚拟机名> - 查看自启列表:
virsh autostart --list
虚拟机信息查询
基本状态查询
1 | # 列出所有虚拟机(运行中+已关闭) |
配置与连接信息
1 | # 导出完整的XML配置(非常重要!) |
资源监控
1 | # 查看CPU使用统计 |
虚拟机配置管理
XML配置编辑(核心)
KVM的所有配置都存储在XML文件中:
编辑配置(推荐):
1 | virsh edit <虚拟机名> |
使用此命令会自动检查XML语法,保存生效。不要直接去改 /etc/libvirt/qemu/ 下的文件,容易出错。
备份配置:
1 | virsh dumpxml <虚拟机名> > vm-config.xml |
从XML恢复/定义:
1 | virsh define vm-config.xml # 注册虚拟机(不启动) |
删除与重命名
取消定义(删除配置): 1
virsh undefine <虚拟机名>
1
virsh undefine --remove-all-storage <虚拟机名>
重命名虚拟机:
1
virsh domrename <旧名称> <新名称>
vagrant cheatsheet

Typing vagrant from the command line will display a list of all available commands.
Be sure that you are in the same directory as the Vagrantfile when running these commands!
Creating a VM
vagrant init– Initialize Vagrant with a Vagrantfile and ./.vagrant directory, using no specified base image. Before you can do vagrant up, you’ll need to specify a base image in the Vagrantfile.vagrant init <boxpath>– Initialize Vagrant with a specific box. To find a box, go to the public Vagrant box catalog. When you find one you like, just replace it’s name with boxpath. For example,vagrant init ubuntu/trusty64.
Starting a VM
vagrant up– starts vagrant environment (also provisions only on the FIRST vagrant up)vagrant resume– resume a suspended machine (vagrant up works just fine for this as well)vagrant provision– forces reprovisioning of the vagrant machinevagrant reload– restarts vagrant machine, loads new Vagrantfile configurationvagrant reload --provision– restart the virtual machine and force provisioning
Getting into a VM
vagrant ssh– connects to machine via SSHvagrant ssh <boxname>– If you give your box a name in your Vagrantfile, you can ssh into it with boxname. Works from any directory.
Stopping a VM
vagrant halt– stops the vagrant machinevagrant suspend– suspends a virtual machine (remembers state)
Cleaning Up a VM
vagrant destroy– stops and deletes all traces of the vagrant machinevagrant destroy -f– same as above, without confirmation
Boxes
vagrant box list– see a list of all installed boxes on your computervagrant box add <name> <url>– download a box image to your computervagrant box outdated– check for updates vagrant box updatevagrant box remove <name>– deletes a box from the machinevagrant package– packages a running virtualbox env in a reusable box
Saving Progress
-vagrant snapshot save [options] [vm-name] <name> – vm-name is often default. Allows us to save so that we can rollback at a later time
Tips
vagrant -v– get the vagrant versionvagrant status– outputs status of the vagrant machinevagrant global-status– outputs status of all vagrant machinesvagrant global-status --prune– same as above, but prunes invalid entriesvagrant provision --debug– use the debug flag to increase the verbosity of the outputvagrant push– yes, vagrant can be configured to deploy code!vagrant up --provision | tee provision.log– Runsvagrant up, forces provisioning and logs all output to a file
Plugins
- vagrant-hostsupdater :
$ vagrant plugin install vagrant-hostsupdaterto update your/etc/hostsfile automatically each time you start/stop your vagrant box.
Notes
- If you are using VVV, you can enable xdebug by running
vagrant sshand thenxdebug_onfrom the virtual machine’s CLI.
ARM64汇编-cheatsheet
sheet1

sheet2

sheet3

Mellanox cheatsheet
状态检查与配置
1 | # IB设备的状态 |
配置和管理
1 | # 配置IB设备,显示IB和以太设备的映射关系 |
固件更新
1 | # 更新NIC卡固件(非OEM卡) |
性能测试和监控
1 | # 测试两设备见IB性能(时延和带宽) |
配置RDMA
1 | # 检查RDMA配置 |
定位问题
1 | # 检查多节点的IB配置 |
配置和管理IB子网
1 | # 显示IB网络信息 |
Mellanox管理命令
1 | # 网卡状态查询 |
配置IB QoS
1 | # Set quality of service policy for InfiniBand |
参考
ftrace技术-静态跟踪(一)
介绍
Ftrace 是一款内部跟踪器,旨在帮助系统开发人员和设计人员了解内核内部的运行情况。它可用于调试或分析用户空间之外发生的延迟和性能问题。
Debugfs 文件结构
Ftrace 使用 debugfs 文件系统来保存控制文件以及用于显示输出的文件。
当 debugfs 配置到内核中时(选择任何 ftrace 选项都会执行此操作),将创建目录 /sys/kernel/debug。要挂载此目录,可以将其添加到 /etc/fstab 文件中: 1
2# /etc/fstab
debugfs /sys/kernel/debug debugfs default 0 01
mount -t debugfs nodev /sys/kernel/debug
1
ln -s /sys/kernel/debug /debug
下表汇总了 ftrace最常用的操作命令,适用于直接操作 /sys/kernel/debug/tracing目录下的文件。
| 操作目的 | 命令示例 | 简要说明 |
|---|---|---|
| 查看可用跟踪器 | cat available_tracers |
显示系统支持的所有跟踪器 。 |
| 设置当前跟踪器 | echo function > current_tracer |
设置跟踪器,如 function,function_graph,sched_switch等 。 |
| 开始/停止跟踪 | echo 1 > tracing_on echo 0 > tracing_on |
控制跟踪的启动和停止 。 |
| 查看跟踪结果 | cat trace |
显示跟踪缓冲区的内容 。 |
| 过滤跟踪函数 | echo sys_* > set_ftrace_filter |
只跟踪函数名匹配 sys_*的函数 。 |
| 过滤跟踪进程 | echo 1234 > set_ftrace_pid |
只跟踪 PID 为 1234 的进程 。 |
| 跟踪特定模块 | echo ':mod:ext4' > set_ftrace_filter |
只跟踪 ext4模块内的函数 。 |
| 启用特定事件 | echo 1 > events/sched/sched_switch/enable |
启用 sched_switch调度事件 。 |
| 清空跟踪缓冲区 | echo > trace |
清空当前跟踪缓冲区以便重新记录 。 |
可通过调试文件系统启用函数跟踪器。确保已设置 ftrace_enabled;否则,此跟踪器将不执行任何操作。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 # sysctl kernel.ftrace_enabled=1
# echo function > current_tracer
# echo 1 > tracing_enabled
# usleep 1
# echo 0 > tracing_enabled
# cat trace
# tracer: function
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
bash-4003 [00] 123.638713: finish_task_switch <-schedule
bash-4003 [00] 123.638714: _spin_unlock_irq <-finish_task_switch
bash-4003 [00] 123.638714: sub_preempt_count <-_spin_unlock_irq
bash-4003 [00] 123.638715: hrtick_set <-schedule
bash-4003 [00] 123.638715: _spin_lock_irqsave <-hrtick_set
bash-4003 [00] 123.638716: add_preempt_count <-_spin_lock_irqsave
bash-4003 [00] 123.638716: _spin_unlock_irqrestore <-hrtick_set
bash-4003 [00] 123.638717: sub_preempt_count <-_spin_unlock_irqrestore
bash-4003 [00] 123.638717: hrtick_clear <-hrtick_set
bash-4003 [00] 123.638718: sub_preempt_count <-schedule
bash-4003 [00] 123.638718: sub_preempt_count <-preempt_schedule
bash-4003 [00] 123.638719: wait_for_completion <-__stop_machine_run
bash-4003 [00] 123.638719: wait_for_common <-wait_for_completion
bash-4003 [00] 123.638720: _spin_lock_irq <-wait_for_common
bash-4003 [00] 123.638720: add_preempt_count <-_spin_lock_irq
[...]
irqoff跟踪
当中断被关闭时,CPU 无法响应外部事件(如硬件中断),这会导致系统响应延迟。irqsoff跟踪器的工作原理是 : - 挂钩关键函数:它在 local_irq_disable()和 local_irq_enable()等关键函数中插入钩子。 - 记录时间戳:当中断被关闭时开始计时,并在中断重新开启时停止计时。 - 记录最大延迟:它会记录下中断关闭的最大时间,并将导致该延迟的调用路径信息保存下来,帮助开发者定位问题根源。
当中断被禁用时,CPU 将无法响应任何其他外部事件(NMI 和 SMI 除外)。这会阻止定时器中断触发,或鼠标中断无法将新的鼠标事件告知内核。其结果是响应时间出现延迟。
irqsoff 跟踪器会跟踪中断被禁用的时间。当达到新的最大延迟时,跟踪器会保存达到该延迟点之前的跟踪记录,以便每次达到新的最大值时,都会丢弃旧的跟踪记录并保存新的跟踪记录。
要重置最大值,请将 0 回显到 tracing_max_latency 中。以下是一个示例: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 # echo irqsoff > current_tracer
# echo 0 > tracing_max_latency
# echo 1 > tracing_enabled
# ls -ltr
[...]
# echo 0 > tracing_enabled
# cat latency_trace
# tracer: irqsoff
#
# irqsoff latency trace v1.1.5 on 4.0.0
# --------------------------------------------------------------------
# latency: 259 us, #4/4, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
# -----------------
# | task: ps-6143 (uid:0 nice:0 policy:0 rt_prio:0)
# -----------------
# => started at: __lock_task_sighand
# => ended at: _raw_spin_unlock_irqrestore
#
#
# _------=> CPU#
# / _-----=> irqs-off
# | / _----=> need-resched
# || / _---=> hardirq/softirq
# ||| / _--=> preempt-depth
# |||| / delay
# cmd pid ||||| time | caller
# \ / ||||| \ | /
ps-6143 0d.h1 0us+: _raw_spin_lock_irqsave <-__lock_task_sighand
ps-6143 0d.h. 259us : _raw_spin_unlock_irqrestore <-__lock_task_sighandlatency: 259 us:这是最重要的信息,表示本次跟踪中发现的最大中断关闭延迟为 259 微秒 。 - task: ps-6143:发生该延迟时正在执行的进程是 ps(PID 为 6143)。 - started at和 ended at:指出了中断关闭开始和结束的函数位置 。 - irqs-off:d表示中断被关闭 。 - delay符号:输出中可能使用特殊符号(如 !表示大于100ms)来直观表示延迟大小。 - 函数调用栈:在跟踪条目下方,通常会显示导致此次延迟的完整函数调用栈,这对于定位问题代码至关重要 。
请注意,上面的示例中未设置 ftrace_enabled。如果我们设置了 ftrace_enabled,则会得到更大的输出: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42# tracer: irqsoff
#
irqsoff latency trace v1.1.5 on 2.6.26-rc8
--------------------------------------------------------------------
latency: 50 us, #101/101, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
-----------------
| task: ls-4339 (uid:0 nice:0 policy:0 rt_prio:0)
-----------------
=> started at: __alloc_pages_internal
=> ended at: __alloc_pages_internal
# _------=> CPU#
# / _-----=> irqs-off
# | / _----=> need-resched
# || / _---=> hardirq/softirq
# ||| / _--=> preempt-depth
# |||| /
# ||||| delay
# cmd pid ||||| time | caller
# \ / ||||| \ | /
ls-4339 0...1 0us+: get_page_from_freelist (__alloc_pages_internal)
ls-4339 0d..1 3us : rmqueue_bulk (get_page_from_freelist)
ls-4339 0d..1 3us : _spin_lock (rmqueue_bulk)
ls-4339 0d..1 4us : add_preempt_count (_spin_lock)
ls-4339 0d..2 4us : __rmqueue (rmqueue_bulk)
ls-4339 0d..2 5us : __rmqueue_smallest (__rmqueue)
ls-4339 0d..2 5us : __mod_zone_page_state (__rmqueue_smallest)
ls-4339 0d..2 6us : __rmqueue (rmqueue_bulk)
ls-4339 0d..2 6us : __rmqueue_smallest (__rmqueue)
ls-4339 0d..2 7us : __mod_zone_page_state (__rmqueue_smallest)
ls-4339 0d..2 7us : __rmqueue (rmqueue_bulk)
ls-4339 0d..2 8us : __rmqueue_smallest (__rmqueue)
[...]
ls-4339 0d..2 46us : __rmqueue_smallest (__rmqueue)
ls-4339 0d..2 47us : __mod_zone_page_state (__rmqueue_smallest)
ls-4339 0d..2 47us : __rmqueue (rmqueue_bulk)
ls-4339 0d..2 48us : __rmqueue_smallest (__rmqueue)
ls-4339 0d..2 48us : __mod_zone_page_state (__rmqueue_smallest)
ls-4339 0d..2 49us : _spin_unlock (rmqueue_bulk)
ls-4339 0d..2 49us : sub_preempt_count (_spin_unlock)
ls-4339 0d..1 50us : get_page_from_freelist (__alloc_pages_internal)
ls-4339 0d..2 51us : trace_hardirqs_on (__alloc_pages_internal)
scdule wakeup跟踪
在实时环境中,了解最高优先级任务从被唤醒到执行所需的唤醒时间至关重要。这也被称为“调度延迟”。
实时环境关注的是最大延迟,也就是事件发生所需的最长延迟,而不是平均延迟。我们可以拥有一个速度非常快的调度器,它可能只是偶尔出现较大的延迟,但这并不适用于实时任务。唤醒跟踪器旨在记录实时任务的最大唤醒延迟。非实时任务不会被记录,因为跟踪器只记录一个最大延迟,而跟踪不可预测的非实时任务会覆盖实时任务的最大延迟。
由于此追踪器仅处理实时任务,因此我们将采用与之前追踪器略有不同的运行方式。我们不会执行“ls”命令,而是在“chrt”命令下运行“sleep 1”命令,这将改变任务的优先级。
1 | # echo wakeup > current_tracer |
在空闲系统上运行此程序,我们发现任务切换仅耗时 4 微秒。请注意,由于调度中的跟踪标记位于实际“切换”之前,因此当记录的任务即将调度时,我们会停止跟踪。如果我们在调度程序末尾添加新的标记,则此情况可能会发生变化。
请注意,记录的任务是“sleep”,进程 ID 为 4901,其 rt_prio 为 5。此优先级为用户空间优先级,而非内核内部优先级。策略为:SCHED_FIFO 为 1,SCHED_RR 为 2。
使用 chrt -r 5 和 ftrace_enabled set 执行相同的操作。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52# tracer: wakeup
#
wakeup latency trace v1.1.5 on 2.6.26-rc8
--------------------------------------------------------------------
latency: 50 us, #60/60, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
-----------------
| task: sleep-4068 (uid:0 nice:0 policy:2 rt_prio:5)
-----------------
# _------=> CPU#
# / _-----=> irqs-off
# | / _----=> need-resched
# || / _---=> hardirq/softirq
# ||| / _--=> preempt-depth
# |||| /
# ||||| delay
# cmd pid ||||| time | caller
# \ / ||||| \ | /
ksoftirq-7 1d.H3 0us : try_to_wake_up (wake_up_process)
ksoftirq-7 1d.H4 1us : sub_preempt_count (marker_probe_cb)
ksoftirq-7 1d.H3 2us : check_preempt_wakeup (try_to_wake_up)
ksoftirq-7 1d.H3 3us : update_curr (check_preempt_wakeup)
ksoftirq-7 1d.H3 4us : calc_delta_mine (update_curr)
ksoftirq-7 1d.H3 5us : __resched_task (check_preempt_wakeup)
ksoftirq-7 1d.H3 6us : task_wake_up_rt (try_to_wake_up)
ksoftirq-7 1d.H3 7us : _spin_unlock_irqrestore (try_to_wake_up)
[...]
ksoftirq-7 1d.H2 17us : irq_exit (smp_apic_timer_interrupt)
ksoftirq-7 1d.H2 18us : sub_preempt_count (irq_exit)
ksoftirq-7 1d.s3 19us : sub_preempt_count (irq_exit)
ksoftirq-7 1..s2 20us : rcu_process_callbacks (__do_softirq)
[...]
ksoftirq-7 1..s2 26us : __rcu_process_callbacks (rcu_process_callbacks)
ksoftirq-7 1d.s2 27us : _local_bh_enable (__do_softirq)
ksoftirq-7 1d.s2 28us : sub_preempt_count (_local_bh_enable)
ksoftirq-7 1.N.3 29us : sub_preempt_count (ksoftirqd)
ksoftirq-7 1.N.2 30us : _cond_resched (ksoftirqd)
ksoftirq-7 1.N.2 31us : __cond_resched (_cond_resched)
ksoftirq-7 1.N.2 32us : add_preempt_count (__cond_resched)
ksoftirq-7 1.N.2 33us : schedule (__cond_resched)
ksoftirq-7 1.N.2 33us : add_preempt_count (schedule)
ksoftirq-7 1.N.3 34us : hrtick_clear (schedule)
ksoftirq-7 1dN.3 35us : _spin_lock (schedule)
ksoftirq-7 1dN.3 36us : add_preempt_count (_spin_lock)
ksoftirq-7 1d..4 37us : put_prev_task_fair (schedule)
ksoftirq-7 1d..4 38us : update_curr (put_prev_task_fair)
[...]
ksoftirq-7 1d..5 47us : _spin_trylock (tracing_record_cmdline)
ksoftirq-7 1d..5 48us : add_preempt_count (_spin_trylock)
ksoftirq-7 1d..6 49us : _spin_unlock (tracing_record_cmdline)
ksoftirq-7 1d..6 49us : sub_preempt_count (_spin_unlock)
ksoftirq-7 1d..4 50us : schedule (__cond_resched)
