基于Linux的环境中可重复的基准测试
|
该页面正在翻译中。 |
导言
本文档是关于在基于Linux的环境中执行性能测试时识别和避免潜在的可重复性陷阱。
当我开始研究Julia语言的性能回归测试时,我很惊讶我找不到一个最新的和noob友好的清单,它简洁地巩固了分散在各种论坛和论文中的性能智慧。 我的希望是,本文档为那些刚开始在Linux上进行性能测试的研究人员提供了一个起点,他们可能正在试图弄清楚为什么理论上相同的基准测试会产生显着不同的结果。
对于不熟悉的人来说,跟踪和消除"操作系统抖动"有时感觉更像是一门艺术而不是一门科学。 您很快就会发现,为严格的性能测试设置适当的环境需要在互联网和学术文献中搜索有关调度程序怪癖和内核标志的深奥引用。 其中一些参数可能会严重影响您的特定基准套件的结果,而其他参数可能需要过多的实验来证明它们根本不会影响您的基准。
本文档的目标是_not_提高应用程序的性能,帮助您模拟真实的生产环境,或为各种内核机制提供深入的解释。 它目前在NUMA特定的细节上有点轻,但唉,我无法访问支持NUMA的机器来玩。 我相信有知识的读者会找到更正和添加的机会,在这种情况下,如果您在这个存储库中提交了一个问题或打开了一个拉请求,我将不胜感激。
处理器屏蔽和过程亲和性
处理器屏蔽是一种调用Linux的技术。http://man7.org/linux/man-pages/man7/cpuset.7.html[脧锚脧赂`[医]cpuset`]伪文件系统,用于设置受Linux调度程序保护的独占处理器和内存节点。 创建和利用处理器屏蔽的最简单方法是http://manpages.ubuntu.com/manpages/precise/man1/cset.1.html[脧锚脧赂`cset,cset`],一个方便的Python包装器 [医]cpuset 界面。 在Ubuntu上, cset,cset 可以通过运行以下安装:
➜ sudo apt-get install cpuset
值得一读https://rt.wiki.kernel.org/index.php/Cpuset_Management_Utility/tutorial[广泛的 cset,cset 教程]可在RTwiki. 作为一个简短的例子,下面是如何保护处理器1和3免受不请自来的线程(包括大多数内核线程,由 -k on):
➜ sudo cset shield -c 1,3 -k on cset: --> activating shielding: cset: moving 67 tasks from root into system cpuset... [==================================================]% cset: kthread shield activated, moving 91 tasks into system cpuset... [==================================================]% cset: **> 34 tasks are not movable, impossible to move cset: "system" cpuset of CPUSPEC(0,2) with 124 tasks running cset: "user" cpuset of CPUSPEC(1,3) with 0 tasks running
设置屏蔽后,您可以通过 -e 标志(请注意,进程的参数必须在 -- 分离器):
➜ sudo cset shield -e echo -- "hello from within the shield" cset: --> last message, executed args into cpuset "/user", new pid is: 27782 hello from within the shield ➜ sudo cset shield -e julia -- benchmark.jl cset: --> last message, executed args into cpuset "/user", new pid is: 27792 running benchmarks...
对于稍低级别的控制,您可以使用 cset,cset其他小组委员会,https://rt.wiki.kernel.org/index.php/Cpuset_Management_Utility/tutorial#The_Proc_Subcommand[脧锚脧赂`proc`]和https://rt.wiki.kernel.org/index.php/Cpuset_Management_Utility/tutorial#The_Set_Subcommand[脧锚脧赂`套装`]. 实际的 [医]cpuset 内核接口http://man7.org/linux/man-pages/man7/cpuset.7.html#EXTENDED_CAPABILITIES[提供更多选项],特别是内存硬连接和调度设置。
为了最大限度地提高试验之间的一致性,您应该确保在屏蔽内执行的单个线程始终使用完全相同的处理器/内存节点配置。 这可以通过使用https://rt.wiki.kernel.org/index.php/Cpuset_Management_Utility/tutorial#Implementing_Hierarchy_with_Set_and_Proc[分层cpusets]将进程固定到在屏蔽cpuset下创建的子cpusets。 用于管理进程关联性的其他实用程序,例如 任务集, n.数字,数字,或 金枪鱼,没有那么有用 cset,cset 因为它们不保护调度程序的专用资源。
虚拟内存设置
Linux官方文档列表https://www.kernel.org/doc/Documentation/sysctl/vm.txt[过多的虚拟内存设置]用于配置Linux的交换,分页和缓存行为。 我鼓励读者独立调查 vm.nr_hugepages, vm。vfs_cache_压力, vm。zone_reclaim_mode,而 vm。min_free_kbytes 属性,但不会深入讨论这些,因为它们在大多数情况下不太可能产生很大的影响。 相反,我将专注于两个更容易实验的属性,并且它们的效果不那么微妙:swappiness和地址空间布局随机化。
交换性,交换性
大多数Linux发行版都配置为https://wiki.archlinux.org/index.php/swap默认情况下,[交换]积极,这可能会增加基准执行期间交换的可能性,从而严重影响性能结果。 幸运的是,通过降低内核的交换倾向很容易驯服。https://en.wikipedia.org/wiki/Swappiness[swappiness]设置,通过控制 vm。交换性,交换性 参数:
➜ sudo sysctl vm.swappiness=10
根据我的经验,降低 vm。交换性,交换性 到周围去 10 在大多数内存限制的基准测试中,至少足以克服与交换相关的噪声。
地址空间布局随机化(ASLR)
地址空间布局随机化(ASLR)是一种安全功能,使恶意程序更难利用缓冲区溢出。 从理论上讲,ASLR可能会显着影响极易受内存布局变化影响的基准的可重复性。 禁用ASLR应该由您自己承担风险-毕竟它是一个安全功能。
ASLR可以通过设置全局禁用 随机化_va_空间 到 0:
➜ sudo sysctl kernel.randomize_va_space=0
如果您不希望全局禁用ASLR,只需运行以下命令即可启动禁用ASLR的shell:
➜ setarch $(uname -m) -R /bin/sh
CPU频率缩放和提升
大多数现代Cpu支持动态频率缩放,这是调整其时钟速率以管理功率使用和温度的能力。 在Linux上,频率缩放行为由启发式方法确定。https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt["州长"],每个州长都优先考虑不同的资源利用模式。 如果在基准测试期间或试验之间进行重新校准,此功能可能会干扰性能结果,但幸运的是,我们可以通过启用 工作表现 所有处理器上的调速器:
➜ echo "performance" | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
您可以通过以下方式检查此命令是否有效 cat/proc|cpuinfo/grep’cpu MHz' 吐出与 猫/sys/设备/系统/cpu/cpu*/cpufreq/cpuinfo_max_freq.
许多Cpu也支持任意性能https://www.kernel.org/doc/Documentation/cpu-freq/boost.txt["boosting"],其类似于动态频率缩放,并且可以对基准再现性产生相同的负面影响。 要禁用CPU提升,您可以运行以下操作:
➜ echo 0 | sudo tee /sys/devices/system/cpu/cpufreq/boost
超线程
超线程,通常称为https://en.wikipedia.org/wiki/Simultaneous_multithreading[同时多线程(SMT)],允许多个软件线程"同时"在单个CPU内核上的"独立"硬件线程上运行。 缺点是这些线程在实践中并不总是实际并发执行,因为它们争夺共享的CPU资源。 令人沮丧的是,Linux将这些线程作为额外的逻辑处理器暴露给操作系统,使得像屏蔽这样的技术难以推理-你怎么知道你的屏蔽"处理器"实际上并没有与非 除非您的用例要求您在超线程环境中运行测试,否则应考虑禁用超线程,以便更容易一致地管理处理器资源。
禁用超线程的第一步是检查它是否在您的计算机上实际启用。 为此,您可以使用 lscpu:
➜ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 60 Stepping: 3 CPU MHz: 3501.000 BogoMIPS: 6999.40 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 8192K NUMA node0 CPU(s): 0-7
在上述输出中, 中央处理器 菲尔德告诉我们有 8 逻辑工艺。 其他字段允许我们进行更精细的细分: 1 套接字时间 4 每个插槽的核心给了我们 4 物理内核,时间 2 每个核心线程给我们 8 逻辑处理器。 由于逻辑处理器多于物理内核,因此我们知道启用了超线程。
在我们开始禁用处理器之前,我们需要知道哪些共享一个物理内核:
➜ cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list 0,4 1,5 2,6 3,7 0,4 1,5 2,6 3,7
上面的每一行都是格式 我,j,并可阅读 逻辑处理器i与逻辑处理器j共用一个物理核. 我们可以通过使多余的兄弟处理器脱机来禁用超线程,每个物理内核只留下一个逻辑处理器。 在我们的示例中,我们可以通过禁用处理器来完成此操作 4, 5, 6,而 7:
➜ echo 0 | sudo tee /sys/devices/system/cpu/cpu4/online 0 ➜ echo 0 | sudo tee /sys/devices/system/cpu/cpu5/online 0 ➜ echo 0 | sudo tee /sys/devices/system/cpu/cpu6/online 0 ➜ echo 0 | sudo tee /sys/devices/system/cpu/cpu7/online 0
现在,我们可以通过检查每个处理器的 线程_siblings_list 又来了:
➜ cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list 0 1 2 3
中断请求和SMP关联
内核会定期发送https://en.wikipedia.org/wiki/Interrupt_request_(PC_architecture)[中断请求(IRQs)]给你的处理器。 顾名思义,Irq要求处理器暂停当前正在运行的任务,以便执行所请求的任务。 有许多不同类型的Irq,特定类型的IRQ对给定基准的干扰程度取决于IRQ与基准工作负载相比的频率和持续时间。
好消息是,大多数类型的Irq允许你设置一个https://cs.uwaterloo.ca/~brecht/servers/apic/SMP-affinity.txt[SMP affinity],它告诉内核IRQ应该发送到哪个处理器。 通过正确配置SMP亲和力,我们可以将Irq发送到基准测试环境中的非屏蔽处理器,从而保护屏蔽处理器免受不必要的中断。
您可以使用Linux的 proc 伪文件系统以获取自上次重新启动以来系统上发生的中断列表:
➜ cat /proc/interrupts
CPU0 CPU1
0: 19 0 IR-IO-APIC-edge timer
8: 1 0 IR-IO-APIC-edge rtc0
9: 0 0 IR-IO-APIC-fasteoi acpi
16: 27 0 IR-IO-APIC-fasteoi ehci_hcd:usb1
22: 12 0 IR-IO-APIC-fasteoi ehci_hcd:usb2
⋮
53: 18021763 122330 IR-PCI-MSI-edge eth0-TxRx-7
NMI: 15661 13628 Non-maskable interrupts
LOC: 140221744 85225898 Local timer interrupts
SPU: 0 0 Spurious interrupts
PMI: 15661 13628 Performance monitoring interrupts
IWI: 23570041 3729274 IRQ work interrupts
RTR: 7 0 APIC ICR read retries
RES: 3153272 4187108 Rescheduling interrupts
CAL: 3401 10460 Function call interrupts
TLB: 4434976 3071723 TLB shootdowns
TRM: 0 0 Thermal event interrupts
THR: 0 0 Threshold APIC interrupts
MCE: 0 0 Machine check exceptions
MCP: 61112 61112 Machine check polls
ERR: 0
MIS: 0
有些中断,比如https://en.wikipedia.org/wiki/Non-maskable_interrupt[不可屏蔽中断(NMI)],无法重定向,但您可以通过将处理器索引写入以下内容来更改其余部分的SMP亲和力 /proc/irq/n/smp_affinity_list,在哪里 n 是IRQ号码。 下面是一个设置IRQ的例子 22SMP与处理器的亲和力 0, 1,而 2:
➜ echo 0-2 | sudo tee /proc/irq/22/smp_affinity_list
配置SMP亲和力的最佳方法在很大程度上取决于您的基准和基准测试过程。 例如,如果你正在运行很多网络绑定的基准测试,它有时可以更有利于均衡以太网驱动程序中断(通常命名为类似 eth0-*)而不是将它们限制在特定的处理器上。
用于确定IRQs对基准测试结果的影响的烟雾测试是查看当您打开/关闭IRQ负载平衡器时会发生什么,例如http://linux.die.net/man/1/irqbalance[脧锚脧赂`[医]平衡`]. 如果这对您的结果有明显的影响,那么可能值得利用SMP亲和力来确定哪些Irq应该远离您的屏蔽处理器。
性能监控中断(PMIs)和 佩尔夫
性能监控中断(PMIs)是由内核发送的https://perf.wiki.kernel.org/index.php/Main_Page[脧锚脧赂`佩尔夫`]子系统,用于设置和管理https://en.wikipedia.org/wiki/Hardware_performance_counter[硬件性能计数器]由内核的其他部分监控。 除非 佩尔夫 是你的基准测试过程的依赖,它可能是有用的降低 佩尔夫的采样率,以便PMIs不会干扰您的实验。 这样做的一种方法是设置https://www.kernel.org/doc/Documentation/sysctl/kernel.txt[脧锚脧赂`内核。perf_cpu_time_max_percent`]参数至 1:
➜ sudo sysctl kernel.perf_cpu_time_max_percent=1
这告诉内核通知 佩尔夫 它应该降低采样速率,使采样消耗的CPU时间少于1%。 更改此参数后,您可能会在系统日志中看到类似的消息:
[ 3835.065463] perf samples too long (2502 > 2500), lowering kernel.perf_event_max_sample_rate
这些消息没什么可担心的—只是内核报告它正在降低 佩尔夫的最大采样率,以尊重 perf_cpu_time_max_percent 我们刚刚设定的财产。
额外资源
*虽然不是高度通航和有点压倒性的新人,内核信息的最权威的资源是托管在官方Linux文档https://www.kernel.org/doc/Documentation/[Linux内核档案]。 *Akkan等人。'的http://dl.acm.org/citation.cfm?id=2318925[2012年关于开发无噪音Linux环境的论文]探讨了将资源与定时器中断和调度器隔离的最佳配置,以及无蜱内核的好处。 论文利用了Linux的https://wiki.archlinux.org/index.php/Cgroups[脧锚脧赂`cg组`],其类似于本文档中讨论的cpusets。 *De等人。'的http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=5161046&tag;=1[2009关于减少多线程系统中OS抖动的论文]类似于Akkan等人。的论文,但重点是最大限度地减少抖动的应用程序,利用超线程/SMT。 他们的实验方法也不同,很大程度上依赖于通过巧妙的基准测试获得的模拟抖动"跟踪"分析。 *有关Linux性能测试生态系统的完整概述,请查看https://www.youtube.com/watch?v=FJW8nGV4jxY[Brendan Gregg关于Linux性能工具的演讲]。 请注意,本次讨论更侧重于调试在大型分布式环境中出现的系统性能问题,而不是应用程序基准测试或实验重现性。 *Https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/[RHEL6性能调优指南]对于向自己介绍可能导致性能问题的各种内核构造非常有用。 你亦可查阅https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Performance_Tuning_Guide/[RHEL7版本]相同的指南,如果你想要更近的东西,但我发现RHEL6版本更具可读性。