相关疑难解决方法(0)

微融合和寻址模式

我使用英特尔®架构代码分析器(IACA)发现了一些意想不到的东西(对我而言).

以下指令使用[base+index]寻址

addps xmm1, xmmword ptr [rsi+rax*1]
Run Code Online (Sandbox Code Playgroud)

根据IACA没有微熔丝.但是,如果我用[base+offset]这样的

addps xmm1, xmmword ptr [rsi]
Run Code Online (Sandbox Code Playgroud)

IACA报告它确实融合了.

英特尔优化参考手册的第2-11节给出了以下"可以由所有解码器处理的微融合微操作"的示例

FADD DOUBLE PTR [RDI + RSI*8]
Run Code Online (Sandbox Code Playgroud)

Agner Fog的优化装配手册也给出了使用[base+index]寻址的微操作融合的例子.例如,请参见第12.2节"Core2上的相同示例".那么正确的答案是什么?

cpu x86 assembly intel iaca

44
推荐指数
4
解决办法
4504
查看次数

Haswell/Skylake的部分寄存器究竟如何表现?写AL似乎对RAX有假依赖,而AH是不一致的

此循环在英特尔Conroe/Merom上每3个周期运行一次,imul按预期方式在吞吐量方面存在瓶颈.但是在Haswell/Skylake上,它每11个循环运行一次,显然是因为setnz al它依赖于最后一个循环imul.

; synthetic micro-benchmark to test partial-register renaming
    mov     ecx, 1000000000
.loop:                 ; do{
    imul    eax, eax     ; a dep chain with high latency but also high throughput
    imul    eax, eax
    imul    eax, eax

    dec     ecx          ; set ZF, independent of old ZF.  (Use sub ecx,1 on Silvermont/KNL or P4)
    setnz   al           ; ****** Does this depend on RAX as well as ZF?
    movzx   eax, al
    jnz  .loop         ; }while(ecx);
Run Code Online (Sandbox Code Playgroud)

如果setnz al …

x86 assembly intel cpu-architecture micro-optimization

30
推荐指数
2
解决办法
1537
查看次数

为什么循环总是被编译成"do ... while"样式(尾部跳转)?

当试图理解汇编(启用编译器优化)时,我看到这种行为:

这样一个非常基本的循环

outside_loop;
while (condition) {
     statements;
}
Run Code Online (Sandbox Code Playgroud)

经常被编译成(伪代码)

    ; outside_loop
    jmp loop_condition    ; unconditional
loop_start:
    loop_statements
loop_condition:
    condition_check
    jmp_if_true loop_start
    ; outside_loop
Run Code Online (Sandbox Code Playgroud)

但是,如果未打开优化,则会编译为通常可理解的代码:

loop_condition:
    condition_check
    jmp_if_false loop_end
    loop_statements
    jmp loop_condition  ; unconditional
loop_end:
Run Code Online (Sandbox Code Playgroud)

根据我的理解,编译后的代码更像是这样的:

goto condition;
do {
    statements;
    condition:
}
while (condition_check);
Run Code Online (Sandbox Code Playgroud)

我看不到巨大的性能提升或代码可读性提升,为什么经常出现这种情况呢?是否有此循环样式的名称,例如"尾随条件检查"?

optimization performance assembly loops micro-optimization

26
推荐指数
1
解决办法
1675
查看次数

在执行uop计数不是处理器宽度倍数的循环时性能是否会降低?

我想知道各种大小的循环如何在最近的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

20
推荐指数
2
解决办法
2048
查看次数

amd64上"条件调用"的表现

在代码的关键部分考虑条件函数调用时,我发现gcc和clang都会在调用中分支.例如,对于以下(通常是微不足道的)代码:

int32_t __attribute__((noinline)) negate(int32_t num) {
    return -num;
}

int32_t f(int32_t num) {
    int32_t x = num < 0 ? negate(num) : num;
    return 2*x + 1;
}
Run Code Online (Sandbox Code Playgroud)

GCC和clang都基本上编译如下:

.global _f
_f:
    cmp     edi, 0
    jg      after_call
    call    _negate
after_call:
    lea     rax, [rax*2+1]
    ret
Run Code Online (Sandbox Code Playgroud)

这让我想到:如果x86有一个像ARM这样的条件调用指令怎么办?想象一下,如果有这样的指令"ccall cc "与语义如cmov cc.然后你可以这样做:

.global _f
_f:
    cmp     edi, 0
    ccalll  _negate
    lea     rax, [rax*2+1]
    ret
Run Code Online (Sandbox Code Playgroud)

虽然我们无法避免分支预测,但我们确实消除了分支.也就是说,在实际的GCC/clang输出中,我们被迫分支,无论是否num < 0.如果num < 0我们必须分支两次.这似乎很浪费.

现在这样的指令在amd64中不存在,但我设计了一种模拟这种指令的方法.我通过分解call func其组成部分来做到这一点:( push rip技术上很好[rip+label_after_call_instruction])然后jmp …

x86 assembly x86-64 branch-prediction

10
推荐指数
1
解决办法
181
查看次数

LSD可以从检测到的循环的下一次迭代中发出uOP吗?

我正在使用一个非常简单的循环开始调查我的Haswell端口0上的分支单元的功能:

BITS 64
GLOBAL _start

SECTION .text

_start:

 mov ecx, 10000000

.loop:

 dec ecx             ;|
  jz .end            ;| 1 uOP (call it D)

jmp .loop            ;| 1 uOP (call it J)

.end:
 mov eax, 60
 xor edi, edi
 syscall
Run Code Online (Sandbox Code Playgroud)

使用perf我们看到循环以1c/iter运行

Performance counter stats for './main' (50 runs):

        10,001,055      uops_executed_port_port_6   ( +-  0.00% )
         9,999,973      uops_executed_port_port_0   ( +-  0.00% )
        10,015,414      cycles:u                    ( +-  0.02% )
                23      resource_stalls_rs          ( +- 64.05% )
Run Code Online (Sandbox Code Playgroud)

我对这些结果的解释是:

  • D和J都是并行发送的.
  • J具有1个周期的倒数吞吐量.
  • D和J都以最佳方式发送.

但是,我们也可以看到RS永远不会满员.
它最多可以以2 uOPs/c的速率发送uOP,但理论上可以得到4 …

x86 assembly cpu-architecture intel-pmu

9
推荐指数
1
解决办法
286
查看次数

一系列x86调用/ ret指令是否形成依赖链?

考虑以下x86-64程序集:

inner:
   ...
   ret

outer:
.top:
   call inner
   dec  rdi
   jnz  .top
   ret
Run Code Online (Sandbox Code Playgroud)

该函数outer只是重复call地对函数inner(其主体未显示) - 它可能是空的.

内部的一系列call指令outer和相应的ret指令是否inner在实践中形成一个依赖链(为了估计性能)?

这条链可以形成多种方式.例如,是否ret依赖于前一条call指令的延迟,然后后续call指令是否依赖于ret,形成call -> ret -> call链?或者也许ret是独立但call不是,形成一个call -> call链?如果有链,是通过内存,寄存器,堆栈引擎,返回地址预测器1还是什么?

动机:这个问题起源于对另一个问题的一系列评论,主要是这个评论和早期评论.


1这里的术语可能有些不清楚:堆栈引擎通常被理解为将转换rsp修改指令处理为具有适当偏移的单个访问,因此push rax; push rbx可能会转换为某些临时寄存器,mov [t0], rax; mov [t0 - 8], …

performance x86 assembly

8
推荐指数
1
解决办法
230
查看次数

在 IvyBridge 上的指针追逐循环中,来自附近依赖商店的奇怪性能影响。添加额外的负载会加快速度吗?

首先,我在 IvyBridge 上进行了以下设置,我将在注释位置插入测量有效负载代码。前 8 个字节buf存储buf自身的地址,我用它来创建循环携带依赖:

section .bss
align   64
buf:    resb    64

section .text
global _start
_start:
    mov rcx,         1000000000
    mov qword [buf], buf
    mov rax,         buf
loop:
    ; I will insert payload here
    ; as is described below 

    dec rcx
    jne loop

    xor rdi,    rdi
    mov rax,    60
    syscall
Run Code Online (Sandbox Code Playgroud)

情况1:

我插入到有效载荷位置:

mov qword [rax+8],  8
mov rax,            [rax]
Run Code Online (Sandbox Code Playgroud)

perf显示循环为 5.4c/iter。有点理解,因为L1d延迟是4个周期。

案例2:

我颠倒了这两条指令的顺序:

mov rax,            [rax]
mov qword [rax+8],  8
Run Code Online (Sandbox Code Playgroud)

结果突然变成9c/iter。我不明白为什么。因为下一次迭代的第一条指令不依赖于当前迭代的第二条指令,所以这个设置应该和 case 1 没有区别。

我也用IACA工具对这两种情况进行静态分析,但是该工具不可靠,因为两种情况预测的结果都是5.71c/iter,与实验相矛盾。 …

x86 assembly micro-optimization microbenchmark micro-architecture

7
推荐指数
1
解决办法
393
查看次数