低延迟调整指南

2020-08-02 17:42:37

本指南介绍如何调优AMD64/x86_64硬件和Linux系统以运行实时或低延迟工作负载。适合此类型调整的示例工作负载:

本文中的术语等待时间指的是接收到某个事件之间的时间和处理该事件的时间之间的时间。例如:

网络接口卡收到网络数据包到应用程序处理完数据包之间的时间。

将请求提交到队列和辅助线程完成处理请求之间的时间。

您可以使用我的工具打嗝来测量减少的系统抖动。在此示例中,它显示了核心3是如何隔离的,并经历了18 us的最大抖动:

$Higcups|Column-t-R 1,2,3,4,5,6cpu Threshold_ns Higcups pct99_ns pct999_ns max_ns 0 168 17110 83697 6590444 17010845 1 168 9929 169555 5787333 9517076 2 168 20728 73359 6008866 16008460 3 168 28336 1354 4870 17869。

系统UEFI或BIOS通常有一个可调整CPU电源状态的能源配置文件设置,您应该将其设置为“最高性能”。

超线程(HT)或同步多线程(SMT)是一种针对每周期低指令数(IPC)的工作负载最大化处理器资源利用率的技术。由于HT/SMT会增加处理器资源的争用,如果您想要减少处理器资源争用带来的抖动,建议将其关闭。

可以在系统的UEFI或BIOS固件设置中关闭HT/SMT。

英特尔Turbo Boost和AMD Turbo Core技术使处理器只要保持在一定的功率和散热范围内,就可以自动超频。如果您有良好的散热(在BIOS中将风扇速度设置为最大),在BIOS中禁用未使用的内核,或者使用CPU热插拔功能,就可以以更高的提升频率持续运行您的应用程序内核。

使用turbostat工具验证每个内核的时钟频率。请注意,涡轮增压器会导致调度抖动,不应在生产期间使用。

考虑给您的处理器超频。以更高的频率运行处理器将减少抖动和延迟。英特尔至强服务器处理器不可能超频,但你可以超频英特尔消费者游戏处理器和AMD处理器。

默认情况下,内核调度程序将跨可用内核对所有线程进行负载均衡。要阻止系统线程干扰您的应用程序线程,您可以使用内核命令行选项isocpus。默认情况下,它会禁用隔离核心的调度程序负载平衡,并导致线程被限制到非隔离核心。请注意,您的关键应用程序线程需要专门固定在隔离的核心上才能在那里运行。

当使用Isolcpus时,内核仍然会在隔离的内核上创建几个内核线程。这些内核线程中的一些可以移到非隔离内核。

此外,需要将内核工作队列移出独立的核心。将所有工作队列移至核心0(Cumask 0x1):

最后,通过检查每个核心发生了多少个线程上下文切换,验证是否成功隔离了核心:

有一个正在进行的补丁集可以进一步改进任务隔离,请参阅内核的完整任务隔离模式。

调度程序定期在每个内核上运行,以便在RunnableRead之间切换。这将为延迟关键型应用程序带来抖动。如果您隔离了应用程序内核,并且正在运行单个应用程序线程每个隔离内核,则可以使用NOHZ_FULL内核命令行选项来抑制计时器中断。

例如,要在内核1-7上启用NOHZ_FULL,请将NOHZ_FULL=1-7RCU_NOcbs=1-7添加到内核命令行。

重要的是要注意,只有当内核上只有一个可运行的线程被调度时,才会在该内核上禁用计时器滴答。您可以在/proc/sched_debug中查看每个内核的可运行线程数。

默认情况下,虚拟内存子系统每1秒运行一次每个内核的统计信息更新任务。您可以通过将vm.stat_interval设置为更高的值(例如120秒)来缩短此间隔:

最后,您可以通过检查/proc/interrupts或使用perf监视计时器中断来验证是否降低了计时器中断频率:

#perf stat-e';irq_Vector:LOCAL_TIMER_ENTRY';-a-A--超时30000系统范围的性能计数器统计信息:CPU031,204 IRQ_VECTIONS:LOCAL_TIMER_Entry CPU1 3,771 IRQ_VECTRUCTS:LOCAL_TIMER_ENTERYCPU2 3 IRQ_VECTIONS:LOCAL_TIMER_ENTRY CPU3 4 IRQ_VECTIONS:LOCAL_TIMER_ENTRY 30.001671482秒已用时间。

在上面的示例中,内核2和3的定时器中断频率降低了。期望Isolcpus+NOHZ_FULL内核每隔一秒左右显示一个定时器中断。不幸的是,定时器滴答不能完全消除。

通过更改中断的CPU亲和性来减少中断处理的抖动。这可以通过运行irqBalance轻松完成。默认情况下,irqBalance将自动隔离内核命令行参数isocpus指定的核心。您还可以使用IRQBALANCE_BANDIRED_CPUS环境变量指定要隔离的核心。

Linux透明巨型页面(THP)支持允许内核自动将常规内存页面提升为大型页面。巨型页面减少了TLB压力,但THP支持在将页面提升为巨型页面以及触发内存压缩时会引入延迟峰值。

通过提供内核命令行PARAMETER TRANSPECTOR_HUGPAGE=NERVER或运行以下命令来禁用透明巨型页面支持:

Linux内核页面合并(KSM)是一种对包含相同数据的内存页面进行重复数据删除的功能。合并过程需要锁定页表并发出TLB击落,从而导致不可预测的内存访问延迟。KSM仅在使用mise(...MADV_MERGEABLE)选择加入samepagEmerging的内存页上运行。如果需要,可以通过运行以下命令在系统范围内禁用KSM:

这取决于应用程序,但请考虑禁用CPU漏洞的缓解。缓解可能会对系统性能产生相当大的性能影响。将mimigations=off添加到内核命令行以禁用所有缓解。

如果您的处理器支持高速缓存分区(英特尔高速缓存分配技术),请考虑使用它将大部分末级高速缓存(LLC)分配给您的应用程序。

转换后备缓冲器(TLB)具有有限数量的条目。如果您的应用程序试图访问TLB中缺失的内存页,则会导致TLB缺失,需要MMU遍历页表。默认的页面大小是4096字节,通过使用2MB或1 GB的巨大页面,您可以减少相同数量的活跃使用的RAM的TLB未命中数量。

#perf stat-e&e;dTLB-Loads,dTLB-Load-Misses,iTLB-Load-Misses';-a--Timeout 10000系统范围&:10,525,620 dTLB-Loads 2,964,792 dTLB-Loads#28.17%的所有dTLB缓存命中1,998,243 iTLB-Load 1,068,635 iTLB-Load

上面的输出显示了未命中的数据加载(DTLB)和指令加载(ITLB)的比例。如果您观察到TLB未命中的很大一部分,您应该考虑使用巨大的页面来减少TLB未命中的数量。您还可以使用其他CPU性能计数器来测量TLB压力,有关TLB相关性能计数器的完整列表,请参阅您的处理器手册。

每个进程都有一个将虚拟地址映射到物理地址的页表。当页表发生变化,导致内存未映射(Munmap)或内存访问受限(mmap更改prot_*标志)时,需要在当前运行应用程序进程的所有核心上刷新TLB。这称为TLB击落,作为处理器间中断(IPI)实现,它会给正在运行的应用程序带来抖动。此外,后续的TLB未命中引入了存储器访问延迟。TLB击落的其他原因还有:透明巨型页面(THP)、内存压缩、内核SamepagEmerging(KSM)、页面迁移和页面缓存写回。