6.3 CPU:实验与调优

上下文说明

本部分涵盖 CPU 性能的实验工具(如 SysBench 等)与调优策略,包括编译器选项、调度优先级、电源状态与 CPU 绑定等内容。

6.8 实验

Figure 6.23 FlameScope

图 6.23 FlameScope

FlameScope 是开源的 [Netflix 19],并在 Netflix 被用于发现了大量的性能提升点。

6.8 实验

本节描述了用于主动测试 CPU 性能的工具。有关背景知识,请参见第 6.5.11 节“微基准测试”。

实验建议

在使用这些工具时,最好让 mpstat(1) 持续运行,以确认 CPU 的使用率和并行度。

6.8.1 临时(Ad Hoc)测试

虽然这很微不足道且不测量任何东西,但它可以作为一个有用的已知工作负载,用于确认可观测性工具确实展示了它们所声称展示的内容。这会创建一个受 CPU 限制的单线程工作负载(“在一个 CPU 上发热”):

# while :; do :; done &

这是一个 Bourne shell 程序,它在后台执行一个无限循环。一旦你不再需要它,就需要将其杀死。

6.8.2 SysBench

SysBench 系统基准测试套件带有一个简单的 CPU 基准测试工具,用于计算素数。例如:

# sysbench --num-threads=8 --test=cpu --cpu-max-prime=100000 run

输出示例:

sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 8

Doing CPU performance benchmark
Threads started!
Done.

Maximum prime number checked in CPU test: 100000


Test execution summary:
    total time:                          30.4125s
    total number of events:              10000
    total time taken by event execution: 243.2310

    per-request statistics:
         min:                                 24.31ms
         avg:                                 24.32ms
         max:                                 32.44ms
         approx.  95 percentile:              24.32ms

Threads fairness:
    events (avg/stddev):           1250.0000/1.22
    execution time (avg/stddev):   30.4039/0.01

这执行了八个线程,最大素数为 100,000。运行时间为 30.4 秒,可用于与其他系统或配置的结果进行比较(这建立在许多假设之上,例如使用了相同的编译器选项来构建软件;参见第 12 章“基准测试”)。

6.9 调优

对于 CPU 来说,最大的性能提升通常来自于消除不必要的工作,这是一种有效的调优形式。第 6.5 节“方法论”和第 6.6 节“可观测性工具”介绍了许多分析和识别已执行工作的方法,帮助您找到任何不必要的工作。还介绍了其他调优方法论:优先级调优和 CPU 绑定。本节包括这些以及其他调优示例。

调优的具体细节——可用的选项以及应将它们设置为什么值——取决于处理器类型、操作系统版本以及预期的工作负载。以下按类型组织的内容,提供了可能有哪些可用选项以及如何调优它们的示例。前面的方法论章节提供了关于何时以及为何要调整这些可调参数的指导。

6.9.1 编译器选项

编译器及其为代码优化提供的选项,可以对 CPU 性能产生巨大的影响。常见的选项包括编译为 64 位而不是 32 位,以及选择优化级别。编译器优化在第 5 章“应用程序”中讨论。

6.9.2 调度优先级与类别

nice(1) 命令可用于调整进程优先级。正的 nice 值会降低优先级,而负的 nice 值(只有超级用户才能设置)会提高优先级。范围是从 -20 到 +19。例如:

$ nice -n 19 command

这会以 nice 值为 19 运行命令——这是 nice 可以设置的最低优先级。要更改已运行进程的优先级,请使用 renice(1)

在 Linux 上,chrt(1) 命令可以直接显示和设置调度优先级以及调度策略。例如:

$ chrt -b command

这将在 SCHED_BATCH 中运行该命令(参见第 6.4.2 节“软件”中的调度类)。

nice(1)chrt(1) 也可以直接指向某个 PID,而不是启动一个新命令(参见它们的手册页)。

调度优先级也可以直接使用 setpriority(2) 系统调用进行设置,而优先级和调度策略可以使用 sched_setscheduler(2) 系统调用进行设置。

6.9.3 调度器选项

您的内核可能提供可调参数来控制调度器行为,尽管通常不太需要调整它们。

