以下摘要大部分由chatgpt生成,然后人工补充了一些遗漏的关键部分

part1:问题背景

  • 本博客是SUSE实验室团队探索内核CPU隔离和其中的核心组件Full Dynticks(或Nohz Full)的技术系列的第一篇。

  • 该系列的文章包括:CPU隔离介绍、Full dynticks内部机制、Nohz_full、清理和权衡、实际示例、Nohz_full故障排查:破损的TSC/时钟源等。

  • CPU隔离是一种强大的功能,可以在为依赖特定且常常极端的延迟或性能要求的工作负载设置背后找到。

  • DPDK(数据平面开发套件)的一些用例可以覆盖这样的例子。

  • 但是,CPU隔离的文档和许多微妙之处的脚注最多是零散的,如果不是落后于最近的发展。

  • 我们的一系列文章旨在为用户提供指导,深入了解我们在上游和SLE15产品中维护的这个不为人知的Linux内核子系统。

  • 内核的角色是通过统一的接口利用硬件资源提供基础服务。

  • 内核通过同步请求提供服务,使用系统调用,并使用如中断、计时器和内核线程等异步处理来维护其职责和内部状态。

  • 这些内核异步片段通常被称为“清理”工作。其中一些可以绑定到特定的CPU,其他则可以解绑,因此可以在任何CPU上执行。

  • 对于需要整个CPU时间且不能承受任何周期盗窃的处理来说,这是个问题。DPDK就是一个这样的例子,其中高带宽网络数据包直接从用户空间轮询,内核的任何微小干扰都可能导致数据包丢失。

  • 让我们从定时器开始更详细地探索内核清理的世界。这个非常有用的内核中心组件历来都是一个不容易消除的干扰源。

  • 不加任何限制时定时器对时间片的占用情况:

    img

  • 启用了CONFIG_NO_HZ_IDLE后的时间片示意图:

    img

part2:解决方案(理论)

  • 这是SUSE实验室团队关于内核CPU隔离技术系列的第二篇博文,主要探讨了全动态时钟中断(Full Dynticks或Nohz Full)这一核心组件。
  • 该系列的文章包括:CPU隔离简介、全动态时钟中断内部机制、无时钟中断模式、内务处理与权衡、实践案例、无时钟中断模式故障排查:时钟源/TSC故障等。
  • 文章介绍了Linux内核定时器时钟中断的作用,以及它在内核内部状态和服务维护中的重要性。
  • 对于需要消除由高频事件引起的CPU周期和CPU缓存污染的敏感工作负载的用户,停止定时器时钟中断并不容易,因为许多内核组件依赖于周期性事件,如定时器、时间管理和调度器等。
  • 当CPU处于空闲状态时,不需要100~1000Hz的心跳,因此,节省电力成为第一个成功的激励条件,用于有条件地打破周期性时钟中断,因为其目标专门应用于空闲优化。
  • CONFIG_NO_HZ_IDLE提供了停止周期性时钟中断的基本机制,并为空闲情况实现了它。这一重大步骤为满足敏感工作负载的需求铺平了道路,提供了一个动态时钟中断的基础设施。
  • 然而,要扩展这个特性,使得在CPU忙碌时也能停止时钟中断,这个目标并没有像人们期望的那样接近。
  • 如果我们想在CPU运行实际任务时停止时钟中断,我们不能忽视这些请求的事件。我们必须使用替代方案来处理它们,或者在最坏的情况下限制我们的服务。有以下几种替代方案可以避免CPU被中断抢占
    • 对于CPU核心无差别对待的任务,可以迁移到其他核心上
    • 对于CPU核心敏感的任务,可以用一些手段花费一些代价转移到其他核心上:RCU Callback/调度器任务迁移等
    • 将一些实现由基于轮询的方式改为基于上下文切换的方式:比如CPU时间统计/RCU空闲统计
  • 在某些情况下,简单地无法在没有周期性事件的情况下解决问题,或者至少需要一个频繁的事件。这就是为什么调度器任务抢占就是这样的例子。为了维护本地公平性,调度器必须能够在多个任务之间分享CPU,并周期性地检查是否需要抢占。因此,在一个CPU上运行一个任务是停止时钟中断进一步进入空闲上下文的要求。
  • 完全停止实际任务的时钟中断是可能的,但用户必须准备好一些权衡。许多陷阱在角落里等待,我们将在接下来的文章中更详细地解释它们。

