相关疑难解决方法(0)

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

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

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

performance x86 cpu-architecture micro-optimization cpu-cache

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

了解lfence对具有两个长依赖链的循环的影响,以增加长度

我正在玩这个答案的代码,稍微修改一下:

BITS 64

GLOBAL _start

SECTION .text

_start:
 mov ecx, 1000000

.loop:

 ;T is a symbol defined with the CLI (-DT=...)

 TIMES T imul eax, eax
 lfence
 TIMES T imul edx, edx


 dec ecx
jnz .loop

 mov eax, 60           ;sys_exit
 xor edi, edi
 syscall
Run Code Online (Sandbox Code Playgroud)

没有lfence我,我得到的结果与答案中的静态分析一致.

当我介绍一个单一 lfence我期望的CPU执行imul edx, edx的序列的第k个平行于迭代imul eax, eax的下一个(的序列K + 1个)迭代.
像这样的东西(调用一个imul eax, eax序列和dimul edx, edx一个): …

performance x86 assembly cpu-architecture perf

13
推荐指数
2
解决办法
472
查看次数

当base + offset与基数不同时,是否存在惩罚?

这三个片段的执行时间:

pageboundary: dq (pageboundary + 8)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx - 8]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

还有这个:

pageboundary: dq (pageboundary - 8)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx + 8]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

还有这个:

pageboundary: dq (pageboundary - 4096)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx + 4096]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

对于第一个片段,在4770K上,每次迭代大约5个周期,对于第二个片段,每次迭代大约9个周期,然后是第三个片段的5个周期.它们都访问完全相同的地址,这是4K对齐的.在第二个片段中,只有地址计算跨越页面边界:rdx并且rdx + 8不属于同一页面,负载仍然是对齐的.如果偏移量很大,则会再次回到5个周期.

这种效果一般如何起作用?


通过ALU指令从加载路由结果,如下所示:

.loop:
    mov rdx, …
Run Code Online (Sandbox Code Playgroud)

performance x86 assembly micro-optimization

11
推荐指数
1
解决办法
456
查看次数

L1内存带宽:使用相差4096 + 64字节的地址,效率下降50%

我想用英特尔处理器实现以下操作的最大带宽.

for(int i=0; i<n; i++) z[i] = x[i] + y[i]; //n=2048
Run Code Online (Sandbox Code Playgroud)

其中x,y和z是浮点数组.我在Haswell,Ivy Bridge和Westmere系统上这样做.

我最初分配了这样的内存

char *a = (char*)_mm_malloc(sizeof(float)*n, 64);
char *b = (char*)_mm_malloc(sizeof(float)*n, 64);
char *c = (char*)_mm_malloc(sizeof(float)*n, 64);
float *x = (float*)a; float *y = (float*)b; float *z = (float*)c;
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我获得了每个系统预期的峰值带宽的大约50%.

峰值计算为frequency * average bytes/clock_cycle.每个系统的平均字节/时钟周期为:

Core2: two 16 byte reads one 16 byte write per 2 clock cycles     -> 24 bytes/clock cycle
SB/IB: two 32 byte reads and one 32 byte write per 2 clock cycles -> …
Run Code Online (Sandbox Code Playgroud)

c memory x86 caching avx

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

x86 bsr/bsf如何具有固定的延迟,而不是数据依赖?它不像伪代码那样循环比特吗?

我正在试图分析一些x86二进制代码的"时序通道".我发布了一个问题来理解bsf/bsr操作码.

如此高级,这两个操作码可以被建模为"循环",它计算给定操作数的前导零和尾随零.该x86手册对这些操作码具有良好的形式化,如下所示:

IF SRC = 0
  THEN
    ZF ? 1;
    DEST is undefined;
  ELSE
    ZF ? 0;
    temp ? OperandSize – 1;
    WHILE Bit(SRC, temp) = 0
    DO
      temp ? temp - 1;
    OD;
    DEST ? temp;
