# 2.6.4.1 带宽控制 - 数据结构

如果需要开启CFS的带宽控制功能，编译内核时需要设置 `CONFIG_CFS_BANDWIDTH=y`, 用于CFS带宽控制的数据结构为:

```
/* file: kernel/sched/sched.h */
struct cfs_bandwidth {
#ifdef CONFIG_CFS_BANDWIDTH
    raw_spinlock_t lock;
    /* 一个周期的时长 */
    ktime_t period;
    /* 一个周期内的时间限额 */
    u64 quota;
    /* 本周期内剩下的可用时间 */
    u64 runtime;
    s64 hierarchical_quota;

    u8 idle;
    u8 period_active;
    u8 slack_started;
    /* 高精度定时器，每个period内定时更新runtime */
    struct hrtimer period_timer;
    /* 回收时间的定时器 */
    struct hrtimer slack_timer;
    /* 所有throttled的cfs_rq挂到该链表上，在定时器的回调函数中遍历该链表执行unthrottle操作
     */
    struct list_head throttled_cfs_rq;

    /* Statistics: */
    int nr_periods;
    int nr_throttled;
    u64 throttled_time;
#endif
};
```

与带宽控制相关的所有信息都封装在该结构中，系统主要通过两个量来对带宽进行控制：

* period: 代表一个周期，带宽控制以周期为单位展开
* quota: 一个周期内的时间限额

带宽控制是以任务组为单位进行的，因此我们可以在任务组的结构体中看到如下字段：

```
/* file: kernel/sched/sched.h */
struct task_group {
    /* 该任务组的带宽控制字段 */
    struct cfs_bandwidth cfs_bandwidth;
};
```

实际的带宽控制将会下沉到任务组的各个cfsrq中去落实，因此cfsrq也包含了与带宽控制相关的字段：

```
/* file: kernel/sched/sched.h */
struct cfs_rq {
#ifdef CONFIG_FAIR_GROUP_SCHED
    struct rq *rq; /* CPU runqueue to which this cfs_rq is attached */

    /* 该 cfs_rq 所属的任务组 */
    struct task_group *tg; /* group that "owns" this runqueue */

    /* 用于带宽控制的字段 */
#ifdef CONFIG_CFS_BANDWIDTH
    /* 是否开启带宽限制 */
    int runtime_enabled;
    /* 当前cfs_rq从task_group中分配到的时间配额的剩余量，如果该时间小于等于0,
     * 则需要重新从task_group中申请时间 */
    s64 runtime_remaining;

    /* 记录cfs_rq被throttle时的时间点，用于统计被throttle的时间 */
    u64 throttled_clock;
    u64 throttled_clock_task;
    u64 throttled_clock_task_time;
    /* 标记当前 cfs_rq 是否被 throttle */
    int throttled;
    /* 记录当前cfs_rq被throttle的次数，如果上层task_group被throttle时，该数字也会增加
     */
    int throttle_count;
    /* 被throttle时挂入cfs_bandwidth->throttled_cfs_rq链表 */
    struct list_head throttled_list;
#endif /* CONFIG_CFS_BANDWIDTH */
#endif /* CONFIG_FAIR_GROUP_SCHED */
};
```

这里主要的字段是 `runtime_enabled` 与 `runtime_remaining`, 调度器主要通过这两个字段来控制cfsrq的带宽，我们在下一节将详细讨论实现细节。


---

# 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/bandwidth-data-structure.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.