在 Linux 系统上,各种 CONFIG 选项在高级别上控制调度器行为,并且可以在内核编译期间进行设置。表 6.12 显示了来自 Ubuntu 19.10 和 Linux 5.3 内核的示例。

表 6.12 Linux 调度器 CONFIG 选项示例

选项默认值描述
CONFIG_CGROUP_SCHEDy允许对任务进行分组,按组分配 CPU 时间
CONFIG_FAIR_GROUP_SCHEDy允许对 CFS 任务进行分组
CONFIG_RT_GROUP_SCHEDn允许对实时任务进行分组
CONFIG_SCHED_AUTOGROUPy自动识别并创建任务组(例如,构建作业)
CONFIG_SCHED_SMTy超线程支持
CONFIG_SCHED_MCy多核支持
CONFIG_HZ250设置内核时钟频率(定时器中断)
CONFIG_NO_HZy无滴答内核行为
CONFIG_SCHED_HRTICKy使用高分辨率定时器
CONFIG_PREEMPTn完全内核抢占(自旋锁区域和中断除外)
CONFIG_PREEMPT_NONEn无抢占
CONFIG_PREEMPT_VOLUNTARYy在自愿的内核代码点处抢占

此外,还有调度器的 sysctl(8) 可调参数可以在正在运行的系统上实时设置,包括表 6.13 中列出的那些,其默认值来自相同的 Ubuntu 系统。

表 6.13 Linux 调度器 sysctl(8) 可调参数示例

sysctl默认值描述
kernel.sched_cfs_bandwidth_slice_us5000用于 CFS 带宽计算的 CPU 时间量。
kernel.sched_latency_ns12000000目标抢占延迟。增加此值可以增加任务在 CPU 上的时间,但代价是增加抢占延迟。
kernel.sched_migration_cost_ns500000任务迁移延迟成本,用于亲和性计算。运行时间距现在小于此值的任务被认为是缓存热的。
kernel.sched_nr_migrate32设置负载均衡时一次可以迁移多少个任务。
kernel.sched_schedstats0启用额外的调度器统计信息,包括 sched:sched_stat* 跟踪点。

这些 sysctl(8) 可调参数也可以从 /proc/sys/sched 进行设置。

6.9.4 扩频调速器

Linux 支持不同的 CPU 扩频调速器,它们通过软件(内核)控制 CPU 时钟频率。这些可以通过 /sys 文件进行设置。例如,对于 CPU 0:

# cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_governors
performance powersave
 
# cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor 
powersave

这是一个未调优系统的示例:当前的调速器是“powersave”,它将使用较低的 CPU 频率以节省电量。可以将其设置为“performance”以始终使用最大频率。例如:

# echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor

必须对所有 CPU(policy0..N)执行此操作。此 policy 目录还包含用于直接设置频率(scaling_setspeed)和确定可能频率范围(scaling_min_freqscaling_max_freq)的文件。

环境代价

将 CPU 设置为始终以最大频率运行,可能会给环境带来巨大的代价。如果此设置不能提供显著的性能改进,请考虑为了地球继续使用 powersave 设置。对于有权访问电源 MSR 的主机(云客户机可能会过滤它们),您也可以使用这些 MSR 来测量在设置和未设置最大 CPU 频率时所消耗的功率,以量化(部分1)环境成本。

6.9.5 电源状态

可以使用 cpupower(1) 工具启用和禁用处理器电源状态。如前面第 6.6.21 节“其他工具”中所见,更深的睡眠状态可能具有较高的退出延迟(之前展示了 C10 为 890 μs)。可以使用 -d 禁用单个状态,而 -D latency 将禁用所有退出延迟高于给定值(以微秒为单位)的状态。这允许您微调可以使用哪些较低功率的状态,并禁用那些延迟过高的状态。

6.9.6 CPU 绑定

一个进程可以绑定到一个或多个 CPU,这可以通过改善缓存热度(缓存亲和性)和内存局部性来提高其性能。

在 Linux 上,这可以使用 taskset(1) 命令来执行,该命令使用 CPU 掩码或范围来设置 CPU 亲和性。例如:

