Live data from Hacker News

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

forrestthewoods.com

31–40 of 115 posts

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

#31

Interesting article. I enjoyed it. I have two thoughts. ==== 1. Regarding the benchmark itself, I wonder out loud if CPU caching could have a meaningful alter on the results. The article says : > I randomly generate 4000 spheres, capsules, segments, and triangles. It is not clear to me if this is enough to fill CPU L1 cache or not. My guess is that it is not. If all the benchmark indeed happens within the L1 cache, I…

I don't see that making a difference in the by-copy/by-reference use on the leaf functions? Since the copies are stack allocated all the data used there is going to be shuffling in and out of the same few cache lines and shouldn't make a perceptible difference in overall cache usage.

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

#33
post #29

You should be careful trying to apply these micro benchmarks to modern optimising compiles, behaviour may be different depending on the exact code being compiled. Rust especially has immutability and known types in generics at compile time, so the compiler can do a lot of pointer and inlining magic that C and other languages can't. In the below example Rust switches to using a pointer when you might think it's doing…

> so the compiler can do a lot of pointer and inlining magic that C and other languages can't. Isn't this a negative for Rust for when you actually do care about such micro-optimizations? It feels as if you not only need to know the language itself but also how the particular version of the compiler you are using has decided to interpret the language and apply optimizations - essentially having to know how the magic…

> It feels as if you not only need to know the language itself but also how the particular version of the compiler you are using has decided to interpret the language and apply optimizations - essentially having to know how the magic trick is performed.

That's also true with C/C++, isn't it? Optimizations should be different if you compile a C program with GCC or CLANG, or even with GCC x or y versions (but I'm not a compiled language programmer, I could be wrong)

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

#34

A good rule is to let the caller decide. If input parameters are by-reference and the caller wants to make them by-reference, congrats, no problem. If caller wants the parameters to by a copy, they can create a clone and pass a reference. But if you impose the input parameters to by copy, there's no way back.

In Rust (end even C++ afaik) it usually makes more sense to let the callee decide. Does it need to own the value? -> Call by value. Does it only need to inspect or (visibly) mutate the value during the function call? -> Call by reference (modulo optimization concerns).

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

#35

Earlier quoted context omitted.

Yes - even if you ask for pass by move, it might pass a reference for a large struct.

That's interesting, and a bit surprising. I know Ada does this, but it's explicit about only specifying semantics ("in, "out" or "in out") and letting the compiler decide. Surely C or C++ optimizers won't do this?

It's not as surprising when you consider that moving the value into the function also makes it permanently unavailable to the caller. So what difference does it really make? The semantics are the same either way. The lifetime of the object ends within the function.

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

#36
In general, in a multi-core/massively-concurrent&&parallel world, copying small, immutable data-structures is preferred. The big reason is cache hits and minimizing contention for cache lines. If you have small data structures at different addresses (that map to different cache lines), then the memory subsystem isn't stepping all over itself with RAR/WAR/RAW hazards because the copies of data structure became essentially independent of each other after the copy finished and wrote-back to L2/L3.

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

#37
post #29

You should be careful trying to apply these micro benchmarks to modern optimising compiles, behaviour may be different depending on the exact code being compiled. Rust especially has immutability and known types in generics at compile time, so the compiler can do a lot of pointer and inlining magic that C and other languages can't. In the below example Rust switches to using a pointer when you might think it's doing…

> so the compiler can do a lot of pointer and inlining magic that C and other languages can't. Isn't this a negative for Rust for when you actually do care about such micro-optimizations? It feels as if you not only need to know the language itself but also how the particular version of the compiler you are using has decided to interpret the language and apply optimizations - essentially having to know how the magic…

In general Rust emphasises semantics over implementation side-effects. For example you use a pass-by-value because you're semantically moving ownership of the value to the function, not because the implementation may be faster/slower at the assembly level. Not nailing down the implementation is what allows the compiler to make so many optimisations.

If you need concise pointer control, use the unsafe trapdoor built into rust (like Rust's Vec). If you need very specialised code use assembly, not by abusing language side-effects like Duff's Device. If you need fast number crunching use the specialised library for it, not by writing a magic for loop with just the right amount of statements in it.

I admit that sometimes you need to micro-optimise, but I haven't come across this case much in my Rust code. When I do I usually hinder more then help it.

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

#38

You should be careful trying to apply these micro benchmarks to modern optimising compiles, behaviour may be different depending on the exact code being compiled. Rust especially has immutability and known types in generics at compile time, so the compiler can do a lot of pointer and inlining magic that C and other languages can't. In the below example Rust switches to using a pointer when you might think it's doing…

0. Generously use black_box

1. a large sample size

2. a single thread

3. high-precision monotonic timestamps on an unloaded system

4. mean/std dev from more than several runs

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

#39
What I find weird is that there is a difference in performance.

If the compiler is smart enough to inline, it should be able to notice that the way arguments are passed make no difference and use the most efficient way regardless of the signature. Do I overestimate the abilities of compilers, or maybe there is some side effect I am not aware of (concurrency?).

Obviously, it only applies when inlining.

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

#40

The Cpp Core Guidelines suggest that the cutoff between copy and const reference should be "up to two or three words" (item F.16). Following this advice, the f32 vector would be passed by value, and the f64 vector would end up in the grey zone. https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...

That explains why I usually see std::span passed by value.
Post reply on HN