The relative performance of C and Rust
dtrace.org
dtrace.org
If c were built with good generics and memory management (not that garbage preprocessor stuff), I expect similarly expressive and good data-structures would be built.
C++ is an affirmation of this because it happens to have good libraries of data-structures which are not really very different from rust's.
I don't think this is as much "rust's design forces the coder to do this" and more "c makes it hard to do as nice of a design"
People can and do get C right, in safety critical systems, at larges scale, all over the world.
By the way, Rust devs are working on a mathematical formalization of those rules. Here's a blog post about a part of this effort: https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html. (There are similar formalization efforts for subsets of C, that led to software like the CompCert verified compiler)
And it would be wrong in differing. Memory and synchronization bugs the kind of Rust prevents are found in the kernel all the time.
The point of the Unsafe Rust is the containment of relative "unsafeness" (that is, however, not equivalent to C/C++'s UB [1]) within a certain boundary. Having less things to audit surely helps.
[1] https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html
That said, of course Rust is not a panacea for memory and synchronization bugs. Rust helps a lot but does not fully solve logical memory leaks and deadlocks for example.
As for a kernel just ending up as a bunch of unsafe, doesn't seem grounded in reality.
https://os.phil-opp.com/minimal-rust-kernel/
> Note that there's an unsafe block around all memory writes. The reason is that the Rust compiler can't prove that the raw pointers we create are valid.
[..]
> I want to emphasize that this is not the way we want to do things in Rust! I
[..]
> So we want to minimize the use of unsafe as much as possible. Rust gives us the ability to do this by creating safe abstractions. For example, we could create a VGA buffer type that encapsulates all unsafety and ensures that it is impossible to do anything wrong from the outside. This way, we would only need minimal amounts of unsafe and can be sure that we don't violate memory safety. We will create such a safe VGA buffer abstraction in the next post.
As is always the response to the "A kernel in rust would be just as unsafe as a kernel in C", the goal is to build safe abstractions.
So you have unsafe, plus some constraints that you enforce at a module level, which wraps the unsafety.
This is not perfect - you'll still write vulnerable unsafe code, I'm sure, sometimes. But the rest of your code can be built on top of it, and now your unsafe code can be the main target of your testing and verification.
We have no real rust kernel the size of Linux to compare to but I think there's plenty of reason to believe that it would have considerably fewer vulnerabilities and would make auditing far simpler.
Kernel devs are of a different opinion than yours.
Hence the Linux Kernel Self Protection Project initiative.
EDIT: corrected as suggested.
https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Pr...
To demonstrate the claim that C and Rust have different idiomatic data structures you need to rewrite software from C to Rust and to Rust from C and see what is hard and what is less hard.
The C stdlib does not come with an AVL tree. Why would one not implement a b-tree in C for this comparison? It’s not as if K&R has “Use binary, not b-trees!” on the front cover.
For example, the benchmark shootout recommends his khash for a hash table.
I don't think anybody will find any consistent performance enhancement in Rust that can not be replicated in C. The problem is how to run it out on real code.
I once did a similar benchmark to the one in the article and found that Rust outperformed C++ because the C++ code was using the builtin std::map. But for reeeeeeally big datasets PostgreSQL beats them both so who cares. :p
A person should understand that no language(programming or otherwise) is perfect. Therefore there is some criticism of any language that is valid. Therefore some criticism should be taken seriously as there may be a real point to the criticism.
There are many posts like this, where there are comparisons of Rust to C. Realistically they are all a little biased towards Rust as Rust is a C++ replacement really. A more proper comparison would be Zig or D as a better C against C.
Just understand that a person defending C is not always an idiot, and maybe they have point. Consider the excessive memory use of any working Rust compiler. That will probably not be remedied anytime soon and is a legitimate complaint. The ideal of how something could be is not how something is. The reality is that C works pretty well most of the time, Rust works well most of the time. They both fail at some things.
You see a lot of people holding up Rust precisely because we've been there for the last 5/10/15/20 years. The day I don't have to write a makefile or build yet another CMakeLists.txt is the day I rejoice.
What Rust offers is another option in the native, non-GC'd language space. A space that has very few languages and even fewer yet that are shipped at scale. Rusts inclusion w/ FF means that the have to address the robustness, security, performance and usability of the language to a degree that you don't commonly see.
Having just blown 4+ hours today dealing with the linker on a mixed C/C++ project I don't really miss a lot of the baggage that comes with native development these days. Rust gives you the option of dropping down to that level while still preserving a set of sane, opinionated defaults that are pretty well thought out.
https://github.com/elrnv/ipopt-rs/blob/master/ipopt-sys/buil...
Others just assume that the libraries are there, but they still require a program to compile them:
https://github.com/cmr/openblas-src/blob/master/build.rs
As long as all of the dependencies are in Rust, things appear nice. At the same time, unless I'm missing something, it seems like crates manages multilanguage projects poorly. Though I have some major gripes with CMake, I've managed multilanguage projects mostly well.
Is there a sane way outside of CMake to manage a multilanguage project with Rust?
When I tried this in build.rs, I had to check modification times myself.
There is an opening for a ninja-type crate in Rust.
If there is no compiler then there is no programming language.
There are videos of nazi bases on the moon.
Yes having a GC is a contender, because not all GCs are implemented the same way, and C did not eliminate Assembly as well.
So if a systems language, with GC, covers 95% of use cases. We can happily use something else for those remaining 5%, while enjoying better productivity and safety.
Companies like Astrobe manage to have enough customers to keep their Oberon compiler for bare metal deployments business alive, just as one possible example.
Ironically, cargo is one of the areas the rust ecosystem falls down completely. Not to mention, there's no ABI...
> What Rust offers is another option in the native, non-GC'd language space.
True, and while this is great in principle for embedded development, not using a GC is overrated.
> Rust gives you the option of dropping down to that level
Well, if you're not dealing with the linker, you're not at "that level"
ATS is far closer and indeed compiles to C. Rust's type system is still less expressive than that of ATS.
http://lmgtfy.com/?q=ats+language
If I remember correctly there were plans to implement GNU Hurd (the Half-Life 3 of kernels) in ATS, but that probably went nowhere. But there is a small osdev community messing with kernels and ATS.
well, which language of C and C++ has the possibility of having traits, structs with function definitions, generics which work through monomorphism, variants, optional, reference-counted pointer and pointer ownership semantics ?
> If you tracked communities so far, you'd see that Rust community is very sensitive on the issue of memory print, performance impact and asm implicitness of Rust.
yeah... like C++ ?
I think they've also figured out that with time C will be squeezed into smaller and smaller areas of use, as is already happening.
Writing robust code hasn't really found a space to live in the mental model of C programmers. Using C outside a kernel or existing C project today is professional negligence.
if you think like this, you will never replace C...
> Using C outside a kernel or existing C project today is professional negligence.
or embedded development lol
Here's a silly prediction: in the next 10 years a significant number of C programmers will retire without replacement. The new generations will rather learn Go, C++ and Rust for low-level stuff and will banish C to pure legacy projects.
Although not politically correct, that is the only way to overcome religious resistance against new technologies.
I see this pattern a lot on HN. Many aren't aware that there are fields alive and well that require the use of unsafe, deterministic C that can compile to programs on the order of kb.
Every body whole who creates a new language would like to see it more and more used thus replacing others.
Just one tiny gripe, don't use a blue and green next to each other in graphs if avoidable. I'm not even blue green colorblind, and I found them hard to distinguish.
Thanks for the great read.
My father can see the two colours just fine, but if they're adjacent to each other and about the same kind of tone, they start to blur into grey.
One particular example I remember growing up. He hated the board game "Game of Life" because there's all these greens (ground) and blues (rivers, lakes, ocean etc) right next to each other all over the board. It was not a pleasant experience to be looking at it.
All this said, you may be correct that there's no such thing as blue-green color-blind, and maybe that's not the best word to describe what I'm trying to say.
Those colors appear quite distinct on my monitor. Others sometimes don't
I'm not sure that comparing "Rust" and "C" performance is even meaningful. The latter is a multi-implementation language, and in most implementations, can be written in a way that gets the compiler to generate the same machine code that the Rust compiler does. (Frequently, they both just go through LLVM.)
when comparing languages you need to include a measure of how idiomatic your programs are.
Of course it is entirely subjective (the author argues for how that is due to a static vs dynamic ownership model) and there is a single data point, which is the author rewriting the code. (two is you consider when he/she swaps one of the data structure)
Then it's not a performance benchmark, it's a style and usability benchmark.
On instance of this becoming a complication would be in the GTK+ world with the Rust bindings to GObject. There's some really good articles about their adventures in that realm you could find.
Meanwhile Rust, in this user's opinion, offers a superior toolset for modeling data and building behavior, namely: sum types and traits.
So if you're looking to extend or integrate with a C codebase, barring some exotic target platform and all else equal, I don't know why you'd opt for C++ over Rust.
where "as much work" means putting `extern "C"` in front of your functions and having a few `static_assert(is_pod_v<type_that_i_pass_in_argument_to_my_c_api>)` or only using opaque typedefs, ie it frankly amounts to nothing
If you are writing C++ in such a way that this does not matter, then you are basically writing C already and `extern C` is all you have to do though, but then you might as well just have been using C this whole time.
But when your API uses templates/generics and other types that C can't comprehend, you need to write additional wrapper functions operating behind opaque C types. It's not rocket science, and tooling/macros can help a lot, but it's still tedious and error prone (you're erasing types, redoing error handling, adding manual memory management, etc.).
OTOH interfacing with C++ is very hard. D might be the only language that has seriously tried it, but from Rust's perspective C++ has largely overlapping, but incompatible set of features, and it's a weird dead-end.
It's one of the few high-quality technical articles that pass through HN... if you don't get hung up on the title.
Normally, "read the article" is a bit not-HN-friendly, but when you call someone out as disingenuous because they didn't say things that they in fact do clearly call out and have a multi-paragraph discussion of, you are earning a "please read the article" response. They're not being disingenuous about what they are doing if they clearly explain what that is and then have a (IMHO) balanced pro-and-con discussion about it.
That comment appears to be downvoted, and in addition the winking emoticon at the end suggests that it was meant to be tongue-in-cheek in any case.
A point of fact is that the two data structures are different. There was even an article on the front page today about how minor changes to data structures can dramatically impact performance.
Anyway, my main point is that there should be a space to discuss the relative merits and issues of languages without it resorting to petty fighting, which even you and the OP and the other commenter are engaging in.
Please everyone try to use the principle of charity when reading a post on this site. There is a good chance the person you are responding to has a reasonable background and isn't totally ignorant. Instead of playing on pedantry, try to understand where they are coming from and understand a one-off post on an internet forum is not the strongest argument they could make.
Can I ask where this impression came from? The original, now-downvoted comment that started this thread wasn't criticizing Rust, it was criticizing the article. If people disagree with that person's criticism of the article (which is itself not a criticism of C, and acknowledges as much), I'm afraid I don't see how that contributes to any perception that people are unjustifiably leaping to defend Rust.
Are you serious now? I mean you are very active Rust activist on both HN and Reddit and you exactly know what Rust Evangelic Strike Force is and where it came from. I've seen multiple threads on HN and Reddit where people do exactly what OP wrote. I don't know if it's denial or ignorance on your side or you are writing this with premeditation.
As to whether my above question is serious, the answer is yes, because truth be told I see more people complaining about Rust Evangelism than I see instances of evangelism in the first place, to the extent that I wonder if that itself has become a meme by now.
I've never wrote anywhere that you encourage that kind of behavior. There is a difference between encouraging and pretending that problem do not exist. Seems that you are just biased and what you are doing here is white washing a community you are part of.
> If you have links to instances of people doing exactly as OP wrote, please paste them here;
I would rather spend time with my family than searching whole HN and Reddit for obvious things that were mentioned here multiple times by multiple people but I've found couple of links fast (not for you, but for other readers) [1][2]. And this are only two examples that I've found fast. Those are examples of things that you surely have read and aware of. Another example is some Animats posts in some C++/Rust debate thread on HN in which he was describing his experience and technical details while criticizing Rust and was downvoted to hell.
Here you have another person writing same thing and dbaupp acknowledging that the problem exist [3].
This comments didn't come from vacuum and denying that problem exist will only make it worse.
[1] https://www.reddit.com/r/programming/comments/5fyhjb/golangs...
Now, I'm having problems understand what that Rust Evangelic Strike Force is, and what nefarious goals it could have. Do you have a pointer? (Also, is it a funny group?)
So, to restate the question clearly and unambiguously, what prior to kibwen's question lends someone to think this is a matter of Rust evangelists taking issue, and not the somewhat common HN interaction of someone calling out someone else for, in their eyes, misinterpreting or ignoring and aspect something and then denigrating it for that lack?
Your statement that they simply are "chalking this up to language differences" is false. It's not surprising that you received a negative reaction.
Although, not entirely, as I'm sure you would agree we can't claim that different data structure is the only reason that the rust program was fast.
Another reason is that the author seems to have put a lot more engineering into the Rust program than the C program. Most of the word-count of the article is devoted to extra engineering on the Rust program! (The whole thing about sorting out lumps, etc). It's reasonable to infer that this also mirrors the situation prior to the first benchmark. If you put more effort into optimizing one program than another, you'd expect the higher-effort program to be faster, all else being equal.
It's embarrassing that HN thinks this article is worth posting. There might be something to write about here, somewhere, but it would have to be framed in a very different way in order to be honest. Also, it would be a much shorter article.
The technical aspects of the article are interesting and well written, but only if it is not viewed as an exercise in rigorous benchmarking.
The context here was that the Rust program was a reimplementation of an existing C program, as part of an effort to learn Rust.
The Rust program was not a faithful reimplementation as the author concedes. I expected a more closer comparison given the somewhat broad title of the article. Claiming the perf benefit came out of the thinking encouraged by the language is okay but debatable.
Because I had written my Rust naively (and my C carefully), my hope was that the Rust would be no more than 20% slower — but I was braced for pretty much anything. ... my naive Rust was ~32% faster than my carefully implemented C.
How about — Why Rust BTreeMaps beat C AVL Trees ?
I don't know if that would be an adequate title, but it doesn't claim that different data structure is the only reason and it doesn't generalize to a claim about C and Rust.
That didn't happen. The data structure difference is discussed and the possibility of the performance difference being down to this is clearly acknowledged. Also discussed is the reason for the different data structures, which is actually the most important take-away.
I agree; this would have been a great stand-alone piece had it focused on this instead of performance.
I can't speak for the author but at my work we found -O2 to give better results on our OpenGL ES rendering engine.
cargo build —release —verbose would tell you for sure; I’m not at a computer right now.
1. Storing an array and its length together and always checking it correctly such that you don't have a buffer overrun.
2. Freeing memory, not leaking memory.
3. Using a union correctly, e.g. always accessing the right variant.
4. Printing unicode characters.
5. Macros which dont' conflict with their scope (are hygenic)
All of those problems seem like they should be easy, are incredibly easy in rust, and are not fully solved problems in C.
I don't think rust makes easy problems harder just because its type-system and macro system and such are all so good compared to C.
It turns out having proper sum types instead of C's garbage unions, and having proper string support, and so on make easy problems easy too!
As I've said before, the two places where Rust has problems with expressive power are backlinks and partially initialized arrays. Those are routine cases which are forced to unsafe code.
Partially initialized arrays are a solved problem- anything more would just be baking `Vec` into the language.
And backlinks are nowhere near "routine."
The issue is a direct consequence of Rust's strict aliasing rules, which I feel any programmer would benefit from groking.
I guess many C programmers might be used to reimplementing data structures for their programs, but I don't think it's useful in a majority of cases
1. Rust's standard library is large and contains data structures. People are good at centralizing on one thing if it's the standard one, if there are 10 competing string libraries, people might say "ah well, let's write our own". That also sometime means using one dependency will pull in others (e.g. in C you might want someone's regex library, but it might be incompatible with your string library because it uses a different one. A stdlib helps ensure libraries have a standard set of types to talk about, and C barely has that).
2. Rust's package manager (cargo) and registry (crates.io) are really good and making finding and adding dependencies much easier. If I want to add a random library on github to my rust project, it's 1 line in my Cargo.toml (whether it's on crates or not). In C, I have to figure out if they're using cmake, meson, autotools, or any of a dozen other things, and possibly vendor the code into a third_party folder, and possible spend several hours hacking on my build system to link against it.
3. Rust's community has made an effort to standardize on certain crates and include their use. See the rustlang nursery. The closest to this in C is stuff like the gnulib I think, which is an ancient effort pushing garbage code that suffers from the lack of good dependency management severely. I know of no recent similar efforts for C.
4. Rust has generics and a better type system in general which makes it much easier to implement generally usable libraries.
It's important to remember that C also predates the internet, and many c codebases also predate modern package management. Legacy practices have a habit of propagating themselves.
If you're worried about the slightly more memory that uses, you can use `Option<NonZeroUsize>` and subtract 1 for all indexing operations.
https://github.com/attractivechaos/klib/blob/master/kbtree.h
In other words, what you took away from the article might not have been what other people did, or what the author meant to express. It surely wasn't what I thought was important (but neither was "rust is faster/slower than C").
https://old.reddit.com/r/programming/comments/9jsqb3/the_rel...
A silly idea I had, wonder if it would be possibly to auto-adjust the B factor of a BTree (the number of nodes) at runtime based the cache line size.
There are a lot of good books from these eras, and there are a lot of good books that teach with the uniform memory model. Most algorithms classes don't talk about the hierarchy at all (even though it distorts the true asymptotic runtime of many algorithms).
The point really is that Rust foists better design choices on the programmer.
Isn't rust based on LLVM?
It would make more sense, for a true apples to apples comparison, to use clang instead of GCC.
Not that I'm pro-C or anti-rust or anything but the beginning of the article goes on about previous tests not being fair.
At the end the author never states that one is faster (yes, the title is misleading, but it is then clearly clarified in the text) the main part is the discussion about intrusive data structures.