$ taskset -pc 7-10 10790
pid 10790's current affinity list: 0-15
pid 10790's new affinity list: 7-10

这将 PID 10790 设置为仅在 CPU 7 到 10 上运行。

numactl(8) 命令也可以设置 CPU 绑定以及内存节点绑定(参见第 7 章“内存”,第 7.6.4 节“NUMA 绑定”)。

6.9.7 独占 CPU 集

Linux 提供了 cpusets,允许将 CPU 分组并将进程分配给它们。这可以像 CPU 绑定一样提高性能,但是通过使 cpuset 独占(防止其他进程使用它),可以进一步提高性能。权衡之处在于系统其余部分可用的 CPU 减少了。

以下带注释的示例创建了一个独占集:

# mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset  # 可能不是必须的
# cd /sys/fs/cgroup/cpuset
# mkdir prodset                    # 创建一个名为 "prodset" 的 cpuset
# cd prodset
# echo 7-10 > cpuset.cpus          # 分配 CPU 7-10
# echo 1 > cpuset.cpu_exclusive    # 使 prodset 独占
# echo 1159 > tasks         # 将 PID 1159 分配给 prodset

供参考,请参见 cpuset(7) 手册页。

中断亲和性

在创建 CPU 集时,您可能还希望研究哪些 CPU 将继续服务中断。irqbalance(1) 守护程序将尝试跨 CPU 分配中断以提高性能。您可以通过 /proc/irq/IRQ/smp_affinity 文件按 IRQ 手动设置 CPU 亲和性。

6.9.8 资源控制

除了将进程与整个 CPU 关联外,现代操作系统还提供了用于细粒度分配 CPU 使用率的资源控制。

对于 Linux,有控制组,它们也可以控制进程或进程组的资源使用情况。CPU 使用率可以通过份额进行控制,而 CFS 调度器允许施加固定限制(CPU 带宽),即按间隔分配 CPU 周期的微秒数。

第 11 章“云计算”描述了一个管理 OS 虚拟化租户 CPU 使用率的用例,包括如何协同使用份额和限制。

6.9.9 安全启动选项

针对 Meltdown 和 Spectre 安全漏洞的各种内核缓解措施具有降低性能的副作用。可能存在某些不需要安全性但需要高性能的场景,此时您希望禁用这些缓解措施。由于这不被推荐(由于安全风险),我不会在此包含所有选项;但您应该知道它们的存在。它们是 grub 命令行选项,包括 nospectre_v1nospectre_v2。这些记录在 Linux 源码的 Documentation/admin-guide/kernel-parameters.txt 中 [Linux 20f];摘录如下:

        nospectre_v1    [PPC] Disable mitigations for Spectre Variant 1 (bounds
                        check bypass). With this option data leaks are possible
                        in the system.

        nospectre_v2    [X86,PPC_FSL_BOOK3E,ARM64] Disable all mitigations for
                        the Spectre variant 2 (indirect branch prediction)
                        vulnerability. System may allow data leaks with this
                        option.

还有一个网站列出了它们:https://make-linux-fast-again.com。该网站缺少内核文档中列出的警告。


6.3 CPU:实验与调优

6.9.10 处理器选项(BIOS 调优)

处理器通常提供一些设置,用于启用、禁用和调优处理器级别的功能。在 x86 系统上,这些设置通常可以在启动时通过 BIOS 设置菜单进行访问。

默认设置与性能

这些设置默认通常提供最大性能,一般不需要进行调整。

目前我调整这些设置最常见的原因是为了禁用 Intel Turbo Boost(睿频加速),以便 CPU 基准测试能以一致的时钟频率执行(需要注意的是,在生产环境使用中,应启用 Turbo Boost 以获得稍快一点的性能)。


6.10 练习

1. 回答以下关于 CPU 术语的问题:

  • 进程和处理器之间的区别是什么?
  • 什么是硬件线程?
  • 什么是运行队列?
  • 用户时间和内核时间之间的区别是什么?

2. 回答以下概念性问题:

  • 描述 CPU 利用率和饱和度。
  • 描述指令流水线如何提高 CPU 吞吐量。
  • 描述处理器指令宽度如何提高 CPU 吞吐量。
  • 描述多进程和多线程模型的优势。

