有没有办法只需写1种算法,且对末尾的数据也能向量化处理呢?
对于“一边读取、一边写入”这种情况,由于读、写的一样平常是不同的数据地区,故有一种办法来实现上面的期望。该办法的关键思路是——先计算好“末尾指针”(向量处理时最后一笔数据的指针地点),然后在循环内每次均检查指针地点,当发现当前指针已经越过“末尾指针”时便逼迫将当前指针设置为“末尾指针”,以完成剩余数据的处理。
使用这种办法,能使末尾的数据也能向量化处理。代价就是——部分末尾的数据会被重复处理。但由于现在是“一边读取、一边写入”,故重复处理并不会带来负面影响。
在向量运算的循环中,增长指针地点判断的分支代码,的确会影响性能。但是由于现在CPU都拥有强大的分支预测能力,对于“末尾指针”判断这种在最后一次循环时才见效的分支,分支预测绝大多数是乐成的,从而掩饰了该分支判断的花费。
实在本系列的前面几篇文章,也是使用这一办法,使末尾的数据也能向量化处理。所以代码中有“The last block is also use vector”的注释。
(另注:在C语言中,C99尺度新增了restrict关键字来标记“指针指向不同的数据地区”情况。restrict用于限定和约束指针,表示这个指针只访问这块内存的唯一方式,也就是告诉编译器,这块内存中的内容的操作都只会通过这个指针,而不会通过其他变量或者指针。C# 目前还没有这样的关键字)
2.2 算法实现
根据上面的思路,编写代码。源代码如下。
public static unsafe void UseVectorsDoBatch(byte* pSrc, int strideSrc, int width, int height, byte* pDst, int strideDst) {
int strideCommon = Math.Min(Math.Abs(strideSrc), Math.Abs(strideDst));
int vectorWidth = Vector<byte>.Count;
int maxX = strideCommon - vectorWidth;
byte* pRow = pSrc;
byte* qRow = pDst + (height - 1) * (long)strideDst; // Set to last row.