通过施加内存压力来降低 CPU 频率

2024-10-31 08:38:00
admin
原创
47
摘要:问题描述:我对我的系统进行了压力测试,看看它如何影响我使用 Stress-ng 编写的一些程序。该程序本身是一个神经网络,主要由一些嵌套循环组成,进行一些乘法运算,总体使用大约 1G 的 RAM,用 C++ 编码。我使用以下方法对系统施加了一些内存压力:stress-ng --vm 4 --vm-bytes ...

问题描述:

我对我的系统进行了压力测试,看看它如何影响我使用 Stress-ng 编写的一些程序。

该程序本身是一个神经网络,主要由一些嵌套循环组成,进行一些乘法运算,总体使用大约 1G 的 RAM,用 C++ 编码。

我使用以下方法对系统施加了一些内存压力:

stress-ng --vm 4 --vm-bytes 2G -t 100s

这会创建 4 个在 mmap 上旋转的工作线程,每个工作线程分配 2G 的 RAM。这会显著减慢我的程序的执行速度(从大约 150ms 减慢到 250ms)。但程序变慢的原因不是缺少内存或内存带宽之类的。相反,CPU 周期从 3.4GHz(不使用 Stress-ng)降低到 2.8GHz(使用 Stress-ng)。CPU 利用率保持不变(99%),正如预期的那样。

我使用以下方法测量了 CPU 频率

sudo perf stat -B ./my_program

有人知道为什么内存压力会降低 CPU 速度吗?

我的 CPU 是 Intel(R) Core(TM) i5-8250U,操作系统是 Ubuntu 18.04。

亲切问候 lpolari


解决方案 1:

Skylake 衍生 CPU 在加载/存储方面遇到瓶颈时会降低核心时钟速度,此时的能源与性能设置更有利于节能。令人惊讶的是,您可以构建人为案例,即使所有存储都命中 L1d 缓存,或从未初始化的内存加载(仍然 CoW 映射到相同的零页),也会发生这种降频。

Skylake 引入了对 CPU 频率的完全硬件控制(硬件 P 状态 = HWP)。https ://unix.stackexchange.com/questions/439340/what-are-the-implications-of-setting-the-cpu-governor-to-performance 频率决策可以考虑内部性能监控,它可以注意到大多数周期停滞或停滞的原因。我不知道 Skylake 到底使用了什么启发式方法。

您可以通过循环遍历大型数组而不进行任何系统调用来重现此1。如果它很大(或者您在人工测试中跨过缓存行),perf stat ./a.out将显示平均时钟速度低于正常的 CPU 绑定循环。


理论上,如果内存完全跟不上 CPU,降低核心时钟速度(并保持内存控制器不变)不会对性能造成太大影响。实际上,降低时钟速度也会降低非核心时钟速度(环形总线 + L3 缓存),从而在一定程度上恶化内存延迟和带宽。

缓存未命中延迟的一部分是将请求从 CPU 核心发送到内存控制器,并且单核带宽受最大并发性(一个核心可以跟踪的未完成请求)/延迟的限制。 为什么 Skylake 在单线程内存吞吐量方面比 Broadwell-E 好得多?

例如,在运行微基准测试时,我的 i7-6700k 从 3.9GHz 降至 2.7GHz,而默认启动设置下,该基准测试仅在 DRAM 上产生瓶颈。(此外,它只能升至 3.9GHz,而不是 4.0 全核或 4.2GHz,如 BIOS 中配置的那样,balance_power在启动时使用默认 EPP 设置或使用balance_performance。)

这种默认设置似乎不太好,对于“客户端”芯片来说太保守了,因为在客户端芯片中,单个内核几乎可以饱和 DRAM 带宽,但只能在全时钟速度下使用。或者,如果从另一个角度来看,在节能方面又过于激进,尤其是对于像我的台式机这样的芯片来说,它具有高 TDP(95W),即使在运行大量使用 AVX2 的 x265 视频编码等耗电程序时,也可以无限期地维持全时钟速度。

使用像 i5-8250U 这样的 ULV 15W 芯片可能更有意义,当 CPU执行更有趣的操作时,尝试留出更多的热量/功率空间。


这是由其能源/性能偏好 (EPP) 设置控制的。默认设置下,这种情况会相当严重balance_power。满载时根本不会发生这种情况performance,一些快速基准测试表明,这balance_performance也可以避免这种省电减速。我在台式机上使用balance_performance

Ice Lake 之前的“客户端”(非 Xeon)芯片将所有核心锁定在一起,因此它们以相同的时钟速度运行(如果其中一个核心正在运行不受内存限制的程序,例如循环,则所有核心的运行速度都会更高while(1) { _mm_pause(); })。但每个逻辑核心仍然有一个 EPP 设置。我总是更改所有核心的设置以使其保持相同:

在 Linux 上,读取设置:

$ grep . /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference
/sys/devices/system/cpu/cpufreq/policy0/energy_performance_preference:balance_performance
/sys/devices/system/cpu/cpufreq/policy1/energy_performance_preference:balance_performance
...
/sys/devices/system/cpu/cpufreq/policy7/energy_performance_preference:balance_performance

写入设置:

sudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;
 do echo balance_performance > "$i"; done'

参见

  • x86_energy_perf_policy(8)手册页

  • Linux 内核文档中有关英特尔性能和能耗偏差提示的内容


注1:实验例:

每条缓存行存储 1 个双字,通过连续的缓存行前进直到缓冲区末尾,然后将指针绕回到起始位置。重复固定数量的存储,无论缓冲区大小如何。

;; t=testloop; nasm -felf64 "$t.asm" && ld "$t.o" -o "$t" && taskset -c 3 perf stat -d -etask-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,uops_issued.any,uops_executed.thread ./"$t"

;; nasm -felf64 testloop.asm
;; ld -o testloop testloop.o
;; taskset -c 3 perf stat -etask-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,uops_issued.any,uops_executed.thread -r1 ./testloop

; or idq.mite_uops 

default rel
%ifdef __YASM_VER__
;    CPU intelnop
;    CPU Conroe AMD
    CPU Skylake AMD
%else
%use smartalign
alignmode p6, 64
%endif

global _start
_start:

    lea        rdi, [buf]
    lea        rsi, [endbuf]
;    mov        rsi, qword endbuf           ; large buffer.  NASM / YASM can't actually handle a huge BSS and hit a failed assert (NASM) or make a binary that doesn't reserve enough BSS space.

    mov     ebp, 1000000000

align 64
.loop:
%if 0
      mov  eax, [rdi]              ; LOAD
      mov  eax, [rdi+64]
%else
      mov  [rdi], eax              ; STORE
      mov  [rdi+64], eax
%endif
    add  rdi, 128
    cmp  rdi, rsi
    jae  .wrap_ptr        ; normally falls through, total loop = 4 fused-domain uops
 .back:

    dec ebp
    jnz .loop
.end:

    xor edi,edi
    mov eax,231   ; __NR_exit_group  from /usr/include/asm/unistd_64.h
    syscall       ; sys_exit_group(0)

.wrap_ptr:
   lea  rdi, [buf]
   jmp  .back


section .bss
align 4096
;buf:    resb 2048*1024*1024 - 1024*1024     ; just under 2GiB so RIP-rel still works
buf:    resb 1024*1024 / 64     ; 16kiB = half of L1d

endbuf:
  resb 4096        ; spare space to allow overshoot

测试系统:Arch GNU/Linux,内核 5.7.6-arch1-1。(以及 NASM 2.14.02,ld来自 GNU Binutils 2.34.0)。

  • 处理器:i7-6700k Skylake

  • 主板:华硕 Z170 Pro Gaming,在 BIOS 中配置为 1 或 2 核睿频 = 4.2GHz,3 或 4 核 = 4.0GHz。但启动时的默认 EPP 设置是balance_power,只会升至 3.9GHz。我的启动脚本更改为balance_pwerformance,仍然只会升至 3.9GHz,因此风扇保持安静,但不那么保守。

  • DRAM:DDR4-2666(与此没有缓存未命中的小测试无关)。

超线程已启用,但系统处于空闲状态,并且内核不会在另一个逻辑核心(我将其固定到的核心的兄弟)上安排任何内容,因此它本身具有一个物理核心。

但是,这意味着 perf 不愿意为一个线程使用更多可编程的 perf 计数器,因此perf stat -d监控 L1d 负载和替换以及 L3 命中/未命中将意味着测量精度降低cycles等等。它可以忽略不计,例如 424k L1-dcache-loads(可能在内核页面错误处理程序、中断处理程序和其他开销中,因为循环没有负载)。实际上甚 L1-dcache-load-missesL1D.REPLACEMENT更低,例如 48k

我使用了一些性能事件,包括exe_activity.bound_on_stores-[存储缓冲区已满并且没有未完成负载的周期]。(有关perf list说明,请参阅 和/或英特尔手册以了解更多信息)。

EPP: balance_power: 降频 2.7GHz,频率为 3.9GHz

EPP 设置:balance_power具有sudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_power > "$i";done'

根据代码正在执行的操作进行节流;在另一个核心上使用暂停循环来保持时钟高位,这将在此代码上运行得更快。或者在循环中使用不同的指令。

# sudo ... balance_power
$ taskset -c 3 perf stat -etask-clock:u,task-clock,context-switches,cpu-migrations,page-faults,cycles,branches,instructions,uops_issued.any,uops_executed.thread,exe_activity.bound_on_stores -r1 ./"$t" 

 Performance counter stats for './testloop':

            779.56 msec task-clock:u              #    1.000 CPUs utilized          
            779.56 msec task-clock                #    1.000 CPUs utilized          
                 3      context-switches          #    0.004 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                 6      page-faults               #    0.008 K/sec                  
     2,104,778,670      cycles                    #    2.700 GHz                    
     2,008,110,142      branches                  # 2575.962 M/sec                  
     7,017,137,958      instructions              #    3.33  insn per cycle         
     5,217,161,206      uops_issued.any           # 6692.465 M/sec                  
     7,191,265,987      uops_executed.thread      # 9224.805 M/sec                  
       613,076,394      exe_activity.bound_on_stores #  786.442 M/sec                  

       0.779907034 seconds time elapsed

       0.779451000 seconds user
       0.000000000 seconds sys

