为了获得更好的性能,可能/不可能的语句应该放在哪里?

问题描述 投票:0回答:1

某些软件(通常是面向性能的,例如 Linux 内核、DPDK)具有 C 帮助程序,用于影响分支预测

我有一个绝对简单的代码片段(假设我知道a>b的百分比)来表示当某些逻辑嵌套时条件嵌套和应用

likely
/
unlikely
的问题:

bool foo()
{
    foo1(1);
    foo2(2);

    /* if (unlikely(a > b)) */
    /* if (a > b)*/
    {
        puts("Ohhh!!! Rare case");
        return true;
    }
    return false;
}

int main(void)
{
    /* if (unlikely(foo())) */
    /* if (foo()) */
    {
        puts("Azaza");
    }
}

那么从理论角度来看,哪两行应该取消注释以获得更好的性能?

显然有3种方法可以帮助编译器进行分支预测:

1.

if (unlikely(a > b))
...
if (unlikely(foo()))

2.

if (a > b)
...
if (unlikely(foo()))

3.

if (unlikely(a > b))
...
if (foo())

理论上哪个最有效?为什么?

c linux-kernel compiler-optimization dpdk likely-unlikely
1个回答
0
投票

据我所知,如果条件变量

not
在缓存中,则likely/unlikely语句显示出最佳效果。让我更详细地解释一下。

在您的代码中,处理器无论如何都必须执行

foo
。因此
likely
在这里不会有任何效果,因为在推测执行期间不能跳过任何代码路径。函数必须被执行。假设您将之前
foo
的结果保存在变量中,代码如下所示:

int x = foo();
if (likely(x))
{
    puts("Azaza");
}

在这种情况下,

likely(x)
可能不会产生任何影响,因为处理器刚刚计算了 x 并且该值很可能缓存在 L1 中(除非它在此时被中断)。

现在假设您有一个全局变量

volatile int c = 15
,我们更改您的代码:

if (likely(b == 15))
{
    puts("Azaza");
} else {
    puts("Bzaza");
}

当我们执行代码并且第一次访问

b
时,它不会在缓存中,处理器必须从内存中获取它。这会花费数百个 CPU 周期,并且 CPU 不会停止运行,而是在不知道 b 值的情况下开始推测性地执行代码。在这种情况下,可能的关键字表明我们应该转到第一个分支。请注意,我们当时不会执行这些指令。现代 x86 处理器可以推测性地执行多达 400 个微操作,并且只有在预测成立时才会提交结果。

因此,为了回答您的问题,我会将

likely/unlikely
关键字放在
a < b
周围。

© www.soinside.com 2019 - 2024. All rights reserved.