微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用展开因子 3 优化此代码?

如何解决如何使用展开因子 3 优化此代码?

void randomImprovedfunction(double a[],double p[],long n)
2 {
3      long i;
4      double last_v,v;
5      last_v = p[0] = a[0];
6      for (i=1; i<n; i++) {
7          v = last_v + a[i];
8          p[i] = v ;
9         last_v = v;
10     }
11
12     return ;
13 }

我有这个功能。作为练习,我被告知可以使用展开因子 3 并仅更改第 7-9 行来优化它。然而,我真的不知道如何做到这一点。

有人可以给我看吗?

谢谢!任何帮助表示赞赏:)

解决方法

展开的主要目标是让 CPU 指令管道更容易处理指令。多条指令可以同时进行,各种因素都会中断流畅的流程。例如,数据相关性:如果较晚的指令需要加载数据并且该数据正在被较早的指令更改,则较晚的指令必须在其加载阶段等待,直到较早的指令保存该数据。 这称为管道停顿。

有关为什么数据依赖性是此示例中的主要瓶颈的原因,请参阅注释。

问题中给出的教科书示例似乎主要是用于熟悉手动展开循环的练习,并非旨在调查任何性能问题。

你的展开代码的初稿看起来像这样,但你会得到不需要的情况

for (i=1; i < n; i+=3) {
    v = last_v + a[i];
    p[i] = v ;
    last_v = v;
    v = last_v + a[i+1];
    p[i+1] = v ;
    last_v = v;
    v = last_v + a[i+2];
    p[i+2] = v ;
    last_v = v;
}

不需要的情况 - 请注意,您要处理的最后一个索引是 (n-1)

n 不需要的情况
5 数组索引 1,2,3 然后 4,5,6 => 展开的代码处理了 2 个不需要的情况,索引 5 和 6
6 数组索引 1,6 => 展开的代码处理 1 个不需要的情况,索引 6
7 数组索引 1,6 => 没有不需要的情况

另见Handling unrolled loop remainder

因此,如果有任何不需要的情况,请消除最后一个循环,然后您将拥有

// `nn` is the adjusted loop limit to avoid an extra loop with unwanted cases 
int nn = n;
if ( (n-1)%3 != 0 ) nn = n - 3;

for (i=1; i < nn; i+=3) {
    v = last_v + a[i];
    p[i] = v ;
    last_v = v;
    v = last_v + a[i+1];
    p[i+1] = v ;
    last_v = v;
    v = last_v + a[i+2];
    p[i+2] = v ;
    last_v = v;
}

此时我们需要处理剩余/缺失的情况:

n nn 迭代器 i 的值
5 2 1,4 => 最终 i = n - 1
6 3 1,4 => 最终 i = n - 2
7 7 1,4,7 => 最终 i = n

如果 i = n - 1,你有 1 个缺失的情况,即索引 n-1
如果 i = n - 2,则有 2 个缺失的情况,即索引 n-2 和 n-1
如果 i = n,你就完成了

if ( i == n - 1 ) { // 1 missing case
    v = last_v + a[n-1]
    p[n-1] = v;
}
if ( i == n - 2 ) { // 2 missing cases
    v = last_v + a[n-2]
    p[n-2] = v;
    last_v = v;
    v = last_v + a[n-1]
    p[n-1] = v;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。