美文网首页iOS 的那些事儿
iOS 中 inline 函数能提升 App 效率吗?

iOS 中 inline 函数能提升 App 效率吗?

作者: uniapp | 来源:发表于2020-06-19 17:55 被阅读0次

在阅读开源库源码时,往往会发现 static inline 的关键字,这标识了该函数为内联样式。据称使用后 App 运行效率会提升。其中最具有支撑性的原因是:内联函数减少了函数调用时的指令转移。真的是这样吗?

使用 iOS 中的单元测试,分别设置如下 3 组函数,对调用时间进行对比。

//对比组1
#define add_define(a,b)  (a + b)
#define add_define2(a,b)  do { int res = a + b; } while(0)
static inline void add_inline(int x, int y) {
    int res = x + y;
}

void add_normal(int x, int y) {
    int res = x + y;
}

static inline int add_inline2(int x, int y) {
    return x + y;
}

int add_normal2(int x, int y) {
    return x + y;
}


//对比组2
static inline CGFloat CGFloatFromPixel(CGFloat value) {
    return value / YYScreenScale();
}

CGFloat CGFloatFromPixel2(CGFloat value) {
    return value / YYScreenScale();
}

CGFloat YYScreenScale() {
    static CGFloat scale;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        scale = [UIScreen mainScreen].scale;
    });
    return scale;
}

//对比组3
//SDWebImage 中 static inline CGRect SDCGRectFitWithScaleMode

(1)分别使用宏定义、内联函数两种方式定义两个数字的加法;(2)选取YYImage中的代码段;(3)选取 SDWebImage 中的代码段。在 iPhone8 真机上分别运行100万次,单元测试中又会运行10次,然后取均值。

- (void)testPerformanceExample {
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
        for (int i=0,j=0; i<1000000; i++,j++) {
            add_define(10000, 10000);
            add_define2(10000, 10000);
            add_normal(10000, 10000);
            add_inline(10000, 10000);
            
            add_normal2(100000, 100000);
            add_inline2(100000, 100000);
            
            CGFloatFromPixel(100);
            CGFloatFromPixel2(100);
            
            CGRect rect = CGRectMake(0, 0, 300, 300);
            SDCGRectFitWithScaleMode(rect, rect.size, 0);
            SDCGRectFitWithScaleMode2(rect, rect.size, 0);
        }
    }];
}

每组实验中以非内联函数为基准,发现 3 组实验中的结果均没有效率的提高,有时候还会出现1%~2% worse的提示。

修改 main.m 文件如下:

int add(int x, int y) {
     return x + y;
}

选中 main.m 文件,在 Xcode->Product->Perform Action->Assemble 中查看汇编后的代码:


    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 15    sdk_version 10, 15, 4
    .globl  _add                    ## -- Begin function add
    .p2align    4, 0x90
_add:                                   ## @add
Lfunc_begin0:
    .file   1 "/Users/zhudongdong/Desktop/iOS/58/TestInLine" "TestInLine/main.m"
    .loc    1 11 0                  ## TestInLine/main.m:11:0
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
Ltmp0:
    .loc    1 12 13 prologue_end    ## TestInLine/main.m:12:13
    movl    -4(%rbp), %eax
    .loc    1 12 15 is_stmt 0       ## TestInLine/main.m:12:15
    addl    -8(%rbp), %eax
    .loc    1 12 6                  ## TestInLine/main.m:12:6
    popq    %rbp
    retq
Ltmp1:
Lfunc_end0:
    .cfi_endproc
                                        ## -- End function
    .section    __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
    .long   0
    .long   64

    .section    __DWARF,__debug_str,regular,debug
Linfo_string:
    .asciz  "Apple clang version 11.0.3 (clang-1103.0.32.62)" ## string offset=0
    .asciz  "/Users/zhudongdong/Desktop/iOS/58/TestInLine/TestInLine/main.m" ## string offset=48
    .asciz  "/Users/zhudongdong/Desktop/iOS/58/TestInLine" ## string offset=111
    .asciz  "add"                   ## string offset=156
    .asciz  "int"                   ## string offset=160
    .asciz  "x"                     ## string offset=164
    .asciz  "y"                     ## string offset=166
    .section    __DWARF,__debug_abbrev,regular,debug
