Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSString – static or inline? Is there any performance gains?

Is there any performance gain if I write

- (NSString *)helloStringWithName:(NSString *)name
    static NSString *formatString = @"Hello %@!";
    return [NSString stringWithFormat:formatString, name];
}

instead of

- (NSString *)helloStringWithName:(NSString *)name
    return [NSString stringWithFormat:@"Hello %@!", name];
}

??

If I were to guess I would think that the latter one is created and autoreleased each time the code is running, but I guess the compiler is smart enough to know what do here..

like image 504
hfossli Avatar asked Aug 15 '13 09:08

hfossli


2 Answers

If you try this out (Menu->Product->Generate Output->Assembly File) - you'll note virtually identical output under clang - with only small changes due to the extra variable assignment & debugging info left.

So in short - no real difference; though the static one may be a bit easier to debug I guess.

    .align  4, 0x90
"-[Foo helloStringWithName1:]":         ## @"\01-[Foo helloStringWithName1:]"
    .cfi_startproc
Lfunc_begin0:
    .loc    1 15 0                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:15:0
## BB#0:
    pushq   %rbp
Ltmp2:
    .cfi_def_cfa_offset 16
Ltmp3:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp4:
    .cfi_def_cfa_register %rbp
    subq    $48, %rsp
    movq    %rdi, -8(%rbp)
    movq    %rsi, -16(%rbp)
    movq    %rdx, %rdi
    callq   _objc_retain
    movq    %rax, -24(%rbp)
    .loc    1 17 5 prologue_end     ## /Users/dirkx/tmp/ccccc/ccccc/main.m:17:5
Ltmp5:
    movq    L_OBJC_CLASSLIST_REFERENCES_$_(%rip), %rax
    movq    "-[Foo helloStringWithName1:].formatString"(%rip), %rdx
    movq    -24(%rbp), %rcx
    movq    L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
    movq    %rax, %rdi
    movb    $0, %al
    callq   _objc_msgSend
    movq    %rax, %rdi
    callq   _objc_retainAutoreleasedReturnValue
    movabsq $0, %rsi
    leaq    -24(%rbp), %rcx
    movl    $1, -28(%rbp)
    .loc    1 18 1                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:18:1
    movq    %rcx, %rdi
    movq    %rax, -40(%rbp)         ## 8-byte Spill
    callq   _objc_storeStrong
Ltmp6:
    .loc    1 18 1                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:18:1
    movq    -40(%rbp), %rax         ## 8-byte Reload
    movq    %rax, %rdi
    callq   _objc_autoreleaseReturnValue
    .loc    1 17 5                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:17:5
Ltmp7:
    addq    $48, %rsp
    popq    %rbp
    ret
Ltmp8:
Lfunc_end0:
    .cfi_endproc

versus

    .align  4, 0x90
"-[Foo helloStringWithName2:]":         ## @"\01-[Foo helloStringWithName2:]"
    .cfi_startproc
Lfunc_begin1:
    .loc    1 20 0                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:20:0
## BB#0:
    pushq   %rbp
Ltmp11:
    .cfi_def_cfa_offset 16
Ltmp12:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp13:
    .cfi_def_cfa_register %rbp
    subq    $48, %rsp
    movq    %rdi, -8(%rbp)
    movq    %rsi, -16(%rbp)
    movq    %rdx, %rdi
    callq   _objc_retain
    leaq    L__unnamed_cfstring_2(%rip), %rdx  <-------------------- 
    movq    %rax, -24(%rbp)
    .loc    1 21 5 prologue_end     ## /Users/dirkx/tmp/ccccc/ccccc/main.m:21:5
Ltmp14:
    movq    L_OBJC_CLASSLIST_REFERENCES_$_(%rip), %rax
    movq    -24(%rbp), %rcx
    movq    L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
    movq    %rax, %rdi
    movb    $0, %al
    callq   _objc_msgSend
    movq    %rax, %rdi
    callq   _objc_retainAutoreleasedReturnValue
    movabsq $0, %rsi
    leaq    -24(%rbp), %rcx
    movl    $1, -28(%rbp)
    .loc    1 22 1                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:22:1
    movq    %rcx, %rdi
    movq    %rax, -40(%rbp)         ## 8-byte Spill
    callq   _objc_storeStrong
Ltmp15:
    .loc    1 22 1                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:22:1
    movq    -40(%rbp), %rax         ## 8-byte Reload
    movq    %rax, %rdi
    callq   _objc_autoreleaseReturnValue
    .loc    1 21 5                  ## /Users/dirkx/tmp/ccccc/ccccc/main.m:21:5
Ltmp16:
    addq    $48, %rsp
    popq    %rbp
    ret
Ltmp17:
Lfunc_end1:
    .cfi_endproc

with as key references:

Lfunc_end2:
    .cfi_endproc

    .section    __DATA,__data
    .align  3                       ## @"\01-[Foo helloStringWithName1:].formatString"
"-[Foo helloStringWithName1:].formatString":
    .quad   L__unnamed_cfstring_

    .section    __TEXT,__cstring,cstring_literals
l_.str:                                 ## @.str
    .asciz   "Hello 1 %@!"

and

    .section    __TEXT,__cstring,cstring_literals
l_.str1:                                ## @.str1
    .asciz   "Hello 2 %@!"
like image 78
Dirk-Willem van Gulik Avatar answered Nov 15 '22 04:11

Dirk-Willem van Gulik


String literals in Objective-C are allocated at compile time, therefore you won't reasonably gain anything in performance.

Considers this

NSString * str = @"Hello";    
NSString * str2 = @"Hello";

NSLog(@"%p", str);  // => 0x860358
NSLog(@"%p", str2); // => 0x860358

Therefore if your intent is to say something like:

"Hey compiler, the format string is always the same so don't bother allocating that more than once"

the answer would be:

"How nice, tell me something I don't know"

NOTE

If you are still skeptical you can take a look at the assembly (check out Dirk's answer), but let me give you a piece of advice here: don't bang your head against such performance issues.

The overhead of using NSString and a high level abstraction as objects in general is definitely predominant in your program performances, so even if you gain a nanosecond per string, you won't reasonably even notice that. And as you rightfully suspect, the compiler is already smart enough to take care of such details.

To wrap it up: let the compiler do its job and you do yours, i.e. writing readable and maintainable code.

like image 13
Gabriele Petronella Avatar answered Nov 15 '22 05:11

Gabriele Petronella