Okay hear me out, please don't wipe me off the face of this subreddit because I mentioned C/C++.
I've had this question for a long while, and asked about it too, but I've never gotten any concrete answers.
I've been told such things as:
-
LLVM is great at optimizing, which generates better assembly, but I don't quite understand this answer, because clang uses LLVM. Hell, I've used LLVM to write JIT, and can't see how it means much here, as I was under the impression that most of this performance would have come from language level compiler optimizations etc.
-
Rust has stricter rules, which opens up better optimization opportunities. I also struggle to think of where this would make any real difference from C/C++, i.e.: Using const where applicable, not making allocations constantly, reusing allocated memory, etc. Though, keep in mind that I am a rust noob, and my four braincells may have missed something incredibly obvious.
-
Rust does a lot of stuff statically - at compile time, which improves runtime performance. What does C/C++ do differently here that costs its runtime performance?
-
Many open source libraries written in Rust are much faster than their counterparts in other languages. This is really great, but I haven't come up upon a proper line-for-line re-implementation of a C/C++ library in Rust that holds true (Not that it is untrue, just that I have not seen any libraries that fulfill such premises). Yes, many of these Rust implementations change a lot to optimize their code to run faster, but then its not exactly a fair comparison at a language level, right?
Compounded on top of these things, I fail to understand how the runtime checks that Rust can introduce would be able to keep it on top of C/C++ in performance. Again, please tell me if my brain lacks wrinkles here.
Time and time again, I get handed benchmarks which clarify that, yes, Rust is faster. However, these benchmarks often vary wildly, from slightly slower than C/C++, to significantly faster. I am aware that these variations are caused by differing compiler arguments that do different things, as well as algorithmic differences, but I can't help but feel like these differences also lead to inaccurate data. Furthermore, they still don't tell me why Rust is faster.
Please don't misunderstand this post as a C/C++ zealot poking trouble, I'm really not trying to, I merely want to gain a better understanding of how Rust is fundamentally better in performance. I know Rust has some fantastic features that make it an ideal selection for modern programming, borrow checking, runtime safety, you name it.
If you've gotten this far, all I ask is that you (the reader) understand where I'm coming from here. I know some people can get quite heated around these things, and I've seen it happen, so please, don't inundate me with messages on why I'm an idiot (which may be true, but not for the reasons these people often attribute it to :P). I look forward to your hearing your words.
- C. D.
Rust is not generally faster than C or C++. For most tasks, well-optimized Rust code can match the performance of well-optimized C or C++ code. And the reverse is true: Well-optimized C or C++ code can match the performance of well-optimized Rust code.
There are a few ways that Rust can improve on the performance of some C/C++ programs:
-
Rust makes it much easier to write correct parallel code. For problems that benefit from parallelism, it can be easier to write a fast program in Rust than in C or C++. Achieving the same performance in C/C++ is still possible, just more difficult.
-
Idiomatic Rust code provides more information to the optimizer about pointer aliasing, which theoretically can enable better optimizations (in particular, better auto-vectorization). However, LLVM does not yet take full advantage of this, so this doesn't provide much benefit today. It could make certain Rust programs faster in the future, though.
It's... complicated.
There's a lot of subtle nuances, each giving a chance to the optimizer to work better for Rust or C++, so it really depends whether the optimizer manages to seize the opportunities, and depending on which it seizes it may advantage one language or another.
Also, beyond the optimizer, there's also code. Rust generally provides more stringent guarantees, which the developer may take advantage of, whereas in C++ this would be dangerous, or outright wrong.
Aggressive use of references
As you pointed out, Rust applications can be structured quite differently from C++ applications, and that's not apples-to-oranges then... or is it?
Unless the goal of a C++ application is pure performance -- and even then -- there is generally a fair amount of defensive programming in C++: the language does not provide many guarantees, leaving ample opportunities to shoot yourself in the foot. After debugging that n-th data-race, or that n-th use-after-free, a developer will decide that enough is enough, and that there's no point going fast if doing so result in incorrect results, and just introduce a little overhead to make an API safer. This results in greater quality, easier maintenance, ... and all it cost was performance.
In Rust, there's much less tension between correctness and performance. The compiler will happily point out any instance of data-race or use-after-free, no worries.
And as a result, Rust software that vies for high-performance will aggressively lean on the compiler:
-
No defensive copies, just use a
&T! -
No lock, just use a
&mut T!
While technically possible in C or C++, in practice such widespread use would result in too many human errors -- so you don't see it.
Destructive moves
I just spotted a SO question yesterday (since deleted), which linked to https://godbolt.org/z/rbsnYrxK8 . Observe how lean the generated assembly is for Rust, and how dreadful it is for C++!
Destructive, bitwise, moves are a godsend for both developers and optimizers:
-
Developer: moves are guaranteed noexcept, move of arrays can be accomplished with a single
memcpy,reallocworks! This makes writing collections so much easier. Lean written code: less for the optimizer to go through. -
Optimizer:
memcpyis often a built-in! The compiler understand exactly what's going on, much more easily at least that with the bizarre pointer manipulations going on in self-referentialstd::string(SSO).
The end result is that Vec, String, etc... are much leaner in Rust than in C++, and, well, you can see the effects in the above link.
Aliasing & Immutability
C++ has little concept of aliasing or immutability. In many instances, const is just a fancy declaration of intention which can just be cast away.
In Rust, however, there's a guarantee that the content pointed to by &T will not be modified under you feet. Or conversely, that nobody else can access the content pointed to by &mut T.
This allows some optimizations, though perhaps less in "business logic" code (many branches, scattered reads/writes) than in "scientific" code (matrixes, large arrays, etc...).
Bounds Checking & Unsafe
Bounds checking does, indeed, add some potential overhead... but a correct application is bounds checked, regardless of the language, and defensive coding will introduce bounds checks even if the language/library does not enforce it.
The effect of bounds checking is also highly dependent on code pattern. A single access is unlikely to have any effect; where bounds checking really is problematic is when it hampers optimizations -- such as loop vectorization, hoisting, etc... -- and if that happens there's always the unsafe hatch in Rust.
And that unsafe hatch matters in general, because any overhead that Rust safety may add can be avoided by using unsafe in the cases where it really matters -- that one hot loop.
As a result:
-
Rust offers high-performance because it's safe by default.
-
Rust safety checks can be disabled when they cost performance.
It's all upsides.
Fastest programming language: C++ vs Rust vs Zig | Dave Plummer and Lex Fridman - Media - Ziggit
A good performance comparision C and Rust
Rust vs. C vs. Go runtime speed comparison
Can C outperform Rust in real-world performance?
Which is better for performance: Rust or C++?
Is Rust or C++ better for startups?
Can I migrate from Rust to C++ easily?
Videos
Hi, a random question popped into my head about something I read a long time ago.
I remember reading that in some benchmarks C was a bit faster than Rust, not by much, but still “faster.” I don't remember many details of the benchmark, but I'm curious because I'm building a project in Rust where performance is absolutely critical.
Is C actually faster than Rust in some cases? Does using unsafe Rust remove that difference? Or is the performance gap irrelevant in most real-world cases?
Thanks in advance.