在x86 CPU中,控制寄存器编号为0.该寄存器的第16位表示"写保护"设置.如果该位清零,CPU可以覆盖只读数据.(在页表条目中配置)在内存中.如果该位置1,CPU不能覆盖内存中的RO数据.
我很好奇的是"这个位的最初目的是什么?" "为什么x86 CPU需要这个?"
我正在对代码的性能关键部分进行微优化,并且遇到了指令序列(在AT&T语法中):
add %rax, %rbx
mov %rdx, %rax
mov %rbx, %rdx
Run Code Online (Sandbox Code Playgroud)
我以为我终于有一个用例xchg可以让我刮一个指令并写:
add %rbx, %rax
xchg %rax, %rdx
Run Code Online (Sandbox Code Playgroud)
然而,根据Agner Fog的指令表,我发现这xchg是一个3微操作指令,在Sandy Bridge,Ivy Bridge,Broadwell,Haswell甚至Skylake上有2个周期延迟.3个完整的微操作和2个周期的延迟!3微操作抛出了我的4-1-1-1的节奏和2周期延迟使得它比在最好的情况下原来的,因为在原来的并行执行可能最后2条指令差.
现在......我得知CPU可能会将指令分解为相当于以下内容的微操作:
mov %rax, %tmp
mov %rdx, %rax
mov %tmp, %rdx
Run Code Online (Sandbox Code Playgroud)
哪里tmp是匿名内部寄存器,我想最后两个微操作可以并行运行,因此延迟是2个周期.
鉴于寄存器重命名发生在这些微架构上,但对我来说这是以这种方式完成的.为什么寄存器重命名器不会交换标签?理论上,这将只有1个周期(可能是0?)的延迟,并且可以表示为单个微操作,因此它会便宜得多.
我正在检查英特尔的"whatif"网站及其事务内存编译器(每个线程必须进行原子提交或回滚系统的内存,就像数据库一样).
这似乎是替换锁和互斥锁的一种有前途的方法,但我找不到很多推荐.这里有人有任何意见吗?
有没有办法在运行Mac OS X的Core i7 mac上以编程方式禁用Turbo Boost?我需要能够在代码优化期间进行基准测试等.如果失败了,任何可以禁用/启用Turbo Boost的实用程序,即使它需要重新启动,也会很有用.
在SO上有一个相关的问题(不是特定于Mac):如何临时关闭Turbo Boost?但即使对于个人电脑来说,似乎也无法以编程方式/即时方式进行此操作?
有没有人知道如何开始编写程序来访问英特尔内存控制器中心,例如英特尔5400 mch或英特尔p45 mch?我是否需要英特尔的Parallel Composer工作室才能开始使用?我可以简单地开始使用Visual Studio C++中的C/C++编程吗?如果是这样,我该如何开始?
我有几个问题悬而未决几天没有答案.问题出现了,因为我有一个OpenMP和一个同样问题的OpenCL实现.OpenCL在GPU上运行完美,但在CPU上运行时性能降低了50%(与OpenMP实现相比).一篇文章已经在讨论OpenMP和OpenCL表演之间的区别,但它没有回答我的问题.目前我面临以下问题:
1)拥有" 矢量化内核 "(就英特尔离线编译器而言)真的那么重要吗?
有一个类似的帖子,但我认为我的问题更为笼统.
据我了解:矢量化内核不一定意味着编译后的二进制文件中没有向量/ SIMD指令.我检查了我的内核的汇编代码,并且有一堆SIMD指令.向量化内核意味着通过使用SIMD指令,您可以在一个CPU线程中执行4(SSE)或8(AVX)OpenCL"逻辑"线程.只有当所有数据连续存储在内存中时,才能实现此目的.但谁拥有如此完美排序的数据?
所以我的问题是:在这个意义上让内核"矢量化"真的很重要吗?
当然,它可以提高性能,但如果内核中的大多数计算密集型部分都是通过向量指令完成的,那么您可能会接近"最佳"性能.我认为我的问题的答案在于内存带宽.可能矢量寄存器更适合高效的存储器访问.在这种情况下,内核参数(指针)必须进行矢量化.
2)如果我在CPU上的本地内存中分配数据,它将在哪里分配?OpenCL将L1缓存显示为本地内存,但它显然与GPU本地内存上的内存类型不同.如果它存储在RAM /全局存储器中,那么将数据复制到其中是没有意义的.如果它在缓存中,其他一些进程可能会将其刷新......所以这也没有意义.
3)"逻辑"OpenCL线程如何映射到真正的CPU软件/硬件(Intel HTT)线程?因为如果我有短的运行内核并且内核像TBB(线程构建块)或OpenMP那样分叉,那么fork开销将占主导地位.
4)什么是线程叉开销?是否为每个"逻辑"OpenCL线程分叉了新的CPU线程,或者是一次分叉的CPU线程,并重用于更"逻辑"的OpenCL线程?
我希望我不是唯一一个对这些小事感兴趣的人,你们中的一些人现在可能会遇到这些问题.先感谢您!
UPDATE
3)目前OpenCL开销比OpenMP更重要,因此高效的运行时执行需要大量内核.在Intel OpenCL中,工作组映射到TBB线程,因此1个虚拟CPU核心执行整个工作组(或线程块).工作组使用3个嵌套for循环实现,如果可能,最内层循环被矢量化.所以你可以想象它是这样的:
#pragam omp parallel for
for(wg=0; wg < get_num_groups(2)*get_num_groups(1)*get_num_groups(0); wg++) {
for(k=0; k<get_local_size(2); k++) {
for(j=0; j<get_local_size(1); j++) {
#pragma simd
for(i=0; i<get_local_size(0); i++) {
... work-load...
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果最内部的循环可以进行矢量化,则可以使用SIMD步骤:
for(i=0; i<get_local_size(0); i+=SIMD) {
Run Code Online (Sandbox Code Playgroud)
4)每个TBB线程在OpenCL执行期间分叉一次并重用它们.每个TBB线程都绑定到一个虚拟核心,即.在计算过程中没有线程迁移.
我也接受@ natchouf的回答.
我想在XeonE5 Sandy Bridge上使用基于精确事件的采样(PEBS)来记录特定事件的所有地址(例如缓存未命中).
但是,Core TM i7处理器和Intel®XeonTM5500处理器性能分析指南(第24页)包含以下警告:
由于PEBS机制在指令完成时捕获寄存器的值,因此无法重建以下类型的加载指令(Intel asm约定)的解除引用的地址.
MOV RAX, [RAX+const]
这种指令主要与指针追逐相关联.
mystruc = mystruc->next;
这是捕获存储器指令地址的这种方法的重大缺点.
根据objdump,我在程序中有许多该表单的加载指令.有什么办法可以避免吗?
由于这是一个特定于英特尔的问题,解决方案不必以任何方式移植,它只需要工作.我的代码是用C语言编写的,我理想地寻找编译器级解决方案(gcc或icc),但欢迎任何建议.
一些例子:
mov 0x18(%rdi),%rdi
mov (%rcx,%rax,8),%rax
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,该指令退役之后(因此当我看到的寄存器值来找出我装到/从)的地址(分别的值%rdi + 18和%rcx + 8 * %rax这些实施例中)通过的结果重写mov.
在最新的 x86 架构上,存储到加载转发失败的成本是多少?
特别是,存储到加载转发会失败,因为加载部分与较早的存储重叠,或者因为较早的加载或存储跨越某些导致转发失败的对齐边界。
当然存在延迟成本:它有多大?是否还存在吞吐量成本,例如,失败的存储到加载转发是否使用了其他加载和存储甚至其他非内存操作无法使用的额外资源?
当存储的所有部分都来自存储缓冲区时,与混合存储缓冲区和 L1 的情况相比,是否有区别?
该文件的vzeroall出现不一致。散文说:
该指令将所有 XMM 或 YMM 寄存器的内容清零。
然而,下面的伪代码表明,在 64 位模式下,只有ymm0通过ymm15的寄存器会受到影响:
IF (64-bit mode)
limit ?15
ELSE
limit ? 7
FOR i in 0 .. limit:
simd_reg_file[i][MAXVL-1:0] ? 0
Run Code Online (Sandbox Code Playgroud)
在AVX-512支持的机器清理到ymm15是不一样的清算“所有”,因为ymm16通过ymm31存在。
散文或伪代码是否正确?
好吧,在Intel 的内在指南中指出,名为“sqrtsd”的指令的延迟为 18 个周期。
我用自己的程序对其进行了测试,例如,如果我们将 0.15 作为输入,则它是正确的。但是当我们取 256(或任何 2^x)个数字时,延迟只有 13。这是为什么呢?
我的一个理论是,由于 13 是“sqrtss”的延迟,它与“sqrtsd”相同,但在 32 位浮点上完成,那么也许处理器足够聪明,可以理解 256 可以适应 32 位,因此使用该版本而 0.15 需要完整的 64 位,因为它不能以有限的方式表示。
我正在使用内联汇编来完成它,这是使用 gcc -O3 和 -fno-tree-vectorize 编译的相关部分。
static double sqrtsd (double x) {
double r;
__asm__ ("sqrtsd %1, %0" : "=x" (r) : "x" (x));
return r;
}
Run Code Online (Sandbox Code Playgroud)