RMS调度详解

1.RMS调度简介

任务按单调速率优先级分配(RMPA)的调度算法,称为单调速率调度(RMS)。RMPA是指任务的优先级按任务周期T来分配。它根据任务的执行周期的长短来决定调度优先级,那些具有小的执行周期的任务具有较高的优先级,周期长的任务优先级低。

2.RMS调度实现介绍

SylixOS目前关于RMS调度分为创建、删除、调度三个部分组成。创建和删除就不予介绍。重点关注下调度算法的实现。调度有两个去完成,一是计算调度前用掉的时间etime,二是睡眠剩余调度的时间temp,如程序清单 21所示。

程序清单2-1 RMS实现源码

/********************************************************************************************
** 函数名称: sched_rms_period
** 功能描述: RMS 调度器
** 输 入  : prms      RMS 调度器
**           period    RMS 周期
** 输 出  : 0 表示正确
**           error == EINTR    表示被信号激活.
** 全局变量: 
** 调用模块: 
                                           API 函数
********************************************************************************************/
LW_API 
int  sched_rms_period (sched_rms_t  *prms, const struct timespec *period)
{
    struct timespec temp;
    struct timespec etime;
    
    if (!prms || !period) {
        errno = EINVAL;
        return  (PX_ERROR);
    }
    
    switch (prms->PRMS_iStatus) {
    
    case PRMS_STATUS_INACTIVE:
        lib_clock_gettime(CLOCK_MONOTONIC, &prms->PRMS_tsSave);  
        prms->PRMS_iStatus = PRMS_STATUS_ACTIVE;
        return  (ERROR_NONE);
        
    case PRMS_STATUS_ACTIVE:
        lib_clock_gettime(CLOCK_MONOTONIC, &temp);
        etime = temp;
        
        __timespecSub(&etime, &prms->PRMS_tsSave);
        if (__timespecLeftTime(period, &etime)) {                       
            lib_clock_gettime(CLOCK_MONOTONIC, &prms->PRMS_tsSave);     
            errno = EOVERFLOW;
            return  (PX_ERROR);
        }
        
        temp = *period;
        __timespecSub(&temp, &etime);
        __timespecAdd(&prms->PRMS_tsSave, period);                      
        return  (nanosleep(&temp, LW_NULL));
        
    default:
        errno = ENOTSUP;
        return  (PX_ERROR);
    }
}

1.      计算调度时间

首先通过系统函数获取准确的时间etime,在和上一次保存的时间PRMS_toSave相减获得在进入调度函数之前所用掉的时间etime。利用etime和需要调度的时间period比较进行处理。计算出需要睡眠的时间temp。

2.      睡眠剩余的调度时间

通过函数nanosleep计算剩余的时间,函数nanosleep具体实现可参考SylixOS源码,其流程如图 21所示。

图2-1 nanosleep流程图

3.RMS调度分析

3.1 RMS调度优势

调度算法中利用PRMS_tsSave保存时间点,为下一次调度作为时间参考,调度按照确定周期运行,这样可以避免因多次调度而累积的误差。代码如下:

        …
        __timespecSub(&temp, &etime);
         
        /*
         *  注意: 这里直接加上周期是为了让每次测算都是以一个固定周期律进行
         *        提高周期精度. (不使用 lib_clock_gettime())
         */
        __timespecAdd(&prms->PRMS_tsSave, period);                      /*  以确定周期运行              */
        return  (nanosleep(&temp, LW_NULL));
        …

3.2 误差分析一

调度算法中存在这样的问题,需要延迟的时间time和延迟函数function是分开的,这就会导致一个问题,在计算出time后有可能进程被调度,而没有进入function。

等下一次调度到进程后再进入function后会导致时间不准确,该进程从被调度到再次被调度中的时间没有被计算。这种情况出现在调度函数sched_rms_period,在计算

出睡眠时间后temp后进程被调度,等下一次被调度后才进入睡眠时间。代码如下:

        __timespecSub(&temp, &etime);
                
        /*
         *  注意: 这里直接加上周期是为了让每次测算都是以一个固定周期律进行
         *        提高周期精度. (不使用 lib_clock_gettime())
         */
        __timespecAdd(&prms->PRMS_tsSave, period);                      /*  以确定周期运行              */
        return  (nanosleep(&temp, LW_NULL));

nanosleep也同样会出现此类问题,在计算平滑过度时间后,也有可能出现进程调度而导致时间计算不准确。代码如下:

        if (__timespecLeftTime(&tvTemp, rqtp)) {                        /*  还有剩余时间需要延迟        */
            struct timespec  tvNeed = *rqtp;
            __timespecSub(&tvNeed, &tvTemp);
            __timePassSpec(&tvNeed);                                   /*  平静度过                    */
        }

3.3 误差分析二

同时我们在该函数中获取高精度时间没有放在函数最开始运行处,在运行到获取高精度时间前也可能出现进程调度。代码如下:

       ulTick = __timespecToTick((struct timespec *)rqtp);
       if (!ulTick) {                                                  /*  不到一个 tick               */
            __timePassSpec(rqtp);                                      /*  平静度过                    */
            if (rmtp) {
                rmtp->tv_sec  = 0;                                     /*  不存在时间差别              */
                rmtp->tv_nsec = 0;
            }
            return  (ERROR_NONE);
        }
      
        __timeGetHighResolution(&tvStart);                             /*  记录开始的时间              */

