2016-07-24 48 views
1

如果我正在搜索每个值的集合并运行代码,并且我希望在找到某个特定质量时打开布尔值,然后在运行代码时返回那个对象,运行一个条件来检查布尔值是否需要被关闭,还是在每个循环中简单地关闭布尔变得更快?多次检查条件与设置变量;低级优化

例如(伪代码):

bool found = false; 
for(particle in literallyAHaystack) { 
    bool isNeedle = particle == "needle"; 

    if(isNeedle) { 
     found = true; 
    } 

    // [some code that uses the 'found' variable] 

    if(isNeedle) { 
     found = false; 
    } 
} 

VS

bool found = false; 
for(particle in literallyAHaystack) { 
    bool isNeedle = particle == "needle"; 

    if(isNeedle) { 
     found = true; 
    } 

    // [some code that uses the 'found' variable] 

    found = false; // a conditional no longer surrounds this statement 
} 

我理解,这是非常低的水平,通常-无意义的优化,但我仍然有兴趣在真相的。我希望不要因为问题的微不足道而得罪任何人。

+0

所以,呃...为什么你有'isNeedle'和'found'?他们似乎是多余的。 – user2357112

+0

@ user2357112:我认为这个想法是想象'found'可能是由'if'内的某个东西来设置的,所以把整个东西写成嵌套的'if()'子句而没有布尔值来记录先前的检查结果将需要代码重复。 –

回答

1

如果bool found是一个局部变量,无条件地将它设置为false几乎肯定会在每种情况下更好,几乎在每个CPU架构上都会更好。如果它在编译器输出中完全存在(而不是仅仅成为分支逻辑的一部分),它可能只会存在于寄存器中。写入注册一个最便宜的操作,比分支便宜得多。

即使它遇到内存,写回缓存也很常见,因此重复存储到同一位置只会碰到L1,而不会产生流量到较大的共享缓存或主内存。


如果编译器发射,实际上在每个循环结束时存储在存储器中的标志,检查下一个迭代中的标志将招致〜5个循环(在Intel的Haswell例如)一个存储转发延迟的代码。

但是,如果出现问题,编译器的错误是不能很好地优化代码。这就是为什么我们使用编译器而不是直接在asm中编写代码:编译器可能完全将found变量优化掉。这很好,并且不是重构您的C的参数。

有关x86上此类内容的更多信息,请参见http://agner.org/optimize/标记wiki中的其他链接。

要查看代码编译,把它挂在http://gcc.godbolt.org/(和使用O3 -march=haswell -ffast-math什么的。)


如果found是全球性的(并有可能被另一个线程被最后修改),它可以或许只有先读取它才有意义,因此运行代码的核心无需使其他核心的缓存行副本无效。

我在想象一个标志,这是不同线程可能使用的共享状态结构的一部分(由受锁定保护的关键部分中的代码使用)。(这将是可怕的设计,在这种情况下,虽然,因为found总是留给使用后false,所以没有持久状态,所以它应该是本地的。)

不过,它可能不值得使用条件分支刚避免该商店。如果在任何循环迭代中标志都被修改了(即如果针头匹配的话),那么你可以随意修改它。

如果您可以从一些商店到相同的地点归零,而不只是减少,避免商店大多只有用。缓存工作。

例如在进行矢量化时,如果要写一个矢量的3个元素而不是全部4个元素,那么对目标进行重叠存储有时很有用,并且可以在超出所存储内容的范围内进行写入。例如在this code

+0

非常感谢。我知道示例代码并不完整,但您完全回答了问题。 –

0

第二将是“更快”,因为没有条件检查,因此,不需要跳转。

它会明显更快吗?几乎肯定不是。无论如何,编译器可能已经做了这个优化,但不要引用它 - 我不知道它是否。