news 2026/6/13 7:25:55

Linux ioc_timer_fn iocost定时器与hweight更新

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux ioc_timer_fn iocost定时器与hweight更新

Linux ioc_timer_fn iocost定时器与hweight更新

ioc_timer_fn是iocost控制器的周期性定时器处理函数,它以固定间隔(默认为64ms)执行,负责iocost的多个核心维护任务:更新iocg的hweight(层级权重)、调整I/O带宽配额、处理过期的等待队列以及触发成本模型的重新校准。该定时器是iocost状态机运转的节拍器。

定时器初始化与调度

iocost定时器在ioc结构体初始化时通过timer_setup注册,每次到期后根据系统负载情况自适应调整下次触发时间。

```c
static void ioc_timer_fn(struct timer_list *timer)
{
struct ioc *ioc = from_timer(ioc, timer, timer);
struct ioc_gq *iocg;
unsigned long expires;
u64 now, next, vtime;
int nr_shortages = 0, nr_lagging = 0;
LIST_HEAD(hlist);

now = ktime_get();
vtime = now - ioc->period;

/*
* 检查当前周期是否结束,若结束则重置周期计数器
* 并刷新全局vtime基准
*/
if (vtime > ioc->period_us * NSEC_PER_USEC) {
ioc->period += ioc->period_us;
vtime = now - ioc->period;
ioc->vtime_base += ioc->period_us * ioc->vtime_rate / 100;
}

/*
* 遍历所有iocg,更新其hweight、检查是否缺乏
* quota或处于滞后状态
*/
list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
u64 hweight, usage;
bool shortage = false;

/*
* hweight的层级更新:根据iocg在cgroup树中的
* 位置和其子节点权重重新分配当前层的权重
*/
hweight = iocg->weight;
if (iocg->level > 0) {
struct ioc_gq *parent = iocg->parent;
if (parent && parent->child_weights)
hweight = parent->hweight * iocg->weight
/ parent->child_weights;
}

iocg->hweight = hweight;

/*
* 计算该iocg的实际使用率(usage),
* 用于后续quota调整决策
*/
usage = iocg->usage_delta * USEC_PER_SEC
/ (now - iocg->usage_timestamp);
iocg->usage_timestamp = now;
iocg->usage_delta = 0;

/*
* 如果usage超过配置的限额,标记为短缺
*/
if (usage > iocg->max_usage) {
shortage = true;
nr_shortages++;
}
}
```

hweight层级权重计算

hweight(hierarchical weight)是iocost实现层级I/O带宽分配的核心概念。每个iocg的hweight由其父节点的hweight和自身在兄弟节点中的权重占比共同决定,确保cgroup树中每一层的带宽分配符合预期比例。

```c
static void ioc_refresh_hweights(struct ioc *ioc)
{
struct ioc_gq *iocg;
u64 total_child_weight = 0;

/*
* 第一遍扫描:统计每个iocg的子节点总权重,
* 如果子节点没有设置权重,则继承父节点权重
*/
list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
struct ioc_gq *child;
u64 child_weight = 0;

list_for_each_entry(child, &iocg->children, sibling_list) {
child_weight += child->weight;
}

iocg->child_weights = child_weight ?: iocg->weight;
}

/*
* 第二遍扫描:自顶向下计算hweight。
* 根iocg的hweight为1.0(用固定点表示法)
*/
list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
if (iocg->parent) {
u64 sibling_total = iocg->parent->child_weights;
if (sibling_total)
iocg->hweight = iocg->parent->hweight * iocg->weight
/ sibling_total;
else
iocg->hweight = iocg->parent->hweight;
} else {
iocg->hweight = HWEIGHT_ONE; /* 根节点 */
}
}
}
```

quota分配与vtime预算

定时器处理函数还负责基于hweight为每个iocg分配I/O时间预算(vtime)。vtime是iocost中衡量I/O资源消耗的虚拟时间单位。

```c
static void ioc_distribute_vtime(struct ioc *ioc, struct list_head *hlist)
{
struct ioc_gq *iocg, *tiocg;
u64 vtime, total_hweight = 0;
u64 vtime_per_cycle;

vtime_per_cycle = ioc->period_us * ioc->vtime_rate / 100;

/*
* 统计所有活跃iocg的hweight总和
*/
list_for_each_entry(iocg, hlist, hweight_list) {
total_hweight += iocg->hweight;
}

if (!total_hweight)
return;

/*
* 根据每个iocg的hweight占比分配vtime预算:
* vtime_budget = vtime_per_cycle * iocg->hweight / total_hweight
*/
list_for_each_entry(iocg, hlist, hweight_list) {
u64 budget = vtime_per_cycle * iocg->hweight / total_hweight;

iocg->vtime_budget += budget;

/*
* 如果iocg的vtime消耗已经超过预算,
* 将其加入延迟队列以限制I/O
*/
if (iocg->vtime_used > iocg->vtime_budget) {
iocg->debt = iocg->vtime_used - iocg->vtime_budget;
iocg->vtime_budget = 0;
}
}
}
```

定时器重调度

在所有维护工作完成后,ioc_timer_fn根据当前系统负载和iocg的短缺情况调整下次定时器触发的间隔。

```c
/*
* 根据短缺和滞后情况决定下次调度间隔
*/
if (nr_shortages) {
/*
* 如果存在短缺,缩短间隔以更快响应
*/
expires = msecs_to_jiffies(IOC_TIMER_INTERVAL_MS / 2);
} else if (nr_lagging) {
expires = msecs_to_jiffies(IOC_TIMER_INTERVAL_MS * 3 / 4);
} else {
expires = msecs_to_jiffies(IOC_TIMER_INTERVAL_MS);
}

mod_timer(&ioc->timer, jiffies + expires);

out_unlock:
spin_unlock_irq(&ioc->lock);
}
```

通过ioc_timer_fn的定期执行,iocost实现了对块I/O资源的动态调度——hweight机制保证了cgroup间按比例分配带宽,vtime预算控制防止了单个cgroup过度使用I/O资源,自适应定时器间隔则在高负载时提供更快的响应。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 7:24:48

大模型相对位置编码层归零技术解析与工程实践

1. 项目概述:这不是一次普通更新,而是一次架构级“蒸发”“Anthropic Just Shipped the Layer That’s Already Going to Zero”——这个标题乍看像科技媒体的夸张头条,但作为连续跟踪Claude模型演进三年、亲手部署过从Sonnet 3.5到Opus全系列…

作者头像 李华
网站建设 2026/6/13 7:05:57

C盘快满了该怎么一步步清理?6个操作步骤从根源腾空间

C盘快满了该怎么一步步清理?6个操作步骤从根源腾空间 C盘越用越满,根本原因往往是系统更新留下的残档、临时目录长期堆积、休眠文件常驻,再加上用户文件默认落在系统盘——几类占用叠在一起,空间就悄悄耗光了。下面按"操作风…

作者头像 李华
网站建设 2026/6/13 7:02:47

用两个NE555搭建可调长延时控制器:从电路原理到继电器驱动实战(调试RP是关键)

双NE555长延时控制器实战:从振荡电路设计到继电器精准驱动项目背景与应用场景在智能家居改造和工业设备控制中,经常需要实现分钟级甚至小时级的延时控制功能。比如自动浇花系统的定时启动、实验室设备的延时关机、展览灯光的分时段控制等场景。虽然市面上…

作者头像 李华