标签: micro-optimization

为什么 clang 的 `-O3` alloca 比 g++ 快 2 倍

关于 alloca 的使用和滥用

在上一个问题的底部获得了一些基准。clang 显然在-O3优化器配置文件中有更好的实现。是什么赋予了?叮当有没有偷工减料?另外,由于 clang 是现代编译器,它的 alloca 实现中是否有任何安全性或其他有趣的属性?

compiler-construction memory-management clang micro-optimization

5
推荐指数
1
解决办法
1119
查看次数

是否有任何关于 AVX2 收集指令延迟的数据?

是否有关于 AVX2 收集延迟的任何数据?

(例如 _mm256_i32gather_ps 指令访问单个缓存行)

performance x86 latency micro-optimization avx2

5
推荐指数
1
解决办法
900
查看次数

codeigniter中的控制器性能

对控制器类响应的最大LOC(LINE OF CODE)影响是否......这是重要的事情..

 1.a)Controller: LOC 120, public functions exist 3.
   b)Controller: LOC 120, public functions exist 3.
   c)Controller: LOC 120, public functions exist 3.

 2.) Controller LOC 720, pubic function 10.
   it handle all the things in the same class.
Run Code Online (Sandbox Code Playgroud)

哪一个更好?

php lines-of-code codeigniter micro-optimization

5
推荐指数
1
解决办法
523
查看次数

GCC 的计算 goto 的 ISO C 替换

背景:

在解释器循环(或其他有限状态机)中,有几种方法可以分派操作(或基于下一个输入的跳转状态)。C 中显而易见的方法是在循环中使用 switch 语句。但是,在循环内使用 switch 存在性能问题。在最坏的情况下,开关可以被编码为一个分支序列,如果操作编码不连续(或者编译器无法推断它是连续的),就会发生这种情况。即使在编译器生成跳转表的乐观情况下,仍然有多余的跳转回调度程序(我还没有看到编译器在看到循环中的开关时内联调度)。此外,调度程序中通常有一个冗余的边界检查。

GCC 团队通过引入 Computed Goto 解决了这个问题。这是一种语言扩展,允许引用标签,稍后可以跳转到goto标签指针上使用。这生成了理想的汇编代码:一个操作码索引的跳转表,在每次操作后都带有内联调度。

题:

有没有办法使用 ISO C 生成类似的汇编代码?

笔记:

我能做到的最接近的方法是将每个操作编写为一个函数,将函数指针放在一个表中,并利用尾调用优化来生成跳转而不是调用。这个问题很明显:它依赖于可能存在也可能不存在的优化。如果没有优化,生成的代码将消耗堆栈并最终使应用程序崩溃。

我试图生成的理想汇编代码(GAS .intel_syntax,类似于 NASM 语法)

.intel_syntax  noprefix

.section .rodata
optable:
  .quad nop
  .quad add
  # more ops here

.section .text
## interpreter loop entry here
nop:
    call  nextinput          # return value = table index in rax
    jmp   [optable + rax]

add:
    # add stuff here
    call  nextinput
    jmp   [optable + rax]
Run Code Online (Sandbox Code Playgroud)

c assembly gcc micro-optimization

5
推荐指数
0
解决办法
1232
查看次数

为什么带有内存操作数的 vpclmulqdq 比 movdqa + pclmulqdq 慢?

vpclmulqdq指令有四个操作数,pclmulqdq有三个操作数,所以我认为vpclmulqdq可以用 代替movdqa + pclmulqdq,但实验结果变慢了。

但是当我使用vpaddd而不是movdqa + paddd,我得到更快的结果。所以我对这个问题感到困惑。代码使用如下paddd指令:

movdqa %xmm0, %xmm8          # slower
movdqa %xmm0, %xmm9
movdqa %xmm0, %xmm10
movdqa %xmm0, %xmm11
paddd (ONE),  %xmm8
paddd (TWO),  %xmm9
paddd (THREE),  %xmm10
paddd (FOUR),  %xmm11

vpaddd (ONE), %xmm0, %xmm8   # faster
vpaddd (TWO), %xmm0, %xmm9
vpaddd (THREE), %xmm0, %xmm10
vpaddd (FOUR), %xmm0, %xmm11
Run Code Online (Sandbox Code Playgroud)

代码使用 pclmulqdq 指令,如:

movdqa %xmm15, %xmm1               # faster
pclmulqdq $0x00, (%rbp), %xmm1
aesenc 16(%r15), %xmm8
aesenc …
Run Code Online (Sandbox Code Playgroud)

x86 assembly sse avx micro-optimization

5
推荐指数
0
解决办法
467
查看次数

指令表中缺少延迟

我目前正在查看 Agner Fog 的指令表以了解常见指令的延迟。

我希望我没有错过文档中这个问题的答案,但是谁能向我解释为什么某些指令没有延迟条目?

