- 论坛徽章:
- 0
|
要将一个线程调度到一个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 |
|