我正在尝试在PETSc框架内编写混合MPI + OpenMP线性求解器。我目前在2个节点上运行此代码,每个节点有2个插槽,每个插槽8个核心。
export OMP_MAX_THREADS=8
export KMP_AFFINITY=compact
mpirun -np 4 --bysocket --bind-to-socket ./program
我已经检查过这给了我一个很好的NUMA友好的线程分发。
我的MPI程序创建8个线程,其中1个应执行MPI通信,而其余7个执行计算。稍后,我可能会尝试超额订阅每个9个线程的套接字。
我目前这样做:
omp_set_nested(1);
#pragma omp parallel sections num_threads(2)
{
// COMMUNICATION THREAD
#pragma omp section
{
while(!stop)
{
// Vector Scatter with MPI Send/Recv
// Check stop criteria
}
}
// COMPUTATION THREAD(S)
#pragma omp section
{
while(!stop)
{
#pragma omp parallel for num_threads(7) schedule(static)
for (i = 0; i < n; i++)
{
// do some computation
}
}
}
}
我的问题是MPI通信需要花费大量时间,因为我将它们放在了OpenMP部分。在OpenMP部分内部,向量分散大约需要0.024秒,如果在OpenMP并行区域之外完成,则小于0.0025秒(快10倍)。
我的两个理论是:
1)MPI / OpenMP执行额外的线程锁定以确保我的MPI调用是安全的,即使它不需要。我已经尝试强制MPI_THREAD_SINGLE,MPI_THREAD_FUNELLED和MPI_THREAD_MULTIPLE看看我是否可以说服MPI已经安全,但这没有效果。有什么我想念的吗?
2)我的计算线程更新了通信所使用的值(它实际上是一个故意的竞争条件 - 好像这已经不够尴尬!)。可能是我面临内存瓶颈。也可能是我面临缓存抖动,但我并没有强迫任何OpenMP刷新,所以我不这么认为。
作为一个额外的问题:如果所有线程都在同一个套接字上,那么OpenMP刷新操作是否足以只刷新共享缓存?
附加信息:矢量分散是使用PETSc函数VecScatterBegin()和VecScatterEnd()完成的。 “原始”MPI实现可能没有这些问题,但是要重新实现向量分散以找出它需要做很多工作,而我宁愿不这样做。据我所知,它是一个有效的MPI发送/ Irecvs循环。