OpenMP使许多内核处于闲置状态

时间:2018-07-31 16:19:52

标签: c++ parallel-processing openmp

我正在尝试使用OMP来并行化一些代码,在我的常规工作站上,我将其与4个内核(我拥有的最大内核)一起使用。 在处理过程中,我所有的内核都达到了100%的速度,而且运行速度很快。 但是,现在我将代码移到服务器上以处理大量数据,并且将内核数更新为30(服务器有32个内核)。

但是,当我启动该进程时,似乎正确启动了30个线程,但是我的大多数内核都为0%,除了大约5%的内核约为20%,但是过程很长。 “ top”报告我的进程使用145%的CPU,如果使用30个内核,则应该接近3000%。

这是我的并行化代码:

#pragma omp parallel for num_threads(N_CORES) schedule(static,1) shared(viImgCounts, viLabelCounts, vfLabelLogLikelihood, ppfMatchingVotes)
      for (int n = 0; n < N_CORES; ++n)
        {
          // Each thread process it's range of files
          for (int i = vpChunkStartEnd[n].first; i <= vpChunkStartEnd[n].second; i++)
            {
              printf("Searching %d of %d ... ", i, vvInputFeats.size());
              ProcessingData(i, viImgCounts, viLabelCounts, vfLabelLogLikelihood, ppfMatchingVotes, ppiLabelVotes);
              printf("\n");
            }
        }

在这里,我将N_CORES定义为30(#define N_CORES 30)。

每个线程都有一系列要处理的文件(vpChunkStartEnd),因此,据我所知,它们都应以100%的速度一起运行,以处理其文件列表。我不确定要为什么不在这里(当它在我的具有4个核心的工作站上)发生这种情况。

我在#pragma中忘记了什么吗?

谢谢。

编辑: 这是我得到的输出:

Searching 6750 of 7482 ... Searching 4000 of 7482 ... Searching 3750 of 7482 ... Searching 5000 of 7482 ... Searching 0 of 7482 ... Searching 500 of 7482 ... Searching 2250 of 7482 ... Searching 5500 of 7482 ... |0|Searching 5750 of 7482 ... |0|Searching 6000 of 7482 ... |0|Searching 7250 of 7482 ... |0|Searching 7000 of 7482 ... Searching 750 of 7482 ... Searching 3250 of 7482 ... Searching 1000 of 7482 ... |1||1|Searching 1500 of 7482 ... Searching 2750 of 7482 ... Searching 2000 of 7482 ... |1|Searching 5250 of 7482 ... |0||0|Searching 3500 of 7482 ... Searching 4500 of 7482 ... |0|Searching 1250 of 7482 ... |1|Searching 4750 of 7482 ... |0||1|Searching 6250 of 7482 ... |1|Searching 250 of 7482 ... |1|Searching 4250 of 7482 ... |0|Searching 1750 of 7482 ... |0||0||0||1||0||1||1|Searching 3000 of 7482 ... |0||0||1||0|Searching 2500 of 7482 ... |0|Searching 6500 of 7482 ... |1||0|
Searching 4001 of 7482 ... |0|
Searching 3001 of 7482 ... |0|
Searching 3251 of 7482 ... |0|
Searching 6751 of 7482 ... |1|
Searching 2251 of 7482 ... |0|
Searching 1751 of 7482 ... |0|
Searching 1501 of 7482 ... |0|
Searching 5501 of 7482 ... |1|
Searching 5001 of 7482 ... |1|
Searching 7001 of 7482 ... |1|
Searching 1251 of 7482 ... |0|
Searching 5251 of 7482 ... |1|
Searching 4501 of 7482 ... |1|
Searching 3751 of 7482 ... |0|
Searching 5751 of 7482 ... |1|
Searching 2751 of 7482 ... |0|
Searching 4002 of 7482 ... |0|
Searching 4751 of 7482 ... |1|
Searching 6251 of 7482 ... |1|
Searching 6501 of 7482 ... |1|
Searching 6001 of 7482 ... |1|
Searching 2001 of 7482 ... |0|
Searching 3501 of 7482 ... |0|
Searching 3252 of 7482 ... |0|

我们可以看到,由于多个线程并行运行,因此在第一次迭代中,文本全部被打乱了,但是此后,所有内容都被正确打印,并且大多数内核都处于空闲状态,因此感觉每次迭代都在等待上一个迭代完成开始。他们可能不会同时完成循环,这可能只是一个巧合,但这会继续处理数千个文件,因此这将是一个巨大的巧合,而且大多数核心都处于闲置状态,我想其他迭代未正确并行化。

编辑2:好的,发生了一些问题。正如评论中提到的,“ top”告诉我没有更多的可用内存(几乎没有800MB),但是资源管理器仅显示了50%的已使用内存(在48GB中)。我开始运行大约20GB的软件,但最终将其杀死。现在“ top”向我显示20GB可用内存(使用的内存没有移动),现在我的程序以1000%的速度运行。 因此,我想知道top是否真的对可用的可用内存是正确的,这就是在减慢我的程序的速度,但是我也想知道为什么启动一个使用大量内存的程序并杀死它会释放该内存。 是否有可能由于内存泄漏而导致内存消失,并且程序请求了内存,所以泄漏的内存已被重用,并且当程序被杀死后,它又将其返回到“空闲”内存中,从而可用于系统吗?

编辑3:好的,看来这不是问题所在。 CPU使用率已恢复到350%(大多数核心再次处于空闲状态),甚至top表示我有20GB的可用内存。 CPU使用率太不均匀了,我不明白。

是否有可能因为我对某些变量使用了“共享”,所以线程不得不等待其他线程完成此变量的访问(例如互斥锁)?因为我确保没有线程将在此变量的相同位置写入。这是为什么它会减慢我的代码的速度吗?

编辑4:好吧,现在我有了一些内存,似乎已经用完了我所有的内核,但是它们都占了30%,这次我有足够的可用内存(很少)其中50%),但这并不疯狂。我应该增加线程数吗?还是只是将它们排队(这不会提高CPU使用率)?

编辑5:我使用htop来获取一些统计信息,看来我一次平均有10个正在运行的任务,如果我启动了30个线程,则相当于30%的CPU使用率(这就是我所拥有的)。因此,似乎不是我所有的线程都一直在运行,但是我不明白为什么。我可能需要对其进行概要分析,但是我使用valgrind进行了测试,使用它的速度很慢(我需要先加载一堆数据,而valgrind却无法使用)。

编辑6:因此,我编写了一个虚拟程序,使用了与代码中相同的omp参数和相同的结构,但是我没有调用ProcessingData函数,而是增加了一个变量,它创建了约30个正在运行的任务,我的CPU使用率达到100%。但是,当我使用函数时,它会创建5至15个正在运行的任务,而我从未达到100%。 我使用htop查看线程的状态,并且他们在“ D”状态(不间断睡眠)花费了很多时间。我想我需要对它们进行分析以了解原因。

1 个答案:

答案 0 :(得分:0)

我们看不到其余的代码,但是您可能想尝试使用以下功能来了解发生了什么:

omp_get_num_threads() // get the number of threads operating in a parallel region    

并且:

omp_set_num_threads(numThreads) // set the number of threads used in a parallel region

与仅查看处理器活动监视器相比,这将使您更好地了解处理器利用率。

还有其他一些很棒的答案,它们对此进行了更详细的描述:

最后,重要的是要记住,内核与线程不是同一回事。您可能知道这一点,但是只是想保持术语的简洁。