Linux实时性评估和测量
1. 名词介绍
实时性操作系统:是保证在一定时间限制内完成特定功能的操作系统,实时操作系统有硬实时和软实时区分。硬实时要求在规定的时间内必须完成,软实时表示只要按照任务优先级,尽可能地完成操作即可。
1.2 Linux非实时说明
根据实时操作系统的要求,高优先级的任务必须在可测量的时间内完成,但由于Linux 中断、软中断、spin lock等存在,导致抢占被关闭,当触发高优先级任务时,如果抢占被关闭了,会导致处理高优先级的任务时间变得不可测量,因此无法满足实时操作系统要求,如下图所示:
如图所示,在t2时刻,软中断唤醒了一个高优先级的任务(Rt task),但Linux中,唤醒该任务,到该任务实际抢占到CPU,中间经过了(t4-t2)时间,而这段时间是无法预测的,因此无法满足实时性要求。
2. Linux实时性改进
2.1 基本改进
为了提供Linux的实时性,降低进程的响应延迟,同时兼顾吞吐量要求,Linux开发人员给出了几种配置,让开发者根据自身产品需求来选择。具体配置如下:
- CONFIG_PREEMPT_NONE
该配置表示不允许高优先级任务抢占低优先级任务,一般如果系统对响应要求比较低,需要提高系统吞吐量,一般是服务器才选择这个配置
- CONFIG_PREEMPT_VOLUNTARY
该配置表示允许高优先级任务抢占低优先级任务,但前提条件是低优先级任务需要主动放弃CPU,如调用sleep、yield等接口
- CONFIG_PREEMPT
该配置表示允许高优先级的任务抢占低优先级任务,无需低优先级任务主动放弃CPU,但在spin lock、中断、软中断中,不允许抢占。
在支持上述可选配置后,Linux系统的实时性有一定的提高,但还是无法满足实时性要求,因为内核态下,很多驱动、子系统都是用了spin lock、中断、软中断处理的时间也无法测量。因此,Linux开发者在此基础上增加了实时内核补丁,实时补丁主要工作如下:
-
将spin lock变化为可睡眠的mutex lock
-
将中断线程化
-
增加配置
CONFIG_PREEMPT_RTB //基本实时(类似CONFIG_PREEMPT)
CONFIG_PREEMPT_RT_FULL //(完全实时)
2.2 实时补丁
为了将内核变成实时内核,需要打上实时补丁,实时补丁网站如下:
https://mirrors.edge.kernel.org/pub/linux/kernel/projects/rt/
选取补丁原则:
-
通过Makefile文件,或者Linux中,通过uname -a命令查看所使用的Linux版本
-
选择与自己使用Linux版本相同的或者比自己使用的Linux版本稍微小一些的实时补丁。
譬如:我司方案中,使用了Linux-4.14.61版本,在RT网站中,只有patch-4.14.59-rt37.patch.gz是最接近的,因此就选这个补丁。
获取到补丁后,通过git apply或者patch命令打上相应的补丁即可,主要要合理解决patch的冲突。
2.3 各种配置内核下实时性测量
测量工具仓库:
https://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git
将该仓库下载回来,编译,即可拿到对应的测量工具cyclictest
关于cyclictest的各个参数具体含义简单说明如下,这只介绍几个常用的。
-p PRIO –prio=PRIO 最高优先级线程的优先级 使用时方法为: -p 90 或者 –prio=90
–policy 指定调度策略
-m –mlockall 锁定当前和将来的内存分配
-c CLOCK –clock=CLOCK 选择时钟 cyclictest -c 1
0 = CLOCK_MONOTONIC (默认)
1 = CLOCK_REALTIME
-i INTV –interval=INTV 基本线程间隔,默认为1000(单位为us)
-l LOOPS –loops=LOOPS 循环的个数,默认为0(无穷个),与 -i 间隔数结合可大致算出整个测试的时间,比如 -i 1000 -l 1000000 ,总的循环时间为1000 * 1000000 = 1000000000 us = 1000s ,所以大致为16分钟多。
-h HISTNUM –histogram=US 在执行完后在标准输出设备上画出延迟的直方图(很多线程有相同的权限)US为最大的跟踪时间限制,这个在下面介绍实例时可以用到,结合gnuplot可以画出我们测试的结果图。
-q –quiet 使用-q参数运行时不打印信息,只在退出时打印概要内容,结合-h HISTNUM参数会在退出时打印HISTNUM行统计信息以及一个总的概要信息。
-f –ftrace ftrace函数跟踪(通常与-b 配套使用,其实通常使用 -b 即可,不使用 -f )
-b USEC –breaktrace=USEC 当延时大于USEC指定的值时,发送停止跟踪,并记录相应函数栈。USEC,单位为微秒(us)
更多用法,参考./cyclictest -h
2.3.1 轻载下测量
测试条件:
- 调频策略设置为performance,CPU频率1.6G
echo performance > sys/devices/system/cpu/cpufreq/policy0/scaling_governor
-
adb shell启动top进程监控
-
测试命令:./cyclictest -p 99 –policy=fifo -m -S -l 1000000 -h 2000 >> log.txt &
2.3.1.1 配置CONFIG_PREEMPT_NONE
测试总结如下:
# Total: 000999998 001000000 001000000 000999991
# Min Latencies: 00015 00015 00015 00014
# Avg Latencies: 00019 00019 00020 00021
# Max Latencies: 02292 00914 00915 00958
# Histogram Overflows: 00002 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0: 31654 62372
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟时间为2292us,平均延迟时间接近20us左右,统计数据如下图所示:
从图中可以分析,在轻载下,配置CONFIG_PREEMPT_NONE的延迟,主要分布在15-25us之间,但区间宽度比较大,效果不是很好。
2.3.1.2 配置CONFIG_PREEMPT_VOLUNTARY
测试总结如下:
# Total: 005000000 005000000 004999986 004999972
# Min Latencies: 00013 00015 00015 00014
# Avg Latencies: 00017 00019 00020 00018
# Max Latencies: 01154 00988 00948 00661
# Histogram Overflows: 00000 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0:
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟时间为1154us,平均延迟时间接近20us左右,统计数据如下图所示:
从图中可以分析,在轻载下,配置CONFIG_PREEMPT_VOLUNTARY的延迟,主要分布在15-25us之间,但区间宽度相对比较大,效果不是很好,但对最大延时有一定改善。
2.3.1.3 配置CONFIG_PREEMPT
测试总结如下:
# Total: 001000000 000999995 000999982 000999963
# Min Latencies: 00019 00017 00018 00018
# Avg Latencies: 00024 00020 00023 00024
# Max Latencies: 00566 01037 00359 00903
# Histogram Overflows: 00000 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0:
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟时间为1037us,平均延迟时间接近20us左右,统计数据如下图所示:
从图中可以分析,在轻载下,配置CONFIG_PREEMPT的延迟,主要分布在15-30us之间,但区间较为集中,说明对实时性有一定收益,但对CONFIG_PREEMPT_VOLUNTARY情况下,最大延时没有很好的改善,对CONFIG_PREEMPT_NONE下,最大延时有一定的改善。
2.3.1.4 配置CONFIG_PREEMPT_RT_FULL
测试总结如下:
# Min Latencies: 00009 00008 00009 00009
# Avg Latencies: 00012 00011 00012 00012
# Max Latencies: 00045 00038 00042 00040
# Histogram Overflows: 00000 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0:
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟为45us,平均延迟12us左右,统计数据如下图所示:
从图中可以分析,在轻载下,配置CONFIG_PREEMPT_RT_FULL的延迟,主要分布在10-15us之间,但区间较为集中,说明对实时性收益非常明显,对最大延时很好的改善。
2.3.2 重载先测量
测试条件:
- 调频策略设置为performance,CPU频率1.6G
echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
-
adb shell启动top进程监控
-
stress-ng模拟系统压力
./stress-arm64 --cpu 4 --io 4 --vm 2 --vm-bytes 128M &
- 测试命令:./cyclictest -p 99 –policy=fifo -m -S -l 1000000 -h 25000 >> log.txt &
2.3.2.1 配置CONFIG_PREEMPT_NONE
测试总结如下:
# Total: 001000000 000994891 000997016 000995234
# Min Latencies: 00016 00016 00016 00015
# Avg Latencies: 00086 00081 00082 00087
# Max Latencies: 20847 16915 17081 16522
# Histogram Overflows: 00000 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0:
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟时间为20847us,平均延迟时间接近80us左右,统计数据如下图所示:
从图中可以分析,在重载下,配置CONFIG_PREEMPT_NONE的延迟,主要分布在15-70us之间,但区间宽度比较大,效果不是很好。
2.3.2.2 配置CONFIG_PREEMPT_VOLUNTARY
测试总结如下:
# Total: 001000000 000999447 000992663 000998372
# Min Latencies: 00015 00015 00015 00016
# Avg Latencies: 00074 00074 00075 00068
# Max Latencies: 20954 17047 16925 16356
# Histogram Overflows: 00000 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0:
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟时间为20954us,平均延迟时间接近75us左右,统计数据如下图所示:
从图中可以分析,在重载下,配置CONFIG_PREEMPT_VOLUNTARY的延迟,主要分布在15-50us之间,区间宽度相对小一些,对实时性有一定增强,对最大延时没有很好的改善。
2.3.2.3 配置CONFIG_PREEMPT
测试总结如下:
# Total: 001000000 000999964 000999864 000999786
# Min Latencies: 00018 00019 00020 00020
# Avg Latencies: 00034 00033 00031 00028
# Max Latencies: 01359 01054 01492 01074
# Histogram Overflows: 00000 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0:
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟时间为1492us,平均延迟时间接近35us左右,统计数据如下图所示:
从图中可以分析,在重载下,配置CONFIG_PREEMPT的延迟,主要分布在15-50us之间,区间宽度相对小一些,对实时性有一定增强,对重载下的最大延时有比较大的收益。
2.3.2.4 配置CONFIG_PREEMPT_RT_FULL
测试总结如下:
# Total: 001000000 000999950 000999885 000999825
# Min Latencies: 00009 00010 00009 00010
# Avg Latencies: 00016 00016 00016 00016
# Max Latencies: 00054 00056 00055 00042
# Histogram Overflows: 00000 00000 00000 00000
# Histogram Overflow at cycle number:
# Thread 0:
# Thread 1:
# Thread 2:
# Thread 3:
从log分析,最大延迟为54us,平均延迟16us左右,统计数据如下图所示:
从图中可以分析,在重载下,配置CONFIG_PREEMPT_RT_FULL的延迟,主要分布在10-25us之间,但区间较为集中,说明对实时性收益非常明显,对最大延时很好的改善。
2.3.3 对中断影响
由于打上RT补丁后,中断被强制线程化,中断线程可能会被高优先级任务抢占,导致中断处理出现延迟,因此需要评估对中断响应的影响。
后续补充相关测量数据和分析。