我正在尝试优化我的时间步长方法,它位于自适应网格上。它设置了三个类:Mesh(基类),Level(标识自适应网格的级别)和Rectangle(其中许多位于给定级别,并保存我问题的所有数据)。
推进时间步长的工作首当其冲在于Rectangle类中的函数FCTTimeStep
,我已经能够在使用标准并行的多个线程上非常有效地运行(根据英特尔的VTune)最紧密的循环上的pragma:
#pragma omp parallel
{
#pragma omp for schedule(guided)
for (int i=1; i<nx; i++) {
#pragma ivdep
for (int j=0; j<np; j++) {
// Work
}
}
#pragma omp for schedule(guided)
for (int i=1; i<dx; i++) {
#pragma ivdep
for (int j=0; j<dp; j++) {
// More Work
}
}
}
这让我几乎没有旋转时间并且工作正常。问题是我在整个程序运行时调用FCTTimeStep
数百万次。经理类调用其Advance
函数:
for (int i = 0; i < 6; i++) { //RungeKutta Steps, must be sequential
EMSolver->AssembleRhoAndJ(); //Single thread
EMSolver->UpdatePotential(); //Single thread
for (unsigned int j = 0; j < settings.q.size(); j++) {
meshes[j]->Advance(timeStep, i); //Mesh call
}
settings.UpdateTime(i, timeStep); //Single thread
EMSolver->RGKStep(i, timeStep); //Single thread
}
Mesh::Advance
调用网格中的每个Level::Advance
(通过for循环 - 多次,其中单线程工作),然后为每个级别调用所有矩形Rectangle::FCTTimeStep
方法(再次通过for循环)。每次访问FCTTimeStep
时都会调用3到10个线程for循环 - 这会导致调用clone
(由于常量fork / join)导致的大量开销。使用4个线程进行的分析测试运行告诉我,25%的运行时间由此占用,12个核心超过60%。
我想尝试的是将整个程序保存在并行编译语中
#pragma omp parallel
{
while (t < T_stop) {
double dt_adaptive = CalculateDt(settings.cfl);
SM.Advance(dt_adaptive); //Call to the managers' Advance function
#pragma omp single
{
//Single work
}
}
}
并将工作人员送到FCTTimeStep
中的孤儿pragma。由于单个工作区域,这将显着增加线程旋转时间,但应该给我一个更好的通用运行时。
因此我的问题如下:有没有办法让OpenMP将工作人员单独发送到线程区域,否则以单一模式运行?否则并行区域将使每个线程调用advance方法,我不确定如何解决在多个类的嵌套for循环结构中设置正确的pragma以阻止它。
我见过这个结构:
#pragma omp parallel
#pragma omp single nowait
{
#pragma omp task
// Work
#pragma omp task
// More Work
#pragma omp taskwait
// Single Work
}
即用单个,然后调用任务来控制整个区域,但这似乎不适用于for pragma。所以也许更好的问题可能是 for pragma可以设置为与 task pragma类似吗?
非常感谢任何一般性帮助或指向适当信息的链接。