为什么全局变量会给函数调用中的编译器优化带来麻烦? [英] Why do global variables cause trouble for compiler optimizations in function calls?

查看:75
本文介绍了为什么全局变量会给函数调用中的编译器优化带来麻烦?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自 http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf:

防止编译器移动内存围绕调用函数的操作,例如pthread mutex lock(),它们本质上被视为对不透明函数的调用,编译器会对此进行调用没有信息.编译器有效地假设pthread mutex lock() 可以读取或写入任何全局变量.因此内存引用不能简单地跨调用移动.这种方法还确保传递调用,例如调用函数 f()然后调用 pthread mutex lock(),被处理以同样的方式或多或少适当地,即内存操作不会在对 f() 的调用中移动或者,无论整个用户程序是否正在立即分析.

To prevent the compiler from moving memory operations around calls to functions such as pthread mutex lock(), they are essentially treated as calls to opaque functions, about which the compiler has no information. The compiler effectively assumes that pthread mutex lock() may read or write any global variable. Thus a memory reference cannot simply be moved across the call. This approach also ensures that transitive calls, e.g. a call to a function f() which then calls pthread mutex lock(), are handled in the same way more or less appropriately, i.e. memory operations are not moved across the call to f() either, whether or not the entire user program is being analyzed at once.

为什么会这样?为什么不能移动引用的任何反例?

Why is that actually so? Any counter example for why references can not be moved?

推荐答案

编译器可以自由移动代码.(稍微简化的)要求是不能有明显的副作用.

The compiler is free to move code around. The (somewhat simplified) requirement is that there can be no visible side effects.

这篇文章描述了为什么需要在编译器级别而不是库级别支持线程.因此,让我们考虑一下编译器优化代码的含义.我将从 Kerrek SB 的优秀示例开始,因为此回复太长,无法发表评论.

The article is describing why threading needs to be supported at the compiler level rather than the library level. So let's consider what it means as the compiler is optimizing the code. I'll start with Kerrek SB's excellent example, since this reply is too long for a comment.

int x = 0;
pthread_mutex_lock(&m);
x = y;

优化器看到一个没有被修改但被设置两次的值.copmiler 可以访问函数内部的代码,并且可以看到没有任何东西可以修改赋值的值.由于没有明显的副作用,优化器可以消除为零的赋值,而只是将其替换为 y 的值.优化器会移除它,把它变成:

The optimizer sees a value that doesn't get modified but gets set twice. The copmiler has access to the code inside the function and can see that nothing can possibly modify the value of the assignment. Since there is no visible side effect, the optimizer can eliminate the assignment to zero and just replace it with the value of y. The optimizer will remove it, turning it into:

pthread_mutex_lock(&m);
int x = y;

这可能不会有任何影响,变量 x 是局部的,没有其他影响.

This will probably not affect anything, the variable x was local and has no other effects.

现在让我们做一个更有问题的人为例子.

Now let's make a more problematic contrived example.

if(globals.hasData) {
  int prelock_value = globals.foo;
  pthread_mutex_lock(&m);
  if(prelock_value != globals.foo) {
    // value changed before we could lock it, do something different
    DoSpecialStuffSinceValueChangedWhileWaiting();
    pthread_mutex_unlock(&m);
    return;
  }
  DoOtherStuff();
  ...

所以现在我们将从优化器的角度来看这个.优化器看到您读取了一个值,然后您执行了一些不会修改该值的操作,然后您针对刚刚存储的值进行测试.由于它看不到明显的副作用,它可能会像这样删除比较:

So now we'll look at this from the optimizer's view. The optimizer sees that you read a value, then you do something that doesn't modify the value, then you test against the value you just stored. Since it cannot see a visible side effect, it might remove the comparison like this:

if(globals.hasData) {
  int prelock_value = globals.foo;
  pthread_mutex_lock(&m);
  if( false /* always false: prelock_value != globals.foo */ ) {
    // value changed before we could lock it, do something different
    DoSpecialStuffSinceValueChangedWhileWaiting();
    pthread_mutex_unlock(&m);
    return;
  }
  DoOtherStuff();
  ...

然后再次查找以删除死代码.它看到一个不必要的整数赋值,一个不必要的条件,因为 if 的结果总是假的,并想出了这个:

Then it looks again to remove dead code. It sees an unnecessary assignment to an integer, an unnecessary conditional since the result of the if is always false, and comes up with this:

if(globals.hasData) {
  pthread_mutex_lock(&m);
  // everything was removed.
  DoOtherStuff();

如果将其与原始函数进行比较,希望很明显这根本不是程序员的本意.

If you compare that to the original function, it is hopefully clear this is not what the programmer intended at all.

多年来已经发现了大量潜在的优化.他们中的许多人假设何时将代码从一个地方移动到另一个地方是安全的,或者假设值只能由该代码块修改.这些假设在并发编程中可能会被破坏.

There are a huge number of potential optimizations that have been discovered over the years. Many of them make assumptions about when it is safe to move code from one place to another or assuming that values are only modified by that block of code. These assumptions can break badly in concurrent programming.

优化器需要了解某些功能位不能移动,某些功能作为障碍不能移动或以其他方式使优化器假设无效.

The optimizer needs to understand that certain bits of functionality cannot be moved, and that certain functions serve as barriers that cannot be moved across or that otherwise invalidate optimizer assumptions.

这篇关于为什么全局变量会给函数调用中的编译器优化带来麻烦?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