Lsection_abbrev:
    .byte   1                       ## Abbreviation Code
    .byte   17                      ## DW_TAG_compile_unit
    .byte   1                       ## DW_CHILDREN_yes
    .byte   37                      ## DW_AT_producer
    .byte   14                      ## DW_FORM_strp
    .byte   19                      ## DW_AT_language
    .byte   5                       ## DW_FORM_data2
    .byte   3                       ## DW_AT_name
    .byte   14                      ## DW_FORM_strp
    .byte   16                      ## DW_AT_stmt_list
    .byte   23                      ## DW_FORM_sec_offset
    .byte   27                      ## DW_AT_comp_dir
    .byte   14                      ## DW_FORM_strp
    .ascii  "\345\177"              ## DW_AT_APPLE_major_runtime_vers
    .byte   11                      ## DW_FORM_data1
    .byte   17                      ## DW_AT_low_pc
    .byte   1                       ## DW_FORM_addr
    .byte   18                      ## DW_AT_high_pc
    .byte   6                       ## DW_FORM_data4
    .byte   0                       ## EOM(1)
    .byte   0                       ## EOM(2)
    .byte   2                       ## Abbreviation Code
    .byte   46                      ## DW_TAG_subprogram
    .byte   1                       ## DW_CHILDREN_yes
    .byte   17                      ## DW_AT_low_pc
    .byte   1                       ## DW_FORM_addr
    .byte   18                      ## DW_AT_high_pc
    .byte   6                       ## DW_FORM_data4
    .byte   64                      ## DW_AT_frame_base
    .byte   24                      ## DW_FORM_exprloc
    .byte   3                       ## DW_AT_name
    .byte   14                      ## DW_FORM_strp
    .byte   58                      ## DW_AT_decl_file
    .byte   11                      ## DW_FORM_data1
    .byte   59                      ## DW_AT_decl_line
    .byte   11                      ## DW_FORM_data1
    .byte   39                      ## DW_AT_prototyped
    .byte   25                      ## DW_FORM_flag_present
    .byte   73                      ## DW_AT_type
    .byte   19                      ## DW_FORM_ref4
    .byte   63                      ## DW_AT_external
    .byte   25                      ## DW_FORM_flag_present
    .byte   0                       ## EOM(1)
    .byte   0                       ## EOM(2)
    .byte   3                       ## Abbreviation Code
    .byte   5                       ## DW_TAG_formal_parameter
    .byte   0                       ## DW_CHILDREN_no
    .byte   2                       ## DW_AT_location
    .byte   24                      ## DW_FORM_exprloc
    .byte   3                       ## DW_AT_name
    .byte   14                      ## DW_FORM_strp
    .byte   58                      ## DW_AT_decl_file
    .byte   11                      ## DW_FORM_data1
    .byte   59                      ## DW_AT_decl_line
    .byte   11                      ## DW_FORM_data1
    .byte   73                      ## DW_AT_type
    .byte   19                      ## DW_FORM_ref4
    .byte   0                       ## EOM(1)
    .byte   0                       ## EOM(2)
    .byte   4                       ## Abbreviation Code
    .byte   36                      ## DW_TAG_base_type
    .byte   0                       ## DW_CHILDREN_no
    .byte   3                       ## DW_AT_name
    .byte   14                      ## DW_FORM_strp
    .byte   62                      ## DW_AT_encoding
    .byte   11                      ## DW_FORM_data1
    .byte   11                      ## DW_AT_byte_size
    .byte   11                      ## DW_FORM_data1
    .byte   0                       ## EOM(1)
    .byte   0                       ## EOM(2)
    .byte   0                       ## EOM(3)
    .section    __DWARF,__debug_info,regular,debug
Lsection_info:
Lcu_begin0:
.set Lset0, Ldebug_info_end0-Ldebug_info_start0 ## Length of Unit
    .long   Lset0
