在优化方面,编译器可以更改非相关命令的顺序。 能否也将它们静默优化以在不同的内核中执行?
例如:
...
for (...)
{
//...
int a = a1+a2;
int b = b1+b2;
int c = c1+c2;
int d = d1+d2;
//...
}
...
是否有可能在优化方面不仅更改执行顺序,而且更改核心数量?编译器在标准上有任何限制吗?
UPD:我不是在问如何并行化代码,而是在问它是否未显式并行化,它是否仍可以由编译器并行化?
答案 0 :(得分:3)
在这里,不仅有眼神。这些指令(在您的示例中)很可能最终会并行运行,但这不是您所想的。
CPU中有许多级别的硬件并行性,多个内核只是最高的 1)。在CPU内核内部,您具有其他级别的硬件并行化,大多数情况下都是透明的 2)(您不通过软件对其进行控制,并且实际上看不到它们,有时可能只是它们的副作用) 。其中包括管道,额外的总线通道,每个核心有多个ALU(算术逻辑单元)和FPU(浮点单元)。
您的指令的不同阶段将在管道中并行运行(现代x86处理器具有十几个管道阶段),并且可能不同的指令将在不同的ALUS中并行运行(现代x86 CPU每个内核具有大约5个ALU)。
所有这些事情都是在编译器不执行任何操作的情况下发生的(sup> 2)。而且它是免费的(考虑到硬件,并非免费在硬件中添加此功能)。在不同内核中执行指令不是免费的。创建不同的线程成本很高。将数据移动到其他内核可用是昂贵的。等待其他内核执行的同步开销很大。创建和同步线程有很多开销。对于这样的小指令,这是不值得的。从多线程中真正受益的情况将涉及到一种分析,该分析如今过于复杂,因此实际上不可行。将来有一天,编译器将能够确定您的串行算法实际上是一种排序算法,并且可以有效,正确地对其进行并行化。在此之前,我们必须依靠语言支持,库支持和/或开发人员支持来并行化算法。
1)好,实际上是超线程。
2)由MSalters指出:
现代的编译器非常了解各种ALU,并且会做 努力从中受益。特别是,寄存器分配是 经过优化,因此您无需ALU争夺同一寄存器, 从抽象顺序可能看不到的东西 模型。
所有这些都间接影响了执行,从而使硬件体系结构受益,没有明确的指令或声明。
答案 1 :(得分:0)
是的,只要生成的可观察行为与代码应具有的可观察行为相匹配,则编译器可以按任何顺序执行操作(包括根本不执行操作)。汇编指令,运行时,线程数等是不可观察的行为。
我还要补充一点,如果没有程序员的明确指示,编译器不太可能决定这样做。即使标准允许,编译器也可以帮助程序员,并且在许多情况下随机启动额外的线程是意外的