如何让g++编译的程序可以利用多核心?

3
我有一个C++程序,其中有多个For循环;每个循环运行约500万次。是否有任何命令可以与g++一起使用,使生成的.exe文件使用多个核心;即使第一个For循环在第一个核心上运行,第二个For循环在第二个核心上同时运行?我尝试了-O3和-O3-ftree-vectorize,但在这两种情况下,我的CPU使用率仍然只停留在大约25%。
编辑: 以下是我的代码,以防有所帮助。基本上,我只是制作一个测试计算机速度能力的程序。
#include <iostream>
using namespace std;
#include <math.h>
int main()
{

float *bob = new float[50102133];
float *jim = new float[50102133];
float *joe = new float[50102133];

int i,j,k,l;
//cout << "Starting test...";
for (i=0;i<50102133;i++)
    bob[i] = sin(i); 
for (j=0;j<50102133;j++)
    bob[j] = sin(j*j);
for (k=0;k<50102133;k++)
    bob[k] = sin(sqrt(k));
for (l=0;l<50102133;l++)
    bob[l] = cos(l*l);
cout << "finished test.";
cout << "the 100120 element is," << bob[1001200];

return 0;
}

2
为什么不使用线程? - Paul R
有些相关:https://dev59.com/-Gox5IYBdhLWcg3wYzQt - Mysticial
5个回答

8
最明显的选择是使用OpenMP。假设您的循环非常容易并行执行多个迭代,那么您可能只需要添加以下代码:
#pragma openmp parallel for

在循环之前添加-fopenmp,并让它以并行方式执行。根据循环内容的不同,这可能会获得接近线性加速或略微降低代码速度。在后一种情况(减速或最小加速)中,您可以使用OpenMP进行其他操作以帮助加速,但是如果不了解代码本身的基础知识,那么很难猜测要做什么或可望获得的最大改进。

您正在获得的另一个建议("使用线程")可能是适当的。 OpenMP基本上是一种自动化方式,用于针对特定类型的并行代码利用线程。对于诸如您所描述的情况(并行执行多个循环迭代),通常更喜欢使用OpenMP-它要简单得多,并且除非您非常了解多线程和/或为将代码并行化而付出大量努力,否则可能会获得更好的性能。

编辑:

你在问题中提供的代码可能不会从多个线程中受益。问题在于,在将结果写入内存之前,它对每个数据项的计算非常少。即使单个核心可以在足够快的时间内完成计算,整体速度也可能受到与内存的带宽有关的限制。

要有机会从多个线程中获得一些实际利益,您可能需要编写一些执行更多计算和更少读写内存的代码。例如,如果我们将您的计算合并在一起,并在单个项目上执行所有计算,然后汇总结果:

double total = 0;

for (int i = 0; i < size; i++)
    total += sin(i) + sin(i*i) + sin(sqrt(i)) + cos(i*i);

通过添加一个编译指示:

#pragma omp parallel for reduction(+:total)

如果我们在for循环之前加入OpenMP,我们有很大的机会看到执行速度的显著提高。没有OpenMP,我得到了如下时间:

Real    16.0399
User    15.9589
Sys     0.0156001

...但是当我编译时启用#pragma和OpenMP,我会得到这样的时间:

Real    8.96051
User    17.5033
Sys     0.0468003

因此,在我的(双核)处理器上,时间从16秒降至9秒 - 并非快了两倍,但相当接近。当然,您获得的改进很大程度上取决于您可用的核心数量。例如,在我的另一台计算机上(使用Intel i7 CPU),我获得了更大的改进,因为它具有更多的核心。

没有OpenMP:

Real    15.339
User    15.3281
Sys     0.015625

...并使用OpenMP:

Real    3.09105
User    23.7813
Sys     0.171875

为了完整起见,这是我使用的最终代码:

#include <math.h>
#include <iostream>

static const int size = 1024 * 1024 * 128;
int main(){
    double total = 0;

#pragma omp parallel for reduction(+:total)
    for (int i = 0; i < size; i++)
        total += sin(i) + sin(i*i) + sin(sqrt(i)) + cos(i*i);
    std::cout << total << "\n";
}

谢谢!我尝试了您优化后的代码,使用优化后的代码,在30秒内能够运行约50亿次计算(与没有使用-fopenmp时的近2分钟相比),而原始的、占用大量内存的程序每秒只能迭代约500万次。 - user3368803

2

编译器无法确定循环内的代码是否可以在多个核心上安全执行。如果您想使用所有核心,请使用线程。


0

C++11 支持 多线程,但 C++ 编译器本身无法进行任何线程操作。


0

使用线程或进程,您可能需要查看OpenMp


0
正如其他人所指出的,您可以手动使用线程来实现这一点。 您可能需要查看类库,例如libdispatch (aka. GCD) 或 Intel's TBB,以在最小的痛苦下帮助您完成此操作。
您提到的-ftree-vectorize选项是为了针对诸如ARM的NEON或Intel的SSE等CPU上的SIMD向量处理器单元。 生成的代码不是线程并行的,而是使用单个线程的操作并行。
上面发布的代码示例非常适合在SIMD系统上进行并行处理,因为每个循环体显然没有依赖于前一个迭代,并且循环中的操作是线性的。
至少在某些ARM Cortex A系列系统上,您可能需要接受略微降低的精度才能获得全部效益。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接