转载地址:https://www.aliyun.com/jiaocheng/1389159.html

  • 摘要:Linux上调度策略为SCHED_FIFO的实时进程是根据优先级抢占运行的。当没有更高优先级的实时进程抢占,而此进程又由于bug等原因长时间运行,不调度其它进程,系统就会出现无响应。这里要分析的RTthrottling就是针对此种情况的,它通过限制每个单位时间内分配给实时进程的CPU运行时间,来防止上述情况的出现。标准的设置是1s的时间内,实时进程的运行时间是950ms,其余的50ms时间给normal进程使用。sched_rt_period_us值为1000000us=1s
  • Linux上调度策略为SCHED_FIFO的实时进程是根据优先级抢占运行的。当没有更高优先级的实时进程抢占,而此进程又由于bug等原因长时间运行,不调度其它进程,系统就会出现无响应。这里要分析的RT throttling就是针对此种情况的,它通过限制每个单位时间内分配给实时进程的CPU运行时间,来防止上述情况的出现。

    标准的设置是1s的时间内,实时进程的运行时间是950ms,其余的50ms时间给normal进程使用。

    sched_rt_period_us值为1000000us=1s,表示单位时间为1s

    sched_rt_runtime_us值为950000us=0.95s,表示实时进程的运行时间为0.95s。

    这两个接口的实现代码如下:

    Kernel/sysctl.c的kern_table片段

    {

    .procname = "sched_rt_period_us",

    .data   = &sysctl_sched_rt_period,

    .maxlen   = sizeof(unsigned int),

    .mode   = 0644,

    .proc_handler = sched_rt_handler,

    },

    {

    .procname = "sched_rt_runtime_us",

    .data   = &sysctl_sched_rt_runtime,

    .maxlen   = sizeof(int),

    .mode   = 0644,

    .proc_handler = sched_rt_handler,

    },

    sched_rt_period_us接口设置的是sysctl_sched_rt_period变量,sched_rt_runtime_us接口设置的是sysctl_sched_rt_runtime变量。读写的实现都是通过sched_rt_handler函数,这里就不具体分析了。

    我们知道了如何设置RT throttling,那么它是如何工作的呢?在实时进程的运行时间超出设定的阈值是如何处理的?

    static void update_curr_rt(struct rq *rq)

    {

    if (curr->sched_class != & rt_sched_class)  /*判断当前进程调度类*/

    return;

    /*运行队列现在的时间与当前进程开始运行时间之差* */

    delta_exec = rq_clock_task(rq) -  curr->se.exec_start ;

    curr->se.sum_exec_runtime +=  delta_exec;  /*更新进程的真实运行时间*/

    curr->se.exec_start =  rq_clock_task(rq);

    if (! rt_bandwidth_enabled())  /*判断RT throttling是否开启*/

    return;

    for_each_sched_rt_entity(rt_se) {  /*/*遍历此实时进程的调度单元*/*/

    struct rt_rq *rt_rq = rt_rq_of_se(rt_se);

    if (sched_rt_runtime(rt_rq) !=  RUNTIME_INF) {

    rt_rq->rt_time +=  delta_exec;

    /*rt_rq的运行时间是否超过了分配给它的时间片*/

    if (sched_rt_runtime_exceeded(rt_rq))

    resched_task(curr);

    }

    }

    }

    update_curr_rt函数用来更新当前实时进程的运行时间统计值,如果当前进程不是实时进程,即调度类不为rt_sched_class,则直接返回。

    delta_exec值为此运行队列的当前时间与此进程开始运行时间之差,也即是此进程此次调度运行的时长。然后更新进程的真实运行时间和开始运行时间。

    rt_bandwidth_enabled函数判断sysctl_sched_rt_runtime变量值是否大于0,如果此变量值设置为RUNTIME_INF(很大的负数),就关掉了RT throttling功能,这里就会直接返回。

    然后遍历此实时进程的调度实体,找到相应的就绪队列,更新运行时间后,通过sched_rt_runtime_exceeded函数判断是否此实时进程是否超过了分配给它的时间片。

    sched_rt_runtime_exceeded代码片段:

    u64 runtime = sched_rt_runtime(rt_rq);   /*获取当前队列的最大运行时间*/

        if (rt_rq->rt_throttled )    /*当前队列的实时调度受到限制*/

    return rt_rq_throttled(rt_rq);

    /*当前队列的最大运行时间大于当前队列的调度周期时间*/

    if (runtime >= sched_rt_period(rt_rq))

    return 0;

    balance_runtime(rt_rq);

    runtime = sched_rt_runtime(rt_rq);   /*重新获取当前队列的最大运行时间*/

    if (runtime == RUNTIME_INF)  /*关闭了RT throttling*/

    return 0;

    runtime值为当前队列的最大运行时间rt_runtime。rt_throttled字段表示当前队列的实时调度是否受到限制,如果受到限制了,就直接返回1,在update_curr_rt函数中就会调用resched_task函数执行进程切换,让出cpu。

    如果当前队列的最大运行时间大于当前队列的调度周期时间,则返回0,这样此运行队列上的任务还能够继续运行。

    balance_runtime函数在RT_RUNTIME_SHARE特性使能的情况下,如果当前队列的运行时间超过了最大运行时间,则可以从其他cpu上借用时间。具体代码这里先不分析,后面分析。

    重新获取当前队列的最大运行时间runtime,如果值等于RUNTIME_INF说明关闭了RT throttling,则直接返回0。

    sched_rt_runtime_exceeded代码片段:

    if (rt_rq->rt_time >  runtime) {  /*累计运行时间大于最大运行时间*/

    struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);

    if (likely(rt_b->rt_runtime )) {

    rt_rq->rt_throttled =  1;

    printk_deferred_once("sched: RT throttling activated\n");

    } else {

    rt_rq->rt_time =  0;

    }

    if (rt_rq_throttled(rt_rq)) {  /*检查队列的实时调度是否受到限制*/

    sched_rt_rq_dequeue(rt_rq);  /*将调度实体从实时运行队列中删除*/

    return 1;

    }

    }

    如果累计运行时间大于最大运行时间,就会执行上面的代码片段。rt_b为运行队列rt_rq的进程组带宽控制结构体指针,如果rt_runtime即此进程组的任务运行时间额度值有效,则设置rt_throttled为1,表明此队列的实时调度受到限制,并打印出“sched: RT throttling activated”信息。接着检查队列的实时调度如果受到限制,则返回1,在update_curr_rt函数中让出cpu。

    在前面讲到balance_runtime在当前队列运行时间超过最大运行时间后,可以从其他cpu上借用时间,下面具体分析代码看下是如何实现的。

    static int balance_runtime(struct rt_rq *rt_rq)

    {

        if (! sched_feat(RT_RUNTIME_SHARE))   /*RT_RUNTIME_SHARE支持多个cpu间的rt_runtime共享*/

    return more;

    if (rt_rq->rt_time >  rt_rq->rt_runtime ) {

    raw_spin_unlock(&rt_rq->rt_runtime_lock );

    more = do_balance_runtime(rt_rq);

    raw_spin_lock(&rt_rq->rt_runtime_lock );

    }

    }

    RT_RUNTIME_SHARE默认是使能的(见kernel/sched/features.h文件)

    SCHED_FEAT(RT_RUNTIME_SHARE, true)

    它表示支持多个cpu间的rt_runtime共享。如果不支持的话,就直接返回。

    如果当前队列的累计运行时间大于最大运行时间,则调用do_balance_runtime函数。

    do_balance_runtime函数代码:

        struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);

        struct root_domain *rd = rq_of_rt_rq(rt_rq)->rd ;

    weight = cpumask_weight(rd->span );

    rt_period = ktime_to_ns(rt_b->rt_period );  /*任务组一个控制周期的时间*/

        for_each_cpu(i, rd->span ) {

    /*找到在另一个cpu上运行的同一任务组的运行队列*/

    struct rt_rq *iter = sched_rt_period_rt_rq(rt_b, i);

    if (iter == rt_rq)  /*同一运行队列则跳过*/

    continue;

    if (iter->rt_runtime ==  RUNTIME_INF)  /*RT throttling关闭,不允许借用时间*/

    goto  next;

    diff = iter->rt_runtime - iter->rt_time ;  /*最大能够借用时间*/

    if (diff > 0) {

    diff = div_u64((u64)diff, weight);

    if (rt_rq->rt_runtime +  diff > rt_period)

    diff = rt_period -  rt_rq->rt_runtime ;  /*修正后可借用*/

    iter->rt_runtime -= diff;

                rt_rq->rt_runtime += diff;

    more = 1;

    if (rt_rq->rt_runtime == rt_period) { /*满足条件退出,否则继续从其他cpu借用*/

    break;

    }

    }

    next:

    }

    rd->span表示此调度域的rq可运行的cpu的一个mask,这里会遍历此mask上的cpu,如果对应的cpu的rq和当前的rq是同一运行队列,则直接跳过;如果对应的cpu的rq已关闭RT throttling功能,则不允许借用时间。内核中关于这块代码的注释是:

    Either all rqs have inf runtime and there's nothing to steal or __disable_runtime() below sets a specific rq to inf to indicate its been disabled and disalow stealing.

    大概意思是如果所有的运行队列都设置为RUNTIME_INF即关闭了RT throttling功能,则没有时间可以借用。或者某个指定的运行队列调用__disable_runtime()函数,则不允许别的借用自己的时间。

    diff是iter运行队列最大能够借用的时间,后面经过修正后,将diff加入到rt_rq的最大可运行时间上。如果新的最大可运行时间等于此任务组的控制周期的时间,则不需要接着再从其他的CPU上借用时间,就直接break退出。

    实时进程所在的cpu占用超时,可以向其他的CPU借用,将其他CPU的时间借用过来,这样此实时进程所在的CPU占有率达到100%,这样做的目的是为了避免实时进程由于缺少CPU时间而向其他的CPU迁移,减少不必要的迁移成本。此cpu上为绑定核的普通进程可以迁移到其他cpu上,这样就会得到调度。但是如果此CPU上有进程绑定核了,那么就只有在这里饿死了。

