Is the question mark operator slow to compile?

Some time ago, when I was doing a cursory investigation regarding slow compile times for a project, the question mark operator caught my attention.

Via derive macros, this project was generating a lot of code that used the ? operator. I made 3 separate files to test. Compile them with rustc -Zno-codegen --cap-lints=allow file.rs using a nightly rustc.

In my testing the file with the ? operator was around 2.5x times slower to compile than the one with the custom macro, with the try! case somewhere between the other two.

Considering these 3 test cases are not exactly equivalent, I am wondering if I should be opening a issue on GitHub. Let me know!

I can't find a way to upload files so here is a summary of the test cases:

// ? operator test case
fn main() -> Result<(), ()> {
  Ok(())?;
  // repeat the previous line 10 000 times
  return Ok(());
}
// custom macro test case
fn main() -> Result<(), ()> {
  macro_rules! t { ($e: expr) => { match $e { Ok(v) => v, e => return e, }}}
  t!(Ok(()));
  // repeat the previous line 10 000 times
  return Ok(());
}
// try! macro test case
fn main() -> Result<(), ()> {
  try!(Ok(()));
  // repeat the previous line 10 000 times
  return Ok(());
}
1 Like

Importantly, this isn't what ? does in two ways:

  1. ? works on multiple types -- Option and Poll, for example, not just Result -- so there's fundamentally more trait solving work that it needs to do.

  2. ? on Result includes a From::from call, so even though (): From<()> does nothing, compiler still needs to do work because of it. (Like having the call to it in MIR, when you're compiling without optimizations at all, or noticing that it does nothing and inlining it if you were to compile with optimizations.)

So this might be fine, especially since doing just about anything 10 000 times in one function makes all kinds of things unhappy. ?'ll always be a bit slower than something that does less, but unless that shows up as material in a more realistic situation, I don't personally think it needs an issue about it.


There's also some implementation detail stuff. In Wishlist: a MIR optimization to simplify the new RFC3058 `?` desugaring · Issue #85133 · rust-lang/rust · GitHub it was noted that an LLVM optimization was improved to better handle ?, and I don't know if that's been picked up yet. Though that's more about runtime performance of this stuff than about compile-time in debug mode.

3 Likes

Drag-then-drop into a reply edit window.

1 Like

I just realized this post was probably more fit for the Rust Internals forum. Oops!

Come to think of it, if you have a ?-heavy example, maybe what would make sense is not to open a bug saying that ? is slow, but to add a useful benchmark to https://github.com/rust-lang/rustc-perf/tree/master/collector/benchmarks so that the performance of it can be tracked over time, and people can chip away at improving it via that data.

4 Likes

I agree that this needs a realistic situation to be an issue. I will try to remove ? usage from the project I mentioned in OP to see if it makes a difference in compile time and post the results here.

I am not particularly interested in the runtime performance at this time. Will this MIR optimization pass reduce the compile time when using rustc -Zno-codegen? I believe this option is used by Cargo in check mode.

I believe serde (or maybe syn?) still uses a custom tri! macro that only works for Result and without error type conversion, because the compile time difference was notable in that project. I don't know the last time that was reëvaluated.

1 Like

Is that so? I thought serde doesn't use ? because it's MSRV is lower than ?'s stabilization. Isn't it compatible with rust 1.0?