_mm_prefetch 是异步的吗?分析显示了很多周期

问题描述

Understanding `_mm_prefetch`有关。

我知道 _mm_prefetch() 会导致请求的值被提取到处理器的缓存中,并且我的代码将在同时预取的东西被执行。

但是,我的 VS2017 分析器指出 5.7% 花费在访问我的 cache 的行上,而 8.63% 花费在 _mm_prefetch 行上。分析器有误吗?如果我正在等待获取数据,我需要它做什么?当我需要它时,我可以在下一个函数调用中等待......

另一方面,总体时间显示了预取调用的显着优势。

那么问题是:数据是异步获取的吗?

其他信息。

我有多个缓存,用于不同的密钥宽度,最多 32 位密钥(我目前正在分析)。对缓存和预取的访问被提取到单独的 __declspec(noinline) 函数中,以将它们与周围的代码隔离。

uint8_t* cache[33];

__declspec(noinline)
uint8_t get_cached(uint8_t* address) {
    return *address;
}

__declspec(noinline)
void prefetch(uint8_t* pcache) {
    _mm_prefetch((const char*)pcache,_MM_HINT_T0);
}

int foo(const uint64_t seq64) {
    uint64_t key = seq64 & 0xFFFFFFFF;
    uint8_t* pcache = cache[32];
    int x = get_cached(pcache + key);
    key = (key * 2) & 0xFFFFFFFF;
    pcache += key;
    prefetch(pcache);
    // code that uses x
}

分析器显示 int x = get_cached(pcache + key); 行为 7.22%,prefetch(pcache); 为 8.97%,而周围代码显示每行 0.40-0.45%。

解决方法

基本上所有在无序 CPU 上都是“异步”的,就像您描述的那样(实际上,并行和无序运行)。从这个意义上说,预取与常规加载并没有真正不同,后者也可能无序运行或与其他指令“异步”。

一旦理解了这一点,预取的确切行为取决于硬件,但我的观察是:

  • 在英特尔上,预取指令可以在其数据到达之前退出。因此,成功开始执行的预取指令在此之后不会阻塞 CPU 管道。但是,请注意“成功执行”:如果预取指令在 L1 中未命中,它仍然需要一个行填充缓冲区 (MSHR),而在 Intel 上,如果该资源不可用,它将等待该资源。因此,如果您并行发出大量预取未命中,它们最终会等待填充缓冲区,这使得它们在这种情况下的行为与普通加载非常相似。

  • 在 AMD Zen [2] 上,如果没有可用的填充缓冲区,预取不会等待填充缓冲区。据推测,预取只是被丢弃了。因此,大量预取未命中的行为与英特尔大不相同:无论是否未命中,它们都会很快完成,但实际上不会提取许多相关的行。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...