对于英特尔架构,是否有一种方法可以指示GCC编译器生成的代码总是强制分支预测在我的代码中采用特定方式?英特尔硬件是否支持此功能?那么其他编译器或硬件呢?
我会在C++代码中使用它,我知道我希望快速运行的情况,并且不关心当另一个分支需要被采取时,即使它最近采用了该分支.
for (;;) {
if (normal) { // How to tell compiler to always branch predict true value?
doSomethingNormal();
} else {
exceptionalCase();
}
}
Run Code Online (Sandbox Code Playgroud)
作为Evdzhan Mustafa的后续问题,该提示是否可以在处理器第一次遇到指令时指定一个提示,所有后续的分支预测都能正常运行?
这与此问题有关,但不一样:x86-64汇编的性能优化 - 对齐和分支预测与我之前的问题略有关系:无符号64位到双倍转换:为什么这个算法来自g ++
以下是一个不真实的测试用例.这种素性测试算法是不明智的.我怀疑任何真实世界的算法都不会执行如此多的小内循环(num大概是2**50的大小).在C++ 11中:
using nt = unsigned long long;
bool is_prime_float(nt num)
{
for (nt n=2; n<=sqrt(num); ++n) {
if ( (num%n)==0 ) { return false; }
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
然后g++ -std=c++11 -O3 -S生成以下内容,包含RCX n和包含XMM6 sqrt(num).请参阅我之前发布的剩余代码(在此示例中从未执行过,因为RCX永远不会变得足够大,不能被视为带符号的否定).
jmp .L20
.p2align 4,,10
.L37:
pxor %xmm0, %xmm0
cvtsi2sdq %rcx, %xmm0
ucomisd %xmm0, %xmm6
jb .L36 // Exit the loop
.L20:
xorl %edx, %edx
movq %rbx, %rax …Run Code Online (Sandbox Code Playgroud) 我想知道各种大小的循环如何在最近的x86处理器上执行,作为uop数的函数.
以下是彼得·科德斯(Peter Cordes)的一句话,他在另一个问题中提出了非多数的问题:
我还发现,如果循环不是4 uop的倍数,则循环缓冲区中的uop带宽不是每个循环的常数4.(即它是abc,abc,......;不是abca,bcab,......).遗憾的是,Agner Fog的microarch doc对循环缓冲区的这种限制并不清楚.
问题是关于循环是否需要是N uop的倍数才能以最大uop吞吐量执行,其中N是处理器的宽度.(即最近的英特尔处理器为4).在谈论"宽度"和计算微动时,有很多复杂因素,但我大多想忽略这些因素.特别是,假设没有微观或宏观融合.
Peter给出了以下一个循环,其中包含7个uop的循环:
一个7-uop循环将发出4 | 3 | 4 | 3 | ...的组我没有测试更大的循环(不适合循环缓冲区),看看是否有可能从下一个指令开始迭代发布在与其分支相同的组中,但我不假设.
更一般地说,声称是x在其体内具有uops 的循环的每次迭代将至少进行ceil(x / 4)迭代,而不是简单地迭代x / 4.
对于部分或全部最新的x86兼容处理器,这是真的吗?
performance x86 assembly cpu-architecture micro-optimization
我将分支目标与NOP对齐,有时CPU执行这些NOP,最多15个NOP.Skylake可以在一个周期内执行多少个1字节NOP?其他与AMD兼容的处理器如何?我不仅对Skylake感兴趣,而且对其他微架构也感兴趣.执行一系列15个NOP可能需要多少个周期?我想知道增加这些NOP的额外代码大小和额外执行时间是否物有所值.这不是我添加这些NOP而是每当我编写align指令时自动添加汇编程序的人.
更新:我已经设法自动插入多字节NOPs.
许多低延迟开发指南讨论了在特定地址边界上对齐内存分配:
https://github.com/real-logic/simple-binary-encoding/wiki/Design-Principles#word-aligned-access
http://www.alexonlinux.com/aligned-vs-unaligned-memory-access
但是,第二个链接是从2008年开始的.在2019年,在地址边界上调整内存是否仍能提高英特尔CPU的性能?我认为英特尔CPU不再会因访问未对齐地址而导致延迟损失?如果没有,在什么情况下应该这样做?我应该对齐每个堆栈变量吗?类成员变量?
有没有人有任何例子表明他们在调整内存方面取得了显着的性能提升?
我在类似嵌入式的环境中工作,每个字节都非常珍贵,远远超过了未对齐访问的额外周期.我从OS开发示例中得到了一些简单的Rust代码:
#![feature(lang_items)]
#![no_std]
extern crate rlibc;
#[no_mangle]
pub extern fn rust_main() {
// ATTENTION: we have a very small stack and no guard page
let hello = b"Hello World!";
let color_byte = 0x1f; // white foreground, blue background
let mut hello_colored = [color_byte; 24];
for (i, char_byte) in hello.into_iter().enumerate() {
hello_colored[i*2] = *char_byte;
}
// write `Hello World!` to the center of the VGA text buffer
let buffer_ptr = (0xb8000 + 1988) as *mut _;
unsafe { *buffer_ptr = hello_colored …Run Code Online (Sandbox Code Playgroud) 在路径中的linux源代码中出现的head.s文件中arch/i386/kernel/head.S,ALIGN使用如下面的ret指令后面给出的代码片段中所示.我的问题是这是什么ALIGN,根据我的知识,这不是指令,而不是汇编指令,那么这是什么以及为什么在这里使用它?
您可以获得head.S以下网站的代码:
http://kneuro.net/cgi-bin/lxr/http/source/arch/i386/kernel/head.S?v=2.4.0
路径: arch/i386/kernel/head.S
/*
* We depend on ET to be correct. This checks for 287/387.
*/
check_x87:
movb $0,X86_HARD_MATH
clts
fninit
fstsw %ax
cmpb $0,%al
je 1f
movl %cr0,%eax
xorl $4,%eax
movl %eax,%cr0
ret
ALIGN /* why ALIGN is used and what it is? */
1: movb $1,X86_HARD_MATH
.byte 0xDB,0xE4
ret
Run Code Online (Sandbox Code Playgroud) x86 ×5
assembly ×4
performance ×3
c++ ×2
intel ×2
optimization ×2
alignment ×1
c ×1
embedded ×1
gcc ×1
latency ×1
linux-kernel ×1
nop ×1
pragma ×1
rust ×1