找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

481

积分

1

好友

55

主题
发表于 4 天前 | 查看: 9| 回复: 0

术语说明

  • NUMA(非统一内存访问,Non-Uniform Memory Access):一种计算机内存设计架构,其中处理单元访问不同物理位置的内存时,延迟存在差异。
  • SNC-3(Sub-NUMA Clustering level 3):CPU封装内对多个NUMA子域进行进一步细分的模式,常见于部分Intel多芯片封装。
  • EEVDF(Earliest Eligible Virtual Deadline First):一种旨在替代或增强CFS(完全公平调度器)的调度策略,以实现更精确的公平调度。
  • newidle balance:调度器在某个CPU刚变为空闲(newly idle)状态时,立即尝试从其他繁忙CPU上拉取任务来执行的负载均衡机制,旨在减少CPU的空闲时间。
  • NEXT_BUDDY / LAST_BUDDY:与任务唤醒(wakeup)相关的调度机制,旨在通过让最近被唤醒的任务更快获得CPU,来提升缓存亲和性。

背景:为何在Linux 6.19进行这些调度器改动?

随着处理器核心数量激增、封装拓扑日益复杂(如更多层级的NUMA拆分SNC),系统对低延迟和高吞吐的需求也水涨船高。这迫使Linux调度器(尤其是公平调度CFS/EEVDF系列)必须在“如何对CPU进行分组”、“何时进行跨CPU任务迁移”以及“优先调度哪个被唤醒任务”等问题上做出更精细的权衡。Linux 6.19的这组调度器改动,正是为了在Intel GNR/CWF等现实硬件以及Schbench、CI/虚拟机汇聚等常见负载场景下,提升系统调度的可预测性与整体效率。

核心改动解析

1. NEXT_BUDDY功能回归并与EEVDF目标对齐

核心要点:曾经被禁用的NEXT_BUDDY功能在Linux 6.19中重新被默认启用,但其实现经过了重写,以更好地契合EEVDF调度器的设计目标。新的逻辑在选择“哪个唤醒者(waker)或哪个被唤醒任务(wakee)应作为下一个伙伴(next buddy)”时,会严格考量其虚拟截止时间(deadline)和资格(eligibility),而非盲目应用旧规则。

启用标识的变更如下:

/* kernel/sched/features.h */
- SCHED_FEAT(NEXT_BUDDY, false)
+ SCHED_FEAT(NEXT_BUDDY, true)

设计动机:当唤醒者与被唤醒者共享大量“热”缓存数据时,让被唤醒者尽早运行可以显著提升缓存局部性。然而,这必须与EEVDF调度器基于vruntime和截止时间进行调度的核心原则相兼容。补丁中的preempt_sync()set_preempt_buddy()逻辑正是为了在“优先保证截止时间”和“优先调度与唤醒者相关的任务”之间找到平衡点。

逻辑片段示例:

/* 选择保留或更新 next_buddy 的逻辑(节选) */
if (cfs_rq->next && entity_before(cfs_rq->next, pse))
    return false;
set_next_buddy(pse);
return true;

2. 针对Intel GNR/CWF平台的NUMA距离优化

核心要点:标准的内核函数node_distance()在启用SNC(Sub-NUMA Clustering)模式的平台上,可能会产生过多、过细粒度的“远程距离”等级,导致调度域(sched domains)的层级结构异常复杂。此补丁允许架构或平台通过弱别名(weak alias)机制提供自己的arch_sched_node_distance实现。在x86架构中,特别为Granite Rapids (GNR) 和 Clearwater Forest (CWF) 平台提供了定制处理:在特定条件下(如启用SNC且存在多个CPU封装包时),使用“平均远程距离”来简化不同封装包之间的NUMA距离度量,从而避免生成过多不必要的调度域层级。这对在云与大型NUMA服务器上构建稳定的任务调度环境至关重要。

关键实现(节选):

/* arch/x86/kernel/smpboot.c */
int arch_sched_node_distance(int from, int to)
{
    int d = node_distance(from, to);
    switch (boot_cpu_data.x86_vfm) {
    case INTEL_GRANITERAPIDS_X:
    case INTEL_ATOM_DARKMONT_X:
        if (!x86_has_numa_in_package || topology_max_packages() == 1 || d < REMOTE_DISTANCE)
            return d;
        /* 使用平均远程距离,减少sched domain层次 */
        d = avg_remote_numa_distance();
    }
    return d;
}

优化效果:有效解决了GNR/CWF平台在SNC-3模式下构建调度域时可能出现的错误或不合理层级划分,简化了调度器对“远程”内存节点的分组逻辑,使得跨NUMA节点的负载均衡(load-balancing)在多封装包系统上更加稳健。

3. 比例化newidle平衡:引入随机化策略按价值触发

核心要点newidle平衡机制虽然旨在减少CPU空闲时间,但在某些调度域(sched domain)上尝试拉取任务的失败率很高,且每次尝试本身也有成本。Linux 6.19引入了一种基于历史成功率的随机化(通过NI_RANDOM调度特性控制)策略。该策略为每个调度域维护newidle_call(调用次数)、newidle_success(成功次数)和newidle_ratio(成功率)等统计指标,并根据这些统计数据动态决定是否在当前newidle机会中执行平衡操作。这样可以将尝试频率与历史成功率相匹配,避免在成功率低的域上做无谓的尝试,这对于优化高并发短任务(如CI构建流水线)和容器宿主机的场景性能尤其有益。

