让g++生成一个可以使用多核的程序?

问题描述 投票:0回答:5

我有一个带有多个 for 循环的 C++ 程序;每个运行大约 500 万次迭代。是否有任何命令可以与 g++ 一起使用来使用多核生成生成的 .exe? IE。使第一个 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;
}
c++ gcc optimization g++ cpu-cores
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,我会遇到这样的情况:

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";
}

2
投票

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


0
投票

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


0
投票

C++11 支持线程,但 C++ 编译器不会/无法自行执行任何线程。


0
投票

正如其他人所指出的,您可以手动使用线程来实现这一点。您可以查看诸如 libdispatch(又名 GCD)或 Intel 的 TBB 之类的库来帮助您以最少的痛苦完成此任务。

您提到的

-ftree-vectorize

选项用于针对CPU上的
SIMD矢量处理器单元,例如ARM的NEON或Intel的SSE。生成的代码不是线程并行的,而是使用单个线程并行操作。

上面发布的代码示例非常适合 SIMD 系统上的并行性,因为每个循环的主体显然不依赖于前一个迭代,并且循环中的操作是线性的。

至少在某些 ARM Cortex A 系列系统上,您可能需要接受稍微降低的精度才能获得全部优势。

© www.soinside.com 2019 - 2024. All rights reserved.