RT throttling分析相关推荐

  1. RT throttling分析【转】

    转自:https://blog.csdn.net/u012728256/article/details/72639612 Linux上调度策略为SCHED_FIFO的实时进程是根据优先级抢占运行的.当 ...

  2. cpu进程调度---RT Throttling【转】

    转自:http://book.2cto.com/201302/16291.html RT Throttling是对分配给实时进程的CPU时间进行限制的功能.使用实时调度策略的进程由于bug等出现不可控 ...

  3. Sched: RT throttling activated

    "Sched: RT throttling activated" 是 Linux 内核中实时调度策略(Real-time scheduling policy)中的一条消息.它通常在 ...

  4. sched_setscheduler分析

    之前在chinaunix上看到有人问了下面这个问题: #define _GNU_SOURCE #include <sched.h> int main() {       int prio ...

  5. Linux进程管理 (9)实时调度类分析,以及FIFO和RR对比实验

    关键词:rt_sched_class.SCHED_FIFO.SCHED_RR.sched_setscheduler().sched_setaffinity().RR_TIMESLICE. 本文主要关注 ...

  6. 一次mmc0: Timeout waiting for hardware interrupt问题分析过程

    1.单板环境 xilinx zynq7z15 soc,Arm cortex A9双核.外设:mmc.emmc.spi.qspi.i2c.gpio.can.uart.cdns-gem(网口).dsp.u ...

  7. 虚拟机+CentOS内核hack7、8、9、17失败记

    一 <Linux内核精髓:精通Linux内核必会的75个绝技>目录 1章 内核入门 HACK #1 如何获取Linux内核 HACK #2 如何编译Linux内核 HACK #3 如何编写 ...

  8. Linux进程调度 - 实时调度器 LoyenWang

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  9. Linux进程调度-deadline调度器

    Linux内核中定义了5个调度器类,分别对应5个调度器,调度优先级顺序由高到低依次为:stop_sched_class.dl_sched_class.rt_sched_class.fair_sched ...

