几句话说清楚4:什么是Pointer Aliasing

指向同一地址的两个相同类型的指针

aliasing本身是一个信号处理方面的概念。是指在信号采样过程中,不同的信号不再能相互区分的现象。

如下图所示的波纹现象,相对于拍摄的采样频率(横纵像素分辨率),墙砖缝隙变化的频率要大于采样频率。或者换句话说,多条墙砖缝隙需要挤在一个像素里面。

同样的现象也会出现在程序员穿着“高密度”的格子衬衫接受电视采访时。

墙砖缝隙出现aliasing后无法再行区分,从字面意义来说,Pointer Aliasing就是不同的指针也无法区分。

指针无法区分,只有一种情况,就是指针的类型和指向的地址都是相同的,这就是Pointer Aliasing

为什么会有性能影响

1
2
3
4
5
void foo(int *array, int *size, int *value) {
for(int i=0; i < *size; ++i) {
array[i] = 2 * *value;
}
}

如果让我们自己“优化”一下这段代码,我们可能会首先将value指向的值存入一个临时变量里,然后将临时变量在循环中直接赋值给array

我们假设个array的初始状态:[0, 1, 2, 3, 4]

如果value指向的值等于3,那么按我们优化的方式,array最终的状态是:[6, 6, 6, 6, 6]

但这里存在一个问题,如果value指向array[3],那么array最终的状态就是:[6, 6, 6, 12, 24]

valuearray[3]就是指向相同地址类型相同的指针。

编译器为了得到最终正确的结果,就不得不取消我们之前提到的”优化”方式。

预防方法

使用__restrict关键字:

1
2
3
4
5
void foo(int * __restrict array, int *__restrict size, int *__restrict value) {
for(int i=0; i < *size; ++i) {
array[i] = 2 * *value;
}
}

当然,前提是自己可以确定代码逻辑中不会引入aliasing

怎么使用

首先明确一点,不是加上了__restrict性能就会提升。

Pointer aliasing对性能根本的伤害不是需要每次重新去某个地址取值,而是因为引入了潜在的数据依赖关系,从而关闭了很多编译器优化代码的能力。

上面两段代码,在-O0优化时生成的汇编代码(gcc 4.8.5)完全相同。不同的地方在于,第一段代码在-O2-O3时生成的汇编代码仍然相同;而第二段做了__restrict处理的代码则会在-O3时加入大量循环展开等优化方式。

在线查看汇编代码:链接

所以__restrict需要在打开较高等级的编译器优化的情况下使用才会有效果。

,
© 2020 DecodeZ All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero