Linux内核- task_h_load

17

我正在试图理解 load_balance 函数的执行过程。
我查看了版本3.14,但也看了一下版本4.3,因为有人告诉我这个机制在这个版本中被改变并且更加清晰。

v3.14 中,该调用是从 move_tasks 中进行的。

v4.3 中,该调用是从 detach_tasks 中进行的。

从我所看到的,它是相同的函数,只不过名称不同而已。

这个函数根据 env->balance 参数将任务从一个队列移动到另一个队列。但我不明白在 task_h_load 中如何计算负载。

有人知道 task_h_load 函数中负载成员代表什么以及如何计算吗?

2个回答

15

如果配置了SMP,则会调用负载均衡。Linux使用完全公平调度器(CFS)对每个任务进行调度,以便每个任务都能获得“公平”的处理器时间份额。CFS使用红黑树的概念。

enter image description here

调度程序在任务进入运行队列时记录当前时间。当进程等待处理器时间时,其“wait”值会增加一个由当前运行队列中的任务总数和进程优先级导出的数量。当处理器运行此任务时,此“wait”值会减少。如果此值降至某个值以下,则调度程序将抢占该任务,并使其他任务更接近处理器以执行。CFS始终尝试通过保持“wait”值为零来保持理想状态。
Linux中有两个函数load_balanceselect_task_rq_fair()用于执行负载平衡任务。
简单来说,CFS负载平衡机制将繁忙的CPU转移到不那么繁忙或理想的CPU上。 task_h_load用于计算任务的权重。
引用:

我不明白的是,在task_h_load函数中如何计算负载,以及如何计算负载?

此权重因子取决于进程的nice值。
weighting factor = weight of process with nice value 0 / weight of current task;

其中 'weight' 大致等于 1024 * (1.25)^(-nice)

例如: 当 nice 值为 1 时,weight 为 820 当 nice 值为 -1 时,weight 为 1277

task_h_load
有关更多负载均衡方法和基础知识,请参阅 kernel comment task_h_load 使用 update_cfs_rq_h_load 计算公平时间调度的运行队列的分层负载,并使用 cfs_rq_load_avg 返回运行队列的平均负载 load_avg

虚拟运行时间是任务在CPU上运行的加权时间。CFS始终尝试保持this红黑树平衡。

enter image description here

<--较小的值 ----------- vruntime 值--------较大的值-->

每个可运行任务都根据 vruntime 放置在自平衡红黑树中。如果任务准备好运行(表示任务没有等待任何资源),则将其放置到树中。如果任务正在等待某些资源(即等待 I/O ),则将其移除。处理时间较短的任务(即较小的 vruntime)位于树的左侧,处理时间更长的任务位于树的右侧。

左节点具有最小的键值(对于 CFS 来说,它是优先级较高的任务)。自平衡红黑树需要 O(lgN) 操作才能导航到左节点。调度程序将此值缓存到 rb_leftmost 中。通过仅检索此值,调度程序确定下一个要运行的任务

这种负载平衡仅用于非实时任务 对于实时任务,使用了由 Steven Rostedt 和 Gregory Haskins 开发的推拉操作。

关于CFS还有一点在公平组调度中也非常有帮助。请参考下图

enter image description here

move_task的作用是尝试将不平衡的加权负载(即在上述计算负载因子后)从繁忙的队列移动到this_rq中。它试图平衡两个运行队列的负载,以便两者都可以获得“公平”的处理器时间。

detach_task将任务从Linux内核的env指针指定的迁移中分离出来。

detach_one_task尝试从env->src_rq中精确地出队一个任务。

detach_tasks()尝试从busiest_rq中分离多达不平衡加权负载的任务。如果无法分离,则返回已分离任务的数量,否则返回零。

要将此已分离任务附加到新的rq(运行队列),根据情况使用attach_task、attach_one_task、attach_tasks

New warning check lockdep_assert_held() is introduced in detach_tasks which was not present in move_tasks

在多处理器上移动任务并不容易,因此cfs会针对特定域进行负载平衡,如下所示: enter image description here

为了理解所有这些内容,我希望您可以查阅以下参考资料。

  1. Per-Entity-Load-Tracking指标用于负载均衡

  2. 权重因子

  3. OpenSUSE

  4. Robert Love第三章

  5. CPU调度

我特别阅读了所有这些文档,以回答您的问题。如果有遗漏之处,请不吝赐教。


_task_h_load 用于计算任务的权重。从这个语句中可以得出答案。如果您仍然希望我指出一些内容,我很乐意改进答案 :-) - Punit Vara
嗨,我同意他的观点...答案并没有回答我的真正问题,但提供了很多周围信息... - boaz
感谢@boaz的评论。那么您想了解纯代码吗?如果我描述一下h_load的作用,这样可以吗? - Punit Vara
我实际上展示了task_h_load的功能以及cfs如何计算它,这也是我展示过的。如果你仔细查看每个链接,你就能理解你的问题。但是,如果你指出具体的问题,我很乐意改进答案。 - Punit Vara

8

CFS 持有一个“调度实体”的树。每个调度实体都可以有自己的树,以此类推,形成递归方式...(例如,将特定用户的所有进程分组到一个调度实体中非常有用;从而防止拥有许多任务的用户比具有较少进程的用户消耗更多的CPU时间)

task_h_load - 代表“任务层次负载”

由于任务可以嵌套在多个树中,因此计算其负载并不简单...

static unsigned long task_h_load(struct task_struct *p){
    struct cfs_rq *cfs_rq = task_cfbs_rq(p);
    update_cfs_rq_h_load(cfs_rq);
    return div64_ul(p->se.avg.load_avg * cfs_rq->h_load,
                           cfs_rq_load_avg(cfs_rq) + 1);
}

在开始时,cfs_rq指向p所在的立即树。如果只有两个嵌套的树,那么计算p的负载就很简单:

task_h_load = task_load_in_its_tree * (load_of_immediate_tree / load_of_containing_tree);

(其中immediate_tree是包含任务的树,containing_tree是包含immediate_tree的树。)

但实际情况并非如此。我们的树可能是另一个树中的嵌套树,而后者本身只是另一棵树中的叶子。

因此,我们首先调用update_cfs_rq_h_load(cfs_rq)来计算cfs_rq及其所有祖先的分层负载系数:该函数沿着树层次结构向上到达根节点,然后从根节点向下到我们的cfs_rq,同时计算每个树的分层负载系数。

计算方式类似:

cfs_rq_h_load = cfs_rq_load_in_its_tree * (load_of_immediate_tree / load_of_containing_tree)

所以,最后我们得到了cfs_rq的分数负载,我们只需要使用相同的公式计算.

task_h_load = task_load_in_its_tree *(immediate_tree的负载 / 包含树的负载)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接