part3:解决方案(实践)

从实践角度介绍上篇的优化方案如何配置和使用:引入nohz_full参数

  • 这篇博客是SUSE实验室团队技术系列的第三篇,探讨内核CPU隔离以及其核心组件之一:完全动态刻度(或Nohz Full)。
  • 这个系列的文章目前包括:CPU隔离-介绍、CPU隔离-完全动态刻度内部结构、CPU隔离-Nohz_full、CPU隔离-家务和权衡、CPU隔离-一个实际例子、CPU隔离-Nohz_full故障排除:破碎的TSC/时钟源。
  • “nohz_full=”内核启动参数是配置完全动态刻度和CPU隔离的主要界面。一个cpu-list参数被传递来定义要隔离的CPU集。
  • 当CPU被包含在nohz_full启动参数的cpu-list中时,内核尝试尽可能多地将内核噪音从该CPU移开。
  • 计时器刻度在可能的情况下被停止,假设满足一些条件:运行在CPU上的任务不能被另一个任务抢占,任务不使用posix-cpu-timers,任务不使用perf事件,如果你在x86上运行,你的机器必须有一个可靠的时间戳计数器(TSC)等。
  • 无绑定的计时器回调执行被移动到nohz_full范围外的任何CPU,所以它们不会在错误的地方触发计时器刻度来服务它们。
  • 大部分的RCU处理被卸载到隔离范围外的CPU。设置为nohz_full的CPU以NOCB模式运行。
  • 即使nohz_full是整个隔离设置的重要部分,你还需要单独关心其他细节,其中包括两个重要项目:用户任务亲和性和IRQs亲和性。
    • 为需要CPU隔离的进程在nohz_full范围内选择一个CPU进行绑定,且每个CPU只绑定一个进程
    • 将其他进程绑定到nohz_full范围以外的CPU
    • 以上操作可以通过低级函数sched_setaffinity()完成,也可以使用高级命令taskset或者cpusets完成
    • 配置硬中断亲和性,将硬中断配置到nohz_full以外的CPUkernel documentation.
  • 所有这些CPU隔离设置都涉及到权衡和陷阱,我们将在下一篇文章中探讨。

part4:为清理工作保留核心

配置了nohz_full后,会影响housekeeping工作,需要为期预留核心

  • 这是SUSE实验室团队关于内核CPU隔离和其核心组件Full Dynticks (或Nohz Full)的技术系列的第四篇博客文章。
  • 该系列的文章列表包括:CPU隔离 - 简介,CPU隔离 - Full dynticks内部,CPU隔离 - Nohz_full,CPU隔离 - 例行清理和权衡,CPU隔离 - 实际例子,CPU隔离 - Nohz_full故障排除:破损的TSC/时钟源等。
  • 需要注意的一个基本原则是,这个领域的噪声很少被完全消除,而是被转移。
  • 例行清理是内核需要进行的周期性或事件驱动的基础工作,例如更新调度器的内部统计信息,或进行时间管理。
  • 在正常配置中,每个CPU都需要分担例行清理工作。相反,nohz_full配置会将所有的例行清理工作移出nohz_full集合。
  • 这意味着如果您有8个CPU,并且您隔离了CPU 1,2,3,4,5,6,7:nohz_full=1-7,那么CPU 0将单独处理例行清理工作负载。
  • 这些工作包括:执行未绑定的计时器回调,执行未绑定的工作队列,执行未绑定的k线程,更新时间管理(jiffies和gettimeofday()),跟踪RCU宽限期,代表隔离的CPU执行RCU回调,代表隔离的CPU处理1Hz的残余负载等。
  • 随着CPU数量的增加,内存和缓存的进一步划分,可能需要共享例行清理工作。通常认为每个NUMA节点有一个清洁工是一个好的开始。
  • 在测试阶段,建议通过像top/htop这样的工具检查和监控清洁工的活动,以确保他们没有被过载。
  • 如果所有的CPU都被传递给“nohz_full=”内核参数,CPU 0将被任意清除出隔离集,并被分配单独的例行清理工作。
  • Full dynticks模式在内核入口和出口上增加了显著的开销,这是由于RCU跟踪和排序,以及cputime计算所导致的。
  • IRQ可以被绑定到例行清理,页面错误可以通过使用mlock()来防止。然后由用户来减轻系统调用的使用。
  • 结论是,CPU隔离和full dynticks可以在某些特定的工作负载上带来显著的优势,但要注意它在许多情况下并不适用。特别是,你必须意识到这两个要点:你需要牺牲至少一个CPU来处理内核的例行内部工作,Full dynticks只适用于CPU绑定的工作负载或基于用户空间驱动器的I/O。

