Xen的调度分析 (二) ——关于credit调度算法

时间:2021-01-03 02:11:34

Xen调度过程是调度机制和策略相分离的,上一节主要分析了调度机制,可以出,调度机制中最关键的调用了do_schedule()函数,该函数在credit算法中是如何实现的呢?

通过整理,我们可以理清一下思路:

首先介绍一下一个VCPU任务都有哪些优先级:

#define CSCHED_PRI_TS_BOOST      0      /* time-share waking up 优先调度*/
#define CSCHED_PRI_TS_UNDER     -1      /* time-share w/ credits 需调度*/
#define CSCHED_PRI_TS_OVER      -2      /* time-share w/o credits 不调度*/
#define CSCHED_PRI_IDLE         -64     /* idle 空闲*/

 

(一)第一个步骤是通过一个判断语句来实现的,如下

    if (!is_idle_vcpu(scurr->vcpu))
    {
        /* Update credits of a non-idle VCPU. */
        //消耗credit值
        burn_credits(scurr, now);
        scurr->start_time -= now;
    }
    else
    {
        /* Re-instate a boosted idle VCPU as normal-idle. */
        //恢复空闲vcpu
        scurr->pri = CSCHED_PRI_IDLE;
    }

这里首先判断了是否是空闲VCPU,如果不是则进行正常调度,通过burn_credits()来消耗该进程的credit值。

若是VCPU则恢复他的优先级。

(二)中间略去一些代码,我们来到第二块

    /*
    * Select next runnable local VCPU (ie top of local runq)
    */
    //选取下一个可运行的本地VCPU(比如链表头)
    //若当前vcpu可运行则 
    if (vcpu_runnable(current))
        //将当前的vcpu插入队列中合适的位置
        __runq_insert(cpu, scurr);
    snext = __runq_elem(runq->next);
    ret.migrated = 0;

这里判断了一下该VCPU是否是还需运行,如果还需要运行,则将该代码插入到CPU链表中从大到小的合适位置。

过插入到合适的位置,来维护整个链表的有序性。

插入后,snext自然是需要调度的下一个VCPU了。

(三)略去一些代码,来到第三部分。第三部分是关于负载均衡的。

    //SMP负载均衡
    //如果下一个最高优先级的VCPU已经用光了credits,看看其他pcpus有没有更紧急的工作
    //没有的话,csched_load_balance() 将会返回snext,返回前该节点从队列移除
    if (snext->pri > CSCHED_PRI_TS_OVER)
        __runq_remove(snext);
    else
        snext = csched_load_balance(prv, cpu, snext, &ret.migrated);

这段代码首先判断了第一个节点的snext的优先级,如果是可以调度的,则取下该节点,准备开始调度该节点的VCPU了。

如果不是,则通过csched_load_balance()来进行负载均衡。

(四)再略去一些代码,我们来到第四步就是返回需要调度的VCPU的信息了。

    ret.time = (is_idle_vcpu(snext->vcpu) ?
                -1 : tslice);
    ret.task = snext->vcpu;

    CSCHED_VCPU_CHECK(ret.task);
    return ret;

tslice就是需要返回的时间大小,snext的VCPU信息就是需要返回需要调度的VCPU。

Xen的调度分析 (二) ——关于credit调度算法

接下来对几个部分的细节进行分析。