Working on a lil pet project in rust rn and discovered that using Result in the hot path is significantly affecting performance, how do people deal with this?
like the overhead is tiny but it adds up substantially
@cas async has a related but slightly different problem
@cas it's very unfortunate to have to produce separate versions of a function for perf like this but i would recommend something like passing in an &mut flag
@cas It is Result by itself or maybe the Error variant is too "heavy"?
@pitbuster not sure, it's just an enum with a few numbers, using thiserror.
@cas hmm, it sounds it shouldn't be much of a problem then :(
@cas @pitbuster that's really weird, maybe the problem is that Result adds a discriminant and makes the original type larger. Sometimes you can fix this by hinting things at the compiler but it really depends on the actual situation.
@cas afaik this is well known and the main reason to use exceptions over a Result-like mechanism, Rust decided the simpler correctness guarantees were more important than performance

@cas some things i might try:

  • reduce the size of the Error payload, ideally to a single word (e.g. by Box'ing the error)
  • if this isn't enough, return nothing in the Err case (() or a unit-struct struct ErrorType;) and store the error data out-of-band ie in a mutable variable somewhere. this makes the overhead of the result type minimal and makes the destructor a no-op. you could also try a hybrid approach where the error type is a plain enum with error codes, and then extra error metadata like strings are stored out of band
  • make the Result-manipulation easier for the compiler to eliminate, so that it can remove the byte-shuffling and only preserve the control flow. if you have a long function using Results, move the "meat" of the logic that doesn't use Result to a separate function, so that part doesn't get inlined. inlining typically stops at a certain function size so breaking code up like this makes it easier for compiler to make more granular inlining decisions. and inlining is super profitable because it allows the compiler to eliminate more code after inlining
@milo @cas would #[inline(always)] be a way to cheat the heuristics?
@hipsterelectron @cas maybe but then you could also risk the compiler having way too big of a function and giving up on optimizations inside that function. maybe worth a shot but ive never found those annotations to make a big difference (tbh the inlining heuristics are already pretty good by default)
@hipsterelectron @cas i would try the other two suggestions before trying to influence the compiler optimization black box lol
@cas i'm vaguely aware of github.com/iex-rs/iex but from what i know it's extremely dubious for all sorts of reasons
GitHub - iex-rs/iex: Idiomatic exceptions for Rust

Idiomatic exceptions for Rust. Contribute to iex-rs/iex development by creating an account on GitHub.

GitHub
@cas ignoring the problem most likely
@cas #[inline(always)] and outlining cold helpers from the error path may help