FI;
Run Code Online (Sandbox Code Playgroud)

但令我惊讶的是,bsf/bsr指令似乎有固定的cpu周期.根据我在这里找到的一些文档:https://gmplib.org/~tege/x86-timing.pdf,似乎它们总是需要8个CPU周期来完成.

所以这是我的问题:

  1. 我确认这些指令有固定的cpu周期.换句话说,无论给出什么操作数,它们总是花费相同的时间来处理,并且没有"时序通道".我在英特尔的官方文档中找不到相应的规格.

  2. 那么为什么有可能呢?显然这是一个"循环"或某种程度,至少是高级别的.背后的设计决策是什么?CPU流水线更容易?

performance x86 assembly intel cpu-architecture

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

PERF STAT不计算内存负载,但计算内存存储

Linux内核:4.10.0-20-generic(也在4.11.3上试过)

Ubuntu:17.04

我一直试图使用收集内存访问的统计信息perf stat.我能够收集内存存储的统计信息,但内存加载的计数返回0值.

以下是内存存储的详细信息: -

perf stat -e cpu/mem-stores/u ./libquantum_base.arnab 100
N = 100, 37 qubits required
Random seed: 33
Measured 3277 (0.200012), fractional approximation is 1/5.
Odd denominator, trying to expand by 2.
Possible period is 10.
100 = 4 * 25

 Performance counter stats for './libquantum_base.arnab 100':

       158,115,510      cpu/mem-stores/u                                            

       0.559922797 seconds time elapsed
Run Code Online (Sandbox Code Playgroud)

对于内存加载,我得到0计数,如下所示: -

perf stat -e cpu/mem-loads/u ./libquantum_base.arnab 100
N = 100, 37 qubits required
Random seed: …
Run Code Online (Sandbox Code Playgroud)

linux x86 intel perf

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

如何在x86_64上准确地对准未对齐的访问速度

答案中,我已经声明未对齐访问的速度与对齐访问的速度几乎相同(在x86/x86_64上).我没有任何数字来支持这个陈述,所以我已经为它创建了一个基准.

你看到这个基准测试有什么缺陷吗?你可以改进它(我的意思是,增加GB /秒,所以它更好地反映了真相)?

#include <sys/time.h>
#include <stdio.h>

