我有一个简单的程序,我用于物理模拟.我想知道如何在OpenMP中实现某种线程范例.
int main()
{
#define steps (100000)
for (int t = 0;t < steps; t++)
{
firstParallelLoop();
secondParallelLoop();
if (!(t%100))
{
checkpoint();
}
}
}
void firstParallelLoop()
{// In another file.c
#pragma omp parallel for
for (int i = 0; i < sizeOfSim;i++)
{
//Some atomic floating point ops.
}
}
Run Code Online (Sandbox Code Playgroud)
以前,我使用pthreads并在我的双核笔记本电脑上获得1.7加速.使用OpenMP时,我似乎无法获得任何加速.我怀疑问题是线程组/池正在快速创建和销毁,带来了灾难性的影响.
在我的pthreads实现中,我需要确保没有创建新线程,并且我的程序表现为客户端 - 服务器.在pthreads方案中,main()是一个服务器,并且调用firstParallelLoop将释放触发线程重新处理数据的互斥锁/信号量.
当我看到CPU利用率时,我预计它将超过30%的标记(4核,2是HT),但它保持在27左右......
如何让OpenMP做类似的事情?如何告诉OpenMP重用我的线程?
GCC OpenMP运行时libgomp通过类似于线程池的东西在POSIX系统上实现线程团队 - 线程仅在遇到第一个并行区域时创建,每个线程运行一个无限的工作循环.进入和退出平行区域是通过障碍实现的.默认情况下,libgomp使用busy-waiting和sleeping组合来实现障碍.忙等待的数量由OMP_WAIT_POLICY环境变量控制.如果未指定,则在屏障上等待的线程将忙 - 等待300000次旋转(在100000次旋转/毫秒时为3 ms)然后将进入休眠状态.如果OMP_WAIT_POLICY设置为active,则忙等待时间增加到30000000000次旋转(5分钟,100000次旋转/秒).您可以通过将GOMP_SPINCOUNT变量设置为忙碌周期数来微调忙碌等待时间(libgomp假设大约100000次旋转/毫秒,但根据CPU的不同,它可能会变化5倍).你可以像这样完全禁用睡眠:
OMP_WAIT_POLICY=active GOMP_SPINCOUNT=infinite OMP_NUM_THREADS=... ./program
Run Code Online (Sandbox Code Playgroud)
这将以某种方式改善线程团队的开始时间,但是以CPU时间为代价,因为空闲线程不会空闲而是忙于等待.
为了消除开销,您应该以更加OpenMP友好的方式重写程序.您的示例代码可以像这样重写:
int main()
{
#define steps (100000)
#pragma omp parallel
{
for (int t = 0; t < steps; t++)
{
firstParallelLoop();
secondParallelLoop();
if (!(t%100))
{
#pragma omp master
checkpoint();
#pragma omp barrier
}
}
}
}
void firstParallelLoop()
{// In another file.c
#pragma omp for
for (int i = 0; i < sizeOfSim; i++)
{
//Some atomic floating point ops.
}
}
Run Code Online (Sandbox Code Playgroud)
请注意以下两点:
parallel for.团队中的所有线程都将执行外部循环steps时间.for环路中firstParallelLoop,通过使用由平行omp for只.因此,如果在OpenMP并行外部调用它将作为串行循环执行,并且当从并行区域内部调用时它将作为并行执行.循环中也应该这样做secondParallelLoop.主循环中的屏障用于确保其他线程在开始下一次迭代之前等待检查点完成.
| 归档时间: |
|
| 查看次数: |
1859 次 |
| 最近记录: |