part5:实操案例

  • 这篇博客是SUSE实验室团队发布的一系列技术文章的第五篇,主要探讨内核CPU隔离以及其核心组件之一:全动态滴答(或Nohz Full)。
  • 到目前为止,该系列的文章包括:CPU隔离-介绍,CPU隔离-全动态滴答内部原理,CPU隔离-Nohz_full,CPU隔离-家务和权衡,CPU隔离-实际示例,CPU隔离-Nohz_full故障排除:破损的TSC/clocksource。
  • 在这个示例中,我们的设置由8个CPU组成。我们将在第8个CPU上运行一个完全隔离的虚拟用户空间循环,即:没有任何干扰。
  • 如果你正在运行SUSE Linux Enterprise Server 15 SP3或更高版本,你不需要担心内核配置要求。否则,确保你有:CONFIG_NO_HZ_FULL=y,CONFIG_CPUSETS=y,CONFIG_TRACING=y。
  • 使用“nohz_full=”引导参数,可以在运行单个任务时关闭定时器滴答,大部分内核未绑定负载也可以迁移到传递的范围之外的CPU。由于我们计划隔离第8个CPU,所以我们需要用以下方式引导内核:nohz_full=7。
  • 任务亲和性有几种方法可以在你的隔离任务和系统的其余部分之间划分CPU。这里首选的方式是使用cpuset。然而,其他解决方案对于可能有特殊需求的人来说是公开的。其他可用的方案包括:
    • isolcpus启动参数:缺点是只能启动时配置一次,系统运行期间不能动态改变;优点是适配广,不需要高层次的应用程序支持
    • Taskset, sched_setaffinity()等
    • IRQs affinity等
  • 我们已经处理了任务亲和性,但硬件中断仍然可以在隔离的CPU上触发并干扰其专用负载。幸运的是,我们可以通过procfs接口将这些中断在housekeeping集上触发。
  • 我们正在处理简单的调度器和基于中断的干扰。更高级的主题,如防止异常(如页面错误)将在后续文章中讨论。
  • 现在,大部分的家务负载应该在CPU 0到6上运行。预计CPU 7已经准备好运行用户空间代码,而不会中断它。所以,让我们用一个启动器来制作一个虚拟循环。
  • 在完美的世界中,如果一切顺利,可以在“trace.7”文件中找到类似于以下的内容:这表明在这段时间内,没有任务或中断干扰了我们的user_loop。注意,这种理想的结果只会在理想的设置、完美的机器和完美的世界中发生。在追踪中可能会发现随机噪声,因此下一篇文章将讨论干扰追踪和故障排除。

part6:故障排除

  • 这是SUSE实验室团队撰写的技术系列文章的第五篇,主要探讨内核CPU隔离以及其核心组件之一:全动态时钟(或Nohz Full)。
  • 文章系列包括以下主题:CPU隔离介绍、全动态时钟内部原理、Nohz_full、CPU隔离的家务事和权衡、CPU隔离的实际示例、Nohz_full故障排除:破损的TSC/时钟源等。
  • 文章讨论了如何隔离CPU并在其上启动专用进程的实际示例。
  • 文章探讨了CPU隔离故障排除,重点关注Nohz_full用户在x86上常遇到的问题。
  • 文章介绍了什么是时钟源和TSC,以及它们的属性和作用。
  • 文章讨论了TSC的可靠性,包括常见问题、值得信赖的架构、扩展信任等。
  • 文章探讨了不可靠TSC的影响,以及如何克服不可靠TSC。
  • 文章讨论了TSC的稳定性,包括从内核的角度看不稳定和不可靠的TSC的含义,以及TSC不稳定时的症状。
  • 文章还讨论了其他架构的问题,指出只有x86有被正式认为是不可靠的时钟源。
  • 文章提供了一些资源、参考文献和进一步阅读的建议。

参考

CPU Isolation - Introduction – by SUSE Labs (part 1) | SUSE Communities

文章目录