RMS调度详解

来源:互联网 发布:淘宝价格设置技巧 编辑:程序博客网 时间:2024/06/10 11:54

1.RMS调度简介

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

2.RMS调度实现介绍

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

程序清单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源码,其流程如图 2‑1所示。


图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中去获取















原创粉丝点击