相关疑难解决方法(0)

L1缓存命中的周期/成本与x86上的Register相比?

我记得假设在我的架构类中L1缓存命中是1个周期(即与寄存器访问时间相同),但在现代x86处理器上实际上是这样吗?

L1缓存命中多少个周期?它与寄存器访问相比如何?

performance x86 cpu-architecture micro-optimization cpu-cache

27
推荐指数
2
解决办法
2万
查看次数

使用自修改代码观察在x86上获取过时的指令

我被告知并且从英特尔的手册中读到可以将指令写入内存,但是指令预取队列已经获取了陈旧的指令并将执行那些旧的指令.我没有成功观察到这种行为.我的方法如下.

英特尔软件开发手册从第11.6节开始说明

对当前在处理器中高速缓存的代码段中的存储器位置的写入导致相关联的高速缓存行(或多个行)无效.此检查基于指令的物理地址.此外,P6系列和奔腾处理器检查对代码段的写入是否可以修改已经预取执行的指令.如果写入影响预取指令,则预取队列无效.后一种检查基于指令的线性地址.

所以,看起来如果我希望执行陈旧的指令,我需要有两个不同的线性地址引用相同的物理页面.所以,我将内存映射到两个不同的地址.

int fd = open("code_area", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
assert(fd>=0);
write(fd, zeros, 0x1000);
uint8_t *a1 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
        MAP_FILE | MAP_SHARED, fd, 0);
uint8_t *a2 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
        MAP_FILE | MAP_SHARED, fd, 0);
assert(a1 != a2);
Run Code Online (Sandbox Code Playgroud)

我有一个汇编函数,它接受一个参数,一个指向我想要更改的指令的指针.

fun:
    push %rbp
    mov %rsp, %rbp

    xorq %rax, %rax # Return value 0

# A far jump simulated with a far return
# Push the …
Run Code Online (Sandbox Code Playgroud)

c x86 caching self-modifying

23
推荐指数
3
解决办法
2563
查看次数

计算机如何将2个数字相乘?

计算机如何对2个数字进行乘法运算,比如100*55.

我的猜测是计算机重复添加以实现乘法.当然,这可能是整数的情况.但是对于浮点数,必须有一些其他逻辑.

注意:这在面试中被问到了.

computer-science mathematical-optimization

22
推荐指数
4
解决办法
2万
查看次数

当我在禁用优化的情况下进行编译时,为什么clang不使用内存目标x86指令?它们有效吗?

我编写了这个简单的汇编代码,运行它并使用GDB查看内存位置:

    .text

.global _main

_main:
    pushq   %rbp
    movl    $5, -4(%rbp)
    addl    $6, -4(%rbp)
    popq    %rbp
    ret
Run Code Online (Sandbox Code Playgroud)

它直接在内存中添加5到6个,根据GDB它可以工作.所以这是直接在内存中执行数学运算而不是CPU寄存器.

现在在C中编写相同的东西并将其编译为汇编,结果如下:

...  # clang output
    xorl    %eax, %eax
    movl    $0, -4(%rbp)
    movl    $5, -8(%rbp)
    movl    -8(%rbp), %ecx   # load a
    addl    $6, %ecx         # a += 6
    movl    %ecx, -8(%rbp)   # store a
....
Run Code Online (Sandbox Code Playgroud)

在将它们添加到一起之前,它会将它们移动到寄存器中.

那么为什么我们不直接在内存中添加?

它慢了吗?如果是这样,为什么直接在内存中添加甚至允许,为什么汇编程序在开始时没有抱怨我的汇编代码?

编辑:这是第二个程序集块的C代码,我在编译时禁用了优化.

#include <iostream>

int main(){
 int a = 5;
 a+=6; 
 return 0;
}
Run Code Online (Sandbox Code Playgroud)

c assembly gcc clang compiler-optimization

19
推荐指数
1
解决办法
1214
查看次数

是x86 CMPXCHG原子,如果是这样,为什么需要LOCK?

Intel的文档

该指令可以与LOCK前缀一起使用,以允许指令以原子方式执行.

我的问题是

  1. 可以CMPXCHG用内存地址操作吗?从文档看来似乎没有,但任何人都可以确认只能在寄存器中使用实际的VALUE,而不是内存地址吗?

  2. 如果CMPXCHG不是原子级和高级语言级CAS必须通过LOCK CMPXCHG(带LOCK前缀)来实现,那么引入这样一条指令的目的是什么?

concurrency x86 compare-and-swap

10
推荐指数
2
解决办法
8761
查看次数

为什么有些C编译器会在奇怪的地方设置函数的返回值?

我在最近关于array[i++]vs 的假设速度的争论中写了这个片段array[i]; i++.

int array[10];