3. 回答以下更深层次的问题:

  • 描述当系统 CPU 超载且充满可运行的工作时会发生什么,包括对应用程序性能的影响。
  • 当没有可运行的工作需要执行时,CPU 会做什么?
  • 当面对一个疑似 CPU 性能问题时,指出你在调查早期会使用的两种方法论,并解释原因。

4. 为你的环境制定以下流程:

  • 一份针对 CPU 资源的 USE 方法 检查清单。包括如何获取每个指标(例如,执行哪个命令)以及如何解释结果。在安装或使用额外的软件产品之前,尽量使用现有的操作系统可观测性工具。
  • 一份针对 CPU 资源的工作负载特征归纳检查清单。包括如何获取每个指标,并尽量优先使用现有的操作系统可观测性工具。

5. 执行以下任务:

  • 计算以下系统的平均负载,该系统处于稳态负载,且没有显著的磁盘/锁负载:
    • 该系统有 64 个 CPU。
    • 系统范围的 CPU 利用率为 50%。
    • 系统范围的 CPU 饱和度(以平均可运行和排队线程的总数来衡量)为 2.0。
  • 选择一个应用程序,并对其用户级 CPU 使用情况进行性能分析。展示哪些代码路径消耗了最多的 CPU。

**6. (可选,进阶)开发 bustop(1)——一个显示物理总线或互连利用率的工具,其展示方式类似于 iostat(1):一个总线列表,包含每个方向的吞吐量列和利用率列。如果可能,包括饱和度和错误指标。这将需要使用 性能监控计数器 (PMC)


6.11 参考文献

[Saltzer 70] Saltzer, J., and Gintell, J., “The Instrumentation of Multics,” Communications of the ACM, August 1970.

[Bobrow 72] Bobrow, D. G., Burchfiel, J. D., Murphy, D. L., and Tomlinson, R. S., “TENEX: A Paged Time Sharing System for the PDP-10*,” Communications of the ACM, March 1972.

[Myer 73] Myer, T. H., Barnaby, J. R., and Plummer, W. W., TENEX Executive Manual, Bolt, Baranek and Newman, Inc., April 1973.

[Thomas 73] Thomas, B., “RFC 546: TENEX Load Averages for July 1973,” Network Working Group, http://tools.ietf.org/html/rfc546, 1973.

[TUHS 73] “V4,” The Unix Heritage Society, http://minnie.tuhs.org/cgi-bin/utree.pl?file=V4, materials from 1973.

[Hinnant 84] Hinnant, D., “Benchmarking UNIX Systems,” BYTE magazine 9, no. 8, August 1984.

[Bulpin 05] Bulpin, J., and Pratt, I., “Hyper-Threading Aware Process Scheduling Heuristics,” USENIX, 2005.

[Corbet 06a] Corbet, J., “Priority inheritance in the kernel,” LWN.net, http://lwn.net/Articles/178253, 2006.

[Otto 06] Otto, E., “Temperature-Aware Operating System Scheduling,” University of Virginia (Thesis), 2006.

[Ruggiero 08] Ruggiero, J., “Measuring Cache and Memory Latency and CPU to Memory Bandwidth,” Intel (Whitepaper), 2008.

[Intel 09] “An Introduction to the Intel QuickPath Interconnect,” Intel (Whitepaper), 2009.

[Levinthal 09] Levinthal, D., “Performance Analysis Guide for Intel® Core™ i7 Processor and Intel® Xeon™ 5500 Processors,” Intel (Whitepaper), 2009.

[Gregg 10a] Gregg, B., “Visualizing System Latency,” Communications of the ACM, July 2010.

[Weaver 11] Weaver, V., “The Unofficial Linux Perf Events Web-Page,” http://web.eece.maine.edu/~vweaver/projects/perf_events, 2011.

[McVoy 12] McVoy, L., “LMbench - Tools for Performance Analysis,” http://www.bitmover.com/lmbench, 2012.

[Stevens 13] Stevens, W. R., and Rago, S., Advanced Programming in the UNIX Environment, 3rd Edition, Addison-Wesley 2013.

