Live data from Hacker News

Rust is now overall faster than C in benchmarks

benchmarksgame-team.pages.debian.net

161–170 of 445 posts

Re: Rust is now overall faster than C in benchmarks

#161
post #76

Earlier quoted context omitted.

I recall an anecdote about how Haskell actually outperformed C on various tree benchmarks because it was using a better implementation. At some point, the C programmers got fed up with the airs of superiority from Haskell programmers, ported the Haskell implementation, and reclaimed their position. I wouldn't be surprised if there's something similar happening here.

The Haskell code on some pathological examples of these implementations that I have seen has so many unsafe construct, strictness annotations, inlining annotations and so forth that it's practically C in a different syntax. It is not idiomatic Haskell at all and loses all of the touted benefits. Is there a separate benchmark that only accepts idiomatic code?

Just like C is pimped up BCPL, a language designed to bootstrap the CPL compiler, 10 years younger than ESPOL/NEWP, 10 years younger than Jovial, 6 years younger than PL/I, among other possible examples from the 60's.

Also C was known for not being a fast language on 80's home hardware, ruled by Assembly.

So low level coding for OS isn't coding like C and is just the way for mechanical sympathy, regardless of the language.

Re: Rust is now overall faster than C in benchmarks

#162

Earlier quoted context omitted.

> null terminated strings feel like idiomatic C to most people Doesn't that mean that null terminated strings is idiomatic C? That is, my understanding of the term idiomatic is that it is defined by whatever is most natural to users of a language regardless of whether it is the most performant.

Null terminated strings are often called cstrings. They’re beyond idiomatic; they’re part of the C standard library.

True. I was skipping over that, but the fact that functions manipulating null terminated strings are part of the standard library is certainly a reason in itself to consider them idiomatic.

Re: Rust is now overall faster than C in benchmarks

#163

Earlier quoted context omitted.

Mostly agree with your comment but linear search through arrays of size less than a few hundred will typically beat more sophisticated structures such as red-black trees or hashtables. This is due to prefetching and avoidance of unpredictable pointer traversals. Asymptotic complexity is only that: asymptotic. In many programs in many domains the sizes of these data structures will rarely exceed this limit.

It might be fast, but it'll load CPU caches with that data and it'll evict another useful data. Which means that while this particular code will be fast or at least not very slow, some other code will be slow because its data have to be fetched again. I have no idea whether that matters or even easy to measure...

You’re stretching there imho.

L1 and L2 are per core. A cacheline is 64 bytes and per-core cache size is on the order of 32kb and 256kb for L1/L2.

Reading data from L1 is on the order of 1 nanosecond (or less) and RAM on the order of 50 nanoseconds.

If you’re scanning an array and load a dozen cachelines that’s almost certainly preferable to several cache-misses (and lines).

Memory access is very often an application’s bottleneck. The answer is almost always more arrays and fewer pointers.

Re: Rust is now overall faster than C in benchmarks

#164
post #74

Earlier quoted context omitted.

At the same time, a lot of those mechanics involve additional overhead (e.g. vtable lookups for dynamic dispatch per inheritance). But yes, some of these do provide hints for the compiler, e.g. constexpr, ownership semantics per unique_ptr. There's nothing stopping a human from writing equivalent C, so my suspicion is that the performance gap is primarily due to the benchmark implementation.

While nothing prevents you from writing C that will generate the equivalent code, it requires several times more lines of C than the equivalent C++. At which point, it becomes an economics discussion. C is usually a choice when pure performance is secondary to other considerations like portability. Most C++ code I see has few vtables, and what vtables exist are mostly removed by the compiler. Java-style inheritance h…

> Most C++ code I see has few vtables, and what vtables exist are mostly removed by the compiler. Java-style inheritance hierarchies are not idiomatic in C++.

FWIW I feel like this is a fairly recent (good!) development. Up through TR/TR1 I think at least half the C++ code I saw was pretty heavy on the "Java envy" and not at all concerned about the cost of dynamic dispatch or memory allocation. Avoiding vtables was derided as part of "C with classes" - today that usually refers more to templates and exceptions but STL implementations were not mature enough and too much code not exception-safe for those to be universally viable back then. Something I heard more than once was that if you had a destructor it should always be virtual just in case someone wanted to subclass it later.

Re: Rust is now overall faster than C in benchmarks

#165
post #86
post #76

Earlier quoted context omitted.

I recall an anecdote about how Haskell actually outperformed C on various tree benchmarks because it was using a better implementation. At some point, the C programmers got fed up with the airs of superiority from Haskell programmers, ported the Haskell implementation, and reclaimed their position. I wouldn't be surprised if there's something similar happening here.

Yes, it seems everyone is always trying to beat C, but really, no one can.

Well, junior Assembly developers had it pretty easy on 80's hardware.

Also C++ and Fortran don't have to spend much effort to achieve that.

Re: Rust is now overall faster than C in benchmarks

#166
post #125

Earlier quoted context omitted.

How often does benchmark code have a function that takes two pointers that could potentially alias each other? If it's as rare as I think it is, it might not have that much of an impact on Rust's position in the benchmarks game. Still, real world performance will probably benefit from this fix so it's a positive change regardless.

I've been fairly convinced for a while that once Rust matures (which is probably fairly close to "now", but I've held this opinion for years) that it's going to have a performance advantage in real code that's going to be hard to capture in benchmarks, because it's easy in a small benchmark to be very careful and ensure that you don't have aliasing, avoid extra copies, etc. Where I expect Rust to really shine perform…

One big advantage when writing average code is that while Rust emphasizes generics and makes them easy to write, C++ makes it so difficult that you try and avoid it at all costs. Big, complex projects are going to probably use polymorphism all over the place in my experience which is not really captured by benchmarks.

However, one advantage for C and C++ for such projects is that they make it far more pleasant to do bulk allocations. With C, you just need to group your mallocs and cast the memory and C++ offers placement new where you pass in the memory explicitly. With Rust, you need to reach into unsafe Rust (rightfully so), but unsafe Rust is very unpleasant to write.

Re: Rust is now overall faster than C in benchmarks

#167
post #130

When Rust is faster than C in a benchmark in which C++ is also faster than C, I know I can safely ignore such benchmark.

> I know I can safely ignore such benchmark And yet, rather than ignoring it, you are commenting on it, with a pithy retort which dismisses the entire benchmark without actually providing any additional insight. Programming languages, compilers, library ecosystems, the groups of people who decide to sit down and try to produce a better result for a given language, and the benchmark maintainers who decide what submiss…

Don't know why you're downvoted, this is a great comment.

By the way, YARV has been "ruby" since 2007; these benchmarks were run with ruby 3.0.0preview1. The name has probably just never been changed.

Re: Rust is now overall faster than C in benchmarks

#168
post #16

Earlier quoted context omitted.

LLVM's support for this is bugged, so rust does not currently take (edit: full) advantage of it.

Rust does not take full advantage of it; that is, &T will still get noalias, it's &mut T that's currently disabled. The tracking bug is https://github.com/rust-lang/rust/issues/54878

Here is an example which, while trivial, demonstrates some of the optimization issues you can run into in C and C++ but not in Rust, even with noalias currently only applying to &T.

C++: https://godbolt.org/z/dTPsbh Rust: https://rust.godbolt.org/z/Mdx87h

In C and C++, compilers are allowed to infer "noalias" based on pointer types; two pointers of different type are not allowed to alias. This is known as type-based alias analysis. But char * is given special treatment, because of its use as a generic pointer type; so if one of your arguments is char * or even signed char * , that disables any optimizations which were relying on type-based alias analysis.

This provides both for performance and undefined-behavior footguns. If you ever try to use some pointer type other than char * or signed char * to refer to data of another type, you may inadvertently cause type-based alias analysis to kick in, causing invalid optimizations and miscompilation. On the other hand, if you have a function which takes both a char * and another pointer, the compiler may not apply optimizations that it otherwise could because char * is allowed to alias anything.

In Rust, there is no such undefined behavior footgun. Because of the LLVM bug, noalias isn't applied to &mut pointers so there are still some cases which could be better optimized, though it sounds like there is some progress being made on the LLVM front so it should be fixed at some point, and there are already places where the compiler can do better optimizations with better safety due to the stronger semantics of &T.

Re: Rust is now overall faster than C in benchmarks

#169
post #157
post #123

Earlier quoted context omitted.

Not for char. Compiler always assumes non-restrict for char pointers and arrays, which is important to remember if you're ever operating on a RGB or YCbCr matrix or something.

Huh. Does that also hold for a "uint8_t"--which is often just a renamed unsigned char rather than being a genuine type of its own?

Yes
Post reply on HN