Caching gcc可以通过两个阵列进行预取吗?(间接预取)

Caching gcc可以通过两个阵列进行预取吗?(间接预取),caching,gcc,optimization,prefetch,Caching,Gcc,Optimization,Prefetch,假设我有两个数组a和b,它们最初不在缓存中。我有一个循环递增I计算b[a[I]]的一些函数。gcc是否能够插入必要的预取,以便b[a[i]]在我们深入循环后进入缓存 没有gcc做不到这一点(至少对于现代x86-64体系结构)。例如,使用-O2编译以下简单代码: double calc(int *add, double *ptr, int N){ double res=0.0; for(int i=0;i<N;i++) res+=1.0/ptr[add[i]];

假设我有两个数组
a
b
,它们最初不在缓存中。我有一个循环递增
I
计算
b[a[I]]
的一些函数。gcc是否能够插入必要的预取,以便
b[a[i]]
在我们深入循环后进入缓存

没有gcc做不到这一点(至少对于现代x86-64体系结构)。例如,使用
-O2
编译以下简单代码:

double calc(int *add, double *ptr, int N){
    double res=0.0;
    for(int i=0;i<N;i++)
       res+=1.0/ptr[add[i]];
    return res;
}
但是,gcc通常不会对直接访问进行任何预取:

double calc(double *ptr, int N){
    double res=0;
    for(int i=0;i<N;i++)
       res+=1.0/ptr[i];
    return res;
}
通常,gcc不会干扰缓存/预取,而是将其留给硬件

正如您正确指出的,
-fprefetch循环数组将提示gcc预取数据():

然而,这并不能使程序更快——硬件足够聪明,可以在没有编译器提示的情况下自行预取数据。我不确定是哪个功能导致了这种情况,我猜是最重要的

您提出了一个问题,即没有足够的“工作”可以与数据的获取交叉进行。这是真的,但即使对于像

double calc(double *ptr, int N){
    double res=0;
    for(int i=0;i<N;i++){
        res+=1.0/ptr[i]*ptr[i]/ptr[i]*ptr[i]/ptr[i]*ptr[i];
    }
    return res;
}

这是一个非常彻底的回答,谢谢。出于某种原因,我认为gcc在加入预取指令时更具攻击性!然而,我确实担心这些例子是有偏见的——对获取的内存所做的工作很少,所以预取也帮不上忙。如果您对每一行缓存都进行了足够的计算,以便有足够的时间获取新的缓存行,则可以完全避免未命中!我想知道gcc是否会抓住这种情况?而且,我相信这个标志可能会改变行为:
-fprefetch循环数组
。你说得对,但在现代cpu上,插入预取并不能使程序更快。不过,对于不太聪明/较旧的体系结构来说,这可能很重要。有关更多详细信息,请参见我的更新。
...
.L3:
        movapd  %xmm2, %xmm1
        addq    $8, %rdi
        divsd   -8(%rdi), %xmm1
        cmpq    %rax, %rdi
        addsd   %xmm1, %xmm0
        jne     .L3
        rep ret
...
.L4:
    movapd  %xmm1, %xmm2
    addl    $8, %edx
    prefetcht0      (%rax)   ;!!! HERE PREFETCH FOR FUTURE
    addq    $64, %rax
    divsd   -160(%rax), %xmm2
    addsd   %xmm2, %xmm0
    movapd  %xmm1, %xmm2
    divsd   -152(%rax), %xmm2
    addsd   %xmm0, %xmm2
    movapd  %xmm1, %xmm0
    divsd   -144(%rax), %xmm0
    addsd   %xmm0, %xmm2
    movapd  %xmm1, %xmm0
    divsd   -136(%rax), %xmm0
    addsd   %xmm2, %xmm0
    movapd  %xmm1, %xmm2
    divsd   -128(%rax), %xmm2
    addsd   %xmm2, %xmm0
    movapd  %xmm1, %xmm2
    divsd   -120(%rax), %xmm2
    addsd   %xmm0, %xmm2
    movapd  %xmm1, %xmm0
    divsd   -112(%rax), %xmm0
    addsd   %xmm0, %xmm2
    movapd  %xmm1, %xmm0
    divsd   -104(%rax), %xmm0
    cmpl    %ecx, %edx
    addsd   %xmm2, %xmm0
    jne     .L4
double calc(double *ptr, int N){
    double res=0;
    for(int i=0;i<N;i++){
        res+=1.0/ptr[i]*ptr[i]/ptr[i]*ptr[i]/ptr[i]*ptr[i];
    }
    return res;
}
.L4:
        movslq  -40(%rax), %r8
        movapd  %xmm1, %xmm2
        prefetcht0      (%rax)  ;HERE rax CORRESPONDS TO add !!
        addl    $16, %ecx
        addq    $64, %rax
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -100(%rax), %r8
        addsd   %xmm2, %xmm0
        movapd  %xmm1, %xmm2
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -96(%rax), %r8
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        movslq  -92(%rax), %r8
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        movslq  -88(%rax), %r8
        addsd   %xmm2, %xmm0
        movapd  %xmm1, %xmm2
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -84(%rax), %r8
        addsd   %xmm2, %xmm0
        movapd  %xmm1, %xmm2
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -80(%rax), %r8
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        movslq  -76(%rax), %r8
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        movslq  -72(%rax), %r8
        addsd   %xmm2, %xmm0
        movapd  %xmm1, %xmm2
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -68(%rax), %r8
        addsd   %xmm2, %xmm0
        movapd  %xmm1, %xmm2
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -64(%rax), %r8
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        movslq  -60(%rax), %r8
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        movslq  -56(%rax), %r8
        addsd   %xmm2, %xmm0
        movapd  %xmm1, %xmm2
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -52(%rax), %r8
        addsd   %xmm2, %xmm0
        movapd  %xmm1, %xmm2
        divsd   (%rsi,%r8,8), %xmm2
        movslq  -48(%rax), %r8
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        movslq  -44(%rax), %r8
        cmpl    %r9d, %ecx
        addsd   %xmm0, %xmm2
        movapd  %xmm1, %xmm0
        divsd   (%rsi,%r8,8), %xmm0
        addsd   %xmm2, %xmm0
        jne     .L4