在总存储顺序 (TSO) 内存一致性模型下,x86 cpu 将有一个写入缓冲区来缓冲写入请求,并且可以为来自写入缓冲区的重新排序的读取请求提供服务。并且它说写缓冲区中的写请求将退出并以FIFO顺序向缓存层次结构发出,这与程序顺序相同。
我很好奇:
为了服务从写缓冲区发出的写请求,一级缓存控制器是否处理写请求,完成写请求的缓存一致性,并按照与发出顺序相同的顺序将数据插入一级缓存?
我有兴趣计算三角形序列1,这是一对对的序列,(i, j): (0, 0), (1, 0), (1, 1), (2, 0), (2, 1) ...
它们迭代所有(i, j)具有限制的对i >= j.具有限制i> j的相同序列也是有趣的.
除了其他之外,这些序列表示从n元素集(对于序列直到(n, n)2)或矩阵3的下部三角元素的索引选择2(可能相同)元素的所有方式.i单独的值序列是OEIS中的A003056,而j单独的是A002262.该序列经常出现在组合算法中,其中它们的性能可能是关键的.
在序列中生成下一个值的简单但分支的方法是:
if (i == j) {
j = 0;
i++;
} else {
j++;
}
}
Run Code Online (Sandbox Code Playgroud)
然而,当计算序列的初始元素时,这会在检查条件时遭受许多错误预测(i == j)- 通常每次i增加一次误预测.随着序列的增加,误预测的数量变得越来越低,因为i随着频率的降低而递增,因此j++分支占主导地位且得到很好的预测.尽管如此,某些类型的组合搜索会反复迭代序列中的小项,因此我正在寻找一种无分支方法或其他方法,这些方法可能会减少错误预测.
对于许多用途,序列的顺序并不重要,因此如果它导致更好的解决方案,则生成不同于上述顺序的值是允许的.例如,j可以倒计时而不是倒数:(0, 0), (1, 1), (1, 0), (2, 2), …
language-agnostic performance sequences bit-manipulation oeis
是否可以al, ah, bl, bh, r8b在x86-64中的索引寻址模式下使用8位寄存器()?例如:
mov ecx, [rsi + bl]
mov edx, [rdx + dh * 2]
Run Code Online (Sandbox Code Playgroud)
特别是,这将允许您使用寄存器的底部8位作为0-255偏移量,这对某些内核可能很有用.
我倾注了英特尔的手册,他们并没有明确说明这一点,但他们给出的所有例子都只有32位或64位的基址和索引寄存器.在32位代码中,我只看到16位或32位寄存器.看一下mod-r/m和SIB字节编码的细节似乎也指向"不",但这足够复杂,有足够的角落情况,我不确定我是否正确.
我最感兴趣的是x86-64行为,但当然如果它只能在32位模式下我想知道.
作为一个太小而且与之相关的附加问题,可以使用16位寄存器作为基数还是索引?例如,mov rax, [rbx + cx].我的调查指出了与上面基本相同的答案:可能不是.
想象一下,我想让一个主线程和一个辅助线程作为两个超线程在同一物理核心上运行(可能通过强制它们的亲和力来大致确保这一点)。
主线程将执行重要的高 IPC、CPU 密集型工作。除了定期更新主线程将定期读取的共享时间戳值之外,辅助线程不应该执行任何操作。更新频率是可配置的,但可以快至 100 MHz 或更高。如此快速的更新或多或少排除了基于睡眠的方法,因为阻塞睡眠太慢,无法在 10 纳秒 (100 MHz) 周期内睡眠/唤醒。
所以我想要忙碌的等待。然而,繁忙等待应该对主线程尽可能友好:使用尽可能少的执行资源,从而给主线程增加尽可能少的开销。
我想这个想法将是一个长延迟指令,不使用很多资源,就像pause并且也有一个固定且已知的延迟。这将使我们能够校准“睡眠”周期,因此甚至不需要读取时钟(如果想要更新周期,P我们只需发出P/L这些指令以进行校准的忙睡眠。但pause不满足后一个标准,因为它的延迟各不相同很多1 .
第二种选择是使用长延迟指令,即使延迟未知,并且在每条指令之后执行一个rdtsc或一些其他时钟读取方法(clock_gettime等)来查看我们实际睡了多长时间。看起来它可能会大大减慢主线程的速度。
还有更好的选择吗?
1还有pause一些关于防止推测性内存访问的特定语义,这可能有利于也可能没有利于这个同级线程场景,因为我实际上并不处于自旋等待循环中。
是否可以使用最近的Intel x86芯片上的性能计数器来衡量成功的存储转发操作的数量?
我看到ld_blocks.store_forward哪些措施无法存储转发的事件,但我很清楚是否可以测量成功案例.
我想在C程序和要由nasm或yasm编译的程序集文件中包括很多魔术数字。
在纯C语言中,文件看起来像一系列定义,例如:
#define BLESS 55378008
#define ANSWER 42
...
Run Code Online (Sandbox Code Playgroud)
在nasm或yasm中,相同的include可以实现为:
%define BLESS 55378008
%define ANSWER 42
...
Run Code Online (Sandbox Code Playgroud)
唯一的不同是C和nasm 的define:前面的主角。#%
有什么办法可以编写一个polygot include,它可以让我将它同时包含在C和nasm中,并且只列出一次常量?
是的,我知道我可以使用sed或其他方法从另一个文件生成一个文件。
考虑以下returnsNull函数并使用泛型类型调用它:
public static <T> List<T> returnNull(Class<? extends T> clazz) {
return null;
}
public static void main( String[] args )
{
List<AtomicReference<?>> l = returnNull(AtomicReference.class);
}
Run Code Online (Sandbox Code Playgroud)
Eclipse编译器在设置为Java 8时接受它,但javac在Java 8中拒绝它:
incompatible types: cannot infer type-variable(s) T
(argument mismatch; java.lang.Class<java.util.concurrent.atomic.AtomicReference> cannot be converted to java.lang.Class<? extends java.util.concurrent.atomic.AtomicReference<?>>)
Run Code Online (Sandbox Code Playgroud)
底层差异似乎是给定两个参数化类型,P1<T>并且P2<T>Eclipse允许从使用原始内部类型参数化的外部类型转换为P1<P2>使用无界通配符的内部类型的下限参数化的外部类型P1<? extends P2<?>>.javac没有.
这不仅仅是一个理论上的思考:如果这个代码被接受,它将解决我的泛型过滤问题.
谁是对的?
是否允许单个访问跨越x86 1之间0和之间的边界?0xFFFFFF...
例如,假设eax(rax在64位中)为零,则允许以下访问:
mov ebx, DWORD [eax - 2]
Run Code Online (Sandbox Code Playgroud)
如果答案不同,我对x86(32位)和x86-64都很感兴趣.
1当然,鉴于该区域已在您的流程中映射等.
多年来,x86 CPU 都支持该rdtsc指令,该指令读取当前 CPU 的“时间戳计数器”。这个计数器的确切定义随着时间的推移而改变,但在最近的 CPU 上,它是一个相对于挂钟时间以固定频率递增的计数器,因此它作为快速、准确时钟或测量时间的构建块非常有用由小段代码获取。
关于rdtsc指令的一个重要事实没有以任何特殊方式与周围的代码一起排序。像大多数指令一样,它可以相对于与它没有依赖关系的其他指令自由地重新排序。这实际上是“正常的”,对于大多数指令,它只是一种使 CPU 更快的几乎不可见的方式(这只是一种长篇大论的无序执行方式)。
因为rdtsc它很重要,因为这意味着您可能没有为您期望的代码计时。例如,给定以下序列1:
rdtsc
mov ecx, eax
mov rdi, [rdi]
mov rdi, [rdi]
rdtsc
Run Code Online (Sandbox Code Playgroud)
您可能希望rdtsc测量追逐加载负载的两个指针的延迟mov rdi, [rdi]。然而,在实践中,即使这两个加载都需要查看时间(如果它们在缓存中丢失,则为 100 秒),您将获得相当小的读取值rdtsc。问题是第二个rdtsc不等待加载完成,它只是乱序执行,所以你没有按你认为的时间间隔计时。也许这两rdtsc条指令实际上甚至在第一次加载开始之前就执行了,这取决于rdi在此示例之前的代码中是如何计算的。
到目前为止,这听起来更像是对一个没人问的问题的回答,而不是一个真正的问题,但我已经到了那里。
您有两个基本用例rdtsc:
作为一种精确的计时机制,例如,在微基准测试中。在这种情况下,您通常会rdtsc根据lfence说明防止重新订购。对于上面的示例,您可能会执行以下操作:
lfence
rdtsc
lfence
mov ecx, eax
...
lfence
rdtsc
Run Code Online (Sandbox Code Playgroud)
确保定时指令 ( ...) 不会逃逸到定时区域之外,并确保来自时间区域内的指令不会进入(可能问题不大,但它们可能会与您想要的代码竞争资源测量)。
多年后,英特尔看不起我们这些可怜的程序员,并提出了一条新指令:rdtscp. 就像rdtsc它返回时间戳计数器的读数一样,这家伙做了更多的事情:它使用时间戳读数原子地读取特定于内核的 MSR …
在 x86-64 SIMD 指令名称以及可用于从 C/C++ 访问它们的内在函数中,您可以找到术语shuffle(例如_mm_shuffle_epi32)和permute(例如_mm_permute_pd)。
从表面上看,它们似乎都用于数据移动的东西。有什么不同?