减少OpenMP开销

时间:2018-01-05 23:49:48

标签: c++ multithreading openmp

我正在尝试并行化一些IIR过滤代码,到目前为止使用gcc 7.2和gomp

以下是相关的代码部分:

void par_iir(std::vector<std::vector<double>>& data, const std::vector<double>& B, int order) {
    int N = data[0].size();
    const int CHUNK_SIZE = 32768;
    int chunks = ceil((double)(N - 2) / (double)CHUNK_SIZE);
    int gChunk;

    #pragma omp parallel private(gChunk) shared(chunks, order, B, data)
    {
        for (gChunk = 0; gChunk < chunks + order - 1; gChunk++) {
            #pragma omp for
            for (int i = 0; i < order; i++) {
                auto chunk = gChunk - i;

                if (chunk >= 0 && chunk < chunks) {
                    auto sz = chunk == (chunks - 1) ? (N - 2) % CHUNK_SIZE : CHUNK_SIZE;
                    auto inp = data[i].data();
                    auto out = data[i + 1].data();

                    filter(inp + chunk * CHUNK_SIZE + 2, B.data() + i * 5, out + chunk * CHUNK_SIZE + 2, sz);
                }
            }
        }
    }
}

功能过滤器定义如下:

inline void filter(const double* in, const double* B, double* out, int sz) {
    for (int i = 0; i < sz; ++i)
        out[i] = in[i] * B[0] + in[i - 1] * B[1] + in[i - 2] * B[2] - out[i - 1] * B[3] - out[i- 2] * B[4];
}

par_iir定义了级联IIR滤波器,filter在级联中应用了单个双四极杆。 order确定有多少级联双四边形组成过滤器。我的电脑有4个核心(8个线程),我选择了一个8阶的过滤器。

由于IIR过滤器具有循环依赖性,我选择将工作划分为块(目前固定大小为32768)。这个想法是,一旦级联中的双四元i的块是完成后,双四元ii+1可以并行完成。

我原以为这会导致接近所有最多使用的8个线程,所以接近8倍的改进。相反,我通常会在每个线程上看到大约33%的负载。

使用perf我对代码进行了分析,发现约有63%的时间用于gomp_thread_start。即使我按比例增加NCHUNK_SIZE,这个~63%也不会改变。

这63%的开销来自哪里?其次,有没有更好的方法来编写这段代码?

有关IIR滤波器的一些细节,如果它有帮助:

就我的目的而言,IIR滤波器由多个双四极滤波器组成。每个双四进制过滤器执行以下操作,其中ab值是常量:

out[n] = b0*in[n] + b1*in[n-1] + b2*in[n-2] - a1*out[n-1] - a2*out[n-2]

级联的每个部分都被赋予前一部分的输出作为其输入。这使得大多数并行方法变得不可行。

0 个答案:

没有答案