我是靠谱客的博主 矮小纸飞机,最近开发中收集的这篇文章主要介绍linux进程调度的实现——进程记账,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

linux进程调度的实现一共由四部分组成

                 (1)、时间记账(就是记录进程已经运行了多长时间了,还要运行多长时间)

                 (2)、进程选择(加入红黑树)

                 (3)、调度器入口

                 (4)、睡眠和唤醒


进程记账:

          这个说的挺形象的,就是记录一个进程占用处理器资源的时间长短。既然要记录,那么就需要存放在一个位置,内核说:放在sched_entity结构中吧!


sched_entity结构(2.6内核源码kernel/sched/fair.c 1134 行):

struct sched_entity {
        struct load_weight      load;           /* for load-balancing */
        struct rb_node          run_node;
        struct list_head        group_node;
        unsigned int            on_rq;

        u64                     exec_start;
        u64                     sum_exec_runtime;
        u64                     vruntime;
        u64                     prev_sum_exec_runtime;

        u64                     nr_migrations;

#ifdef CONFIG_SCHEDSTATS
        struct sched_statistics statistics;
#endif

#ifdef CONFIG_FAIR_GROUP_SCHED
        struct sched_entity     *parent;
        /* rq on which this entity is (to be) queued: */
        struct cfs_rq           *cfs_rq;
        /* rq "owned" by this entity/group: *
        struct cfs_rq           *my_q;
#endif
};


注意下上面标准为红色的成员变量。vruntime,这个可以看成是virtual run time 直接翻译过来是虚拟运行时间,书上给的定义叫虚拟实时。
这个vruntime变量就是用来记录进程已经运行的时间长短,或者说 占用处理器已经多长时间了。那么这个时间越长就证明进程运行的时间越长,就越容易被其他的进程挤掉,也就是,其他进程容易抢占进来!linux系统对于进程的调度是要看这个变量来采取行动的。那么这个虚拟实时(就是个时间值)怎么计算出来的呢?(其实这个计算过程就是 进程记账的过程),内核使用update_curr()函数来实现这个过程,源码如下(kernel/sched/fair.c 684 行):


static void update_curr(struct cfs_rq *cfs_rq)
{
        struct sched_entity *curr = cfs_rq->curr;
        u64 now = rq_of(cfs_rq)->clock_task;
        unsigned long delta_exec;

        if (unlikely(!curr))
                return;

        /*
         * Get the amount of time the current task was running
         * since the last time we changed load (this cannot
         * overflow on 32 bits):
         */
        delta_exec = (unsigned long)(now - curr->exec_start);
        if (!delta_exec)
                return;

        __update_curr(cfs_rq, curr, delta_exec);
        curr->exec_start = now;

        if (entity_is_task(curr)) {
                struct task_struct *curtask = task_of(curr);

                trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime);
                cpuacct_charge(curtask, delta_exec);
                account_group_exec_runtime(curtask, delta_exec);
        }

        account_cfs_rq_runtime(cfs_rq, delta_exec);
}

说实话,我基本上没看明白。
但是其中的几个变量和函数名 还是很清楚的,curr是一个sched_entity结构指针,接受函数传进的参数。函数参数那个结构是什么?不清楚,反正是把其中的一个成员复制给curr变量。看名字可以知道是指进程当前的状态(当然,包括虚拟实时)。接着定义了一个无符号长整型变量delta_exec,查一下delta有增量的意思,而exec是执行,那么从名字上看就是值执行的增量(这里,其实就是时间的增量)。然后,看到delta_exec被赋值为now和exec_start的差值,exec_start这个可以知道这是开始,现在减开始的,那就是已经运行的时间。最后执行__update_curr函数将当前的进程账本,和已经运行的时间作为参数传入,那么先来看看__update_curr这个函数(kernel/sched/fair.c 664 行):


static inline void 
__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
              unsigned long delta_exec)
{
        unsigned long delta_exec_weighted;

        schedstat_set(curr->statistics.exec_max,
                      max((u64)delta_exec, curr->statistics.exec_max));

        curr->sum_exec_runtime += delta_exec;
        schedstat_add(cfs_rq, exec_clock, delta_exec);
        delta_exec_weighted = calc_delta_fair(delta_exec, curr);

        curr->vruntime += delta_exec_weighted;
        update_min_vruntime(cfs_rq);

#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
        cfs_rq->load_unacc_exec_time += delta_exec;
#endif
}


主要还是看红色的代码,传入的参数curr,delta_exec,执行了calc_delta_fair,也是从名字入手,这是计算,计算什么呢?增量,还是公平的,那就是加入了权重,这样计算出了权重值。接着在vruntime上加以权重,这就是进程运行的时间,记账完成。





最后

以上就是矮小纸飞机为你收集整理的linux进程调度的实现——进程记账的全部内容,希望文章能够帮你解决linux进程调度的实现——进程记账所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部