我在写一个粒子模拟。 我创建了一个所有计算都发生的工作类,并使用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 += -fopenmp
和QMAKE_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);
}
}
}
感谢很多提前循环! :)
我在这里使用它,尽管在Fedora Linux 64位上,它工作正常。我认为OpenMP可能无法正确链接?进行调试构建和配置文件,然后在配置文件中查找'omp'函数。 – iksemyonov
请停止downvoting,这是一个有效的问题,虽然它可能缺乏调试工作。 – iksemyonov
另外,发布代码也许有意义,也许OpenMP代码本身是错误的。我想你最好调用'omp_get_num_threads()'来检查创建的线程数量,而不是'_procs()'。 – iksemyonov