最新文章

  1. web应用程序和web网站_Web应用程序和移动应用程序的基本启动清单
  2. 用一条sql获取分组中最大值时的ID
  3. DBSCAN的两个核心参数是什么?如何获取最佳参数?如何可视化获取的过程?
  4. 快速深入一门语言的几个问题 - Shell909090 - 随笔杂记
  5. 成功的九字真言(冯唐)
  6. java中集合的排序
  7. java中spring的注解_spring中的各种注解解析
  8. 【蜕变之路】第29天 CAST和CONVERT的区别(2019年3月19日)
  9. apache cxf java_Java-Apache CXF Web服务问题
  10. 为什么Linux内核常用unsigned long来代替指针
  11. Dokcer使用总结(Dockerfile、Compose、Swarm)
  12. opencv数字图像处理(2) - 直方图处理方法【直方图均衡化与直方图规定化】
  13. js 改变change方法_JS获取和设置元素的属性以及属性值
  14. MVP架构模式简单示例
  15. 分盘后磁盘空间不够,用分区助手增加某个磁盘空间
  16. dell服务器经常自动关机,戴尔电脑老是自动关机的解决方法
  17. OpenGL(十三) Alpha测试、剪裁测试
  18. 金属塑性成形计算机模拟仿真,金属塑性成形计算机模拟的若干进展
  19. 商城尺码选择效果 jquery
  20. 经纬度换算数值_Excel中经纬度数据转换公式

热门文章

  1. iPhone X 的适配
  2. 电子技术基础(三)__第1章 并联电路的电阻_电阻的分流公式
  3. 简单制作一个Python聊天机器人
  4. 适合微信小程序作品的极简番茄时钟
  5. 手机存量市场下的激烈角逐:VO荣米格局初定
  6. Cadence OrCAD Capture 打印图纸的某一个部分的方法
  7. 二分法查找--Dichotomy search
  8. 《两日算法系列》之第四篇:隐马尔可夫模型HMM
  9. 用python画爱心及代码演示
  10. 神奇宝贝:面向开发人员的免费RESTful神奇宝贝API