[Perf 15] “Tutorial: Linux kernel profiling with perf,” perf wiki, https://perf.wiki.kernel.org/index.php/Tutorial, last updated 2015.

[Gregg 16b] Gregg, B., “The Flame Graph,” Communications of the ACM, Volume 59, Issue 6, pp. 48–57, June 2016.

[ACPI 17] Advanced Configuration and Power Interface (ACPI) Specification, https://uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf, 2017.

[Gregg 17b] Gregg, B., “CPU Utilization Is Wrong,” http://www.brendangregg.com/blog/2017-05-09/cpu-utilization-is-wrong.html, 2017.

[Gregg 17c] Gregg, B., “Linux Load Averages: Solving the Mystery,” http://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html, 2017.

[Mulnix 17] Mulnix, D., “Intel® Xeon® Processor Scalable Family Technical Overview,” https://software.intel.com/en-us/articles/intel-xeon-processor-scalable-family-technical-overview, 2017.

[Gregg 18b] Gregg, B., “Netflix FlameScope,” Netflix Technology Blog, https://netflixtechblog.com/netflix-flamescope-a57ca19d47bb, 2018.

[Ather 19] Ather, A., “General Purpose GPU Computing,” http://techblog.cloudperf.net/2019/12/general-purpose-gpu-computing.html, 2019.

[Gregg 19] Gregg, B., BPF Performance Tools: Linux System and Application Observability, Addison-Wesley, 2019.

[Intel 19a] Intel 64 and IA-32 Architectures Software Developer’s Manual, Combined Volumes 1, 2A, 2B, 2C, 3A, 3B, and 3C. Intel, 2019.

[Intel 19b] Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3B, System Programming Guide, Part 2. Intel, 2019.

[Netflix 19] “FlameScope Is a Visualization Tool for Exploring Different Time Ranges as Flame Graphs,” https://github.com/Netflix/flamescope, 2019.

[Wysocki 19] Wysocki, R., “CPU Idle Time Management,” Linux documentation, https://www.kernel.org/doc/html/latest/driver-api/pm/cpuidle.html, 2019.

[AMD 20] “AMD μProf,” https://developer.amd.com/amd-uprof, accessed 2020.

[Gregg 20d] Gregg, B., “MSR Cloud Tools,” https://github.com/brendangregg/msr-cloud-tools, last updated 2020.

[Gregg 20e] Gregg, B., “PMC (Performance Monitoring Counter) Tools for the Cloud,” https://github.com/brendangregg/pmc-cloud-tools, last updated 2020.

[Gregg 20f] Gregg, B., “perf Examples,” http://www.brendangregg.com/perf.html, accessed 2020.

[Gregg 20g] Gregg, B., “FlameGraph: Stack Trace Visualizer,” https://github.com/brendangregg/FlameGraph, last updated 2020.

[Intel 20a] “Product Specifications,” https://ark.intel.com, accessed 2020.

[Intel 20b] “Intel® VTune™ Profiler,” https://software.intel.com/content/www/us/en/develop/tools/vtune-profiler.html, accessed 2020.

[Iovisor 20a] “bpftrace: High-level Tracing Language for Linux eBPF,” https://github.com/iovisor/bpftrace, last updated 2020.

[Linux 20f] “The Kernel’s Command-Line Parameters,” Linux documentation, https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html, accessed 2020.

[Spier 20a] Spier, M., “A D3.js Plugin That Produces Flame Graphs from Hierarchical Data,” https://github.com/spiermar/d3-flame-graph, last updated 2020.

[Spier 20b] Spier, M., “Template,” https://github.com/spiermar/d3-flame-graph#template, last updated 2020.

[Valgrind 20] “Valgrind Documentation,” http://valgrind.org/docs/manual, May 2020.

[Verma 20] Verma, A., “CUDA Cores vs Stream Processors Explained,” https://graphicscardhub.com/cuda-cores-vs-stream-processors, 2020.

Footnotes

  1. 基于主机的功率测量没有考虑服务器空调、服务器制造和运输以及其他成本造成的环境成本。