1. 77
    1. 19

      At this rate, he might as well write a book on Rust. Learnt so much from his posts. ✅💯

      1. 10

        I think it’d actually be nice to put some of his guides into the rust docs. Stuff like typical profile setups, error handling infrastructure, serialization, time and rng handling that are totally fine to just include in your application. Obviously you can’t put this in the permanent rust docs or book as they’re very opinionated and may be outdated easily.

        But what I’ve seen is that new people, who didn’t see the ecosystem grow since 2015 and follow the trends, are pretty easily overwhelmed with the question of what you should use and what is a fair price to pay performance wise* (backtraces,auto-boxing for errors etc). So it’ll probably be the rust commons ? And I think it should be done sooner than later, because while rust didn’t add a fat std for obvious reasons, it’s hard to search through stackoverflow just to find out what the typical rust way of doing logging/backtraces/errors/regex/.. is (or that you should watch out for async-std vs tokio vs tokio 1.0 in async land). And some will certainly just start to write their own (whacky) solutions instead of using the exisiting ones, creating an even bigger time-to-mvp and thus less motivating results of what you actually wanted to accomplish.

        * I’ve watched myself and other people deciding against backtraces (stable_eyre), auto-boxing (anyhow) and tracing simply because in rust you can actually think about the overhead this may introduce. Meanwhile nobody will think about turning off backtraces on a hard crash in java/python/nodejs. And I’m very certain this is premature optimization which is preventing you from debugging failures and giving you a harder time using rust also contributes to the “hard to learn” feeling.

        1. 4

          Autoboxing with errors can actually improve performance if the type in your Err variant is large. This is because Rust enums are the size of their largest variant. So if the Err variant of a returned Result is large, the return slot of that particular function will always be large even if the “happy path” (the Ok variant, since errors should be rare) is small or even unsized (()). Boxing ensures the Err variant is only pointer sized.

          Of course this isn’t always the case, but it’s common enough that it’s a reason crates like anyhow use this pattern.

          1. 1

            Hm yeah true - didn’t think about that even though I know how rust enums work.. Another pitfall to add to the list. I guess many people just optimize for no-alloc. But I honestly don’t know how well you can do error-kind matching over anyhow/eyre, apart from some type-testing. Which would be my go-to for autoboxing.

    2. 16

      As valuable as this is specifically to Rust builds, this article clearly illuminates the author’s meta-cognitive process. It:

      • Explains how to use “mechanical sympathy”, how to use an understanding of what a computer is trying to do in order to understand why certain types of solution work. Bridges a general understanding of compilation and linking from C to Rust specifically.
      • Explain when / how / why to measure.
      • Is not afraid to guess and play. The author introduces a new knob e.g. codegen units and wonders “what if I make this big? What if I make this small? What do the measurements show?”.
      • Goes deep and covers multiple domains, for example you can ask cargo to self-report what it is doing, or just use strace which works in all situations but suffers from verbosity.

      From an educator / educational perspective, remarkable and superb. I would read a book by this author.

    3. 3

      I scrolled down to the conclusion section hoping to learn about why it is slow in some quick words. But there was none :/ Any TLDR folks?

      1. 12

        In this case, it is because of known compile time regression in Rust 1.57.0 which will be fixed in 1.58.0. Compared to methods, the answer itself is rather unenlightening.

        1. 6

          Yeah, in this case it’s more about the journey taken to figure it out.

      2. 4

        TL;DR: There was a giant generic type that took forever for the compiler to handle. That type came from a web server library called “warp”, which is famous for its extreme use of generics and playing games with the type system. The fix was to use dynamic dispatch instead of monomorphization, which erases the type so the compiler doesn’t have to keep track of it. If that sounds hard, it’s not. It’s literally just one method on the end of the normal type called “boxed”.

    4. 2

      What a wonderful read. I did some recent works related to measuring build time recently and having a flame graph out of the box definitely helps a ton.

      I would also suggest having CI retain the long term trend of build timing data with strict timeout. You should be able to spot regression pretty easily.

    5. [Comment removed by author]

      1. [Comment removed by author]

        1. 1

          As you’ve seen yourself it’s a corner case. And the build time is on-par with c++? https://prev.rust-lang.org/en-US/faq.html#why-is-rustc-slow

          Because rust tries to improve its build times using cranelift. https://github.com/rust-lang/rust/pull/77975

          And there are so many more answers to that problem (>300 crates for this post, how many generics are used, how many proc-macros…).

          if it were any other modern language then I wonder if this type of regression would have made it this far

          It’s a fluke and testing against compile performance is done on https://perf.rust-lang.org/

          There are even whole ecosystem runs for releases: https://crater-reports.s3.amazonaws.com/pr-87050/full.html to run performance tests. And warp didn’t get caught.