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

时间:2014-03-01 17:22:06

标签: c++ gcc optimization g++ core

我有一个带有多个For循环的c ++程序;每个运行大约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;
}

5 个答案:

答案 0 :(得分:7)

最明显的选择是使用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";
}

答案 1 :(得分:2)

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

答案 2 :(得分:0)

C ++ 11获得了对threading的支持,但c ++编译器不会/不能自己做任何线程。

答案 3 :(得分:0)

使用主题或进程,您可能希望查看OpenMp

答案 4 :(得分:0)

正如其他人指出的那样,您可以手动使用线程来实现此目的。您可以查看libdispatch(aka。GCD)或Intel's TBB等库来帮助您以最少的痛苦来完成这项工作。

您提到的-ftree-vectorize选项用于定位CPU上的SIMD矢量处理器单元,例如ARM的NEON或Intel的SSE。生成的代码不是线程并行的,而是使用单个线程并行操作。

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

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