统计与控制逻辑片段示例:

/* sd 新增统计与随机化控制(节选) */
sd->newidle_call++;
sd->newidle_success += success;
if (sd->newidle_call >= 1024) {
    sd->newidle_ratio = sd->newidle_success;
    sd->newidle_call /= 2;
    sd->newidle_success /= 2;
}

/* 调度尝试处(节选) */
if (sched_feat(NI_RANDOM)) {
    u32 d1k = sched_rng() % 1024;
    weight = 1 + sd->newidle_ratio;
    if (d1k > weight) {
        update_newidle_stats(sd, 0);
        continue;
    }
}

直观理解:将newidle平衡看作一次“有回报的尝试”,系统只在“历史赔率好(成功率高)”时才更频繁地进行尝试,从长期看有效减少了低效平衡操作带来的开销。

4. 调度器基础设施改进:引入scoped_guard与统一状态管理

核心要点:内核调度器代码中大量函数从手动管理锁(lock/unlock)、任务出列入列(dequeue/enqueue)的方式,迁移到使用scoped_guard(sched_change, p, flags)的模式。这种RAII(资源获取即初始化)风格的用法统一了“修改任务调度状态”的进入和退出语义,使代码更易于推理,减少了重复代码,并降低了潜在的锁管理错误风险。想要深入了解Linux系统底层开发中这类代码重构的最佳实践,可以参考社区的相关讨论。

示例(节选):

/* 使用 scoped_guard 的模式示例(节选) */
scoped_guard (sched_change, tsk, queue_flags) {
    sched_change_group(tsk);
    if (!for_autogroup)
        scx_cgroup_move_task(tsk);
    if (scope->running)
        resched = true;
}
if (resched)
    resched_curr(rq);

其他辅助改进:引入了set_need_resched_current()函数,用于替代此前分散在各处的set_tsk_need_resched()set_preempt_need_resched()组合调用,清理了冗余代码。

实际应用价值与潜在考量

应用价值

  • 大型NUMA服务器/云主机:针对GNR/CWF的NUMA距离优化,使得具备SNC拆分的多封装包系统能够构建更合理的调度域,减少了负载均衡器构建的复杂度与错误触发概率,提升了在虚拟机密集场景下的任务分配稳定性。
  • 高并发短任务负载:比例化newidle平衡机制能有效避免在多调度域上频繁进行低收益的任务迁移与抢占,从而降低整体调度开销,提升系统吞吐量,非常适用于持续集成(CI)、软件构建及云原生环境。
  • 延迟敏感型应用:改进后的NEXT_BUDDY机制在任务唤醒时更倾向于保持缓存亲和性,同时努力与EEVDF的延迟目标相协调,适用于存在热点数据共享的“生产者-消费者”或链式唤醒模式。

潜在风险与考量

  • 复杂度与行为波动:重新启用NEXT_BUDDY增加了调度决策的复杂性。尽管实现已向EEVDF对齐,但在极端负载条件下,其行为仍可能出现波动。补丁作者也指出早期测试结果“往往表现出更高的可变性”。
  • 平台特定代码的维护arch_sched_node_distance()中的特殊处理分支是为GNR/CWF定制的,并且对封装包数量做出了假设(代码中包含WARN_ONCE(topology_max_packages() > 2))。未来若平台拓扑更加复杂,可能需要重新审视这部分逻辑。
  • 可观测性适配:广泛采用scoped_guard等新模式进行代码重构后,虽然提升了代码结构清晰度,但也可能改变传统的函数调用栈和跟踪(trace)行为。这意味着依赖于ftrace、kprobe等工具的调试流程和性能分析脚本可能需要相应更新以适应新的代码布局。

总结与展望

  1. 组合优化效应:单个改动(如重新启用NEXT_BUDDY)可能带来的收益有限或不稳定,但当其与NUMA拓扑简化、newidle平衡概率化以及底层代码结构重构等一系列改动协同作用时,整体上体现了调度器从“对每次调度机会一视同仁”向“依据拓扑价值和历史成功率智能调配资源”的策略转变。
  2. 平台感知调度成为趋势:通过架构层提供arch_sched_node_distance()钩子并对特定平台(x86 GNR/CWF)进行定制化处理,表明现代调度器已无法仅凭一套通用假设应对所有硬件。未来我们可能会看到更多针对特定架构或平台拓扑的调度器微调。
  3. 随机化作为工程优化手段:比例化newidle平衡采用统计学与随机化来关联“尝试频率”与“成功概率”,这体现了一种经典的工程折衷:通过引入可控的随机性,来避免在复杂系统拓扑下确定性策略可能带来的长期低效。这类思路在运维/DevOps领域的大规模系统优化中日益常见。
  4. 可维护性与可观测性需同步演进:引入scoped_guard等现代编程模式显著提升了内核调度代码的一致性与可维护性,但同时也对依赖旧有代码模式进行跟踪和调试的工具链提出了适配要求。更新相应的tracepoints、调试文档及性能分析指南是必要且长期有益的后续工作。

Linux 6.19调度器优化概览

参考链接:相关补丁提交详情可查阅 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6d2c10e889db596938bb7b4d3cdd42d67208439a




上一篇:DeepSeek-V3.2-Speciale与Gemini 3 Pro对比测试:基于提示词生成HTML5肉鸽游戏实战
下一篇:移动基站核心概念解析:入门必读,详解小区、扇区与载波的关键差异
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-7 02:51 , Processed in 0.138279 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表