Live data from Hacker News

Should small Rust structs be passed by-copy or by-borrow? (2019)

forrestthewoods.com

211–220 of 238 posts

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#212

Earlier quoted context omitted.

Blog author here. I somewhat agree, somewhat disagree. This line makes me uneasy: > I always ask them to either prove it or write the simple thing. If the code in question isn't hot enough to bother benchmarking it, the performance benefits probably aren't worth it _even if they exist_. One of my philosophies is that death by a thousand cuts is fine, but death by ten thousand cuts isn’t. A team of 10 engineers can pr…

Very little of your code is in hot loops. If the code that takes half a millisecond per frame could be twice as fast, but the hot loop is very optimized, then it doesn't really matter. And that's what I would think of by default for having many many cuts. Better to spend the optimization effort elsewhere. > shared_ptr is a canonical example of death by ten thousand cuts Why does that count as ten thousand cuts rather…

> Very little of your code is in hot loops.

Very few programs have "hot loops" as small, contained things. "hot loops" is at this point as much of a bad trope as "but premature optimizations!" is.

> Why does that count as ten thousand cuts rather than one cut? That doesn't sound intractable to fix if you have months.

Why spend months re-writing code you could have just written correctly the first time if a single person had spent an hour messing around with benchmarks to figure out the proper guidance?

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#213
post #14

Earlier quoted context omitted.

> This is one advantage of Ada, where parameters are abstractly declared as "in" or "in out" or "out". Also Fortran has "in", "inout" and "out".

C++23 is not too late to the party https://en.cppreference.com/w/cpp/memory/out_ptr_t/out_ptr

Ehh that's not quite what those are. The types being added for C++23 are designed for FFI.

Herb made a proposal for proper in/out parameters for C++ in 2020 https://youtu.be/6lurOCdaj0Y

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#214
post #180

Earlier quoted context omitted.

Why is performance so much better in this case? That seems like a suspiciously large delta from the first test. Were the other benchmarks run in debug mode / with optimizations turned off or something like that? What compiler & flags are you using?

>"Were the other benchmarks run in debug mode / with optimizations turned off or something like that?" Why would I do something like that? Of course all builds are release mode, optimize for speed. Rust - Windows - By-Copy: 14124, By-Borrow: 8150 C++ - Windows MS Compiler - By-Copy: 12160, By-Ref: 11423 C++ - Windows LLVM 15 - By-Copy: 4397, By-Ref: 4396 >"Why is performance so much better in this case?" Not sure and…

It may be the default fp mode for msvc is causing C++ to suffer here ( https://learn.microsoft.com/en-us/cpp/build/reference/fp-spe... ). It looks like the default behavior is quite conservative it what it allows to happen - like it won't even use FMAs with the default behavior?

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#215

Earlier quoted context omitted.

Very little of your code is in hot loops. If the code that takes half a millisecond per frame could be twice as fast, but the hot loop is very optimized, then it doesn't really matter. And that's what I would think of by default for having many many cuts. Better to spend the optimization effort elsewhere. > shared_ptr is a canonical example of death by ten thousand cuts Why does that count as ten thousand cuts rather…

> Very little of your code is in hot loops. Very few programs have "hot loops" as small, contained things. "hot loops" is at this point as much of a bad trope as "but premature optimizations!" is. > Why does that count as ten thousand cuts rather than one cut? That doesn't sound intractable to fix if you have months. Why spend months re-writing code you could have just written correctly the first time if a single per…

> Very few programs have "hot loops" as small, contained things. "hot loops" is at this point as much of a bad trope as "but premature optimizations!" is.

If you say so. I can pretty easily and meaningfully divide my current program into "happens once per frame or less" and "happens hundreds or more times in a row".

> Why spend months re-writing code you could have just written correctly the first time if a single person had spent an hour messing around with benchmarks to figure out the proper guidance?

If they could have figured it out that easily I understand even less how this example works.

Let me put it this way: If a benchmark can change huge swaths of significantly performance important code, then it's "hot enough to bother" by orders of magnitude. I thought we were talking about microbenchmarks for individual cuts!

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#217
It's not like you can do arithmetic with references, so maybe the ergonomics of by-value vs. by-reference shouldn't really be that different.

The cost of by-value lies in memory copies, while the cost of by-reference lies in dereferencing pointers where the values are needed, which might mean many more memory reads are needed than with by-value (depends on what you're doing). So it's just hard to tell which will do better in general -- there's no answer to that.

For a library, maybe providing by-value and by-reference interfaces should be good (except that will bloat the library). For everything else just use by-value as it has the best ergonomics.

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#218
post #115

Earlier quoted context omitted.

I work in a Rust codebase that uses a lot of functional functions, and I’ll say this: on average the imperative style takes less lines of code and less indentation. I also find it more readable personally, and idiomatic.

Just because we’re on the topic of performance: the rust optimizer can sometimes generate better code if you use map / filter / etc. The slice iterator in any context is a huge win over manual array iteration because it only needs to do bounds checking once. Javascript (v8, last I checked) is the opposite. Simple for loops almost always outperform anything else.

This is premature optimization imo. Unless you’re using par_iter

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#219
post #218

Earlier quoted context omitted.

Just because we’re on the topic of performance: the rust optimizer can sometimes generate better code if you use map / filter / etc. The slice iterator in any context is a huge win over manual array iteration because it only needs to do bounds checking once. Javascript (v8, last I checked) is the opposite. Simple for loops almost always outperform anything else.

This is premature optimization imo. Unless you’re using par_iter

Without knowing the domain, you have no way of knowing that.

It’s also much easier to stick to for() loops in javascript as you code than it is to rewrite everything later when tuning for performance. If that’s something you expect to need to do.

Re: Should small Rust structs be passed by-copy or by-borrow? (2019)

#220
post #190

Earlier quoted context omitted.

I just updated Visual Studio 2022 with all the latest updates and installed the Clang toolchain. I also updated Rust to latest. C++ MSVC: By-Copy: 12,077 By-Ref: 11,901 C++ Clang: By-Copy: 5,020 By-Ref: 5,029 Rust: By-Copy: 3,173 By-Borrow: 3,148 All on Windows, and on the same i7-8700k desktop I used for the original post in 2019. Your Rust numbers are particularly curious. Maybe run `rustup update` and try again?

Just did this rustup update. Much better now. So the finals are: Rust - By-Copy: 2685, By-Borrow: 2694 C++ - Windows MS Compiler - By-Copy: 12160, By-Ref: 11423 C++ - Windows LLVM 15 - By-Copy: 4397, By-Ref: 4396 My CPU is AMD Ryzen 5950X so it seems like Rust kicks the shit out of C++ in this case. I am going to try LLVM 16 and GCC tomorrow. Happy New Year

Such stark difference in performance is really fishy and needs a deeper analysis. I just checked it with different compilers (all based on LLVM) and here are the results:

  rustc 1.58 (LLVM 13): By-Copy: 10804, By-Borrow: 7198
  rustc 1.64 (LLVM 14): By-Copy: 7385,  By-Borrow: 7328
  rustc 1.66 (LLVM 15): By-Copy: 2667,  By-Borrow: 2777
  clang++ (LLVM 14):    By-Copy: 2439,  By-Ref: 2589
  clang++ (LLVM 15):    By-Copy: 2473,  By-Ref: 2556
When compared with the same LLVM version clang much better utilised LLVM-14 than rustc - C++ is 3x faster. With LLVM-15 they are much closer.
Post reply on HN