碰巧的是,这个正好达到了 2.7GHz。通常会有一些噪音或启动开销,而且会低一点。请注意,5217951928 个前端微指令/2106180524 个周期 = 每个周期平均发出 ~2.48 个微指令,流水线宽度为 4,所以这不是低吞吐量代码。由于宏融合比较/分支,指令数量更高。(我本可以展开更多,这样更多的指令是存储,更少的添加和分支,但我没有。)

(我重新运行了perf stat几次命令,因此 CPU 不会在时间间隔开始时从低功耗睡眠中唤醒。间隔内仍然存在页面错误,但在 3/4 秒的基准测试中,6 个页面错误可以忽略不计。)

balance_performance:全速 3.9GHz,此款 EPP 的最高速度

根据代码的操作不进行任何限制。

# sudo ... balance_performance
$ taskset -c 3 perf stat -etask-clock:u,task-clock,context-switches,cpu-migrations,page-faults,cycles,branches,instructions,uops_issued.any,uops_executed.thread,exe_activity.bound_on_stores -r1 ./"$t" 

 Performance counter stats for './testloop':

            539.83 msec task-clock:u              #    0.999 CPUs utilized          
            539.83 msec task-clock                #    0.999 CPUs utilized          
                 3      context-switches          #    0.006 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                 6      page-faults               #    0.011 K/sec                  
     2,105,328,671      cycles                    #    3.900 GHz                    
     2,008,030,096      branches                  # 3719.713 M/sec                  
     7,016,729,050      instructions              #    3.33  insn per cycle         
     5,217,686,004      uops_issued.any           # 9665.340 M/sec                  
     7,192,389,444      uops_executed.thread      # 13323.318 M/sec                 
       626,115,041      exe_activity.bound_on_stores # 1159.827 M/sec                  

       0.540108507 seconds time elapsed

       0.539877000 seconds user
       0.000000000 seconds sys

在时钟周期基础上大致相同,尽管存储缓冲区已满时的总周期略多。(这是在核心和 L1d 缓存之间,而不是核心外,因此我们期望循环本身大致相同。重复-r1010 次,该数字在运行过程中稳定在 +- 0.01%。)

performance:4.2GHz,全速加速至最高配置频率

根据代码的操作不进行任何限制。

# sudo ... performance
taskset -c 3 perf stat -etask-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,uops_issued.any,uops_executed.thread -r1 ./testloop

 Performance counter stats for './testloop':

            500.95 msec task-clock:u              #    1.000 CPUs utilized          
            500.95 msec task-clock                #    1.000 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                 7      page-faults               #    0.014 K/sec                  
     2,098,112,999      cycles                    #    4.188 GHz                    
     2,007,994,492      branches                  # 4008.380 M/sec                  
     7,016,551,461      instructions              #    3.34  insn per cycle         
     5,217,839,192      uops_issued.any           # 10415.906 M/sec                 
     7,192,116,174      uops_executed.thread      # 14356.978 M/sec                 
       624,662,664      exe_activity.bound_on_stores # 1246.958 M/sec                  

       0.501151045 seconds time elapsed

       0.501042000 seconds user
       0.000000000 seconds sys

总体性能与时钟速度线性相关,因此与 相比,这相当于约 1.5 倍的加速balance_power( 1.44balance_performance具有相同的 3.9GHz 全时钟速度)。

当缓冲区足够大以致于导致 L1d 或 L2 缓存未命中时,核心时钟周期仍然存在差异。

解决方案 2:

需要记住的是,现代 CPU(尤其是英特尔生产的 CPU)具有可变时钟频率。轻负载时 CPU 会缓慢运行以节省电量,从而延长电池寿命,但在负载下会加速运行。

限制因素是热量,也就是说,在调整频率以降低功耗并减少热量产生之前,CPU 只能达到一定温度。

在具有多个内核的芯片上,单个内核可以非常快速地运行而不会出现热节流。两个内核必须运行得更慢,它们产生的热量实际上是原来的两倍,并且当使用所有四个内核时,每个内核必须共享较小一部分整体热预算。

在测试运行时值得检查您的 CPU 温度,因为它可能会达到某种上限。

解决方案 3:

上次我查看时,启用“节能 Turbo”设置允许处理器执行此操作。粗略地说,硬件会监控每周期指令数,如果增加的频率不能带来足够的吞吐量增加,则不会继续增加 Turbo 频率。对于 STREAM 基准测试,频率通常会下降几个档位,但性能在渐近性能的 1% 以内。

我不知道英特尔是否记录了“节能 Turbo”设置如何与各种“节能性能偏好”交互。在我们的生产系统中,“节能 Turbo”在 BIOS 中被禁用,但有时默认启用。...

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用