# 2.6.2.3 调度逻辑 - 调度周期

从CFS的调度原理来考虑的话，CFS似乎不需要调度周期的概念，因为CFS并不是预先给任务分配时间片，而是根据大家当前的运行时间来判断谁应该是下一个该执行的任务，这样所有任务都随着时间的推进齐头并进。但为了用来调度延迟，CFS也需要引入调度周期。

什么是调度延迟呢？CFS不仅需要保证时间分配的公平，还要保证各个任务每隔一段时间就能够执行一次，一个任务在两次被调度到的时间间隔就是调度延迟。相反，调度器还需要保证任务在每次得到机会执行时，除了任务主动放弃CPU, 尽量不要太快地被踢出来，因为太频繁的上下文切换会导致系统的总体性能降低。所以 CFS 没有使用固定的时间长度作为调度周期，而是根据当前队列中的任务数量动态计算出调度周期的长度，该逻辑由函数 `__sched_period` 实现：

```
/* file: kernel/sched/fair.c */
/* 参数 nr_running 表示当前 cfs_rq 中的任务总数 */
static u64 __sched_period(unsigned long nr_running) {
/* sched_nr_latency: 8 */
if (unlikely(nr_running > sched_nr_latency))
/* sysctl_sched_min_granularity: 0.75ms */
return nr_running * sysctl_sched_min_granularity;
else
/* sysctl_sched_latency: 6ms*/
return sysctl_sched_latency;
}
```

当队列中所有的任务超过8个时，CFS的调度周期为任务总数乘以0.75ms，否则调度周期为固定的6ms, 这样可以保证任务的切换频率比较合理。

算出调度周期之后，系统还需要为任务计算其在一个调度周期内的时间配额，函数 `sched_slice` 用来实现该逻辑：

```
/* file: kernel/sched/fair.c */
static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se) {
unsigned int nr_running = cfs_rq->nr_running;
u64 slice;

/* 调度周期 */
slice = __sched_period(nr_running + !se->on_rq);

/* 暂时不考虑组调度，此处的循环只会执行一次 */
for_each_sched_entity(se) {
struct load_weight *load;
struct load_weight lw;

cfs_rq = cfs_rq_of(se);
/* 整个运行队列 cfs_rq 的总权重 */
load = &cfs_rq->load;

/* se->load.weight为se的权重，调用函数__calc_delta得到slice*se->load.weight/load.weight,
    * 即根据 se 在整个队列中的权重比例分配时间 */
slice = __calc_delta(slice, se->load.weight, load);
}

if (sched_feat(BASE_SLICE))
slice = max(slice, (u64)sysctl_sched_min_granularity);

return slice;
}
```

当任务在当前调度周期内的耗时超过自己的配额时，调度器就会将其踢出去，换其他任务来执行，下一节将会详细讨论该逻辑。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://s3.shizhz.me/linux-sched/cfs-sched/logic-period.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
