Skip to content

Reduced performance when using question mark operator instead of try! #37939

Closed

Description

@birkenfeld

This was reported on the users forum , and I don't want it to get lost. Basically, replacing try! by ? resulted in ~20% performance loss in benchmarks:

ratel-rust/ratel-core#48 (comment)

I've reproduced, but not further investigated, these findings. Is that expected right now? It's not a good argument for adopting the question mark :)

Activity

  1. arthurprs commented on Nov 24, 2016

    @arthurprs
    Contributor

    I didn't read the implementation until now, I though they expanded to the exact same thing as try!()

  2. sfackler commented on Nov 24, 2016

    @sfackler
    Member

    Might just need to stick a couple of #[inline]s on Carrier methods.

  3. StefanoD commented on Nov 26, 2016

    @StefanoD

    I'm curious why this issue doesn't even get a label like I-Slow.

  4. birkenfeld commented on Dec 3, 2016

    @birkenfeld
    ContributorAuthor

    @sfackler I tried this (#[inline] on the trait method definitions and the impl methods), but didn't seem to get any different bench numbers.

  5. added
    I-slowIssue: Problems and improvements with respect to performance of generated code.
    on Dec 8, 2016
  6. bluss commented on Dec 11, 2016

    @bluss
    Contributor

    @arielb1 I've implemented a test version of the "variant copy prop" by hacking into CopyPropagation. However @eddyb has unfortunately 😉 said that it's much better to make a more general version of that that can propagate copies of aggregates (somehow).

  7. added 3 commits that reference this issue on Jun 1, 2017
  8. kdy1 commented on Sep 28, 2017

    @kdy1
    Contributor

    I think this issue is fixed.

    Generated asm is same for try! and ?.

    https://play.rust-lang.org/?gist=625d88df305ace951a088e1cee2ec13a

    Edit: Typo

  9. StefanoD commented on Sep 28, 2017

    @StefanoD

    Even if this is fixed: Is there a unit test which prevents regression?

  10. kennytm commented on Sep 28, 2017

    @kennytm
    Member

    We could have a codegen test for this.

    Someone tag this as E-needstest please...

  11. 5 remaining items

  12. arielb1 commented on Feb 1, 2018

    @arielb1
    Contributor

    @mati865

    I know that. It has a bug that I couldn't quite pin out.

  13. removed
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on Feb 1, 2018
  14. kornelski commented on Apr 24, 2018

    @kornelski
    Contributor
  15. added
    WG-llvmWorking group: LLVM backend code generation
    on Apr 24, 2018
  16. mehcode commented on Aug 31, 2018

    @mehcode
    Contributor

    This seems to be fixed (in stable). Tried the play link above.

    ; Function Attrs: noinline norecurse nounwind readnone uwtable
    define { i64, i64 } @try_op(i64, i64) unnamed_addr #2 {
      %3 = tail call { i64, i64 } @try_macro(i64 %0, i64 %1) #2
      ret { i64, i64 } %3
    }

    try_op:
    	jmp	try_macro
    
    try_macro:
    	xorl	%eax, %eax
    	testq	%rdi, %rdi
    	setne	%al
    	movq	%rsi, %rdx
    	retq
  17. added
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on Aug 31, 2018
  18. bluss commented on Dec 1, 2018

    @bluss
    Contributor

    You can still provoke it to make a difference and introduce conditionals or more copies for the ? operator than for the try!() macro if you change the payload types for the Result, for example using (i32, i32) or String.

    type T = (i32, i32);
    type E = T;
    type R = Result<T, E>;
    
    #[no_mangle]
    pub fn try_op(a: R) -> R {
        Ok(a?)
    }
    
    #[no_mangle]
    pub fn try_macro(a: R) -> R {
        Ok(try!(a))
    }
  19. added
    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.
    on Dec 1, 2018
  20. mati865 commented on Apr 3, 2019

    @mati865
    Member

    Looks like it regressed: https://godbolt.org/z/awKD_U

  21. mati865 commented on Aug 17, 2022

    @mati865
    Member

    We are fast again (at least for the examples given above) since Rust 1.52 which contains LLVM 12 upgrade!

    Once somebody adds test (or confirms that similar test already exists) this issue could be closed.

  22. Kobzol commented on Aug 17, 2022

    @Kobzol
    Member

    There's this codegen test, but I'm not sure if it's enough to check for this.

  23. StefanoD commented on Aug 17, 2022

    @StefanoD

    According to this blog post, Rust has to this date (Rust 1.62.1) performance problems with the question mark operator, resulting in a 4% performance loss.

  24. scottmcm commented on Aug 17, 2022

    @scottmcm
    Member

    but I'm not sure if it's enough to check for this.

    Definitely not -- you'll notice it's both -Zunsound-mir-opts and FIXME: broken.

    But there's good news! LLVM 15 merged a few days ago, bringing the fix mentioned in #85133 (comment).

    With that, both of these are nops now:

    #![feature(try_blocks)]
    
    pub fn result_nop_match(x: Result<i32, u32>) -> Result<i32, u32> {
        match x {
            Ok(x) => Ok(x),
            Err(x) => Err(x),
        }
    }
    
    pub fn result_nop_traits(x: Result<i32, u32>) -> Result<i32, u32> {
        try {
            x?
        }
    }

    https://rust.godbolt.org/z/71dYnrMf6

    example::result_nop_match:
            mov     rax, rdi
            ret
    
    example::result_nop_traits:
            mov     rax, rdi
            ret

    For comparison, on 1.63 even the match version needs a bunch of code: https://rust.godbolt.org/z/oarec37sG

    example::result_nop_match:
            xor     ecx, ecx
            test    edi, edi
            setne   cl
            movabs  rax, -4294967296
            and     rax, rdi
            or      rax, rcx
            ret

    EDIT: I opened #100693 to have a codegen test here.

  25. JohnTitor commented on Dec 21, 2022

    @JohnTitor
    Member

    Triage: #100693 added the test for this case (thank you @scottmcm!), closing as fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-enhancementCategory: An issue proposing an enhancement or a PR with one.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.I-slowIssue: Problems and improvements with respect to performance of generated code.WG-llvmWorking group: LLVM backend code generation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions