实时Linux主要有两类方案:

  • 单内核方案:对主线传统的Linux内核打入PREEMPT_RT补丁,使内核成为硬实时操作系统
  • 双内核方案:主线传统Linux内核+实时内核的双内核方案,常见的主流方式有:RT-Linux,RTAI、Xenomai。

本文重点讲解单内核PREEMPT_RT补丁方案。

概念基础

实时性

​ 实时分为硬实时和软实时,两者主要的区别主要就是就绪运行时间确定性。然后,主线Linux是软实时系统,加入实时补丁后将其改造为硬实时系统。

可抢占性

​ 实现实时内核很重要的特点是可抢占性,就绪的高优先级的任务能够抢占低优先级任务。Linux内核在2.6版本之后引入了抢占模型,支持任务抢占。

主线Linux支持如下三种抢占模型:

 (1) No Forced Preemption (Server): 传统的 Linux 抢占模型,面向吞吐量。系统调用返回和中断是唯一的抢占点。(2) Voluntary Kernel Preemption (Desktop):  此选项通过向内核代码 [. . . ] 以稍微降低吞吐量为代价。除了显式抢占点外,系统调用返回和中断返回都是隐式抢占点 (3) Preemptible Kernel (Low-Latency Desktop):  此选项通过使所有内核代码(不在临界区中执行的)可抢占来减少内核的延迟。隐式抢占点位于每个抢占禁用部分之后。

对于软实时的嵌入式系统来说,内核抢占模式配置为Preemptible Kernel (Low-Latency Desktop)最佳。

进程调度策略

​ Linux内核支持实时进程和非实时进程调度(无PREEMPT_RT补丁支持也是支持实时进程调度,只是软实时,有补丁后就是硬实时)。

​ 对于Linux进程任务来说,Linux 内核实现了多种调度策略。它们分为非实时和实时策略。调度策略已经在主线 Linux 中实现。

非实时策略:

  • SCHED_OTHER: 每个任务都有一个所谓的“nice值”。它是一个介于 -20(最高 nice 值)和 19(最低 nice 值)之间的值。任务执行时间的平均值取决于相关的 nice 值。
  • SCHED_BATCH: 此策略源自 SCHED_OTHER 并针对吞吐量进行了优化。
  • SCHED_IDLE: 它也是从 SCHED_OTHER 派生的,但它的值比 19 弱。

实时策略:

  • SCHED_FIFO: 任务的优先级介于 1(低)和 99(高)之间。在此策略下运行的任务将被调度,直到它完成或更高优先级的任务抢占它。
  • SCHED_RR: 此策略源自 SCHED_FIFO。与 SCHED_FIFO 的区别在于任务在定义的时间片的持续时间内运行(如果它没有被更高优先级的任务抢占)。一旦时间片用完,它可以被具有相同优先级的任务中断。时间片定义在 procfs (/proc/sys/kernel/sched_rr_timeslice_ms) 中导出。
  • SCHED_DEADLINE: 此策略实施全局最早deadline优先 (GEDF) 算法。在此策略下调度的任务可以抢占使用 SCHED_FIFO 或 SCHED_RR 调度的任何任务。

设置api:

sched_setscheduler()

PREEMPT_RT 实时补丁

打入PREEMPT_RT补丁,可实现硬实时内核。

PREEMPT_RT下载地址:http://cdn.kernel.org/pub/linux/kernel/projects/rt/

PREEMPT_RT补丁主要做了如下修改,修改背后的原理后续文章再深入描述:

  • 高分辨率定时器
  • 中断线程化
  • 自旋锁spinlock_t改为互斥锁rt_mutex,要使用自旋锁则使用raw_spinlock_t

打入PREEMPT_RT后内核抢占模型配置则会多了如下两项:

  • Preemptible Kernel (Basic RT): 这种抢占模型类似于“抢占内核(低延迟桌面)”模型。除了上面提到的属性外,线程中断处理程序是强制的(就像使用内核命令行参数时一样threadirqs)。该模型主要用于 PREEMPT_RT 补丁实现的替代机制的测试和调试。
  • Fully Preemptible Kernel (Real-Time): 除了少数选定的关键部分之外,所有内核代码都是可抢占的。线程中断处理程序是强制的。此外,还实现了几种替代机制,如睡眠自旋锁和 rt_mutex,以减少抢占禁用部分。此外,大的抢占禁用部分被单独的锁定结构取代。必须选择这种抢占模型以获得硬实时行为。

PREEMPT_RT 实时补丁的限制

​ 某些环境当前不能很好地与 Preempt-RT 配合使用。由于不兼容,CONFIG_PREEMPT_RT_FULL=y 禁用了几个功能。

禁用的配置选项,主要是虚拟化配置:

  • CONFIG_TRANSPARENT_HUGEPAGE
  • CONFIG_OPROFILE
  • CONFIG_XEN (arm64)
  • CONFIG_X86_POWERNOW_K8
  • CONFIG_BCACHE
  • CONFIG_HIGHMEM(mips,powerpc)
  • CONFIG_KVM_MPIC (powerpc)
  • CONFIG_RT_GROUP_SCHED
  • CONFIG_CPUMASK_OFFSTACK

PREEMPT_RT 实时补丁修改步骤

1、下载PREEMPT_RT补丁

对应内核版本选择PREEMPT_RT补丁的版本,不对应版本选择则可能出现不可预估性的问题或者打补丁出现大量冲突。

下载地址:http://cdn.kernel.org/pub/linux/kernel/projects/rt/

2、打补丁以及配置内核

传统的打补丁方法:

git apply xxx.patch
# 或
git am xxx.patch

传统的配置内核方法:

# 1、输入配置内核命令
make menuconfig
# 2、选中全功能实时抢占配置,保存退出
(*)Fully Preemptible Kernel (Real-Time)

因为我用的是yocto来构建系统,如下是我的菜谱追加文件

FILESEXTRAPATHS_prepend := "${THISDIR}/preempt-rt-patch:" ## 存放补丁和配置的目录
PATCHTOOL = "git"
SRC_URI += "file://preempt_full.cfg"        ## 配置片段
SRC_URI += "file://patch-5.10.8-rt24.patch" ## 补丁

preempt_full.cfg配置片段:

CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_PREEMPT_LAZY=y
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_RT=y
CONFIG_RCU_BOOST=y
CONFIG_RCU_BOOST_DELAY=500
CONFIG_EXPERT=y
# CONFIG_SGETMASK_SYSCALL is not set
# CONFIG_DEBUG_RSEQ is not set
CONFIG_EMBEDDED=y
# CONFIG_PC104 is not set
# CONFIG_SLUB_MEMCG_SYSFS_ON is not set
# CONFIG_SUSPEND_SKIP_SYNC is not set
# CONFIG_DPM_WATCHDOG is not set
# CONFIG_FIRMWARE_MEMMAP is not set
# CONFIG_VIRTUALIZATION is not set
CONFIG_ARCH_SUPPORTS_RT=y
# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
# CONFIG_PCIE_BUS_TUNE_OFF is not set
CONFIG_PCIE_BUS_DEFAULT=y
# CONFIG_PCIE_BUS_SAFE is not set
# CONFIG_PCIE_BUS_PERFORMANCE is not set
# CONFIG_PCIE_BUS_PEER2PEER is not set
# CONFIG_WIRELESS_WDS is not set
# CONFIG_TTY_PRINTK is not set
# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set
# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
# CONFIG_SND_SOC_SOF_DEVELOPER_SUPPORT is not set
CONFIG_MXC_GPU_VIV=y
# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set
# CONFIG_DEBUG_MEMORY_INIT is not set

3、编译以及烧写镜像

make Image

4、下载实时测试工具套件

运行下面指令下载实时测试工具,然后按照你的环境对其交叉编译:

git clone git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git

5、实时性测试

实时性测试主要有两个点:模拟负载和cyclictest。
模拟负载就是通过运行一些程序让系统处于高负载的状态。
cyclictest就是开源的Linux实时性测试工具。
模拟负载有多种方式,比如stress、stress-ng、hackbench、脚本模拟。
如下是我模拟负载脚本(stress_loades.sh ),内部使用了dd、hackbench、ping、taskset、cyclictest命令,其中cyclictest、hackbench是上面下载的实时测试工具套件内部自带的,其他三个命令也是一般系统都会自带的:

#!/bin/bash# 如果参数小于1
if [ "$1" == "-h" ]
then echo "example:"echo "          ./stress_loades.sh [Level]"echo "option:"echo "       1: heavy cpu load"echo "      -h: help "exit 0
fi# 如果参数等于1
if [ "$1" == "1" ]
thenwhile true; do dd if=/dev/zero of=bigfile bs=1024000 count=1024; done > /dev/null &while true; do killall hackbench; sleep 5; done > /dev/null &while true; do ./hackbench 20; done > /dev/null &
fitaskset -c 0 ping -l 65535 -q -s 10 -f localhost > /dev/null &
taskset -c 1 ping -l 65535 -q -s 10 -f localhost > /dev/null &
taskset -c 2 ping -l 65535 -q -s 10 -f localhost > /dev/null &
taskset -c 3 ping -l 65535 -q -s 10 -f localhost > /dev/null &while true; do taskset -c 3 du / ; done  > /dev/null &time ./cyclictest -t50 -p 80 -i 10000 -s -l 100000000000 -d 86400  -a 3 > /dev/null &

实时测试脚本(cyclictest.sh):

#!/bin/bash
./cyclictest -S -p 99 -i 1000 -D 5m -m -s -h400 -q >no_load_output ./stress_loades.sh ./cyclictest -S -p 99 -i 1000 -D 5m -m -s -h400 -q >light_load_output./stress_loades.sh 1./cyclictest -S -p 99 -i 1000 -D 5m -m -s -h1000 -q >heavy_load_output

这里为了展示效果,我只运行了5分钟测试,实际上应以产品的应用场景时长做测试,这样比较能反应其实时稳定性。

6、实时测试总结

我测试 Voluntary Kernel Preemption (Desktop)、Preemptible Kernel (Low-Latency Desktop)、Fully Preemptible Kernel (Real-Time) 三种抢占模型在无负载、一般负载、超重负载下的实时性。
在无负载的情况下,三种抢占模型基本上都能稳定实时响应,在一般负载和超重负载下,Voluntary和Preemptible模型出现了比较大延时抖动,其中Voluntary在一般负载下,最大延时达到395us,在超重负载下最大延时达到2599us,而Preemptible在一般负载下,最大延时达到241us,但是在超重负载下,最大延时达到了11920us。然而Fully Preemptible模型,在三种负载都表现出稳定实时性能,无负载下,最大延时49us,一般负载下,最大延时55us,超重负载下,最大延时79us。
由于测试的时间短以及实时性也跟处理器性能有关系,因此该测试仅作为简单参考。
最后,测试结果的直方图如下:

Voluntary Kernel Preemption (Desktop)抢占模型:

无负载:

一般负载:

超重负载:

Preemptible Kernel (Low-Latency Desktop)抢占模型:

无负载:

一般负载:

超重负载:

Fully Preemptible Kernel (Real-Time) 抢占模型:

无负载:

一般负载:

超重负载:

实时应用程序开发

对于有实时需求的应用程序,一般需要设置调度策略,优先级等等参数。一般常用的api函数如下:

sched_setscheduler()
pthread_attr_setschedpolicy()
pthread_attr_setschedparam()
pthread_attr_setinheritsched()

示例如下:

/* POSIX Real Time Example* using a single pthread as RT thread */#include <limits.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>void *thread_func(void *data)
{/* Do RT specific stuff here */return NULL;
}int main(int argc, char* argv[])
{struct sched_param param;pthread_attr_t attr;pthread_t thread;int ret;/* Lock memory */if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {printf("mlockall failed: %m\n");exit(-2);}/* Initialize pthread attributes (default values) */ret = pthread_attr_init(&attr);if (ret) {printf("init pthread attributes failed\n");goto out;}/* Set a specific stack size  */ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);if (ret) {printf("pthread setstacksize failed\n");goto out;}/* Set scheduler policy and priority of pthread */ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);if (ret) {printf("pthread setschedpolicy failed\n");goto out;}param.sched_priority = 80;ret = pthread_attr_setschedparam(&attr, &param);if (ret) {printf("pthread setschedparam failed\n");goto out;}/* Use scheduling parameters of attr */ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);if (ret) {printf("pthread setinheritsched failed\n");goto out;}/* Create a pthread with specified attributes */ret = pthread_create(&thread, &attr, thread_func, NULL);if (ret) {printf("create pthread failed\n");goto out;}/* Join the thread and wait until it is done */ret = pthread_join(thread, NULL);if (ret)printf("join pthread failed: %m\n");out:return ret;
}

FAQ

Scheduling - RT throttling

实时任务具有较高优先级,Linux内核优先调度高优先级任务。

如果实时应用程序中的编程失败会导致整个系统挂起,这种失败可能就像调用了一个“while(true){}”循环。

当实时应用程序具有尽可能高的优先级并使用 SCHED_FIFO 策略进行调度时,没有其他任务可以抢占它。

这会导致系统阻塞所有其他任务并以 100% 的 CPU 负载调度此循环。

实时节流是一种通过限制每个实时任务的周期执行时间来避免这种情况的机制。

这些设置被导出到 proc 文件系统中。

默认设置为:

# cat /proc/sys/kernel/sched_rt_period_us
1000000
# cat /proc/sys/kernel/sched_rt_runtime_us
950000

如果要使实时任务的 CPU 使用率仅达到 50% ,可以使用以下命令更改这些值:

# echo 2000000 > /proc/sys/kernel/sched_rt_period_us
# echo 1000000 > /proc/sys/kernel/sched_rt_runtime_us

如果想要禁用实时节流, 通过将 -1 写入 sched_rt_runtime_us 来自动完成的:

# echo -1 > /proc/sys/kernel/sched_rt_runtime_us

实时Linux之PREEMPT_RT篇相关推荐

  1. 2020-02-14 转载 开发应该知道的Linux系统分析-网络篇

    开发应该知道的Linux系统分析-网络篇 原文地址:https://cloud.tencent.com/developer/article/1583803 常用网络工具有: 通过ping命令检测网络的 ...

  2. Linux实操篇笔记

    Linux实操篇 远程登陆Linux 先检查一下sshd服务打开没有( " * " 表示打开): setup 选择系统设置,进入下面页面: Xshell 是一个强大的安全终端模拟软 ...

  3. 第五章-Linux实操篇

    title: 第五章 Linux实操篇 categories: Linux tags: linux typora-root-url: - abbrlink: 93414991 date: 2019-0 ...

  4. 嵌入式 Linux 开发工具篇问题整理//C语言测试(杨辉三角、递归调用实现阶乘、计算器、统计字符串出现次数)//2018.07.12.//

    嵌入式 Linux 开发工具篇问题整理 1. 嵌入式开发与传统开发的区别?(同类问题:单片机开发与嵌入式开发的区别)             是否有无操作系统:     2. 移植操作系统的好处有哪些 ...

  5. Linux基础入门篇知识回顾

    Linux基础入门篇知识回顾 一.回顾书籍 二.基础知识 1.计算机基础知识 1.1计算机的特点及发展趋势 ①特点 ②发展趋势 1.2计算机系统组成 ①计算机硬件概念 ②计算机硬件各部分功能 ![在这 ...

  6. 实时 Linux 架构剖析

    转自@https://www.ibm.com/developerworks/cn/linux/l-real-time-linux/#resources 本文探索了一些支持实时特性的 Linux 架构, ...

  7. Linux基本应用篇

    Linux基本应用篇 该文档适合新员工入职或者想了解Linux运维的初学者学习使用. 王斌 2020/5/18 1. Linux深入篇 1.1. 构建Nginx WEB服务器 nginx [engin ...

  8. 菜鸟学Linux 第044篇笔记 算法和私有CA

    菜鸟学Linux 第044篇笔记 算法和私有CA 证书吊销列表CRL(Certificate Revocation List ) 如何解决私钥丢失 PKI: Public Key Infrastruc ...

  9. 计算机书籍-Linux内核 入门篇

    去天猫看看智能鼠标 书名:奔跑吧 Linux内核 入门篇 作者:张天飞 出版社:人民邮电出版社 出版时间:2019年02月

  10. windows pxe 安装linux,菜鸟学Linux 第103篇笔记 pxe自动化安装linux

    菜鸟学Linux 第103篇笔记 pxe自动化安装linux 内容总览 linux的系统安装 kickstart文件的组成部分 DHCP (Dynamic Host Configuration Pro ...

最新文章

  1. 戈峻:英特尔推动嵌入式教育 意在双赢
  2. 如何安装使用MQCache缓存服务器(适用X300型或者X500型)
  3. 关于2017届学长制作分享软件share(失物招领)的使用体验和需改进的内容
  4. 1 python简介与安装
  5. 电话聊天狂人(25 分)(散列函数)
  6. spring-第三篇之ApplicationContext的事件机制
  7. 计算机考研408每日一题 day158
  8. android q mix3,Android Q+5G 小米MIX3流畅播放8K视频
  9. 摄影_光圈、快门、曝光度(ISO)
  10. 基于Tensorflow 2.0实现的图片风格迁移
  11. 【】每日360题,2019.11.05日19点财会类考试习题答案
  12. 查看电脑的数据库地址
  13. 复杂领域的Cynefin模型和Stacey模型
  14. 钢筋计数VOC数据集
  15. 以下不是python语言合法变量_违法行为的客体是指法律所保护的而为违法行为所侵害的:()...
  16. 用Python将excel表格按照列拆分为多个表格
  17. 微信小程序实现长按复制和点击复制
  18. Java基础之jvm,堆的分类新生代、老生代和永久代详解
  19. 会导致小程序onhide码 手机息屏_小程序onshow事件
  20. 异或运算 ^(xor)小解

热门文章

  1. IP地址子网划分基础知识
  2. 磁盘占用率100%——哪些程序可以禁用(详细版)【还讲到独立显卡、集成显卡、双显卡、固态硬盘卡机卡死卡顿解决】
  3. Does love become hate or forgiveness after a double deviation?文章阅读
  4. 如何关闭mysql secure_file_priv
  5. 密码分析之单表代换原理详解与算法实现
  6. ECMAScript 6基础总结
  7. 苹果即将迎来新应用,一个新行业正在崛起
  8. java轮训算法_轮询算法 - 小虾米的java梦 - 博客园
  9. C语言程序设计(2020)编程题答案——第14章结构体、共用体和用户定义类型
  10. iOS系统自带指纹验证的使用