2.6.4.2 带宽控制 - 带宽时间
前文提到实际的带宽控制是在任务组下属的cfs_rq队列中进行的,而cfs_rq 对带宽时间的操作归总起来就两点:更新与申请。
cfsrq申请到的时间保存在字段 runtime_remaining 中,每当更新任务的时间时,系统也会更新该字段。前面讨论vruntime时我们提到系统通过函数 update_curr 来更新与任务相关的时间信息,实际上该函数也会更新与带宽控制相关的时间:
/* file: kernel/sched/fair.c */
static void update_curr(struct cfs_rq *cfs_rq) {
struct sched_entity *curr = cfs_rq->curr;
u64 now = rq_clock_task(rq_of(cfs_rq));
u64 delta_exec;
/* 本次更新 vruntime 与上次更新 vruntime 之间的差值 */
delta_exec = now - curr->exec_start;
/* 省略其他更新时间的代码,这部分在讨论vruntime时已经讨论过 */
/* 更新与带宽控制相关的字段 */
account_cfs_rq_runtime(cfs_rq, delta_exec);
}
/* 判断是否启用了带宽控制,如果是的话调用函数__account_cfs_rq_runtime更新对应字段
*/
static __always_inline void account_cfs_rq_runtime(struct cfs_rq *cfs_rq,
u64 delta_exec) {
if (!cfs_bandwidth_used() || !cfs_rq->runtime_enabled)
return;
__account_cfs_rq_runtime(cfs_rq, delta_exec);
}
static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {
/* 从剩余时间中减去这次消耗掉的部分,注意这里可能导致cfs_rq->runtime_remaining为负数
*/
cfs_rq->runtime_remaining -= delta_exec;
/* 如果还有剩余时间,则函数返回 */
if (likely(cfs_rq->runtime_remaining > 0))
return;
/* 接下来要向所在的任务组申请时间,但如果当前cfs_rq已经被挂起了的话,就不用麻烦了
*/
if (cfs_rq->throttled)
return;
/*
* 此时我们调用函数assign_cfs_rq_runtime向任务组申请时间。如果申请时间失败,则cfs_rq应该被挂起。
* 这里调用resched_curr标记cfs_rq->curr的TIF_NEED_RESCHED位,以便随后将其调度出去
*/
if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr))
resched_curr(rq_of(cfs_rq));
}更新带宽时间的逻辑其实很简单,就是从 cfs->runtime_remaining 减去本次执行的物理时间。如果此时调度器发现时间余额已经耗尽,则会立即尝试从任务组中申请,如果申请失败,说明在本周期内整个任务组的时间都已经耗尽了,而如果当前正在执行的任务在本cfsrq中的话,则需要将其调度出去。从任务组中申请时间的函数是 assign_cfs_rq_runtime:
Last updated
Was this helpful?