Ldebug_info_start0:
    .short  4                       ## DWARF version number
.set Lset1, Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section
    .long   Lset1
    .byte   8                       ## Address Size (in bytes)
    .byte   1                       ## Abbrev [1] 0xb:0x5e DW_TAG_compile_unit
    .long   0                       ## DW_AT_producer
    .short  16                      ## DW_AT_language
    .long   48                      ## DW_AT_name
.set Lset2, Lline_table_start0-Lsection_line ## DW_AT_stmt_list
    .long   Lset2
    .long   111                     ## DW_AT_comp_dir
    .byte   2                       ## DW_AT_APPLE_major_runtime_vers
    .quad   Lfunc_begin0            ## DW_AT_low_pc
.set Lset3, Lfunc_end0-Lfunc_begin0     ## DW_AT_high_pc
    .long   Lset3
    .byte   2                       ## Abbrev [2] 0x2b:0x36 DW_TAG_subprogram
    .quad   Lfunc_begin0            ## DW_AT_low_pc
.set Lset4, Lfunc_end0-Lfunc_begin0     ## DW_AT_high_pc
    .long   Lset4
    .byte   1                       ## DW_AT_frame_base
    .byte   86
    .long   156                     ## DW_AT_name
    .byte   1                       ## DW_AT_decl_file
    .byte   11                      ## DW_AT_decl_line
                                        ## DW_AT_prototyped
    .long   97                      ## DW_AT_type
                                        ## DW_AT_external
    .byte   3                       ## Abbrev [3] 0x44:0xe DW_TAG_formal_parameter
    .byte   2                       ## DW_AT_location
    .byte   145
    .byte   124
    .long   164                     ## DW_AT_name
    .byte   1                       ## DW_AT_decl_file
    .byte   11                      ## DW_AT_decl_line
    .long   97                      ## DW_AT_type
    .byte   3                       ## Abbrev [3] 0x52:0xe DW_TAG_formal_parameter
    .byte   2                       ## DW_AT_location
    .byte   145
    .byte   120
    .long   166                     ## DW_AT_name
    .byte   1                       ## DW_AT_decl_file
    .byte   11                      ## DW_AT_decl_line
    .long   97                      ## DW_AT_type
    .byte   0                       ## End Of Children Mark
    .byte   4                       ## Abbrev [4] 0x61:0x7 DW_TAG_base_type
    .long   160                     ## DW_AT_name
    .byte   5                       ## DW_AT_encoding
    .byte   4                       ## DW_AT_byte_size
    .byte   0                       ## End Of Children Mark
Ldebug_info_end0:
    .section    __DWARF,__debug_macinfo,regular,debug
Ldebug_macinfo:
    .byte   0                       ## End Of Macro List Mark
    .section    __DWARF,__apple_names,regular,debug
Lnames_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   1                       ## Header Hash Count
    .long   12                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   1                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .long   0                       ## Bucket 0
    .long   193486030               ## Hash in Bucket 0
.set Lset5, LNames0-Lnames_begin        ## Offset in Bucket 0
    .long   Lset5
LNames0:
    .long   156                     ## add
    .long   1                       ## Num DIEs
    .long   43
    .long   0
    .section    __DWARF,__apple_objc,regular,debug
Lobjc_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   0                       ## Header Hash Count
    .long   12                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   1                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .long   -1                      ## Bucket 0
    .section    __DWARF,__apple_namespac,regular,debug
Lnamespac_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   0                       ## Header Hash Count
    .long   12                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   1                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .long   -1                      ## Bucket 0
    .section    __DWARF,__apple_types,regular,debug
Ltypes_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   1                       ## Header Hash Count
    .long   20                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   3                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .short  3                       ## DW_ATOM_die_tag
    .short  5                       ## DW_FORM_data2
    .short  4                       ## DW_ATOM_type_flags
    .short  11                      ## DW_FORM_data1
    .long   0                       ## Bucket 0
    .long   193495088               ## Hash in Bucket 0
