2016-09-24 17 views
0

我在写一个粒子模拟。 我创建了一个所有计算都发生的工作类,并使用movetothread()将它移动到QThread,以保持GUI响应(正常工作)。当在QThread上使用时,OpenMP线程只能在一个CPU上运行。 (Qt,C++)

现在为了加速计算,我想在worker中使用openMP。 奇怪的是,所有openMP线程似乎只在一个CPU内核上运行。 我注意到了这一点,因为无论是否使用openMP,CPU使用率(4个逻辑核心上的25%左右)和运行模拟的时间都不会改变。

当在worker中调用omp_get_num_procs()时,它返回4,但我没有观察到加速。我手动将num_threads()设置为4,以确保它不起作用。

该程序编译和计算是正确的(也使用openMP时)。

我听说在同时使用QThread和openMP时可能会出现问题。显然,由openMP产生的所有线程仅在分配给工作者移动到的QThread的CPU上运行。我使用的是Windows 10 64位,Qt Creator 3.6.1,Qt 5.6.0(MSVC 2013,32位)。 在.pro文件中,我添加了QMAKE_CXXFLAGS += -fopenmpQMAKE_LFLAGS += -fopenmp。也LIBS += -fopenmp

qmake的是:

qmake.exe ParticleSimulations.pro -r -spec Win32的克++ “CONFIG + =调试”, “CONFIG + = qml_debug”

提出的是:

mingw32-make.exe in C:\ ...

编辑: 我也叫'omp_get_num_threads()'返回4.我感兴趣的是线程是在单独的CPU上运行还是仅在一个上运行。

编辑: 通过请求下面是我的一些代码(不知道是否有帮助得多) 这是从第二的QThread创建mainwindow.cpp,负责计算:

Pot=new LennardJones(sig,eps,mass,acc); 
    if (ParticlesTypeID==0) 
     Part=new TestParticles(confDia->getTestParticlesID(),L,Duration); 
    else if (ParticlesTypeID==1) 
     Part=new RandomParticles(n,L,Duration); 
    else if (ParticlesTypeID==2) 
     Part=new FileParticles(confDia->getValuesFromFile(),L,Duration); 

    thread = new QThread; 
    Pot->moveToThread(thread); 

    connect(Pot, SIGNAL(finished()), thread, SLOT(quit())); 
    connect(Pot, SIGNAL(finished()), Pot, SLOT(deleteLater())); 
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
    connect(this, SIGNAL(CancelClick()), Pot, SLOT(onCancelClick())); 
    connect(Pot, SIGNAL(sendProgress(int)), this, SLOT(on_Progress(int))); 
    connect(Pot, SIGNAL(sendTime(double)), this, SLOT(on_Time(double))); 

    thread->start(); 
    // Calculation 
     Part->setParticleData(Pot->Newton(Part->getParticleData(),Part->gettspan(),Part->getL(),MaxNewtonIterations,MaxSteps,MinSteps)); 

这是部分计算发生的地方(就如一个例子)。调用omp_get_num_threads()或omp_get_num_procs()让我相信OpenMP原则上工作正常。

void LennardJones::NewtonIteration(Eigen::MatrixXd &ParticleData, Eigen::VectorXd &FirstDer, Eigen::MatrixXd &SecDer, Eigen::VectorXd &GKplus1, Eigen::MatrixXd &GderInvKplus1, Eigen::MatrixXd &temp, int &k, double &deltat, int &maxiterations){ 
int counter=0; 
while(((temp-ParticleData.col(k)).norm() > accuracy) && (counter<maxiterations)){ 
    #pragma omp parallel sections 
    { 
     #pragma omp section 
     { 
      FirstDer=FirstDerivative(ParticleData); 
      GKplus1=BuildGKplus1(ParticleData,FirstDer,deltat); 
     } 
     #pragma omp section 
     { 
      SecDer=SecondDerivative(ParticleData); 
      GderInvKplus1=BuildGderInvKplus1(ParticleData,SecDer,deltat);    
     } 

    }  
    temp = ParticleData.col(k); 
    ParticleData.col(k)=ParticleData.col(k)-GderInvKplus1*GKplus1; 
    counter++; 
} 

}

