相关疑难解决方法(0)

如何通过按顺序提交load-> store重新排序?

ARM允许重新排序加载后续存储,以便以下伪代码:

// CPU 0 | // CPU 1 temp0 = x; | temp1 = y; y = 1; | x = 1;

可以导致temp0 == temp1 == 1(并且,这在实践中也是可观察到的).我无法理解这是怎么发生的; 似乎有序提交会阻止它(这是我的理解,它存在于几乎所有的OOO处理器中).我的理由是"在提交之前,负载必须具有其值,它在存储之前提交,并且在提交之前,存储的值不会对其他处理器可见."

我猜我的一个假设肯定是错的,并且必须遵循下列之一:

  • 说明不需要提交一路有序.稍后的存储可以安全地提交并在之前的加载之前变得可见,只要在存储提交核心时可以保证先前的加载(以及所有中间指令)不会触发异常,并且加载的地址是保证与商店不同.

  • 负载可以在其值已知之前提交.我不知道如何实现这一点.

  • 商店在提交之前可以显示.也许某个内存缓冲区允许将存储转发到另一个线程的加载,即使负载先前已加入?

  • 还有别的吗?

有许多假设的微体系结构特征可以解释这种行为,但我最好的是那些实际存在于现代弱有序CPU中的那些.

arm cpu-architecture memory-barriers

6
推荐指数
1
解决办法
546
查看次数

C / ++。为什么将volatile上的简单整数加法转换为gcc和clang上不同的asm指令?

我写了一个简单的循环:

int volatile value = 0;

void loop(int limit) {
  for (int i = 0; i < limit; ++i) { 
      ++value;
  }
}
Run Code Online (Sandbox Code Playgroud)

我用gcc和clang(-O3 -fno-unroll-loops)进行了编译,得到了不同的输出。它们++value部分不同:

铛:

  add dword ptr [rip + value], 1 # ++value
  add edi, -1                    # --limit
  jne .LBB0_1                    # if limit > 0 then continue looping
Run Code Online (Sandbox Code Playgroud)

gcc:

  mov eax, DWORD PTR value[rip] # copy value to a register
  add edx, 1                    # ++i
  add eax, 1                    # increment a copy of value …
Run Code Online (Sandbox Code Playgroud)

c++ assembly gcc volatile clang

2
推荐指数
1
解决办法
160
查看次数

为什么在执行指针追逐时这条跳转指令如此昂贵?

我有一个执行指针追踪的程序,我正在尝试尽可能地优化指针追踪循环。我注意到perf record检测到函数中大约 20% 的执行时间myFunction()用于执行跳转指令(用于在读取特定值后退出循环)。

需要注意的一些事项:

  • 指针追踪路径可以轻松放入 L1 数据缓存
  • 使用__builtin_expect以避免分支预测错误的成本没有显着影响

perf record 有以下输出:

Samples: 153K of event 'cycles', 10000 Hz, Event count (approx.): 35559166926                                                                                                                                                               
myFunction  /tmp/foobar [Percent: local hits]                                                                                                                                                                            
Percent?      endbr64                                                                                                                                                                                                                       
      ...
 80.09 ?20:   mov     (%rdx,%rbx,1),%ebx                                                                                                                                                                                                    
  0.07 ?      add     $0x1,%rax                                                                                                                                                                                                             
       ?      cmp     $0xffffffff,%ebx                                                                                                                                                                                                      
 19.84 ?    ? jne     20                                                                                                                                                                                                                    
      ...
Run Code Online (Sandbox Code Playgroud)

我希望在这个循环中花费的大部分周期都用于从内存中读取值,这是由 perf 确认的。我还希望剩余的周期在执行循环中剩余的指令时会有些均匀地花费。相反, perf 报告的是剩余周期的很大一部分用于执行跳转。

我怀疑通过了解用于执行这些指令的微操作,我可以更好地了解这些成本,但我对从哪里开始有点迷茫。

x86 assembly pointers cpu-architecture perf

2
推荐指数
1
解决办法
100
查看次数

“perf annotate”内存加载/存储时间报告不一致

我很难解释英特尔性能事件报告。

\n

考虑以下主要读/写内存的简单程序:

\n
#include <stdint.h>\n#include <stdio.h>\n\nvolatile uint32_t a;\nvolatile uint32_t b;\n\nint main() {\n  printf("&a=%p\\n&b=%p\\n", &a, &b);\n  for(size_t i = 0; i < 1000000000LL; i++) {\n    a ^= (uint32_t) i;\n    b += (uint32_t) i;\n    b ^= a;\n  }\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我用gcc -O2以下命令编译它并运行perf:

\n
#include <stdint.h>\n#include <stdio.h>\n\nvolatile uint32_t a;\nvolatile uint32_t b;\n\nint main() {\n  printf("&a=%p\\n&b=%p\\n", &a, &b);\n  for(size_t i = 0; i < 1000000000LL; i++) {\n    a ^= (uint32_t) i;\n    b += (uint32_t) i;\n    b ^= a;\n  }\n …
Run Code Online (Sandbox Code Playgroud)

performance assembly x86-64 micro-optimization perf

2
推荐指数
1
解决办法
394
查看次数