Lib*_*rus 1 c++ optimization gcc
我想知道gcc中是否存在可以使某些单线程代码(如下例)并行执行的优化.如果不是,为什么?如果是,可以进行哪种优化?
#include <iostream>
int main(int argc, char *argv[])
{
int array[10];
for(int i = 0; i < 10; ++ i){
array[i] = 0;
}
for(int i = 0; i < 10; ++ i){
array[i] += 2;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
添加:
感谢OpenMP链接,并且我认为它很有用,我的问题与编译相同的代码有关,而无需重写smth.所以基本上我想知道是否:
是的,例如,gcc with-ftree-parallelize-loops=4将尝试自动并行化 4 个线程。
我不知道 gcc 在自动并行化方面做得如何,但这是编译器开发人员多年来一直在努力的事情。正如其他答案所指出的那样,为编译器提供一些 OpenMP pragma 指导可以提供更好的结果。(例如,通过让编译器知道发生的顺序无关紧要,即使这可能会稍微改变结果,这对于浮点数来说很常见。浮点数数学不是关联的。)
而且,只对#pragma omp循环进行自动并行化意味着只有真正重要的循环才能得到这种处理。 -ftree-parallelize-loops可能受益于 PGO(配置文件引导的优化)以了解哪些循环实际上是热的并且值得并行化和/或矢量化。
这与找到 SIMD 可以利用的并行性类型有关,用于自动矢量化循环。(默认情况下-O3在 gcc 中启用,-O2在 clang 中启用)。
编译器可以尝试自动并行化您的代码,但它不会通过创建线程来实现.它可以使用向量化指令(例如,用于intel CPU的intel内在函数)一次操作多个元素,在那里它可以检测到使用这些指令是可能的(例如,当您在连续元素上执行多次相同的操作时)正确对齐的数据结构).您可以通过告诉编译器支持哪种内部指令集来帮助编译器(-mavx, -msse4.2 ...例如).
您也可以直接使用这些说明,但它需要为程序员完成大量工作.还有一些库已经这样做了(参见Agner Fog博客中的矢量类).
您可以使用OpenMP(OpenMP介绍)使编译器使用多个线程进行自动并行化,这比编译器自动并行化更能指示编译器自动并行化.
只要可观察行为(参见1.9 [intro.execution]第8段)与[correct(*)]程序指定的行为相同,编译器就可以做任何他们想做的事情.可观察行为是根据I/O操作(使用标准C++库I/O)和volatile对象访问来指定的(尽管编译器实际上并不需要volatile特别对待特殊对象,如果它可以证明它们不在可观察的内存中).为此,C++执行系统可以采用并行技术.
您的示例程序实际上没有可观察到的结果,编译器是一个很好的常量折叠程序,以发现该程序实际上什么都不做.充其量,从CPU辐射的热量可能是工作的指示,但消耗的能量不是可观察到的影响之一,即C++执行系统不需要这样做.如果您使用clang并打开优化(-O2或更高版本)来编译上面的代码,它实际上将完全删除循环(使用-S选项让编译器发出汇编代码以合理地轻松检查结果).
假设你实际上有被迫执行的循环,大多数现代编译器(至少是gcc,clang和icc)将尝试利用SIMD指令对代码进行矢量化.要做到这一点,编译器需要理解的操作代码,以证明并行执行不会改变结果或引入数据竞争(据我所知,确切的结果其实并不一定是保留在浮点操作参与,因为一些编译器愉快地并行化,例如,循环添加floats虽然浮点加法不是关联的).
我不知道当前的编译器会利用不同的执行线程来提高执行速度,而不需要像Open MP的pragma这样的提示.但是,委员会会议上的讨论意味着编译器供应商至少正在考虑这样做.
(*)如果程序执行导致未定义的行为,C++标准对C++执行系统没有任何限制.正确的程序不会调用任何形式的未定义行为.
tl; dr:允许编译器但不要求并行执行代码,大多数现代编译器在某些情况下都这样做.