Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 这种内联结果常见吗?_C_Optimization_Inline_Inlining - Fatal编程技术网

C 这种内联结果常见吗?

C 这种内联结果常见吗?,c,optimization,inline,inlining,C,Optimization,Inline,Inlining,由于大学的工作,我不得不研究一个简单的优化,内联 以下是基本代码: #include <stdio.h> #include <sys/time.h> #include <stdlib.h> #define ITER 1000 #define N 3000000 int i, j; float x[N], y[N], z[N]; void add(float x, float y, float *z){ *z = x + y; } void in

由于大学的工作,我不得不研究一个简单的优化,内联

以下是基本代码:

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

#define ITER 1000
#define N 3000000

int i, j;
float x[N], y[N], z[N];

void add(float x, float y, float *z){
    *z = x + y;
}

void initialVersion(){
    struct timeval inicio, final;
    double time;

    gettimeofday(&inicio, 0);
    for(j = 0; j < ITER; j++){
        for(i = 0; i < N; i++){
            add(x[i], y[i], &z[i]);
        }
    }

    gettimeofday(&final, 0);

    time = (final.tv_sec - inicio.tv_sec + (final.tv_usec - inicio.tv_usec)/1.e6);

    printf("Time: %f\n", time);

}
#包括
#包括
#包括
#定义ITER 1000
#定义300万新西兰元
int i,j;
浮点数x[N],y[N],z[N];
无效添加(浮动x、浮动y、浮动*z){
*z=x+y;
}
void initialVersion(){
结构timeval inicio,最终版本;
双倍时间;
gettimeofday(&inicio,0);
对于(j=0;j
下面是带有内联的代码:

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

#define ITER 1000
#define N 3000000

int i, j;
float x[N], y[N], z[N];

void inliningVersion(){
    struct timeval inicio, final;
    double time;

    gettimeofday(&inicio, 0);
    for(j = 0; j < ITER; j++){
        for(i = 0; i < N; i++){
            z[i] = x[i] + y[i];
        }
    }

    gettimeofday(&final, 0);

    time = (final.tv_sec - inicio.tv_sec + (final.tv_usec - inicio.tv_usec)/1.e6);

    printf("Time: %f\n", time);

}
#包括
#包括
#包括
#定义ITER 1000
#定义300万新西兰元
int i,j;
浮点数x[N],y[N],z[N];
无效InlineVersion(){
结构timeval inicio,最终版本;
双倍时间;
gettimeofday(&inicio,0);
对于(j=0;j
使用带有gcc的选项-O0进行编译,基本版本的结果为14.27秒,带有内联的版本的结果为4.45秒。这很普遍吗?我执行了10次程序,结果总是相似的。你觉得怎么样

然后,使用选项-O1编译,两个版本的结果相似,大约为1.5秒,因此我假设gcc使用O1为我进行内联

顺便说一句,我知道gettimeofday计算总时间,不仅计算程序本身使用的时间,还要求我专门使用该函数


提前谢谢

让我们分析GCC 7.2(使用
O0
)为两个版本的代码生成的程序集输出


无内联 首先,让我们检查计算机需要完成多少工作才能通过单独的功能完成任务:

void add(float x, float y, float *z){
    *z = x + y;
}

int main ()
{
    float x[100], y[100], z[100];
    for(int i = 0; i < 100; i++){
             add(x[i], y[i], &z[i]);
        }
}
代码的处理部分大约需要32条指令(介于
L4
L3
之间的指令以及
add
函数的指令)

大部分指令用于进行函数调用

理解函数调用如何工作的一种简化方法是:

  • 参数被推送到调用堆栈上
  • 返回地址被推送到调用堆栈上
  • 函数被调用
  • 制作帧指针的副本
  • 在堆栈上为本地人腾出空间
  • 执行实际的功能代码
  • 恢复函数调用之前的状态
  • 返回给打电话的人
  • 上述步骤(第6步除外)需要附加说明来执行所需的处理。这称为函数调用开销


    带内联 现在让我们检查一下,如果函数是内联的,计算机需要做多少工作

    int main ()
    {
        float x[100], y[100], z[100];
        for(int i = 0; i < 100; i++){
                z[i] = x[i] + y[i];
            }
    }
    
    处理代码(标签
    L3
    L2
    之间的指令)大约有14条指令。在此程序集输出中,不存在所有负责进行函数调用的指令,这节省了大量CPU周期

    通常,当函数的运行时间是函数调用开销的几倍以上时,函数调用的开销是不相关的。在代码中,函数的运行时间非常短,因此函数调用开销非常大

    如果使用
    O1
    标志,编译器确实会为您进行内联。您可以通过检查使用
    O1
    生成的程序集来查找,也可以直接检查GCC手册中使用
    O1
    尝试的程序集


    您可以使用
    -S
    标志生成程序集输出,也可以使用在线生成(本篇文章从这里获取了程序集输出)。

    什么样的问题是“您认为如何?”?因此,这不是一个讨论论坛。你要求CPU做的越多,花费的时间就越多,而且考虑到每次只需执行一个简单的计算,函数调用的成本就越高。编译器优化器会删除或多或少明显的不必要代码,甚至可能会重新排列代码。我可以编辑问题并询问“这是否常见?”。为了避免重复,我问了“你觉得怎么样”,因为在标题中我问的是第一个@melpomeneYes,内联可以节省时间,这就是为什么编译器会为您这样做。同时,当您使用优化进行编译时,内联节省大量时间并不常见,因为编译器无论如何都会为您这样做。正如我上面所说的,有时手工内联是值得的(对于C以外的其他语言更是如此),但因为它降低了可读性,编译器在实际使用中可能会为您做一些事情,所以您只会在热路径中进行内联,并测量以确保实际获得(在某些情况下,您甚至可以使事情变得更慢)无需假设,自动内联是任何C编译器中的标准优化。只要您启用优化器,您就会发现。因此,手工操作是没有必要的。而且可能是有害的,您可能会内联太多,从而降低处理器缓存的效率。也许今天不会,但代码很少变小。但最重要的是,它永远不足以损害代码的可读性。
    int main ()
    {
        float x[100], y[100], z[100];
        for(int i = 0; i < 100; i++){
                z[i] = x[i] + y[i];
            }
    }
    
    main:
            pushq   %rbp
            movq    %rsp, %rbp
            subq    $1096, %rsp
            movl    $0, -4(%rbp)
    .L3:
            cmpl    $99, -4(%rbp)
            jg      .L2
            movl    -4(%rbp), %eax
            cltq
            movss   -416(%rbp,%rax,4), %xmm1
            movl    -4(%rbp), %eax
            cltq
            movss   -816(%rbp,%rax,4), %xmm0
            addss   %xmm1, %xmm0
            movl    -4(%rbp), %eax
            cltq
            movss   %xmm0, -1216(%rbp,%rax,4)
            addl    $1, -4(%rbp)
            jmp     .L3
    .L2:
            movl    $0, %eax
            leave
            ret