2.7.4 负载追踪 - 更新负载
知道了负载及其计算原理之后,更新负载的逻辑就比较好理解了。系统通过函数 update_load_avg 来完成对调度实体与其cfsrq的负载更新,该函数的实现如下:
/* file: kernel/sched/fair.c */
static inline void update_load_avg(struct cfs_rq *cfs_rq,
struct sched_entity *se, int flags) {
/* 当前时间,精度为ns */
u64 now = cfs_rq_clock_pelt(cfs_rq);
int decayed;
if (se->avg.last_update_time && !(flags & SKIP_AGE_LOAD))
__update_load_avg_se(now, cfs_rq, se); /* 更新se的负载信息 */
/* 其余代码删除 */
}这里我们只关注更新 se 负载的逻辑,该部分逻辑通过 __update_load_avg_se 完成:
/* file: kernel/sched/pelt.c */
int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq,
struct sched_entity *se) {
/* 先更新se 的负载总和 */
if (___update_load_sum(now, &se->avg, !!se->on_rq, se_runnable(se),
cfs_rq->curr == se)) {
/* 更新 se 的平均负载,平均负载的计算逻辑与负载总和与权重有关 */
___update_load_avg(&se->avg, se_weight(se));
cfs_se_util_change(&se->avg);
trace_pelt_se_tp(se);
return 1;
}
return 0;
}其中函数 ___update_load_sum 用来更新负载的累计总和,而 ___update_load_avg 会根据se的负载总和算出其平均负载,计算时会考虑se的负载总和与权重。前者的实现如下:
该函数主要就是调用前面已经讨论过的 accumulate_sum 更新负载总和,并且记录一下更新的时间点。我们再看一下系统如何计算平均负载:
平均负载的计算公式为: load_avg = weight * decay(runnable time) / decay(total time), 其中 decay(runnable time) 就是负载总和,而 decay(total time) 是按照计算负载总和的相同算法计算出来的所有时间的总和,其结果就是函数 get_pelt_divider 的返回值,上一节我们已经详细讨论过了如何求级数之和,这里不再详述。
通过该算法我们知道,平均负载是任务的权重与运行时间的综合考量,如果一个任务一直运行,那么其平均负载就会越来越趋近于它的权重。
Last updated
Was this helpful?