【问题标题】:gcc branch predictiongcc 分支预测
【发布时间】:2012-07-02 05:36:32
【问题描述】:

这是我的演示程序:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int cmp(const void *d1, const void *d2)
{
    int a, b;

    a = *(int const *) d1;
    b = *(int const *) d2;

    if (a > b)
        return 1;
    else if (a == b)
        return 0;

    return -1;
}

int main()
{
    int seed = time(NULL);
    srandom(seed);

    int i, n, max = 32768, a[max];

    for (n=0; n < max; n++) {

        int r = random() % 256;
        a[n] = r;

    }

    qsort(a, max, sizeof(int), cmp);

    clock_t beg = clock();

    long long int sum = 0;

    for (i=0; i < 20000; i++) 
    {
        for (n=0; n < max; n++) {
            if (a[n] >= 128)
                sum += a[n];
        }
    }

    clock_t end = clock();

    double sec = (end - beg) / CLOCKS_PER_SEC;

    printf("sec: %f\n", sec);
    printf("sum: %lld\n", sum);

    return 0;
}



unsorted
sec: 5.000000
sum: 63043880000

sorted
sec: 1.000000
sum: 62925420000

这是该程序两个版本的汇编差异,一个带有qsort,一个没有:

--- unsorted.s  
+++ sorted.s    
@@ -58,7 +58,7 @@
    shrl    $4, %eax
    sall    $4, %eax
    subl    %eax, %esp
-   leal    4(%esp), %eax
+   leal    16(%esp), %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
@@ -83,6 +83,13 @@
    movl    -16(%ebp), %eax
    cmpl    -24(%ebp), %eax
    jl  .L7
+   movl    -24(%ebp), %eax
+   movl    $cmp, 12(%esp)
+   movl    $4, 8(%esp)
+   movl    %eax, 4(%esp)
+   movl    -32(%ebp), %eax
+   movl    %eax, (%esp)
+   call    qsort
    movl    $0, -48(%ebp)
    movl    $0, -44(%ebp)
    movl    $0, -12(%ebp)

据我了解的程序集输出,排序后的版本由于将值传递给qsort 而只有更多代码,但我没有看到任何分支优化/预测/任何东西。也许我看错了方向?

【问题讨论】:

  • 分支预测由 CPU 完成,而不是编译器。
  • @Blastfurnace:没有。该问题询问为什么处理排序数组比处理未排序数组更快,答案是分支预测。这个问题问为什么在汇编中看不到任何分支预测。
  • 注意:double sec = (end - beg) / CLOCKS_PER_SEC; 仅以整数值计算;你必须想办法让它浮起来。
  • @wildplasser,是的,错过了……

标签: c gcc assembly branch-prediction


【解决方案1】:

分支预测不是您在汇编代码级别看到的;它是由 CPU 自己完成的。

【讨论】:

  • 如果代码针对 Prescott 进行了优化分析,编译器可能会发出静态分支预测提示 (0x3e)。但当时它并没有任何可衡量的性能优势,这就是为什么所有较新的处理器都会默默地忽略该分支提示。
【解决方案2】:

Built-in Function:长__builtin_expect (long exp, long c)

您可以使用__builtin_expect 为编译器提供分支预测信息。 一般来说,你应该更喜欢使用实际的 对此的个人资料反馈 (-fprofile-arcs),因为程序员是 众所周知,他们不擅长预测他们的程序的实际执行情况。 但是,有些应用程序很难收集这些数据。

返回值为exp的值,应该是一个整数表达式。内置的语义是预计 exp == c。例如:

if (__builtin_expect (x, 0))
  foo ();

表示我们不希望调用foo,因为我们希望x。由于您仅限于exp积分表达式,因此您 应该使用诸如

之类的结构
if (__builtin_expect (ptr != NULL, 1))
  foo (*ptr);

在测试指针浮点值时。

否则分支预测由处理器决定...

Branch prediction 预测分支目标并启用 处理器在分支为真之前很久就开始执行指令 执行路径是已知的。所有分支都使用分支预测 用于预测的单元 (BPU)。本单元预测目标地址不 只基于分支的 EIP 也基于执行 执行到达此 EIP 的路径。 BPU 可以 有效预测以下分支类型:

• 条件分支。

• 直接调用和跳转。

• 间接调用和跳转。

• 返回。


The microarchitecture tries to overcome this problem by feeding the most probable branch into the pipeline and execut[ing] it speculatively.

...Using various methods of branch prediction.

【讨论】:

    猜你喜欢
    • 2013-09-04
    • 2014-04-25
    • 2014-03-03
    • 2016-07-01
    • 2011-02-01
    • 2015-11-24
    • 2017-06-12
    • 2015-09-20
    • 2012-12-10
    相关资源
    最近更新 更多