我目前正在使用OpenMP在4核Phenom2上并行化程序。然而,我注意到我的并行化对性能没有任何影响。自然地,我认为我错过了什么(如false sharing、锁定序列化等),但是我没有找到任何类似的问题。此外,从CPU利用率来看,似乎程序只在一个核上执行。根据我所发现的,sched_getcpu()
应该给我当前调度线程的核心ID。因此,我编写了以下测试程序:
#include <iostream>
#include <sstream>
#include <omp.h>
#include <utmpx.h>
#include <random>
int main(){
#pragma omp parallel
{
std::default_random_engine rand;
int num = 0;
#pragma omp for
for(size_t i = 0; i < 1000000000; ++i) num += rand();
auto cpu = sched_getcpu();
std::ostringstream os;
os<<"\nThread "<<omp_get_thread_num()<<" on cpu "<<sched_getcpu()<<std::endl;
std::cout<<os.str()<<std::flush;
std::cout<<num;
}
}
在我的电脑上,这将输出以下内容(随机数当然会有所不同):
Thread 2 on cpu 0 num 127392776
Thread 0 on cpu 0 num 1980891664
Thread 3 on cpu 0 num 431821313
Thread 1 on cpu 0 num -1976497224
从这里我推断所有线程都在同一个核心上执行(即id为0的那个)。为了更确定,我还尝试了这个答案中提到的方法。结果也是一样的。此外,使用
#pragma omp parallel num_threads(1)
并没有使执行变慢(事实上略微加快了),从而证明了所有线程使用同一个CPU的理论可信度,但是CPU始终显示为0
让我有点怀疑。此外,我检查了GOMP_CPU_AFFINITY
,最初没有设置它,所以我尝试将其设置为0 1 2 3
,这应该将每个线程绑定到不同的核心。然而,这并没有什么区别。由于我在Windows系统上开发,我在虚拟机中使用Linux进行开发。因此我认为可能虚拟系统无法访问所有核心。然而,检查virtualbox的设置显示虚拟机应该获得所有4个核心,并且同时执行我的测试程序4次似乎使用了所有4个核心,从CPU利用率(以及系统非常不响应的事实)来判断。
因此,我的问题基本上是这里究竟发生了什么。更重要的是:我的推断所有线程使用同一个核心是正确的吗?如果是,可能是什么原因导致了这种行为?
OMP_NUM_THREADS
,但由于openmp会创建4个线程,我认为不需要设置。 - Grizzly