不同进程(task_struct)中的的cfs_rq 是相同的吗
时间: 2024-03-19 10:40:12 浏览: 13
不同进程(task_struct)中的 cfs_rq 并不相同。每个进程都有自己的 cfs_rq,用于记录该进程在调度器中的调度状态。在 CFS 调度器中,每个进程都被看作是一个在红黑树中的节点,而 cfs_rq 则是红黑树的节点。每个进程的 cfs_rq 包含了进程的运行状态、虚拟运行时间和优先级等信息。
当一个进程被调度器选中时,它的 cfs_rq 会被加入到调度器的运行队列中,然后根据进程的优先级和虚拟运行时间来计算下一个时间片结束时的时间点。当进程的时间片用完时,它的 cfs_rq 会从运行队列中移除,然后根据进程的虚拟运行时间重新计算优先级,并将其加入到合适的位置,等待下次调度。
因此,每个进程都有自己的 cfs_rq,它们是相互独立的,用于记录该进程的调度状态。
相关问题
cfs_rq 创建的源码
CFS 运行队列的创建主要是在 Linux 内核的调度器代码中实现的。下面是 CFS 运行队列的创建源码示例:
```c
static inline void
enqueue_task_cfs_rq(struct sched_entity *se, bool head)
{
struct cfs_rq *cfs_rq;
cfs_rq = task_cfs_rq(se->task);
update_curr(cfs_rq);
__enqueue_entity(cfs_rq, se, head);
}
```
上述代码实现了将一个调度实体(sched_entity)插入到相应 CFS 运行队列(cfs_rq)的操作,其中 `task_cfs_rq` 函数用于获取该调度实体所在的 CFS 运行队列。在将调度实体插入到队列时,会调用 `__enqueue_entity` 函数进行实际的操作。同时,还会调用 `update_curr` 函数更新队列中每个调度实体的当前 CPU 时间片(vruntime)和动态权重(load.weight),以便后续的调度决策。
调度器初始化cfs_rq 的源码
调度器初始化 cfs_rq 的源码位于 Linux 内核的 sched_init() 函数中。sched_init() 函数是在内核启动时被调用,用于初始化调度器和调度器相关的数据结构。该函数的定义在文件 kernel/sched/core.c 中。
以下是 sched_init() 函数中初始化 cfs_rq 的代码片段:
```
void __init sched_init(void)
{
...
for_each_possible_cpu(i) {
struct rq *rq = cpu_rq(i);
struct cfs_rq *cfs_rq = &rq->cfs;
/* Initialize cfs_rq */
rq->nr_running = 0;
rq->nr_uninterruptible = 0;
cfs_rq->min_vruntime = (u64)(-(1LL << 20));
cfs_rq->tasks_timeline = RB_ROOT_CACHED;
cfs_rq->load.weight = SCHED_LOAD_SCALE;
cfs_rq->nr_running = 0;
cfs_rq->nr_spread_over = 0;
cfs_rq->last_weight = 0;
cfs_rq->avg.load_sum = 0;
cfs_rq->avg.util_sum = 0;
cfs_rq->avg.runnable_sum = 0;
cfs_rq->avg.load_avg = 0;
cfs_rq->avg.util_avg = 0;
cfs_rq->avg.runnable_avg = 0;
cfs_rq->avg.last_update_time = sched_clock();
cfs_rq->next = cfs_rq->prev = cfs_rq;
cfs_rq->h_load.next = cfs_rq->h_load.prev = NULL;
cfs_rq->leaf_cfs_rq_list.next = cfs_rq->leaf_cfs_rq_list.prev = cfs_rq;
init_rq_bintree(rq);
atomic_set(&rq->nr_iowait, 0);
rq->online = 1;
rq->cpu_capacity_orig = capacity_orig_of(i);
rq->cpu_capacity = rq->cpu_capacity_orig;
rq->cpu_capacity_boosted = 0;
rq->cpu_capacity_orig_boosted = 0;
rq->idle_at_tick = 0;
rq->last_schedule_tick = 0;
rq->skip_clock_update = 0;
rq->avg_idle = 0;
rq->avg_idle_sum = 0;
rq->avg_idle_mis = 0;
rq->avg_idle_mis_sum = 0;
rq->clock_update_flags = 0;
rq->next_balance = jiffies + HZ;
rq->next_task_fair = jiffies;
rq->clock = 0;
rq->clock_task = NULL;
rq->idle_stamp = jiffies;
rq->last_load_update_tick = jiffies;
rq->nr_iowait = 0;
rq->iowait_contrib = 0;
rq->nr_iowait_last = 0;
init_cfs_bandwidth(&cfs_rq->bandwidth);
}
...
}
```
在上述代码中,通过 for_each_possible_cpu(i) 遍历每个 CPU,并分别初始化它们的 cfs_rq 数据结构。具体来说,调用 cpu_rq(i) 函数得到第 i 个 CPU 的 rq 对象,然后将 rq->cfs 指向的 cfs_rq 对象的各个成员初始化为默认值。其中包括 min_vruntime、tasks_timeline、load 等字段。这样,所有 CPU 的 cfs_rq 对象都被初始化完成,调度器初始化工作也就完成了。