共享内存多处理系统通常需要为缓存一致性生成大量流量。核心 A 写入缓存。Core B 稍后可能会读取相同的内存位置。因此,内核 A,即使它本来可以避免写入主内存,也需要向内核 B 发送通知,告诉 B 如果该地址正在缓存中,则该地址无效。
究竟什么时候需要这样做,这是一个复杂的问题。不同的 CPU 架构有不同的内存模型,这里上下文中的内存模型是一组关于观察到的事情发生的顺序的保证。内存模型越弱,A 在发送通知的确切时间就越放松对于 B,A 和 B 更容易并行做更多的事情。不同 CPU 架构的内存模型总结:https : //en.wikipedia.org/wiki/Memory_ordering#Runtime_memory_ordering
所有的讨论似乎是关于当失效发生时,什么为了事情发生英寸
但在我看来,在许多工作负载中,A 写入的大部分数据永远不会被 B 使用,因此如果可以完全消除那些缓存失效的总线流量会更好。专用于执行缓存一致性的硬件仍然需要存在,因为 A 和 B 有时需要共享数据,但写入共享总线是 CPU 可以做的更耗能的事情之一,并且电池寿命和散热通常是现在限制资源,因此减少总线流量将是一个有用的优化。有没有办法做到这一点?
从效率的角度来看,理想的情况是如果忽略总线流量是默认的(因为大多数写入的数据不与其他线程共享),并且您必须在需要缓存一致性的地方显式地发出内存屏障。另一方面,这可能是不可能的,因为假设它在 x86 或 ARM 上运行的现有代码量很大;有没有办法反过来,向 CPU 指示给定的缓存行永远不会对任何其他线程感兴趣?
我会对任何系统的答案感兴趣,但最特别是 x64、ARM 或 RISC-V 上 Linux 最常见的当前/未来服务器配置。
multithreading cpu-architecture memory-model memory-barriers cpu-cache
Write-Combine缓冲区是如何物理连接的?我已经看到了说明许多变体的方框图:
它是依赖于微架构的吗?
我正在尝试将一些高性能的汇编函数编写为练习,并且遇到了在运行程序时发生的奇怪的段错误,但在valgrind或nemiver中却没有.
基本上一个不应该运行的cmov,带有一个越界的地址,即使条件总是假的,也会让我发生段错误
我有一个快速和慢速的版本.缓慢的一直在工作.快速的一个工作,除非它收到一个非ascii字符,此时它崩溃可怕,除非我在adb或nemiver上运行.
ascii_flags只是一个128字节的数组(最后有一点空间),包含所有ASCII字符(alpha,numeric,printable等)的标志
这工作:
ft_isprint:
xor EAX, EAX ; empty EAX
test EDI, ~127 ; check for non-ascii (>127) input
jnz .error
mov EAX, [rel ascii_flags + EDI] ; load ascii table if input fits
and EAX, 0b00001000 ; get specific bit
.error:
ret
Run Code Online (Sandbox Code Playgroud)
但这不是:
ft_isprint:
xor EAX, EAX ; empty EAX
test EDI, ~127 ; check for non-ascii (>127) input
cmovz EAX, [rel ascii_flags + EDI] ; load ascii table if input fits
and EAX, flag_print ; get …Run Code Online (Sandbox Code Playgroud) 为什么我们不能将数据直接从内存位置移动到另一个内存位置.
请原谅我,如果我问一个愚蠢的问题,但我认为这是一个真实的情况,至少对于我遇到的问题(8085,8086 n 80386)
我并不是在寻找一种移动数据的解决方案(例如,使用movs n all),但实际上是这种异常的原因.
我有一个名为reorder.cc的源文件,如下所示:
void reorder(float *output, float *input) {
output[56] = input[0];
output[57] = input[1];
output[58] = input[2];
output[59] = input[3];
output[60] = input[4];
...
output[75] = input[19];
output[76] = input[20];
output[77] = input[21];
output[78] = input[22];
output[79] = input[23];
output[80] = input[24];
...
output[98] = 0;
output[99] = 0;
output[100] = 0;
output[101] = 0;
output[102] = 0;
output[103] = 0;
output[104] = 0;
output[105] = input[1];
output[106] = input[2];
output[107] = input[3];
output[108] = input[4];
output[109] = input[5];
output[110] = …Run Code Online (Sandbox Code Playgroud) 这个问题让我想知道,当前的现代编译器是否曾经发出REP MOVSB/W/D指令。
基于此讨论,似乎REP MOVSB/W/D在当前 CPU 上使用可能是有益的。
但无论我如何尝试,我都无法让当前的任何编译器(GCC 8、Clang 7、MSVC 2017 和 ICC 18)发出这条指令。
对于这个简单的代码,emit 可能是合理的REP MOVSB:
void fn(char *dst, const char *src, int l) {
for (int i=0; i<l; i++) {
dst[i] = src[i];
}
}
Run Code Online (Sandbox Code Playgroud)
但是编译器会发出一个未优化的简单字节复制循环,或者一个巨大的展开循环(基本上是内联的memmove)。是否有任何编译器使用此指令?
这与这个问题有关
但是考虑一下,在现代的英特尔CPU上,SEC阶段是以微码实现的,这意味着将进行检查,从而使用烧入的密钥来验证PEI ACM上的签名。如果不匹配,则需要执行某些操作;如果不匹配,则需要执行其他操作。假定这是作为MSROM过程实现的,则必须有一种分支方式,但是鉴于MSROM指令没有RIP。
通常,当一个分支错误地预测到将要采取的指令然后退出时,ROB将检查异常代码,并因此将指令长度添加到ROB行的RIP或仅使用下一个ROB条目的IP,这将导致前端在分支预测更新中恢复到该地址。有了BOB,此功能现在已借给跳转执行单元。显然,这与MSROM例程不可能发生,因为前端与此无关。
我的想法是,有一条特定的跳转指令,只有MSROM例程才能发出,它会跳转到MSROM中的其他位置,并且可以进行配置,以便始终预测不采用MSROM分支指令,并且在分支执行单元遇到此指令时指令并执行分支,它会产生异常代码,并可能将特殊的跳转目标连接到它,并且在退出时会发生异常。另外,执行单元可以处理它,并且可以使用BOB,但我的印象是BOB由分支指令RIP索引,然后还存在这样一个事实,即通常会在退休时处理生成MSROM代码的异常。分支错误预测不需要我不认为的MSROM,而是所有操作都在内部执行。
我问的是使用Irvine库在x86程序集中将字符串中的字符向右或向左移动的最佳方法是什么.有一个例子:ABCD - > DABC等等
我写了这段代码,但它给了我错误的结果.
r1:
push ecx
mov ecx,lengthof arr
mov al,[esi+lengthof arr]
mov bl,[esi]
mov [esi],al
mov [esi+1],bl
inc esi
innr1:
mov al,[esi]
mov bl,[esi+1]
mov [esi],al
inc esi
loop innr1
pop ecx
loop r1
Run Code Online (Sandbox Code Playgroud)