【问题标题】:Windows taking same time to execute an inline and no-inlined function. Why?Windows 需要相同的时间来执行内联和非内联函数。为什么?
【发布时间】:2013-12-09 08:21:12
【问题描述】:

我编写了一个自定义 C 代码,其中包含 main 和另一个由 main 调用的函数。我多次执行此功能(〜100万)。在一个代码中,我将此函数声明为 __inline,而在另一个代码中,我将其声明为 __declspec(noinline)。我使用 WinDBG 监视了反汇编,发现后者像普通函数调用一样使用 push pop 和分支,而前者没有使用此类指令并正确内联函数。然而他们两人的时间却完全一样。以下是代码: (在 A9 cortex CPU (Tegra 3) 上执行此代码)

__inline int multifunc(int a, int b);

int main(int argc, char **argv) {

    unsigned long int timeBefore, i;
    unsigned long int timeAfter;
    unsigned int a[11500], j, k, l;
    double elapsed;
    timeBefore = GetTickCount();
    printf("\n%ld", timeBefore); 


    for(l=1; l<300;l++)
    {
for(i=0; i<11500; i++)
{
    j = i+l;
    k=1;
    a[i] = multifunc(j, k);
}

    }
printf("\n%ld", timeBefore);
    timeAfter = GetTickCount();

    printf("\n%ld", timeAfter);


    return -1;
}

__inline int multifunc(int a, int b)
{
    int d;
    d = a+b;
printf("%d", d);
    return d;
}

谁能解释我为什么?我为第二次测试所做的只是将 __inline 更改为 __declspec(noinline)。

【问题讨论】:

  • 恕我直言,这很可能根本不重要,因为 printf 无论如何都是一个非常昂贵的函数;如果 printf 需要 10000 个周期,那么初始化堆栈帧的 6 个周期开销应该几乎不会被注意到。

标签: c


【解决方案1】:

printf() 调用非常昂贵。函数调用时间与执行printf() 所需的时间相比相形见绌。

实证检验

printf() 比函数调用慢多少?你不会得到相同的结果。我正在使用 Linux、X11 和 xterm。

109 函数调用

__attribute__((noinline))
static int function(int x)
{
    return x;
}
int main(int argc, char *argv[])
{
    int i, a = 0;
    for (i = 0; i < 1000000000; i++)
        a += function(i);
    return a;
}

105printf()

#include <stdio.h>
int main(int argc, char *argv[])
{
    int i;
    for (i = 0; i < 100000; i++)
        printf("%d\n", i);
    return 0;
}

结果

我系统上的挂钟时间显示printf() 程序所用的时间是函数调用的7.6 倍,这意味着printf() 是函数调用的76,000 倍。将内联决策留给您的编译器。

【讨论】:

  • 这是为了验证/确保编译器没有应用任何巧妙的优化,例如将其转换为对 puts 的巨大调用。
  • @H2CO3:这将需要展开一个 100k 元素循环的循环——谢天谢地,nm -D 表明确实使用了printf
  • 不错。可以理解,这将是巨大的,真的。但是我已经看到编译器做了一些非常巧妙的事情,比如我对this question 的回答,clang 基本上恒定折叠了整个函数体。
【解决方案2】:

您的函数包含一个 printf。打印到控制台比调用单个函数要慢几个数量级,所以不管它是否内联,大部分时间都花在了 printf 上。

【讨论】:

  • 但重点是即使使用 printf,这两个函数也应该显示出一些差异。由于调用的数量很大,因此这两个函数的时间应该显示出巨大的差异。这 10000 个循环对两个程序都是通用的。但 6 个周期在其中一个中是额外的。这应该显示几秒钟的差异。
  • 两次运行是否都显示了完全相同的滴答计数?它们可能会有所不同。即使您运行相同的程序两次,它甚至会相差几个滴答声。内联的好处消失在任何使程序以不同速度运行的背景噪音中,即使您连续运行两次:缓存、后台任务、室温和随机机会。
  • @nvoigt 是正确的。在具有重要 I/O 子系统的现代操作系统上,信噪比将非常差。
【解决方案3】:

只是猜测,您正在内联一个带有printf 的函数。 由于 printf 指令远不止是几个 push,因此内联的好处几乎是 0。请注意,您标记了 Windows 正在占用相同的时间:我想 Linux 上也会发生同样的情况也。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-26
    • 2020-06-05
    • 2018-07-02
    • 1970-01-01
    • 2021-09-04
    • 2014-09-19
    • 2017-05-29
    • 2016-03-10
    相关资源
    最近更新 更多