在哪一点编译器需要重新排序执行以进行优化?
In which point compiler needs to reorder executions for optimization?
我正在检查互斥量、信号量、spin_locks 内存屏障等,我只是想到了 execution reorder
事情。我在 wiki 上读到了一些关于它的内容,但它对我来说真的没有任何意义,为优化问题重新排序执行?这不是破解密码吗?有什么限制。它在这个维基页面中说 Java Memory Model
On modern platforms, code is frequently not executed in the order it was written. It is reordered by the compiler, the processor and the memory subsystem to achieve maximum performance. On multiprocessor architectures, individual processors may have their own local caches that are out of sync with main memory.
所以特别是多线程概念它带来了性能,但它使您的程序不稳定或不一致。你必须非常小心。因此,由于特定的性能原因,这是否过于复杂,并且代码重新排序看起来很可怕。
Isn't that break the code ?
优化仅限于不违反语言做出的保证的更改。关键是许多语言没有完全指定行为。当两个线程执行 x = 1
和 x = 2
时,结果是 not fully specified.
So isn't this over complexity for the specific performance reasons, and code reordering it looks scary.
是否过于复杂取决于您的目标。有些语言非常安全,有些则非常宽松。所有语言都为您提供了编写安全程序的工具。这些工具以及使其工作的难度各不相同。此外,性能各不相同。
作为重新排序的好方案,请考虑以下情况:
A = B / C; => read B, C + compute + write to A
D = E + F; => read E, F + compute + write to D
翻译为:
read B, C
compute B/C
write result to A
read E, F
compute E+F
write result to D
可以重新排序为:
read B, C, E, F ==> force reads as soon as possible
compute B / C => slow operation (could do something usefull such as read E, F in the meanwhile)
compute E + F
write A, write D => defer writes as late as possible
这不会破坏单线程排序保证并实现更好的执行吞吐量。
此外,here概念描述得很好。
这是一个可能被重新排序的代码示例:
extern bool b;
extern int x;
extern int y;
extern int z;
void foo() {
z = x;
if (b)
y = x;
}
所谓的想法如下:首先将全局z
设置为某物,如果设置了b
,则也设置y
。假设有另一个线程,它正在以某种方式查询 z
,一旦它变成它想要的,它就会设置 b
- 从而允许 foo()
分配 y
。
这段代码当然有多个问题,但我将重点放在重新排序上。该代码生成以下程序集:
foo():
cmpb [=11=], b(%rip)
movl x(%rip), %eax
movl %eax, z(%rip)
je .L1
movl %eax, y(%rip)
.L1:
rep ret
如你所见,首先检查了b! than x
被复制到 z
,然后执行 than 跳转。执行已重新排序 - 在分配完成之前检查布尔标志,并且整个想法被打破。 (无论如何它都会被打破,所以这个例子只是一个重新排序的例子)。
我正在检查互斥量、信号量、spin_locks 内存屏障等,我只是想到了 execution reorder
事情。我在 wiki 上读到了一些关于它的内容,但它对我来说真的没有任何意义,为优化问题重新排序执行?这不是破解密码吗?有什么限制。它在这个维基页面中说 Java Memory Model
On modern platforms, code is frequently not executed in the order it was written. It is reordered by the compiler, the processor and the memory subsystem to achieve maximum performance. On multiprocessor architectures, individual processors may have their own local caches that are out of sync with main memory.
所以特别是多线程概念它带来了性能,但它使您的程序不稳定或不一致。你必须非常小心。因此,由于特定的性能原因,这是否过于复杂,并且代码重新排序看起来很可怕。
Isn't that break the code ?
优化仅限于不违反语言做出的保证的更改。关键是许多语言没有完全指定行为。当两个线程执行 x = 1
和 x = 2
时,结果是 not fully specified.
So isn't this over complexity for the specific performance reasons, and code reordering it looks scary.
是否过于复杂取决于您的目标。有些语言非常安全,有些则非常宽松。所有语言都为您提供了编写安全程序的工具。这些工具以及使其工作的难度各不相同。此外,性能各不相同。
作为重新排序的好方案,请考虑以下情况:
A = B / C; => read B, C + compute + write to A
D = E + F; => read E, F + compute + write to D
翻译为:
read B, C
compute B/C
write result to A
read E, F
compute E+F
write result to D
可以重新排序为:
read B, C, E, F ==> force reads as soon as possible
compute B / C => slow operation (could do something usefull such as read E, F in the meanwhile)
compute E + F
write A, write D => defer writes as late as possible
这不会破坏单线程排序保证并实现更好的执行吞吐量。
此外,here概念描述得很好。
这是一个可能被重新排序的代码示例:
extern bool b;
extern int x;
extern int y;
extern int z;
void foo() {
z = x;
if (b)
y = x;
}
所谓的想法如下:首先将全局z
设置为某物,如果设置了b
,则也设置y
。假设有另一个线程,它正在以某种方式查询 z
,一旦它变成它想要的,它就会设置 b
- 从而允许 foo()
分配 y
。
这段代码当然有多个问题,但我将重点放在重新排序上。该代码生成以下程序集:
foo():
cmpb [=11=], b(%rip)
movl x(%rip), %eax
movl %eax, z(%rip)
je .L1
movl %eax, y(%rip)
.L1:
rep ret
如你所见,首先检查了b! than x
被复制到 z
,然后执行 than 跳转。执行已重新排序 - 在分配完成之前检查布尔标志,并且整个想法被打破。 (无论如何它都会被打破,所以这个例子只是一个重新排序的例子)。