改进措施:尽量将__timeGetHighResolution获取开始延迟的时间点函数靠前,避免nanosleep在执行获取高精度时间之前出现进程调度的情况;

可以将要延迟的时间起始点以参数的形式传递给要睡眠的函数,比如nanosleep这类函数就可以在调用者处确定延迟的时间点tvStart,而不是在

nanosleep中去获取

时间: 2024-10-08 15:49:26

RMS调度详解的相关文章

资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解

欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯云容器服务团队 源码为 k8s v1.6.1 版本,github 上对应的 commit id 为 b0b7a323cc5a4a2019b2e9520c21c7830b7f708e 本文将对 Scheduler 的调度算法原理和执行过程进行分析,重点介绍 Scheduler 算法中预选和优选的相关内容. Kubernetes Scheduler的基本功能 Kubernetes Scheduler 的作用是根据特定的调度算法将

k8s之pod调度详解

通常情况下,使用的都是k8s默认的调度调度方式,但是在有些情况下,我们需要将pod运行在具有特点的标签的node上才能都运行,这个时候,pod的调度策略就不能使用k8s默认的调度策略了,这个时候,就需要指定调度策略,告诉k8s需要将pod调度到那些node(节点)上. nodeSelector常规情况下,会直接使用nodeSelector这种调度策略.labels(标签) 是k8s里面用来编标记资源的一种常用的方式,我们可以给node标记特殊的标签,然后nodeSelector会将pod调度到带

Yarn 调度器Scheduler详解

理想情况下,我们应用对Yarn资源的请求应该立刻得到满足,但现实情况资源往往是有限的,特别是在一个很繁忙的集群,一个应用资源的请求经常需要等待一段时间才能的到相应的资源.在Yarn中,负责给应用分配资源的就是Scheduler.其实调度本身就是一个难题,很难找到一个完美的策略可以解决所有的应用场景.为此,Yarn提供了多种调度器和可配置的策略供我们选择. 一.调度器的选择 在Yarn中有三种调度器可以选择:FIFO Scheduler ,Capacity Scheduler,FairS ched

Linux进程上下文切换过程context_switch详解--Linux进程的管理与调度(二十一)【转】

转自:http://blog.csdn.net/gatieme/article/details/51872659 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme 目录(?)[-] 前景回顾 1 Linux的调度器组成 2 调度工作 进程上下文 1 进程上下文的概念 2 上下文切换 context_switch进程上下文切换 1 context_switch完全注释 2 prepare_arch_switch切换前的准备工作

Linux进程退出详解(do_exit)--Linux进程的管理与调度(十四))

日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度 Linux进程的退出 linux下进程退出的方式 正常退出 从main函数返回return 调用exit 调用_exit 异常退出 调用abort 由信号终止 _exit, exit和_Exit的区别和联系 _exit是linux系统调用,关闭所有文件描述符,然后退出进程. exit是c语言的库函数,他最

Linux下进程的创建过程分析(_do_fork/do_fork详解)--Linux进程的管理与调度(八)

日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的创建 参照 分析Linux内核创建一个新进程的过程 前言 Unix标准的复制进程的系统调用时fork(即分叉),但是Linux,BSD等操作系统并不止实现这一个,确切的说linux实现了三个,fork,vfork,clone(确切说vfork创造出来的是轻量级进程,也叫线程,是共享资源的进程)

LVS类型详解及其调度方法

1.LVS简介 LVS 是 Linux  Virtual Server ,Linux 虚拟服务器.可以实现LINUX平台下的简单负载均衡.一般来说,LVS采用三层结构:负载调度器.服务器池.共享存储.工作在TCP/IP协议的四层,其转发是依赖于四层协议的特征进行转发的,由于其转发要 依赖于协议的特征进行转发,因此需要在内核的TCP/IP协议栈进行过滤筛选,可想而知,这就需要在内核的模块来完成,而这样的过滤转发规则又是由管理员 进行定义的,所以,LVS就是两段式的架构设计,在内核空间中工作的是"i

LinuxELF文件格式详解--Linux进程的管理与调度(十二)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-04 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的描述 对象文件格式 对象文件 首先,你需要知道的是所谓对象文件(Object files)有三个种类: 可重定位的对象文件(Relocatable file) 可执行的对象文件(Executable file) 可被共享的对象文件(Shared object file) 可重定位的对象文件(Re

Linux- Linux自带定时调度Crontab使用详解

Linux自带定时调度Crontab使用详解 在Linux当中,有一个自带的任务调度功能crontab,它是针对每个用户,每个用户都可以调度自己的任务. 示例:每分钟执行一次,将时间写入到指定文件当中 crontab -e //编辑定时任务调度 ###first crontab */1 * * * * /bin/date >> /root/log.txt 列出目前所有的定时任务 crontab -l 删除所有的定时任务 crontab -r 或者在该定时任务前加上"#"注释