免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2103 | 回复: 0
打印 上一主题 下一主题

solaris源码分析 - 调度器如何选择CPU [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-10-13 13:29 |只看该作者 |倒序浏览

                                                要将一个线程调度到一个cpu上,如何选取cpu在操作系统中是很有讲究的,下面看看solaris是如何选择cpu的。
static cpu_t *cpu_choose(kthread_t *t, pri_t tpri){    ASSERT(tpri     if ((((lbolt - t->t_disp_time) > rechoose_interval) &&        t != curthread) || t->t_cpu == cpu_inmotion) {        return (disp_lowpri_cpu(t->t_cpu, t->t_lpl, tpri, NULL));    }
如果上次的运行的cpu已经offline了,或者在申请移动的分区里(t->t_cpu == cpu_inmotion),那么就得重新选择了。
如果要调度的线程不是当前线程,并且分配器计时超过了3个tick((lbolt - t->t_disp_time) > rechoose_interval),那么也得重新选择cpu。如果没超过3个tick,那说明把线程放回到上次运行的cpu上,很有可能还可以利用cpu的硬件cache,这样系统performance会从中受益。
    /*     * Take a trip through disp_lowpri_cpu() if the thread was     * running outside it's home lgroup     */    if (!klgrpset_ismember(t->t_lpl->lpl_lgrp->lgrp_set[LGRP_RSRC_CPU],        t->t_cpu->cpu_lpl->lpl_lgrpid)) {        return (disp_lowpri_cpu(t->t_cpu, t->t_lpl, tpri,            (t == curthread) ? t->t_cpu : NULL));    }
如果上次运行的cpu不在该线程的局域分组(lgroup)里面,那么得重新选择一个cpu。
    return (t->t_cpu);
否则,我们就选用线程上次运行的那个cpu.
}
现在我们来看看disp_lowpri_cpu()是如何来寻找正运行最低优先级线程的cpu的。
cpu_t *disp_lowpri_cpu(cpu_t *hint, lpl_t *lpl, pri_t tpri, cpu_t *curcpu){    cpu_t    *bestcpu;    cpu_t    *besthomecpu;    cpu_t   *cp, *cpstart;    pri_t   bestpri;    pri_t   cpupri;    klgrpset_t    done;    klgrpset_t    cur_set;    lpl_t        *lpl_iter, *lpl_leaf;    int        i;    /*     * Scan for a CPU currently running the lowest priority thread.     * Cannot get cpu_lock here because it is adaptive.     * We do not require lock on CPU list.     */    ASSERT(hint != NULL);    ASSERT(lpl != NULL);    ASSERT(lpl->lpl_ncpu > 0);
该函数传入第一个参数为上次运行的cpu,第二个参数为该线程所在局域分组的负载均值,第三个参数为线程的优先级,最后一个参数为当前的cpu,如果要调度的线程不是当前线程,当前cpu为NULL。
    /*     * First examine local CPUs. Note that it's possible the hint CPU     * passed in in remote to the specified home lgroup. If our priority     * isn't sufficient enough such that we can run immediately at home,     * then examine CPUs remote to our home lgroup.     * We would like to give preference to CPUs closest to "home".     * If we can't find a CPU where we'll run at a given level     * of locality, we expand our search to include the next level.     */    bestcpu = besthomecpu = NULL;    klgrpset_clear(done);
初始化变量,清空局域分区的bitmap,准备查找。
   
    /* start with lpl we were passed */    lpl_iter = lpl;
从我们参数传入的lpl还是找起。    do {        bestpri = SHRT_MAX;        klgrpset_clear(cur_set);        for (i = 0; i lpl_nrset; i++) {
局域分组是树型的,从0开始,到整个树的叶子数目。
            lpl_leaf = lpl_iter->lpl_rset;
获取当前局域分组。
            if (klgrpset_ismember(done, lpl_leaf->lpl_lgrpid))                continue;
如果当前局域分组属于done局域分组系列,结束本次循环,进入下次循环。            klgrpset_add(cur_set, lpl_leaf->lpl_lgrpid);
将当前局域分组加入到当前局域分组系列。            if (hint->cpu_lpl == lpl_leaf)                cp = cpstart = hint;
            else                cp = cpstart = lpl_leaf->lpl_cpus;
如果上次运行的cpu的局域分组等于该片枝叶,从上次运行的cpu开始找。
否则从该片局域分组枝叶的cpu列表开始找。            do {                if (cp == curcpu)                    cpupri = -1;
如果cpu为当前cpu,优先级为负值。
                else if (cp == cpu_inmotion)                    cpupri = SHRT_MAX;
如果cpu下线或者在移动分区申请里,优先级为最大值(32767)。
                else                    cpupri = cp->cpu_dispatch_pri;
否则优先级为cpu的分配器优先级,这个分配器优先级就是cpu运行的线程的优先级,选择创建时的优先级和优先级继承的优先级中优先级高的那个。
                if (cp->cpu_disp->disp_maxrunpri > cpupri)                    cpupri = cp->cpu_disp->disp_maxrunpri;
cpu优先级为该cpu的最大运行优先级
                if (cp->cpu_chosen_level > cpupri)                    cpupri = cp->cpu_chosen_level;
cpu优先级为该cpu在被选择调度时的优先级,内核抢占队列中,cpu_chosen_level为抢占进程的优先级。
                if (cpupri                     if (CPU_IDLING(cpupri)) {                        ASSERT((cp->cpu_flags &                            CPU_QUIESCED) == 0);                        return (cp);
如果cpu优先级为-1,该cpu被选中,直接返回。
                    }                    bestcpu = cp;                    bestpri = cpupri;                }            } while ((cp = cp->cpu_next_lpl) != cpstart);
继续遍历下一个cpu,直到这个局域分组里面所有的cpu都被遍历过。
        }        if (bestcpu && (tpri > bestpri)) {            ASSERT((bestcpu->cpu_flags & CPU_QUIESCED) == 0);            return (bestcpu);
如果找到的最低优先级的cpu比当前进程的优先级低,那么这个cpu就能马上让这个线程运行,这种情况最好,我们直接返回该cpu。        }        if (besthomecpu == NULL)            besthomecpu = bestcpu;
否则我们记录我们找到的最低优先级的cpu。        /*         * Add the lgrps we just considered to the "done" set         */        klgrpset_or(done, cur_set);    } while ((lpl_iter = lpl_iter->lpl_parent) != NULL);   
继续遍历下一个局域分组,直到所有的局域分组都被遍历到。
我们可以看到,disp_lowpri_cpu()的目的就是寻找最低优先级的cpu,一旦找到一个比当前要调度的线程的优先级别低的,立即返回这个cpu。否则就按局域分组的距离顺序来遍历。代码对于局部性的考虑优于对优先级的考虑。注意针对一个cpu是找它最高的优先级,在一个局域分组里面是找这些最高优先级中最低的那个。这个有点搞,呵呵。
    /*     * The specified priority isn't high enough to run immediately     * anywhere, so just return the best CPU from the home lgroup.     */    ASSERT((besthomecpu->cpu_flags & CPU_QUIESCED) == 0);    return (besthomecpu);}
如果没找到可以立即执行的,我们也返回最好的cpu,即,最高优先级最低的。
               
               
               
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/41699/showart_1287655.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP