如何解决如何使用展开因子 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 举报,一经查实,本站将立刻删除。