另一个代码snipplet。在这里,我尝试并行化的它运行n次(n是颗粒的数量,应该有很大的性能提升)

#pragma omp parallel for 
for (int i=1;i<=n;i++){ 
    for (int j=1;j<=n;j++){ 
     if(j!=i){ 
      //Positionsvektoren die in diesem Schritt betrachtet werden 
      v1K=ParticleData.block(3*(n+i-1),ParticleData.cols()-2,3,1); 
      v2K=ParticleData.block(3*(n+j-1),ParticleData.cols()-2,3,1); 
      v1Kplus1=ParticleData.block(3*(n+i-1),ParticleData.cols()-1,3,1); 
      v2Kplus1=ParticleData.block(3*(n+j-1),ParticleData.cols()-1,3,1); 

      //Distanz r 
      rK = (v1K-v2K).norm(); //Distance(v1K,v2K); 
      rKplus1 = (v1Kplus1-v2Kplus1).norm(); //Distance(v1Kplus1,v2Kplus1); 

      //Großer ausklammerbarer Term in der ersten Ableitung 
      tempK=-12*epsilon*(pow(sigma,12)/pow(rK,14) - pow(sigma,6)/pow(rK,8)); 
      tempKplus1=-12*epsilon*(pow(sigma,12)/pow(rKplus1,14) - pow(sigma,6)/pow(rKplus1,8)); 

      // Erste Ableitungen 
      FirstDerK.segment(3*i-3,3)+=tempK*(v1K-v2K); 
      FirstDerKplus1.segment(3*i-3,3)+=tempKplus1*(v1Kplus1-v2Kplus1); 


     } 
    } 
} 

感谢很多提前循环! :)

+0

我在这里使用它,尽管在Fedora Linux 64位上,它工作正常。我认为OpenMP可能无法正确链接?进行调试构建和配置文件,然后在配置文件中查找'omp'函数。 – iksemyonov

+0

请停止downvoting,这是一个有效的问题,虽然它可能缺乏调试工作。 – iksemyonov

+0

另外,发布代码也许有意义,也许OpenMP代码本身是错误的。我想你最好调用'omp_get_num_threads()'来检查创建的线程数量,而不是'_procs()'。 – iksemyonov

回答

0

我使用OpenMP与QThread和他们一起正常工作。在问题所描述的情况的两个主要区别是:

1)我使用Linux与GCC6

2)工人阶级和QThread类是分开的。由此,我的意思是有一个纯粹的STL/Eigen /无论什么,但Qt的,工人阶级。然后,有一个包装类继承自QObject,并拥有一个worker类的实例。信号插槽连接是在应用程序和包装器类之间建立的,然后再调用worker类的方法。

通过这样的设置,并发度等于核心数量。

为了进一步调试并发性问题,我建议下载免费的英特尔Parallel Studio XE并执行配置文件运行。然后,您将能够观察到(a)并发程度和(b)是否正在使用OpenMP,因为从现在开始,您可以在配置文件中看到_ omp函数。

这样,我看到2个线程(主GUI + QThread之一),然后在调用OpenMP的函数时创建12个(Xeon X5650 HT on)。因此,我得出结论QThread线程与OpenMP的线程是分开的。顺便说一句,我使用纯粹的GDB调试器来管理它,因为每次创建新线程时都会输出一条消息。

除此之外,我看到一组不同的标志被推荐使用OpenMP:-fopenmp-lgomp。所以,你的情况,

QMAKE_CXXFLAGS += -fopenmp 
QMAKE_LFLAGS += -lgomp 

虽然在GCC5和GCC6,只是第一个标志,-fopenmp,已经足够了。

+0

明天我会试试。谢谢! – Squidward1314

+0

@ Squidward1314建议的解决方案是否解决了问题? – iksemyonov

相关问题