template <int N>
__attribute__((noinline))
void loop32(const char *v) {
    for (int i=0; i<N; i+=160) {
        __asm__ ("mov     (%0), %%eax" : : "r"(v) :"eax");
        __asm__ ("mov 0x04(%0), %%eax" : : "r"(v) :"eax");
        __asm__ ("mov 0x08(%0), %%eax" : : "r"(v) :"eax");
        __asm__ ("mov 0x0c(%0), %%eax" : : "r"(v) :"eax");
        __asm__ ("mov 0x10(%0), %%eax" : : "r"(v) :"eax");
        __asm__ ("mov 0x14(%0), %%eax" : : "r"(v) :"eax");
        __asm__ ("mov 0x18(%0), %%eax" : : "r"(v) :"eax"); …
Run Code Online (Sandbox Code Playgroud)

performance benchmarking x86 x86-64 inline-assembly

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

存储转发地址与数据:英特尔优化指南中的STD和STA有什么区别?

我想知道是否有任何英特尔专家可以告诉我STD和STA在英特尔Skylake内核方面的区别。

在英特尔优化指南中,有一张图片描述了英特尔酷睿的“超标量端口”。

这是PDF。图片在第40页上。

这是相关图形的图片

这是第78页的另一张图片,该图片描述了“存储地址”和“存储数据”:

  1. 使用存储的数据地址准备存储转发和存储退出逻辑。

  2. 准备存储转发和存储退出逻辑以及要存储的数据。

考虑到Skylake可以在每个时钟周期执行一次#1 3x,但是在每个时钟周期只能执行一次#2,我很好奇这两者之间的区别。

在我看来,将存储转发到数据地址是“自然的”。但是我无法理解何时进行数据存储转发(又名:STD /端口4)。是否有任何组装/优化专家可以帮助我准确了解STD和STA之间的区别?

optimization performance assembly intel cpu-architecture

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

即使 RS 未完全充满,RESOURCE_STALLS.RS 事件是否也可能发生?

RESOURCE_STALLS.RSIntel Broadwell 硬件性能事件的描述如下:

此事件对由于保留站 (RS) 中缺少合格条目而导致的停顿周期进行计数。这可能是由于 RS 溢出,或由于 RS 阵列写入端口分配方案导致的 RS 解除分配(每个 RS 条目有两个写入端口而不是四个。因此,无法使用空条目,尽管 RS 并未真正满) . 这计算管道后端阻止来自前端的 uop 传递的周期。

这基本上说有两种情况会发生 RS 停顿事件:

  • 当RS 的所有符合条件的条目都被占用并且分配器没有停止时。
  • 当因为只有两个写端口而发生“RS 解除分配”时,并且分配器没有停止。

在第一种情况下,“合格”是什么意思?这是否意味着并非所有条目都可以被各种 uop 占用?因为我的理解是,在现代微体系结构中,任何条目都可以被任何类型的 uop 使用。还有什么是 RS 阵列写入端口分配方案,即使并非所有条目都被占用,它如何导致 RS 停顿?这是否意味着 Haswell 中有四个写端口,而现在 Broadwell 中只有两个?即使手册没有明确说明,这两种情况是否适用于 Skylake 或 Haswell?

performance x86 intel cpu-architecture intel-pmu

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

为什么jnz需要在内循环中完成2个循环

我在IvyBridge上.我发现jnz内循环和外循环中的性能行为不一致.

以下简单程序有一个固定大小为16的内部循环:

global _start
_start:
    mov rcx, 100000000
.loop_outer:
    mov rax,    16

.loop_inner:
    dec rax
    jnz .loop_inner

    dec rcx
    jnz .loop_outer

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

perf工具显示外循环运行32c/iter.它表明jnz需要2个周期才能完成.

然后我在Agner的指令表中搜索,条件跳转有1-2"倒数吞吐量",注释"如果没有跳转就快".

在这一点上,我开始相信上述行为是以某种方式预期的.但为什么jnz在外循环中只需要1个循环来完成?

如果我.loop_inner完全删除部件,外部循环运行1c/iter.行为看起来不一致.

我在这里缺少什么?

编辑以获取更多信息:

perf上述程序的结果带命令:

perf stat -ecycles,branches,branch-misses,lsd.uops,uops_issued.any -r4 ./a.out
Run Code Online (Sandbox Code Playgroud)

是:

 3,215,921,579      cycles                                                        ( +-  0.11% )  (79.83%)
 1,701,361,270      branches                                                      ( +-  0.02% )  (80.05%)
        19,212      branch-misses             #    0.00% of all branches          ( +- 17.72% )  (80.09%)
        31,052      lsd.uops                                                      ( …
Run Code Online (Sandbox Code Playgroud)

x86 micro-optimization microbenchmark micro-architecture

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

cpu缓存和cpu之间的总线宽度

在此输入图像描述 我无法计算出现代 PC 中 cpu 和 cpu 缓存之间的总线宽度。我在互联网上没有找到任何可靠的东西。我所拥有的只是Zen (AMD) 微架构的框图,其中表示 L1 和 L2 缓存每个周期可以传输 32B(256b)。我猜测总线宽度是 256 条线(假设单数据速率)。但是,存在双倍数据速率传输,例如内存控制器和 DDR 内存之间。

总结:

  1. cpu和cpu缓存之间的总线宽度是256线吗?
  2. 如果是,这是否意味着从 L1 读取整个缓存行需要两个 cpu 周期?

cpu x86 cpu-architecture cpu-cache amd-processor

3
推荐指数
1
解决办法
1204
查看次数