在最近的x86体系结构上,失败的存储到加载转发的成本是多少?
特别是,由于加载与先前的存储部分重叠,或者由于先前的加载或存储跨越了导致转发失败的某些对齐边界而失败的存储到加载转发。
当然存在延迟成本:它有多大?是否还存在吞吐量成本,例如,失败的存储到加载转发是否使用了其他加载和存储甚至其他非内存操作不可用的额外资源?
当存储的所有部分都来自存储缓冲区时,与存储缓冲区和L1混合的情况相比,是否存在差异?
在英特尔桑迪桥系列中,商店转发摊位不能与其他商店转发摊位一起进行管道传输。即使在独立地址上,它们也会在吞吐量方面发生冲突。请参阅商店转发示例,常春藤桥的一个更有趣的实验,以及Alex对咖啡湖(Skylake衍生物)的答案。
但是失败的(慢速路径)存储转发似乎不会阻碍成功的存储转发。在Skylake (i7-6700k)上测试时,我做了一个测试循环,其中包括两个依赖链:
;; nasm -felf64 testloop.asm
;; ld -o testloop testloop.o
;; taskset -c 3 perf stat -etask-clock:u,context-switches:u,cpu-migrations:u,page-faults:u,cycles:u,branches:u,instructions:u,uops_issued.any:u,uops_executed.thread:u,idq.dsb_uops:u -r1 ./testloop
default rel
%ifdef __YASM_VER__
CPU Conroe AMD
CPU Skylake AMD
%else
%use smartalign
alignmode p6, 64
%endif
global _start
_start:
lea rdi, [buf]
mov ebp, 100000000
align 64
.loop:
mov [rdi+64], ecx
; mov rcx, [rdi+64] ; reload here: 16c. Or 16.8 if we *also* reload after the %rep block
%rep 3
mov [rdi], eax
mov eax, [rdi]
%endrep
mov rcx, [rdi+64] ; reload here: 15c
dec ebp
jnz .loop
.end:
;;NASM-only, not YASM: %if __BITS__ == 32
%ifidn __OUTPUT_FORMAT__, elf32
mov eax,1
xor ebx,ebx
int 0x80 ; sys_exit(0) 32-bit ABI
%else
xor edi,edi
mov eax,231 ; __NR_exit_group from /usr/include/asm/unistd_64.h
syscall ; sys_exit_group(0)
%endif
section .bss
align 4096
buf: resb 4096
性能结果:
$ t=testloop; asm-link -dn "$t".asm && taskset -c 3 perf stat --all-user -etask-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,uops_issued.any,uops_executed.thread,ld_blocks.store_forward,resource_stalls.sb -r2 ./"$t"
+ nasm -felf64 -Worphan-labels testloop.asm
+ ld -o testloop testloop.o
testloop: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 8d 3d f9 0f 00 00 lea rdi,[rip+0xff9] # 402000 <__bss_start>
401007: bd 00 e1 f5 05 mov ebp,0x5f5e100
40100c: 0f 1f 84 00 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
401014: 0f 1f 84 00 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
40101c: 0f 1f 84 00 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
401024: 0f 1f 84 00 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
40102c: 0f 1f 84 00 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
401034: 0f 1f 84 00 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
40103c: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
0000000000401040 <_start.loop>:
401040: 89 4f 40 mov DWORD PTR [rdi+0x40],ecx
401043: 89 07 mov DWORD PTR [rdi],eax
401045: 8b 07 mov eax,DWORD PTR [rdi]
401047: 89 07 mov DWORD PTR [rdi],eax
401049: 8b 07 mov eax,DWORD PTR [rdi]
40104b: 89 07 mov DWORD PTR [rdi],eax
40104d: 8b 07 mov eax,DWORD PTR [rdi]
40104f: 48 8b 4f 40 mov rcx,QWORD PTR [rdi+0x40]
401053: ff cd dec ebp
401055: 75 e9 jne 401040 <_start.loop>
0000000000401057 <_start.end>:
401057: 31 ff xor edi,edi
401059: b8 e7 00 00 00 mov eax,0xe7
40105e: 0f 05 syscall
Performance counter stats for './testloop' (two runs):
385.85 msec task-clock # 0.999 CPUs utilized ( +- 0.02% )
0 context-switches # 0.000 /sec
0 cpu-migrations # 0.000 /sec
2 page-faults # 5.183 /sec
1,503,701,305 cycles # 3.897 GHz ( +- 0.01% )
1,000,000,130 instructions # 0.67 instructions per cycle ( +- 0.00% )
900,084,383 uops_issued.any # 2.333 G/sec ( +- 0.00% )
1,300,091,135 uops_executed.thread # 3.369 G/sec ( +- 0.00% )
99,933,928 ld_blocks.store_forward # 258.998 M/sec ( +- 0.02% )
443,686,304 resource_stalls.sb # 1.150 G/sec ( +- 4.87% )
0.386139 +- 0.000119 seconds time elapsed ( +- 0.03% )
这并不是一个完整的答案,但仍然证明了惩罚是可见的。
MSVC 2022 基准测试,编译器与 /标准:c 最新
。
#include <chrono>
#include <iostream>
struct alignas(16) S
{
char* a;
int* b;
};
extern "C" void init_fused_copy_unfused(int n, S & s2, S & s1);
extern "C" void init_fused_copy_fused(int n, S & s2, S & s1);
extern "C" void init_unfused_copy_unfused(int n, S & s2, S & s1);
extern "C" void init_unfused_copy_fused(int n, S & s2, S & s1);
int main()
{
using namespace std::chrono;
S s1, s2;
constexpr int N = 1'000'000'000;
auto t1 = system_clock::now();
init_fused_copy_fused(N, s2, s1);
auto t2 = system_clock::now();
init_fused_copy_unfused(N, s2, s1);
auto t3 = system_clock::now();
init_unfused_copy_fused(N, s2, s1);
auto t4 = system_clock::now();
init_unfused_copy_unfused(N, s2, s1);
auto t5 = system_clock::now();
std::cout
<< "init fused copy fused " << duration_cast<duration<double>>(t2 - t1) << "\n"
<< "init fused copy unfused " << duration_cast<duration<double>>(t3 - t2) << "\n"
<< "init unfused copy fused " << duration_cast<duration<double>>(t4 - t3) << "\n"
<< "init unfused copy unfused " << duration_cast<duration<double>>(t5 - t4) << "\n";
}
.code
c db 0
i dd 0
s dq byte ptr [c], dword ptr [i]
ALIGN 16
init_fused_copy_fused PROC
movups xmm0,xmmword ptr [s]
movups xmmword ptr [r8],xmm0
movups xmm1,xmmword ptr [r8]
movups xmmword ptr [rdx], xmm1
dec ecx
jnz init_fused_copy_fused
ret
init_fused_copy_fused ENDP
ALIGN 16
init_unfused_copy_fused PROC
lea rax, byte ptr [c]
mov qword ptr[r8], rax
lea rax, dword ptr [i]
mov qword ptr[r8 + 8], rax
movups xmm1,xmmword ptr [r8]
movups xmmword ptr [rdx], xmm1
dec ecx
jnz init_unfused_copy_fused
ret
init_unfused_copy_fused ENDP
ALIGN 16
init_fused_copy_unfused PROC
movups xmm0,xmmword ptr [s]
movups xmmword ptr [r8],xmm0
mov rax, qword ptr[r8]
mov qword ptr[rdx], rax
mov rax, qword ptr[r8 + 8]
mov qword ptr[rdx +8], rax
dec ecx
jnz init_fused_copy_unfused
ret
init_fused_copy_unfused ENDP
ALIGN 16
init_unfused_copy_unfused PROC
lea rax, byte ptr [c]
mov qword ptr[r8], rax
lea rax, dword ptr [i]
mov qword ptr[r8 + 8], rax
mov rax, qword ptr[r8]
mov qword ptr[rdx], rax
mov rax, qword ptr[r8 + 8]
mov qword ptr[rdx +8], rax
dec ecx
jnz init_unfused_copy_unfused
ret
init_unfused_copy_unfused ENDP
END
init fused copy fused 0.664739s
init fused copy unfused 0.935631s
init unfused copy fused 4.34326s
init unfused copy unfused 1.02741s
CPU:Intel(R)Core(TM)i7-8750H CPU@2.20GHz 2.21 GHz
我对结果的解释如下:
最后一个2字节加载从紧邻的前一个存储区中获取第二个字节,但从前一个存储区中获取第一个字节。这个加载可以被存储转发吗,还是需要等到前面的两个存储都提交到L1? 请注意,通过这里的存储转发,我包含了任何机制,这些机制可以满足来自仍然在存储缓冲区中的存储的读取,而不是等待它们提交到L1,即使这是一个比“从单个存储转发”的最佳情况更慢的路径。
我正在使用react-native-firebase与我们的Firebase帐户一起进行身份验证、firestore和存储。尝试将照片上载到存储区失败,出现未知错误。以下是尝试的代码: 在iOS模拟器中测试,并使用调试器检测错误,我只是返回了这个错误: https://github.com/invertase/react-native-firebase/issues/1177 https://gi
我在尝试将文件上载到blob存储时遇到此错误。在本地主机上运行和在Azure函数中运行时都会出现错误。 我的连接字符串如下所示:DefaultEndpoint sProtocol=https; AcCountName=xxx; AcCountKey=xxx; Endpoint Suffix=core.windows.net 身份验证信息的格式不正确。检查授权标头的值。时间:2021 10月14日1
我有一个git存储库,它完全存在于我的PC中的本地。我想在github.com上创建它的远程克隆。怎么做呢?
我记得在我的体系结构类中,假设一级缓存命中率为1个周期(即与寄存器访问时间相同),但在现代x86处理器上,这是真的吗? L1缓存命中需要多少个周期?它与注册访问相比如何?
> 出错原因:任务“:app:mergereleaseResources”执行失败。 [drawable-HDPI-v4/node_modules_reactnavigation_stack_src_views_assets_backicon]C:\users\victo\documents\git\melhor\app-user\android\app\src\srp\src\src\src\s