Eug*_*eev 0 c++ macos cpu xcode throttling
我有一个对性能敏感的 XCode C++ 项目,并且我正在使用 CPU 节流技巧。本质上我添加了这段代码:
// function to occupy a thread for an infinite amount of time
void coreEngager() {
while (true) {}
}
// call it in the background thread
std::thread t1(coreEngager);
// call it once the work is done
t1.detach();
Run Code Online (Sandbox Code Playgroud)
这个小技巧可以将计算速度提高约 50%,这对我来说非常重要。但我最近发现了一个问题 - 如果我尝试在发布模式下运行该项目,此代码会崩溃。函数中发生崩溃coreEngager。我以前没有这个问题,现在在 Linux 和 Windows 上也没有这个问题。您能否告知发生了什么变化或如何使 CPU 限制在 MacOS 上发挥作用?
有时,我在进行基准测试时使用pause循环来保持 CPU 频率,但我不愿意将整个核心浪费在无限循环上以供生产使用。 相反,请调整您的 CPU 电源管理设置,或建议您的用户在安装指南中这样做。或者让您的程序(或单独的脚本)检查设置并建议更改。
在 C++ 中,没有 I/O 或 a volatileoratomic操作的无限循环是未定义的行为。编译器可以删除它们(https://eel.is/c++draft/intro.progress#1),而 clang 会积极地这样做。它不会为您的函数发出 asm 指令coreEngager(),因此执行只会进入二进制文件中下一个函数。
此 C++ 规则旨在在循环条件不重要时帮助编译器,因此编译器可能难以证明循环确实终止。
有趣的事实:ISO C 有一个不同的规则,如果循环条件是像 之类的常量表达式1,则无限循环是明确定义的。但是 IIRC,clang 在这种情况下有一个 bug,仍然应用 C++ 规则。
要实际解决此问题,请asm volatile("")在循环内放置一个空语句,以使编译器满意,无论目标如何,而无需实际运行额外的指令。
#if defined(__x86_64__) || defined(__i386__)
#include <immintrin.h>
#define SPIN() _mm_pause() // heat up the CPU less
#else
#define SPIN() /**/
#endif
void coreEngager() {
while (true) {
asm(""); // counts as a volatile op for infinite-loop UB.
SPIN(); // x86 pause or whatever
}
}
Run Code Online (Sandbox Code Playgroud)
Godbolt显示它可以按需要进行编译:
# clang16 -O3 for x86-64
coreEngager_buggy(): # zero asm instructions for your orig source!
coreEngager_fixed():
.LBB1_1:
pause
jmp .LBB1_1
Run Code Online (Sandbox Code Playgroud)
# clang16 -O3 for AArch64
coreEngager_buggy():
coreEngager_fixed():
.LBB1_1:
b .LBB1_1
Run Code Online (Sandbox Code Playgroud)
如果存在与 x86 等效的 AArch64 pause,请使用它。可能不会,因为还没有 SMT AArch64 CPU(多个逻辑核心共享一个物理核心),并且它们在自旋循环中没有内存顺序错误推测,因为它们没有 x86 的强有序内存模型。x86-compat 内存模型模式下的 M1 除外;也许苹果有pause类似的指令?
我假设您正在调整像 Skylake 这样的 CPU,其中内存绑定代码可以让 CPU 降频,例如在我的 i7-6700k 上降频到 2.7GHz,而不是 3.9GHz,硬件 P 状态管理设置为 或balance_power(balance_performance与设置为完整performance)与 Linux 的energy_performance_preference. (通过施加内存压力来降低CPU频率)
或者您是否有其他线程有时会完全睡眠,并且如果没有旋转线程,它们最初会以空闲频率出现?(为什么这个延迟循环在没有睡眠的情况下经过几次迭代后开始运行得更快?)
有关的:
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |