微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

通过施加内存压力来降低CPU频率 脚注1:实验示例:

如何解决通过施加内存压力来降低CPU频率 脚注1:实验示例:

我强调了我的系统,以了解它如何影响我使用Stress-ng编写的某些程序。

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

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

Add-Type -AssemblyName PresentationCore

会创建4个在mmap上旋转的工作程序,并分别分配2G RAM。这会极大地减慢我的程序的执行速度(从大约150ms到250ms)。但是程序变慢的原因不是缺少内存,内存带宽等。取而代之的是,cpu周期从3.4GHz(无压力ng)降低到2.8GHz(有压力ng)。与预期的一样,cpu利用率保持不变(99%)。

我使用来测量cpu频率

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

有人知道为什么内存压力会减慢cpu速度吗?

我的cpu是Intel®Core™i5-8250U,而我的操作系统是Ubuntu 18.04。

亲切的问候北极星

解决方法

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内核发送到内存控制器,而单内核带宽受最大并发(一个内核可以跟踪的未决请求)/延迟的限制。 Why is Skylake so much better than Broadwell-E for single-threaded memory throughput?

例如当运行微基准测试时,我的i7-6700k从3.9GHz下降到2.7GHz,在默认启动设置下,该基准仅对DRAM造成瓶颈。 (此外,在BIOS中配置的1或2个核心处于活动状态时,它只能上升到3.9 GHz而不是4.0全核或4.2 GHz,并且在启动时使用默认的balance_power EPP设置,或者在balance_performance下运行。 )

该默认值似乎不太好,对于“客户端”芯片来说太保守了,在这种情况下,单核几乎可以饱和DRAM带宽,但只能以全时钟速度进行。如果您从其他POV角度来看,也可能过于省电,特别是对于像我的台式机那样具有高TDP(95W)的芯片,即使在运行诸如x265视频编码这样的耗电大功率的东西时,它们也可以无限期地保持全时钟速度的AVX2。

使用像i5-8250U这样的ULV 15W芯片可能更有意义,以便在CPU 做更多有趣的事情时尝试留出更多的散热/功率余量。


这取决于他们的“能源/性能偏好”(EPP)设置。在默认的balance_power设置下,它发生得非常强烈。完全performance根本不会发生这种情况,一些快速的基准测试表明balance_performance也避免了这种省电的速度。我在桌面上使用balance_performance

Ice Lake之前的“客户端”(非至强)芯片将所有内核锁定在一起,因此它们以相同的时钟速度运行(即使其中一个正在运行不受内存限制的内容,例如{{ 1}}循环)。但是每个逻辑核心仍然有一个EPP设置。我一直只是更改所有内核的设置以使其保持不变:

在Linux上,阅读设置:

while(1) { _mm_pause(); }

编写设置:

$ 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

另请参见


脚注1:实验示例:

每条高速缓存行存储1个双字,在连续的高速缓存行中前进直至缓冲区结束,然后将指针回绕到起点。不管缓冲区大小如何,都对固定数量的商店重复上述操作。

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

测试系统:Arch GNU / Linux,内核5.7.6-arch1-1。 (以及NASM 2.14.02,;; 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,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 ,来自GNU Binutils 2.34.0)。

  • CPU:i7-6700k Skylake
  • 主板:Asus Z170 Pro Gaming,在BIOS中配置为1或2核心Turbo = 4.2GHz,3或4核心= 4.0GHz。但是引导时的默认EPP设置为ld,只有在高达3.9GHz时才能设置。我的启动脚本更改为balance_power,但仍然只能达到3.9GHz,因此风扇保持安静,但不那么保守。
  • DRAM:DDR4-2666(与这次没有高速缓存未命中的小型测试无关)

启用了超线程,但是系统处于空闲状态,内核不会在另一个逻辑内核(我固定它的同一个内核)中调度任何内容,因此它本身具有物理内核。

但是,这意味着perf不愿意在一个线程上使用更多可编程的perf计数器,因此balance_pwerformance来监视L1d负载和替换,L3命中/未命中意味着perf stat -d和以此类推。可以忽略不计,例如424k L1-dcache-loads(可能在内核页面错误处理程序,中断处理程序和其他开销中,因为循环没有负载)。 cycles实际上是L1-dcache-load-misses,甚至更低,例如48k

我使用了一些性能事件,包括L1D.REPLACEMENT-[存储缓冲区已满且没有未完成的负载的周期]。 (有关说明,请参见exe_activity.bound_on_stores,有关更多信息,请参见Intel的手册。)

EPP:perf list:3.9 GHz之外的2.7 GHz时钟

EPP设置:balance_powerbalance_power

根据代码的执行情况进行限制;如果另一个内核上有一个暂停循环,使时钟保持高电平,则在此代码上运行速度会更快。或在循环中使用不同的指令。

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

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

(我几次运行# sudo ... balance_power $ taskset -c 3 perf stat -etask-clock:u,task-clock,branches,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 命令,所以CPU不仅在定时间隔开始时从低功耗睡眠中醒来。间隔中仍然存在页面错误,但是6在3/4秒的基准时间内,页面错误可以忽略不计。)

perf stat:完整3.9GHz,此EPP的最高速度

无需根据代码的执行情况进行限制。

balance_performance

在逐个时钟的基础上大致相同,尽管存储缓冲区已满的总周期略多。 (这是在核心缓存和L1d缓存之间,而不是在核心缓存之外,因此我们希望循环本身大致相同。使用# sudo ... balance_performance $ taskset -c 3 perf stat -etask-clock:u,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,030,096 branches # 3719.713 M/sec 7,016,729,050 instructions # 3.33 insn per cycle 5,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 重复10次,该数字在每次运行中稳定+-0.01%。)

-r10:4.2 GHz,完全加速到最高配置频率

无需根据代码的执行情况进行限制。

performance

总体性能与时钟速度成线性比例关系,因此与# sudo ... performance taskset -c 3 perf stat -etask-clock,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,551,461 instructions # 3.34 insn per cycle 5,839,192 uops_issued.any # 10415.906 M/sec 7,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.44,具有相同的3.9GHz全时钟速度。)

由于缓冲区的大小足以导致L1d或L2高速缓存未命中,因此核心时钟周期仍然存在差异。

,

重要的是要记住,现代CPU(尤其是Intel制造的CPU)具有可变的时钟频率。轻负载以节省功率时,CPU会缓慢运行,以延长电池寿命,但在负载下可能会加速运行。

限制因素是热量,也就是说,只有在调整频率以降低功耗并扩展热量产生之前,才允许CPU变热。

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

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

,

我上次查看此文件时,它启用了“节能Turbo”设置,该设置允许处理器执行此操作。粗略地说,硬件会监视“每个周期的指令”,并且如果频率增加不能充分提高吞吐量,则可以避免继续增加Turbo频率。对于STREAM基准测试,频率通常会下降几个bin,但是性能在渐近性能的1%以内。

我不知道英特尔是否已经记录了“节能涡轮”设置如何与“节能性能偏好”的所有各种方式相互作用。在我们的生产系统中,BIOS中禁用了“ Energy Efficient Turbo”,但有时默认情况下会启用...。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。