Live data from Hacker News

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

forrestthewoods.com

31–40 of 238 posts

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

#31
post #7
post #6

It is a problem of statistics and depends on internals of underlying operating system. I’m not sure you really need that sort of optimisation

What does this have to do with the operating system? There are no syscalls in the code measured here.

The "C ABI" is really "the platform ABI", because most OS are interacted with through libc (or equivalent).

Though that should not apply to Rust at all, as it does not pledge to follow the C ABI internally (aka `extern "Rust"`).

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

#32
post #11

I would go with the version that gives the clean user interface (that is, by copy in this case). If it turns out that the other version is significantly more performant and this additional performance is critical for the end users consider adding the by-borrow option. The clarity of the code using a particular library is such an big (but often under-appreciated) benefit that I would heavily lean in this direction whe…

Agreed - and this applies in nearly every language: start simple, trust your compiler, and optimize only when performance becomes untenable.

The assumption behind such arguments is when a performance problem does arise, a profiler will point to a single, easy to fix, smoking gun. Unfortunately this is not always the case. Performance problems can be hard to diagnose and hard to fix. A lot of damage has been done by unexamined / dogmatic "root of all evil" mantra.

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

#33
post #14
post #3

This is one advantage of Ada, where parameters are abstractly declared as "in" or "in out" or "out". The compiler can then decide how to best implement it for that specific size and architecture.

> 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".

Also, MSVC has similar annotations for various static analyses: https://learn.microsoft.com/en-us/cpp/code-quality/understan...

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

#34
post #14
post #3

This is one advantage of Ada, where parameters are abstractly declared as "in" or "in out" or "out". The compiler can then decide how to best implement it for that specific size and architecture.

> 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".

And Swift also has "inout" parameters.

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

#35

It's compiled, so, without any investigation at all, I would have been disappointed if there were any significant difference in the code emitted in these cases. I would expect the compiler to do the efficient thing based on usage rather than the particular syntax. I may have too much faith in the compiler.

I'd expect your claim to be true whenever the callee is inlined into the caller. In this case, the compiler has all the relevant information at the right point in time. As other commenters have pointed out, by enabling inlining the author has gone down a rabbit hole somewhat unrelated to the question, because any copies can be simply elided.

If there's no inlining at play, I'd expect vast differences to be possible. For example, imagine a chain of 3 functions - f calls g, g calls h, where one of the arguments is a 1kB struct and the options are passing by copy or by borrowing. In this case, each stack frame will be 1kB in size in the copy case and there will be a large performance overhead as opposed to the by-reference case. One would expect simply calling the function to be similar in overhead to an uncached memory load.

Within a single crate the inlining is possible, with multiple crates it's only possible with LTO enabled (and I'm not sure how _probable_ it is that the inlining would occur).

In either case, the difference between a 32 byte and 8 byte argument in terms of overhead is likely meaningless - the sort of thing to be optimized if profiling says it's a problem as opposed to ahead of time.

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

#37
The benchmarks lack the standard deviation, so the results may well be equivalent. Don't roll your own micro-benchmark runners.

References may get optimized to copies where possible and sound (i.e. blittable and const), a common heuristic involves the size of a cache line (64b on most modern ISAs, including x86_64).

Using a Vector4 would have pushed the structure size beyond the 64b heuristic. You would also need to disable inlining for the measured methods.

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

#38
post #35

It's compiled, so, without any investigation at all, I would have been disappointed if there were any significant difference in the code emitted in these cases. I would expect the compiler to do the efficient thing based on usage rather than the particular syntax. I may have too much faith in the compiler.

I'd expect your claim to be true whenever the callee is inlined into the caller. In this case, the compiler has all the relevant information at the right point in time. As other commenters have pointed out, by enabling inlining the author has gone down a rabbit hole somewhat unrelated to the question, because any copies can be simply elided. If there's no inlining at play, I'd expect vast differences to be possible.…

> Within a single crate (more specifically, codegen unit) the inlining is possible

Cross-crate inlining happens all the time. In order to be eligible for inlining, a function needs to have its IR included in the object's metadata. This happens automatically for every generic function (it's the only way monomorphization can work), and for non-generic functions can be enabled manually via the `#[inline]` attribute (which does not force inlining, it only makes it possible to inline at the backend's discretion).

However, as you, say, if you have LTO enabled then "cross-crate" inlining can happen regardless, since it's all just one giant compilation unit at that point.

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

#39
There is no single answer to this question because it's going to depend completely on call patterns further up. Especially in regards to how much of the rest of the running program's data fits in L1 cache, and most especially in regards to what's going on in terms of concurrency.

The benchmark made here could completely fall apart once more threads are added.

Modern computer architectures are non-uniform in terms of any kind of memory accesses. The same logical operations can have extremely varied costs depending on how the whole program flow goes.

Post reply on HN