繁体   English   中英

为什么 AMD-CPU 有如此愚蠢的 PAUSE-timing

[英]Why have AMD-CPUs such a silly PAUSE-timing

我已经为 C++ 开发了一个类似 Java 的监视器对象,并进行了一些改进。 主要的改进是不仅有一个用于锁定和解锁的自旋循环,还有用于等待事件的自旋循环。 在这种情况下,您不必锁定互斥锁,而是在 wait_poll 函数上提供一个谓词,并且代码反复尝试锁定互斥锁轮询,如果它可以锁定互斥锁,它会调用返回(或移动)一对的谓词布尔值和结果类型。

等待 kernel 中的信号量和/或事件对象 (Win32) 很容易花费 1.000 到 10.000 个时钟周期,即使调用立即返回也是如此,因为之前已经设置了信号量或事件。 因此,必须有一个与此等待间隔具有合理关系的旋转计数,fe 旋转 kernel 中花费的最小间隔的十分之一。

对于我的监视器对象,我从 glibc 中获取了自旋计数重新计算算法。 我也在使用暂停指令。 但是我发现在我的 CPU(TR 3900X)上暂停指令太快了。 平均约为 0.78ns。 在 Intel-CPU 上,大约 30ns 更合理。

这是代码:

#include <iostream>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <immintrin.h>

using namespace std;
using namespace chrono;

int main( int argc, char **argv )
{
    static uint64_t const PAUSE_ROUNDS = 1'000'000'000;
    auto start = high_resolution_clock::now();
    for( uint64_t i = PAUSE_ROUNDS; i; --i )
        _mm_pause();
    double ns = (int64_t)duration_cast<nanoseconds>( high_resolution_clock::now() - start ).count() / (double)PAUSE_ROUNDS;
    cout << ns << endl;
}

为什么 AMD 采取了如此愚蠢的暂停时间? PAUSE 用于自旋等待循环,应该与缓存行内容翻转到不同核心并返回所需的时间非常匹配。

但是我发现在我的 CPU(TR 3900X)上暂停指令太快了。 平均约为 0.78ns。 在 Intel-CPU 上,大约 30ns 更合理。

pause指令与时间没有任何关系,也不打算用作时间延迟。

pause的目的是防止 CPU 浪费其资源(推测性地)并行执行循环的许多迭代; 这在超线程情况下特别有用,在这种情况下,核心中的不同逻辑处理器可以使用这些资源,但也有助于改善条件改变时退出循环所需的时间(因为你没有“N 次迭代”在条件改变之前排队的指令数)。

鉴于这种; 对于一个可能同时有 200 条指令在运行的极其复杂的 CPU, pause本身可能会立即发生,但会在其唤醒时导致“200 个周期长”的管道气泡; 对于一个极其简单的 CPU(“按顺序”,没有推测性执行), pause可能/应该实际上什么都不做(被视为nop )。

PAUSE 用于自旋等待循环,应该与缓存行内容翻转到不同核心并返回所需的时间非常匹配。

不。假设缓存行在不同 CPU 的缓存中的“修改”state 中, pause后的指令类似于“ cmp [lock],0 ”,这会导致 CPU 尝试将缓存行放入“共享” " state。在pause之后但在尝试将缓存行放入“共享”state 之前,CPU 应该无缘无故地浪费时间多长时间?

注意:如果您确实需要一个微小的时间延迟,那么您需要查看umwait指令。 你不需要时间延迟 - 你想要一个超时(例如“ pause旋转;直到rdtsc说已经过了一定的时间)。为此我很想把它分成一个内部循环确实“ pause并检查条件 N 次”然后执行“如果时间限制尚未到期则重试内部循环”的外部循环。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM