这种优化技术的名称是什么?
what is the name of this optimization technique?
以下优化技术的名称是什么?为什么它比以前的实施更好?
const int size = 100;
int arr1[size];
int arr2[size];
来自双循环
for(int i=0; i<size; ++i)
arr1[i] = 1;
for(int i=0; i<size; ++i)
arr2[i] = 1;
单循环
for(int i=0; i<size; ++i) {
arr1[i] = 1;
arr2[i] = 1;
}
编辑
选项是;
- 指针别名
- 循环不变代码运动
- 复制 elison
- 循环融合
- 循环展开
它被称为 loop fusion(或循环干扰,正如维基百科帮助指出的那样),正如您可能理解的那样,只要两个相邻循环在同一范围内迭代而不相互交叉引用,它就可能发生。
请注意,这并不一定会提高速度。
维基百科将此优化称为 loop fusion。这个想法是,两个循环的循环控制流开销不会加倍。如果组合循环的内存访问模式不佳,这可能不会对性能产生预期的影响,但由于您示例中的两个循环都按顺序访问连续的内存块,因此硬件应该能够有效地处理它。
在转换之前,每个循环都这样做:
- 用 0.
初始化 i
- 加载常量
size
。
- 如果
i >= size
,则跳转到8。
- 加载数组开始的地址
arr1
。
- 将常量1存入地址
arr1 + i
.
- 将
i
加一。
- 跳转到 3.
- 结束
然后立即再次:
- 用 0.
初始化 i
- 加载常量
size
。
- 如果
i >= size
,跳转到16。
- 加载数组开始的地址
arr2
。
- 将常量1存入地址
arr2 + i
。
- 将
i
加一。
- 跳转到 11。
- 结束
任何编译器可能做的第一件事就是将“加载常量size
”和“加载地址arr
”移出循环体。然而,总工作量与有用工作量之比并不是很好。将此与组合循环进行比较:
- 用 0.
初始化 i
- 加载常量
size
。
- 如果
i >= size
,跳转到10。
- 加载数组开始的地址
arr1
。
- 将常量1存入地址
arr1 + i
.
- 加载数组开始的地址
arr2
。
- 将常量1存入地址
arr2 + i
。
- 将
i
加一。
- 跳转到 3.
- 结束
将要点计数作为机器指令的衡量标准并不是推断性能的最准确方法。您需要知道您的实际硬件支持哪些指令才能实际比较所需指令的数量。
我觉得这更像是悲观!
您完全破坏了在循环中访问的数据的内存局部性,并可能导致大量缓存未命中。
唯一可以确定的方法当然是测量它,但是得出结论这是一个 "optimization",只是因为你只对 [= 进行了一半的增量和比较10=],很傻。
以下优化技术的名称是什么?为什么它比以前的实施更好?
const int size = 100;
int arr1[size];
int arr2[size];
来自双循环
for(int i=0; i<size; ++i)
arr1[i] = 1;
for(int i=0; i<size; ++i)
arr2[i] = 1;
单循环
for(int i=0; i<size; ++i) {
arr1[i] = 1;
arr2[i] = 1;
}
编辑
选项是;
- 指针别名
- 循环不变代码运动
- 复制 elison
- 循环融合
- 循环展开
它被称为 loop fusion(或循环干扰,正如维基百科帮助指出的那样),正如您可能理解的那样,只要两个相邻循环在同一范围内迭代而不相互交叉引用,它就可能发生。
请注意,这并不一定会提高速度。
维基百科将此优化称为 loop fusion。这个想法是,两个循环的循环控制流开销不会加倍。如果组合循环的内存访问模式不佳,这可能不会对性能产生预期的影响,但由于您示例中的两个循环都按顺序访问连续的内存块,因此硬件应该能够有效地处理它。
在转换之前,每个循环都这样做:
- 用 0. 初始化
- 加载常量
size
。 - 如果
i >= size
,则跳转到8。 - 加载数组开始的地址
arr1
。 - 将常量1存入地址
arr1 + i
. - 将
i
加一。 - 跳转到 3.
- 结束
i
然后立即再次:
- 用 0. 初始化
- 加载常量
size
。 - 如果
i >= size
,跳转到16。 - 加载数组开始的地址
arr2
。 - 将常量1存入地址
arr2 + i
。 - 将
i
加一。 - 跳转到 11。
- 结束
i
任何编译器可能做的第一件事就是将“加载常量size
”和“加载地址arr
”移出循环体。然而,总工作量与有用工作量之比并不是很好。将此与组合循环进行比较:
- 用 0. 初始化
- 加载常量
size
。 - 如果
i >= size
,跳转到10。 - 加载数组开始的地址
arr1
。 - 将常量1存入地址
arr1 + i
. - 加载数组开始的地址
arr2
。 - 将常量1存入地址
arr2 + i
。 - 将
i
加一。 - 跳转到 3.
- 结束
i
将要点计数作为机器指令的衡量标准并不是推断性能的最准确方法。您需要知道您的实际硬件支持哪些指令才能实际比较所需指令的数量。
我觉得这更像是悲观!
您完全破坏了在循环中访问的数据的内存局部性,并可能导致大量缓存未命中。
唯一可以确定的方法当然是测量它,但是得出结论这是一个 "optimization",只是因为你只对 [= 进行了一半的增量和比较10=],很傻。