int main(){
    int i=0;
    while(i < 10){
        array[i] = 0;
        i++;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译器资源管理器的代码段:https://godbolt.org/g/de7TY2

正如所预期的,编译器输出相同ASM array[i++]array[i]; i++与至少-O1.然而令我感到惊讶的是,xor eax, eax在更高的优化级别中,看似随机地放置在函数中.


GCC

-O2,GCC会将xor在之前ret预期

    mov     DWORD PTR [rax], 0
    add     rax, 4
    cmp     rax, OFFSET FLAT:array+40
    jne     .L2
    xor     eax, eax
    ret
Run Code Online (Sandbox Code Playgroud)

然而,它在第二个之后将xor置于mov-O3

    mov     QWORD PTR array[rip], 0
    mov     QWORD PTR array[rip+8], 0
    xor …
Run Code Online (Sandbox Code Playgroud)

c optimization assembly gcc compilation

8
推荐指数
2
解决办法
307
查看次数

在预测现代超标量处理器上的操作延迟时需要考虑哪些因素以及如何手动计算它们?

我希望能够手动预测任意算术的长度(即没有分支或内存,尽管这也很好)x86-64汇编代码将采用特定的体系结构,考虑到指令重新排序,超标量,延迟,消费者价格指数等

什么/描述必须遵循的规则才能实现这一目标?


我想我已经找到了一些初步规则,但是我没有找到任何关于将任何示例代码分解为这个详细程度的引用,所以我不得不做一些猜测.(例如,英特尔优化手册甚至几乎没有提到指令重新排序.)

至少,我正在寻找(1)确认每条规则是正确的,或者是每条规则的正确陈述,以及(2)我可能忘记的任何规则的列表.

  • 每个循环发出尽可能多的指令,从当前循环开始按顺序开始,并且可能与重新排序缓冲区大小一样远.
  • 如果出现以下情况,可以在给定周期发出指令:
    • 没有影响其操作数的指令仍在执行中.和:
    • 如果它是浮点指令,则它之前的每个浮点指令都被发出(浮点指令具有静态指令重新排序).和:
    • 该循环有一个功能单元可用于该指令.每个(?)功能单元是流水线的,这意味着它可以在每个周期接受1个新指令,并且对于给定功能类的CPI,总功能单元的数量是1/CPI(这里模糊不清:可能是例如addps并且subps使用相同的功能) unit?我如何确定?).和:
    • 4此循环已经发出少于超标量宽度(通常)指令的数量.
  • 如果不能发出指令,则处理器不会发出任何称为"停顿"的条件.

例如,请考虑以下示例代码(计算交叉产品):

shufps   xmm3, xmm2, 210
shufps   xmm0, xmm1, 201
shufps   xmm2, xmm2, 201
mulps    xmm0, xmm3
shufps   xmm1, xmm1, 210
mulps    xmm1, xmm2
subps    xmm0, xmm1
Run Code Online (Sandbox Code Playgroud)

我试图预测Haswell的延迟看起来像这样:

; `mulps`  Haswell latency=5, CPI=0.5
; `shufps` Haswell latency=1, CPI=1
; `subps`  Haswell latency=3, CPI=1

shufps   xmm3, xmm2, 210   ; cycle  1
shufps   xmm0, xmm1, 201   ; cycle  2
shufps   xmm2, xmm2, 201   ; …
Run Code Online (Sandbox Code Playgroud)

assembly pipeline latency x86-64 superscalar

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

如何在Win32中获取CPU周期数?

在Win32中,有没有办法获得一个独特的cpu循环计数或类似的东西,对于多个进程/语言/系统/等是统一的.

我正在创建一些日志文件,但是必须生成多个日志文件,因为我们正在托管.NET运行时,并且我想避免从一个调用到另一个来进行日志记录.因此,我认为我只生成两个文件,将它们组合在一起,然后对它们进行排序,以获得涉及跨世界调用的连贯时间线.

但是,每次通话都不会增加GetTickCount,因此不可靠.是否有更好的号码,以便在排序时以正确的顺序接听电话?


编辑:感谢@Greg把我带到QueryPerformanceCounter的轨道,这就是诀窍.

winapi timer cpu-cycles

7
推荐指数
2
解决办法
8393
查看次数

通过计算条件早期避免拖延管道

在谈论ifs的表现时,我们通常会谈论错误预测如何阻止管道.我看到的推荐解决方案是:

  1. 相信通常有一个结果的条件的分支预测器; 要么
  2. 如果合理可能的话,避免使用一点点魔法分支; 要么
  3. 有条件的移动尽可能.

我找不到的是我们是否能尽早计算出病情,以便在可能的情况下提供帮助.所以,而不是:

... work
if (a > b) {
    ... more work
}
Run Code Online (Sandbox Code Playgroud)

做这样的事情:

bool aGreaterThanB = a > b;
... work
if (aGreaterThanB) {
    ... more work
}
Run Code Online (Sandbox Code Playgroud)

这样的事情可能会完全避免这个条件的停顿(取决于管道的长度和我们可以放在bool和if之间的工作量)?这并不一定是因为我写的,但有什么办法,以评估条件语句早,所以CPU不必尝试和预测的分支

此外,如果这有帮助,编译器可能会做什么呢?

language-agnostic performance cpu-architecture compiler-optimization branch-prediction

7
推荐指数
2
解决办法
550
查看次数

如何在处理器周期中测量x86和x86-64汇编命令的执行时间?

我想用遗传算法为gcc写一堆优化.我需要测量某些统计和拟合函数的汇编函数的执行时间.不能使用通常的时间测量,因为它受缓存大小的影响.
所以我需要一张桌子,我可以看到这样的东西.

command | operands | operands sizes | execution cycles
Run Code Online (Sandbox Code Playgroud)

我想念一些东西吗?抱歉英语不好.

x86 assembly gcc profiling execution-time

6
推荐指数
1
解决办法
1904
查看次数