例如,操作数为 r,r,m 的 PEXT 指令的延迟对于 Skylake 留空?

丢失延迟的解释是什么,为什么一开始就很难获得延迟(如果是这种情况)?

x86 assembly micro-optimization

5
推荐指数
1
解决办法
197
查看次数

更改单个指令时,为什么此代码未命中 Haswell 上的微操作缓存?

我试图了解我的 Haswell 芯片上的 uop 缓存(英特尔文档中的 DSB)的行为。我基于 Intel 优化手册和 Agner pdfs。

我发现了一组案例,其中前端可靠地回退到 MITE 解码器,这取决于代码中的细微变化,这让我感到困惑。

一个例子看起来像这样(在 gnu as 中-msyntax=intel):

    mov rax, 100000000
    .align 64

1:
// DSB-cacheable nops to
// overflow LSD
    .fill 12, 1, 0x90
    .align 32
    .fill 12, 1, 0x90
    .align 32
    .fill 12, 1, 0x90
    .align 32
    .fill 12, 1, 0x90
    .align 32

// this first block should fill up way 1 of our uop-cache set
    add ecx, ecx
    nop
    nop
    nop
    add ecx, ecx
    add ecx, …
Run Code Online (Sandbox Code Playgroud)

x86 assembly cpu-architecture micro-optimization micro-architecture

5
推荐指数
0
解决办法
120
查看次数

在内存中交换未对齐的 64 位值的字节的最快方法是什么?

我在内存中有大量 64 位值。不幸的是,它们可能不会与 64 位地址对齐。我的目标是改变所有这些值的字节序,即交换/反转它们的字节。

我知道bswap交换 32 位或 64 位寄存器字节的指令。但是因为它需要一个寄存器参数,所以我不能将它传递给我的内存地址。当然我可以先将内存加载到寄存器中,然后交换,然后写回:

mov rax, qword [rsi]
bswap rax
mov qword [rsi], rax
Run Code Online (Sandbox Code Playgroud)

但这是否正确,因为地址可能未对齐?

另一种可能性是手动进行交换:

mov al, byte [rsi + 0]
mov bl, byte [rsi + 7]
mov byte [rsi + 0], bl
mov byte [rsi + 7], al

mov al, byte [rsi + 1]
mov bl, byte [rsi + 6]
mov byte [rsi + 1], bl
mov byte [rsi + 6], al

mov al, byte [rsi + 2]
mov bl, …
Run Code Online (Sandbox Code Playgroud)

performance assembly x86-64 endianness micro-optimization

5
推荐指数
1
解决办法
510
查看次数

为什么 gcc 在 uint64_t * 内存区域中有条件地设置位时将 btq 与 btcq 结合使用

基本上我试图理解代码:https : //gcc.godbolt.org/z/7xxb3G

void __attribute__((noinline))
cond_unset_bit(uint64_t * v, uint32_t b) {
    if(__builtin_expect(!!(*v & ((1UL) << b)), 1)) {
        *v ^= ((1UL) << b);
    }
}
Run Code Online (Sandbox Code Playgroud)

编译为:

cond_unset_bit(unsigned long*, unsigned int):
        movq    (%rdi), %rax
        btq     %rsi, %rax
        jnc     .L6
        btcq    %rsi, %rax
        movq    %rax, (%rdi)
.L6:
        ret
Run Code Online (Sandbox Code Playgroud)

基于Agner Fog 的指令表(skylake 是第 238 页)btq并且btcq在寄存器上操作时具有完全相同的成本。btcq还将进位标志设置为前一位,因此似乎可以在没有btq指令的情况下实现完全相同的逻辑(具有更好的性能),即:

cond_unset_bit(unsigned long*, unsigned int):
        movq    (%rdi), %rax
        btcq    %rsi, %rax
        jnc     .L6
        movq    %rax, (%rdi) …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc x86-64 micro-optimization

5
推荐指数
0
解决办法
129
查看次数

现代 CPU 是否需要花费大量资源来保持标志更新?

据我了解,在现代无序 CPU 上,最昂贵的事情之一是状态,因为必须在多个版本中跟踪该状态,并在许多指令中保持最新状态等。

一些像 x86 和 ARM 的指令集大量使用了标志,当成本模型不是今天的样子时引入了标志,而标志只需要几个逻辑门。诸如每个算术指令设置标志以检测零、进位和溢出之类的事情。

这些在现代乱序实现上保持更新是否特别昂贵?例如,一条 ADD 指令更新进位标志,这必须被跟踪,因为虽然它可能永远不会被使用,但有可能其他指令可以在 N 条指令后使用它,对 N 没有固定的上限?

在没有这些标志的指令集架构(如 MIPS)上,诸如加法和减法之类的整数运算是否更便宜?

performance assembly cpu-architecture micro-optimization eflags

5
推荐指数
1
解决办法
120
查看次数