Live data from Hacker News

Performance of Rust Language [pdf]

github.com

101–110 of 146 posts

Re: Performance of Rust Language [pdf]

#101

Earlier quoted context omitted.

> Rust's metaprogramming capabilities are now on par with C++ (they weren't always). Is that really true, though? I haven't really written any Rust code, so I have no idea, but I don't think Rust has static reflection. Also, aren't const generics much more limited? I've also heard there is no template specialization and no "if constexpr". Or what about dynamic allocations in constexpr functions?

> I don't think Rust has static reflection. Before C++ in fact through procedural macros. You can do everything you can do with C++ static reflection. Now, it could be better. Proc macros require you to pull in secondary packages for parsing the token stream. But all the sorts of operations you can do via static reflection you can do via proc macros. That's how the most popular rust serialization package like serde w…

> You can do everything you can do with C++ static reflection.

Are you really sure about that?

I have a slight problem with such sweeping statements and also with your original claim that "Rust's metaprogramming capabilities are now on par with C++". I think you can only make such claims if you know both languages really, really well.

That being said, I acknowledge that Rust's metaprogramming capabilities have improved significantly in recent years.

> Both have been added and expanded.

In stable Rust?

Re: Performance of Rust Language [pdf]

#102

Earlier quoted context omitted.

> I don't think Rust has static reflection. Before C++ in fact through procedural macros. You can do everything you can do with C++ static reflection. Now, it could be better. Proc macros require you to pull in secondary packages for parsing the token stream. But all the sorts of operations you can do via static reflection you can do via proc macros. That's how the most popular rust serialization package like serde w…

> You can do everything you can do with C++ static reflection. Are you really sure about that? I have a slight problem with such sweeping statements and also with your original claim that "Rust's metaprogramming capabilities are now on par with C++". I think you can only make such claims if you know both languages really, really well. That being said, I acknowledge that Rust's metaprogramming capabilities have improv…

It's hard to be concrete without talking about something specific. At the limit, in stable Rust (for 8 years?), a proc_macro consumes and emits an arbitrary token stream at compile time; it's not ergonomic, but it's possible.

The equivalent in C++ is in the realm of arbitrary codegen.

Re: Performance of Rust Language [pdf]

#103

Earlier quoted context omitted.

Panics in Rust do not currently time-travel like that (including panics from failed bounds checks), and that's a good thing. The reason is that panicking does not imply terminating the process - they can be caught and handled, just like exceptions in C++. In fact, they use the same stack unwinding mechanism by default. What the compiler is allowed to do is to shorten the loop by one and unconditionally panic after th…

It's true that panics (unlike UB) cannot automatically time-travel, but your justification is weak. Recovering from panics can only prevent this optimization if the loop have side effects, and LLVM knows when panic=abort is set.

I mean, sure, dead code elimination applies to all optimized code. The important thing to understand is that panicking in Rust does not get magic treatment by the Rust compiler. It’s just a function that is declared in the type system to never return.

Re: Performance of Rust Language [pdf]

#104
post #4

Rust is in an awkward position of being already complicated enough that adding proofs for skipping bounds checks probably will not happen for a long time, even though this kind of low-level operation is where a lot of optimisation is lost. Compounding on this, Rust is also unstable underneath, since there is no public, stable contract for carrying high-level semantics from HIR into MIR. Because these high-level invar…

The benchmarks in this talk show that the bounds checks are mostly insignificant, and actually it's the integer overflow checks that are far more costly. Actually nm, I forgot those are disabled in release mode. Good decision I guess.

Do they even count towards safety if they aren't in release mode?

Re: Performance of Rust Language [pdf]

#105

Earlier quoted context omitted.

Of course you can write the above as: a[0..32].iter_mut().for_each(|el| *el = 1) and have per-iteration bounds checks elided in Rust today.

Or as mentioned in the OP, just add at the top: assert!(a.len() >= 32); for i in 0..32 { a[i] = 0; } Or: for i in 0..std::cmp::min(a.len(), 32) { a[i] = 0; } I confess I hadn't thought about the implications of any of this before reading the article. If you need to squeeze the last 10% of performance out of your code, I'd consider it required reading. As for the speed comparisons with C++, the OP says at the end you…

Both rewrites differ semantically from:

for i in 0..32 { a[i] = 1; }

If a.len() == 16, the indexed loop writes a[0]..a[15] and then panics at a[16]. By contrast, both assert!(a.len() >= 32); and a[0..32].iter_mut().for_each(|el| *el = 1) fail before any writes occur. The former at the explicit assertion, the latter while creating the a[0..32] subslice. That difference is observable if the panic is caught, and the panic location/message may also differ. This is why these are valid manual rewrites only when the intended precondition is "the slice has length at least 32," not generally valid compiler rewrites of the original loop.

The GitHub issue discussion is directly about these concerns and discuss whether bounds checks may fail early, whether intermediate writes are observable after catch_unwind and whether panic behavior must be preserved.

Re: Performance of Rust Language [pdf]

#107

I would summarize it thusly: Rust is roughly as performant as C. This matches my experience and Rust is more ergonomic than C in many regards. The caveat is that modern C++ is notably more performant than C and by implication Rust. This also matches my experience for both C and Rust. I think most of this is attributable to the ergonomics of compile-time expressiveness. C++ can effortlessly do things that require moun…

>> The caveat is that modern C++ is notably more performant than C and by implication Rust. Please provide proof for this outrageous statement.

Is it outrageous because "performant" is kind of a vague term. Does it mean... Fast? GPU-friendly? Scalable? Energy-efficient? Reliable? User-friendly? Maintainable? For what kind of applications?

Modern Fortran has a lot to offer for scientific and numeric computation - easier to learn than C++, and easier to optimize in many cases. Scales from small systems to supercomputers, and there is even CUDA Fortran.

Re: Performance of Rust Language [pdf]

#108

Earlier quoted context omitted.

The benchmarks in this talk show that the bounds checks are mostly insignificant, and actually it's the integer overflow checks that are far more costly. Actually nm, I forgot those are disabled in release mode. Good decision I guess.

Do they even count towards safety if they aren't in release mode?

You can enable them in release mode optionally. But I would say not. Really we need ISAs to provide a no-overhead way to check integer overflow.

Re: Performance of Rust Language [pdf]

#110

Earlier quoted context omitted.

Panics in Rust do not currently time-travel like that (including panics from failed bounds checks), and that's a good thing. The reason is that panicking does not imply terminating the process - they can be caught and handled, just like exceptions in C++. In fact, they use the same stack unwinding mechanism by default. What the compiler is allowed to do is to shorten the loop by one and unconditionally panic after th…

It's true that panics (unlike UB) cannot automatically time-travel, but your justification is weak. Recovering from panics can only prevent this optimization if the loop have side effects, and LLVM knows when panic=abort is set.

The post-panic situation is a problem in Rust. After a panic, you're in a somewhat abnormal state. Rust panics are not supposed to be a catchable exception system. If something other than program termination is in the near future, that's a problem.

That does create a problem for early panics, panicking when panic becomes inevitable but has not happened yet. This deserves more thought.

Post reply on HN