如何自动并行化堆阵列?

时间:2019-01-14 19:41:39

标签: c++ visual-studio performance parallel-processing x86

我试图编写一个函数,使用并行的for循环,将堆上的数组乘以常量,但是当试图在Visual Studio 2017中使用/ Qpar-report:2设置编译时,我收到消息“循环由于原因“ 1000”而无法并行化。我对其进行了查找,并显示消息“编译器在循环体内检测到数据依赖性。”:

https://docs.microsoft.com/en-us/cpp/error-messages/tool-errors/vectorizer-and-parallelizer-messages?view=vs-2017#BKMK_ReasonCode100x

文本描述了(例如)不同的通行证取决于其他通行证的结果的情况,但此处不适用。我能想到的唯一情况是优化器可能会担心两个数组在内存中重叠,但是如何说服编译器不是这种情况呢?

我尝试使用#pragma ivdep语句强制执行该操作,并且代码可以编译,但是函数在调用时挂起。

经过大量的故障排除后,我确定如果在函数内部的堆栈上创建虚拟数组并对其进行循环,则可以成功并行化。不幸的是,我不能依靠我会接受的足够小的数组来完全复制到堆栈上。

我在SO和google上检查了并行执行类似简单数组操作的其他示例,它们都使用堆栈分配的数组。当然,有一种干净的方法可以并行处理堆数组上的操作?

#include "stdafx.h"
#include "CppUnitTest.h"
#include "../UnitsConversion/UnitsConversion.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

#define ARRAY_SIZE 10000000

double* testInD;
double* testOutD;

namespace UnitTest
{

TEST_CLASS(Parallel)
{
public:

    TEST_CLASS_INITIALIZE(setup) {
        testInD = new double[ARRAY_SIZE];
        testOutD = new double[ARRAY_SIZE];

        for (int i = 0; i < ARRAY_SIZE; i++) {
            testInD[i] = (double)rand() / (double)RAND_MAX;
            testOutD[i] = (double)rand() / (double)RAND_MAX;
        }

    }

    TEST_CLASS_CLEANUP(cleanup) {
        delete testInD;
        delete testOutD;
    }

    TEST_METHOD(PressuresD)
    {
        Assert::AreEqual(
            (int)1,
            PressureD(
                testInD,
                testOutD,
                ARRAY_SIZE
            )
        );
    }

}

int __stdcall PressureD(
    double* dblInValue,
    double* dblOutValue,
    int n) {

#pragma loop(hint_parallel(0))
    for (int i = 0; i < n; ++i) {
    dblOutValue[i] = dblInValue[i] * 5.0;
    }

    return 1;
}

无论出于何种原因,即使我认为这将是一个普遍的问题,我也没有运气与Google或SO合作找到解决方案。我想念什么吗?

编辑:

将循环更改为以下内容可以使其并行化:

for (int i = 0; i < n; ++i) {
    //dblOutValue[i] = dblInValue[i] * factor; (old version)
    dblOutValue[i] *= factor;
}

但是,当我尝试运行单元测试时,代码挂起并最终(约15秒后)中止。当我在调试模式下运行该代码时,该代码有效,但我95%的确信这是因为在调试中运行时,该代码不会并行化。

1 个答案:

答案 0 :(得分:1)

这是一个简单的新/删除不匹配。您的单元测试具有数组new[]和标量delete

放弃手动内存管理,并使用std::unique_ptr<double[]>std::vector<double>。为了使并行化成功,您可能需要在循环之前获取一个指向数据的裸露指针(实际上,PressureD根本不需要更改),但是您无需手动管理生命周期