.set Lset6, Ltypes0-Ltypes_begin        ## Offset in Bucket 0
    .long   Lset6
Ltypes0:
    .long   160                     ## int
    .long   1                       ## Num DIEs
    .long   97
    .short  36
    .byte   0
    .long   0

.subsections_via_symbols
    .section    __DWARF,__debug_line,regular,debug
Lsection_line:
Lline_table_start0:

替换成内联函数的样式:

static inline int add(int x, int y) {
     return x + y;
}

再次查看汇编代码:

        .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 15    sdk_version 10, 15, 4
    .section    __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
    .long   0
    .long   64

    .section    __DWARF,__apple_names,regular,debug
Lnames_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   0                       ## Header Hash Count
    .long   12                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   1                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .long   -1                      ## Bucket 0
    .section    __DWARF,__apple_objc,regular,debug
Lobjc_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   0                       ## Header Hash Count
    .long   12                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   1                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .long   -1                      ## Bucket 0
    .section    __DWARF,__apple_namespac,regular,debug
Lnamespac_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   0                       ## Header Hash Count
    .long   12                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   1                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .long   -1                      ## Bucket 0
    .section    __DWARF,__apple_types,regular,debug
Ltypes_begin:
    .long   1212240712              ## Header Magic
    .short  1                       ## Header Version
    .short  0                       ## Header Hash Function
    .long   1                       ## Header Bucket Count
    .long   0                       ## Header Hash Count
    .long   20                      ## Header Data Length
    .long   0                       ## HeaderData Die Offset Base
    .long   3                       ## HeaderData Atom Count
    .short  1                       ## DW_ATOM_die_offset
    .short  6                       ## DW_FORM_data4
    .short  3                       ## DW_ATOM_die_tag
    .short  5                       ## DW_FORM_data2
    .short  4                       ## DW_ATOM_type_flags
    .short  11                      ## DW_FORM_data1
    .long   -1                      ## Bucket 0

.subsections_via_symbols

发现汇编后的指令确实少了一些。但是从 Unit 测试结果上来看,执行效率并没有提升,个人猜测 CPU 执行时统一进行了优化,和是否使用内联函数无关。

总结

根据测试,得到如下结论:
1 在 iOS 设备上内联函数并不能大幅提高函数执行效率;
2 内联函数相比宏的优势: 类似普通函数一样,调用时会对传入的参数进行检查;不会出现宏修改导致Xcode重新编译缓慢的问题。

相关文章

  • iOS 中 inline 函数能提升 App 效率吗?

    在阅读开源库源码时,往往会发现 static inline 的关键字,这标识了该函数为内联样式。据称使用后 App...

  • 内联函数(inline)

    缘由 程序调用函数时步骤过于繁琐,导致运行效率低下,故引入inline函数。 格式 对象中inline函数使用 错...

  • iOS-inline内联函数

    iOS-inline内联函数

  • OC 内联函数 inline

    在iOS的一些框架中, static inline 是经常出现的关键字组合,主要是为了提高函数调用的效率。 内联函...

  • Kotlin内联函数使用

    inline 本质 Kotlin中的内联函数使用inline关键字修饰,形如: 编译时,inline会将内联函数中...

  • 内联函数

    内联函数 在类中定义的函数,但是实现却在类外面。并且在函数前加了 inline 就是内联函数,内联函数效率一般比较...

  • iOS之UIView

    初识iOS APP开发#### 在iOS APP开发中, main函数仍是程序的入口和出口, 但main函数不需要...

  • iOS OC中内联函数inline

    inline 在iOS中的一些框架中,static inline是经常出现的关键字组合。 static自不用多说,...

  • 提升iOS开发效率的一些keys

    提升iOS开发效率的一些keys 提升iOS开发效率的一些keys

  • iOS 内联函数 inline

    OC中使用inline,主要是为了提高函数调用的效率 使用例子: 我们通常会发现,inline 会有 static...

网友评论

    本文标题:iOS 中 inline 函数能提升 App 效率吗?

    本文链接:https://www.haomeiwen.com/subject/qwkbxktx.html