【问题标题】:What happens if an invalid address is prefetched?如果预取无效地址会怎样?
【发布时间】:2016-10-19 10:02:48
【问题描述】:

简单的 MWE:

int* ptr = (int*)malloc(64 * sizeof(int));
_mm_prefetch((const char*)(ptr + 64), _MM_HINT_0);
  1. 这是已定义的行为还是未定义的行为?
  2. 这会引发信号并中止程序运行吗?

我之所以问,是因为我可以在编译器生成的代码中看到这样的预取,在循环中预取是在不检查地址的情况下完成的(存储在 rbx 中):

400e73:       49 83 c5 40             add    r13,0x40
400e77:       62 f1 f9 08 28 03       vmovapd zmm0,ZMMWORD PTR [rbx]
400e7d:       4d 3b ec                cmp    r13,r12
400e80:       62 d1 f9 08 eb 4d ff    vporq  zmm1,zmm0,ZMMWORD PTR [r13-0x40]
400e87:       90                      nop
400e88:       62 d1 78 08 29 4d ff    vmovaps ZMMWORD PTR [r13-0x40],zmm1
400e8f:       72 03                   jb     400e94 <main+0x244>
400e91:       49 89 c5                mov    r13,rax
400e94:       62 f1 78 08 18 53 1d    vprefetch1 [rbx+0x740]
400e9b:       ff c1                   inc    ecx
400e9d:       62 f1 78 08 18 4b 02    vprefetch0 [rbx+0x80]
400ea4:       48 83 c3 40             add    rbx,0x40
400ea8:       81 f9 00 00 10 00       cmp    ecx,0x100000
400eae:       72 c3                   jb     400e73 <main+0x223>

【问题讨论】:

  • 你看过文档了吗?
  • 英特尔内部指南没有说明任何内容。也不是英特尔内部参考。也不是英特尔至强融核指令集参考(反汇编代码是为 KNC 编译的)。据我所知。我在每个程序员都应该知道的关于内存的知识中只找到了这句话:程序可以在程序中的任何指针上使用 _mm_prefetch 内在函数。大多数处理器(当然是所有 x86 和 x86-64 处理器)都会忽略无效指针导致的错误,从而大大简化程序员的工作。
  • 好点。感谢您在问这个问题之前先看看。有趣的是,如此重要的细节仍未记录在案!
  • 请注意:至强融核指令集参考未列出 VPREFETCHx 的页面错误 (PF) 异常。对于具有内在函数的通用编程,因此应该通过检查所有可能架构的指令引用来找到答案。

标签: c caching assembly disassembly prefetch


【解决方案1】:

首先,编译器执行它或您执行它在理论上是非常不同的事情。仅仅因为它看起来等效并不能使它如此,因此允许编译器使用任何有效的脏技巧,无论它们是可表达的还是在完全标准的 C 中定义的。

当然,预取不会产生信号*,如果它产生了,它几乎是无用的。但是,对于某些无效指针,它可能会非常慢,具体取决于它们是否触发 TLB 未命中。所以编译器可以安全地使用它,但它不应该不分青红皂白地使用它。

现在使用指针算法来创建越界指针(除了刚刚结束)在理论上是 UB,但是当应用于指针时,它是一种无论如何都可以正常工作的 UB(对于平面内存,它只是一个加法,它可能失败的唯一方法是如果编译器不遗余力地检测它,这意味着它必须对动态大小进行推理)。显然,上述情况必须得到声称支持 SSE 内在函数的编译器的支持,否则您无法合理地使用预取,正如这个答案所证明的那样(并且他们必须在标准之上做出更多额外的保证)。

* 来自手册:

PREFETCHh 指令只是一个提示,并不影响程序行为。

信号会影响程序行为,因此无法生成。

【讨论】:

  • 虽然创建越界指针在常见架构上表现良好,但未来的编译器可能会假设如果您计算一个指针,它是有效的并且编译器可以提前取消引用它/ 推测性地,因此如果它无效,则会导致未定义的行为。
  • @FUZxxl IA64 编译器已经这样做了,但那里没问题。尽管如此,在使用该指针进行预取的情况下,它不能像那样至少中断,否则它只会被破坏。
  • UB?这是硬件,而不是语言标准。
  • 这也是一个 hack,_mm_prefetch 不是 C/C++ 标准的一部分。我询问了更多关于 CPU 的作用,也许 C 中的 MWE 不是一个好主意。但是,正如您所指出的,根据标准,即使 C++ 中的越界指针也是 UB(最后一个特殊情况除外)。
  • 预取无效地址是否会影响性能?
猜你喜欢
  • 2018-06-06
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
  • 2012-03-20
  • 2011-10-21
  • 1970-01-01
相关资源
最近更新 更多