您如何同时迭代两个以优化方式未等距排列的数组?

时间:2018-10-26 07:16:38

标签: c++ optimization branch-prediction

假设我要将两个数组(例如A[MAX_BUFFER]B[MAX_BUFFER](用MAX_BUFFER = 256)相乘。

由于某些原因,每个B[MAX_BUFFER]值都是以固定的控制速率(例如,8)计算的,因为每个值都会被大量处理。

稍后,考虑到(引入的)不同的间距,我需要将彼此乘以C[MAX_BUFFER]。因此,将A设置为256个值,我将得到一个B,其大小可变(在本示例中为32,因为控制率为8)。

这里是AutoValue

#include <iostream>
#include <math.h>

#define MAX_BUFFER 256

double HeavyFunction(double value) {
    if (value == 0) return 0.0;

    return pow(10.0, value); // heavy operations on value...
}

int main()
{    
    int blockSize = 256;
    int controlRate = 8;

    double A[MAX_BUFFER];
    double B[MAX_BUFFER];
    double C[MAX_BUFFER];

    // fill A
    for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex++) {
        A[sampleIndex] = sampleIndex;
    }

    // fill B (control rated)
    int index = 0;
    for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex += controlRate, index++) {
        B[index] = HeavyFunction(index);
    }

    // calculate C
    for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex++) {     
        C[sampleIndex] = A[sampleIndex] + B[sampleIndex / 8];

        std::cout << C[sampleIndex] << std::endl;
    }
}

我需要性能,因为我将并行处理许多这些操作,并在1秒内发送许多数据(例如,在blockSize <= MAX_BUFFER中分割了44100个样本)。

我想避免分支(即if)和除法(如上例)那样的操作,而不是类似CPU的操作(处理大量数据)。

在前面的示例中,这将引入sampleIndex / 8 * N“无效”的N操作;如果我为数百万个样本调用该过程,那将是一件很有趣的事情...

您将如何以一种花哨的方式为CPU重构此代码?

2 个答案:

答案 0 :(得分:0)

我认为优化器可能单独完成这项工作,但是您可以展开循环以避免划分:

// calculate C
const max = blockSize / 8;
int j = 0;
for (int i = 0; i != max; ++i) {
    const auto b = B[i];
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
    C[j] = A[j] + b; std::cout << C[j] << std::endl; ++j;
}

答案 1 :(得分:0)

  

您如何同时迭代两个未以优化方式等距排列的数组?

简短答案:专注于HeavyFunction,避免在线程之间共享不必要的内容。

不幸的是,您的例子不适合他的问题。数组

double A[MAX_BUFFER];
double B[MAX_BUFFER];
double C[MAX_BUFFER];

仅通过移动堆栈指针就可以在堆栈上分配,因此可以说它们与一个连续数组非常相似。

即使不是现代高速缓存,也是如此复杂,以至于通过尝试进行微优化,最终可能会降低性能。

假设您有

BUFFER_SIZE = 1024 * 1024 * 1024;
std::vector<double> A(MAX_BUFFER);
std::vector<double> B(MAX_BUFFER);

一个很好的改进是

std::vector<double> C{A};
for (int i = 0; i < blockSize/controlRate; i++) { 
     const double b = B[i];
     int indexStart = i*controlRate;
     for(int j = 0 ; j < controlRate; ++j){
        Cprime[indexStart+j] += b;
     }

}

您一次读取A(以块为单位),一次读取B(一次为两倍),然后访问C的时间相同。