1、linux 实时性方案:

        -单内核方案:主线软实时内核,打PREEMPT_RT补丁,使内核成为硬实时内核

        -双内核方案:主线普通内核+实时内核,例如:RT-linux ,RTAI,Xenomai。

2、实时性和抢占性

实时性:

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

可抢占性:

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

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

源码路径:kernel/Kconfig.preempt 

choice
    prompt "Preemption Model"
    default PREEMPT_NONE

config PREEMPT_NONE                                                                                                                                                    
    bool "No Forced Preemption (Server)"  

//这是传统的Linux抢占模式,旨在吞吐量它仍将提供良好的延迟——大多数时间,但没有保证,偶尔会有更长的延迟是可能的。

//如果您正在为服务器或科学/计算系统,或者如果您想最大化内核的原始处理能力,与调度无关延迟。

config PREEMPT_VOLUNTARY
    bool "Voluntary Kernel Preemption (Desktop)"
    depends on !ARCH_NO_PREEMPT

//此选项通过添加更多延迟来减少内核的延迟“显式抢占指向”内核代码。这些新的已选择抢占点以减少最大值重新调度的延迟、提供更快的应用程序反应,以稍低的吞吐量为代价。

//这允许通过允许低优先级进程,即使它正在内核模式下执行系统调用。这允许即使系统处于在负载下。

//如果您正在为桌面系统构建内核,请选择此选项。

config PREEMPT
    bool "Preemptible Kernel (Low-Latency Desktop)"
    depends on !ARCH_NO_PREEMPT
    select PREEMPT_COUNT
    select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK
//此选项通过使所有内核代码(不在关键部分执行)可抢占。这允许通过以下方式对交互式事件做出反应允许低优先级进程被非自愿地抢占即使它在内核模式下执行系统调用否则就不会达到自然抢占点。这使得应用程序即使在系统处于负载状态,代价是吞吐量略低以及内核代码的轻微运行时开销。

//如果您正在为桌面或具有毫秒级延迟要求的嵌入式系统范围

//对软实时性的嵌入式系统,最后一个就能满足。

3、进程调度策略

非实时策略:

        

  • 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 调度的任何任务。

函数接口与数据结构:

extern int sched_setscheduler(struct task_struct *, int, const struct sched_param *);

sched_setscheduler(worker->task, SCHED_FIFO, &sparam);

static const struct sched_param sparam = {
    .sched_priority = MAX_USER_RT_PRIO / 2,
};

4、PREEMPT_RT实时补丁

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

PREEMPT_RT补丁地址:Index of /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

5、打补丁

git apply xxx.patch

or

git am xxx.patch

6、实时性测试工具

cyclictest就是开源的Linux实时性测试工具

下载地址:https://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git

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

7、实时应用程序开发

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

-sched_setscheduler()

-pthread_attr_setschedpolicy()

-pthread_attr_setschedparam()

-pthread_attr_setinheritsched()

实时节流的配置:

# cat /proc/sys/kernel/sched_rt_period_us

1000000

# cat /proc/sys/kernel/sched_rt_runtime_us

950000

如果想禁用实时节流,就 echo -1 > /proc/sys/kernel/sched_rt_runtime_us。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