Visual studio 2017 在Visual Studio 2017中启用开放式MP支持会降低代码的速度

Visual studio 2017 在Visual Studio 2017中启用开放式MP支持会降低代码的速度,visual-studio-2017,openmp,eigen,Visual Studio 2017,Openmp,Eigen,我正在尝试使用OpenMP来加速我的神经网络计算代码。由于我正在使用Visual Studio 2017,我需要在属性页中启用OpenMP支持。但是,在我这样做之后,代码的某些部分会减慢大约5倍,即使我没有在代码中包含任何#pragma omp 我已经隔离了这些部分,并发现这一特定功能导致了问题: void foo(Eigen::Matrix<float,3,Eigen::Dynamic> inputPts) { std::vector<Eigen::MatrixXf&

我正在尝试使用OpenMP来加速我的神经网络计算代码。由于我正在使用Visual Studio 2017,我需要在属性页中启用OpenMP支持。但是,在我这样做之后,代码的某些部分会减慢大约5倍,即使我没有在代码中包含任何
#pragma omp

我已经隔离了这些部分,并发现这一特定功能导致了问题:

void foo(Eigen::Matrix<float,3,Eigen::Dynamic> inputPts)
{
    std::vector<Eigen::MatrixXf> activation;
    activation.reserve(layerNo);
    activation.push_back(inputPts);

    int inputNo = inputPts.cols();

    for (int i = 0; i < layerNo - 2; i++)
        activation.push_back(((weights[i]*activation[i]).colwise()+bias[i]).array().tanh());

    activation.push_back(((weights[layerNo - 2]*activation[layerNo - 2]).colwise()+bias[layerNo - 2]));

    val = activation[layerNo - 1]/scalingFactor;

    std::vector<Eigen::MatrixXf> delta;
    delta.reserve(layerNo);

    Eigen::Matrix<float, 1, Eigen::Dynamic> seed;
    seed.setOnes(1, inputNo);
    delta.push_back(seed);

    for (int i = layerNo - 2; i >= 1; i--)
    {
        Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic>
                d_temp = weights[i].transpose()*delta[layerNo - 2 - i],
                d_temp2 = 1 - activation[i].array().square(),
                deltaLayer = d_temp.cwiseProduct(d_temp2);

        delta.push_back(deltaLayer);
    }

    grad = weights[0].transpose()*delta[layerNo - 2];
}
void foo(特征::矩阵输入)
{
载体激活;
激活。保留(layerNo);
激活。推回(输入点);
int inputNo=inputps.cols();
对于(int i=0;i=1;i--)
{
本征矩阵
d_temp=weights[i].transpose()*delta[layerNo-2-i],
d_temp2=1-激活[i].array().square(),
deltaLayer=d_temp.cwiseProduct(d_temp2);
delta.推回(deltaLayer);
}
梯度=权重[0]。转置()*delta[layerNo-2];
}
两个for环路的速度显著降低(从~3ms到~20ms)。奇怪的是,虽然这个函数在程序中被多次调用,但只有其中一些函数受到影响

我已经包含了头文件
。我不确定这是否是由于到处都使用的特征库。我尝试定义
EIGEN\u DONT\u PARALLELIZE
并按照中的建议调用
EIGEN::initParallel()
,但没有任何帮助


奇怪的是,我甚至没有包含任何
并行pragma
,处理OpenMP函数不应该有任何开销?为什么它仍在减速?

如果启用OpenMP,默认情况下,Eigen的矩阵产品是多线程的。问题可能是以下因素的组合:

  • 您的CPU是超线程的,例如,您有4个物理内核可以运行8个线程
  • OpenMP不允许知道物理内核的数量,因此Eigen将启动8个线程
  • Eigen的矩阵积内核经过充分优化,利用了近100%的CPU容量。因此,在一个内核上没有空间运行两个这样的线程,性能会显著下降(缓存污染)
  • 因此,解决方案是将OpenMP线程的数量限制为物理内核的数量,例如通过设置OMP_NUM_threads环境变量。您还可以通过在编译时定义宏
    Eigen\u DONT\u PARALLELIZE
    来禁用Eigen的多线程

    更多信息请访问

    有关超线程如何降低性能的更多详细信息:
    使用“超线程”,您可以在一个内核上以交错方式运行两个线程。他们轮流执行每项指令。如果您的线程使用的CPU资源(在计算方面)不少于一半,那么这是一个胜利,因为您将利用更多的计算单元。但是,如果单个线程已经使用了100%的计算单元(如优化良好的矩阵积),那么您将失去性能,因为1)管理两个线程的自然开销,2)因为一级缓存现在由两个不同的任务共享。矩阵核的设计考虑了精确的L1容量。使用两个线程,一级缓存几乎变得无效。这意味着,在大多数情况下,不是获取非常快的一级缓存,而是访问速度慢得多的二级缓存,从而导致性能大幅下降。与Linux和Windows不同,在OSX上,我没有观察到这样的性能下降,很可能是因为如果CPU已经太忙,系统能够取消第二个线程的调度。

    谢谢您的回复。我添加了行
    omp\u set\u num\u线程(2);特征::setNbThreads(1);Eigen::initParallel()(请参阅),运行时将恢复正常。不幸的是,即使我添加了
    #pragma
    语句,我的计时也没有改进。在我的例子中,并行线程是不够的。只需要澄清一下:超线程是如何导致这个问题的?将OMP_NUM_THREADS设置为2会提供通常的运行时间,但4会降低代码的速度。这就是我在回答中试图解释的,我用更多细节扩展了回答。