9 ms·
Rust is already very close to C and C++ performance, and getting to equivalence or possibly better will mean a long slog through these kinds of edge cases. This
by api 6y ago
Rust is already very close to C and C++ performance, and getting to equivalence or possibly better will mean a long slog through these kinds of edge cases. This was already done in C and C++ compiler toolchains, which is why these languages are so fast, and it's a bit of a feedback loop because their popularity and centrality to systems development is what led to the work being done in the first place.
Rust + LLVM will already handily beat a naive bare bones C or C++ compiler that isn't loaded with sophisticated optimization tricks.
If the work is done I expect Rust to be faster than C and C++ for the same reason that C++ can sometimes be faster than C: a more advanced type system can allow better optimization in many cases.
In C++ for example you can do algorithms with templates, while in C you generally end up with function pointers all over the place. See qsort() vs. std::sort<> for one common case.
With Rust you can do all this generic stuff plus leverage better safety to do more strict aliasing optimizations, less unnecessary memory fencing, and so on.
- killercup 6y ago> If the work is done I expect Rust to be faster than C and C++ for the same reason that C++ can sometimes be faster than C: a more advanced type system can allow better optimization in many cases. Every now and then I check in on whether LLVM can deal with rustc spamming "noalias" on all references. You can find the latest change in [1]. While in theory this unlocks _a ton_ of optimizations, noalias is used very rarely in C/C++ code so these compiler passes are not exercised a lot by existing LLVM tests and/or not realized in full. [1] https://github.com/rust-lang/rust/pull/82834 https://github.com/rust-lang/rust/pull/82834
- api 6y agoThis is why I think Rust could eventually be faster than C and C++ for a lot of things. The work has to be done though. You're right that noalias enabled optimizations are neglected because you can rarely use them in C code. On the Rust side I think the language needs some way to annotate if's as likely/unlikely. This doesn't matter in most cases but can occasionally matter a lot in tight high performance code. It can allow the compiler to emit code that is structured so as to cause the branch predictor to usually be right, which can have a large impact.
- steveklabnik 6y agoThat's tracked by https://github.com/rust-lang/rust/issues/26179 https://github.com/rust-lang/rust/issues/26179 by the way.
- drran 6y agoWhy not just use PGO (Profile Guided Optimizations)? Sadly, PGO does not work with cross-language LTO, because of conflict of LLVM module name ('Profile').
- deleted 6y ago[deleted]
- amelius 6y agoA more advanced type system may also drive you into a corner where you make bad decisions wrt performance.
- titzer 6y agoCan you give an example?
- Arnavion 6y agoNot amelius, but one case that happened to me is that Rust requires wrapping a `T` in a `RefCell` if two closures use it as `&mut T`. This happens even if you the caller know that the closures are invoked from a single thread and do not invoke each other, and thus only one `&mut T` will be in effect at any time. This is because closures are effectively structs with the captures as fields, so both struct values (and thus both `&mut` borrows) exist at the same time even though their respective fields are not used at the same time. Not only do you have to use `RefCell`, but you now also have panicking code when the `RefCell` borrow "fails", even though you know it can't. rustc is also not smart enough to notice the exclusivity at compile-time and elid away the RefCell borrow flag test and the panic branch. fn foo(mut cb1: impl FnMut(), mut cb2: impl FnMut()) { for _ in 0..10 { cb1(); cb2(); } } let mut x = String::new(); foo(|| x.push_str("cb1,"), || x.push_str("cb2,")); https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9b3aaad390070ffa3dcd0420203a0833 https://play.rust-lang.org/?version=stable&mode=debug&editio... Fixed using `RefCell`: https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=b1d8781fc5d5962a40c485b3b148ff2d https://play.rust-lang.org/?version=stable&mode=release&edit... . Inspect the ASM and trace the use of the string constant "already borrowed"; you'll see it being used for the borrow flag test because it wasn't elided. The equivalent non-Rust program could use String pointers for the two closures. I'm not sure whether they could be noalias or not, but at the very least they wouldn't need to generate any panicking code.
- Diggsey 6y agoThe "used from a single thread" aspect is a red herring: RefCell can only be used from a single thread anyway, and the compiler enforces this statically. The "state" value in a RefCell is overhead, although it's fairly minor given that it doesn't need any synchronization to access. The extra panic branches are probably the largest overhead. That said, these overheads stem from Rust's safety guarantees rather than its strong type system: you can have a language with a strong type system that does not do these checks. Furthermore, there are of course ways to avoid this overhead within safe Rust: if you can use the type system to prove that the cell cannot be borrowed at the same time, then you don't need to do the checks, and in that sense a strong type system can actually help avoid overheads that were introduced by being a safe language.
- MaxBarraclough 6y agoI think Ada/GNAT performs roughly on par with C and C++, so we have reason to be optimistic. It's not just the dominant languages that end up with mature optimizing compilers.
- pjmlp 6y agoHaving been there when C compilers used to generate lousy code and we had legends like Mike Abrash teaching an whole industry how to write high performance Assembly, it always feels ironic that there is this myth about C and C++ being blazing fast since they were created.
- mids_hn 6y agoC was fast. On a PDP-11.
- anthk 6y agoC++ was always taken as big, bloated and unusable compared to C.
- pjmlp 6y agoOnly by C developers that still believe C generates faster code than C++, while their beloved C compiler has been rewritten in C++.
- anthk 6y agogcc is not my daily compiler.
- pjmlp 6y agoI found another tinyc user.
- bcrl 6y agoThat's not what I believe. C generates the code I expect, rather than the insanely bloated crap that comes out of C++. C++ obfuscates what is actually going on. Oh, and then there are all the problems with the C++ standard library. It's unusable in high performance embedded style code due to many aspects of the standard library being unconstrained - things like memory allocations and unspecified complexity. In some cases we were able to use boost, but in many cases we had to reimplement many algorithms where the implementation performed allocations at init time, and no allocs at runtime. But oh how does an event driven, multithreaded and hot running messaging system go fast...
- gnulinux 6y agoI write compilers for fun (hobby) and I just transpile my IR data structure to C++ (I'm also experimenting with other targets like Haskell (similar to agda compiler) and Rust (work in progress)). My friends usually treat this approach "too amateur" and a "real language" should compile all the way to assembly. The reason I don't do that is if you transpile to a well-known language and then manage that compiler to go all the way to machine code, you get insane amount of optimizations for free. Like C++ compilers are so good, you rarely need think about low-level optimizations, as long as your program is asymptotically sound (i.e. you don't keep random inserting into an array) it gives pretty good performance regardless.
- Flow 6y agoBut then you miss all the fun with doing a nanopass compiler. Maybe that's not entirely true though, you can still generate C/C++ in the end I guess.
- zokier 6y agoNim compiler also generates C, so I'd say you are in pretty good company there.
- Blikkentrekker 6y agoThe Idris 2 compiler compiles to Chez Scheme; the Idris 1 compiler compiled to C, and the former actually produces significantly faster executables than the latter. I sometimes see programmers have very strange, irrational purity misgivings a particular case was someone who did not wish to fork off `grep` for some task, but actually wrote his own implementation which broke input into lines and used and manually searched for substrings; — he was initially convinced that this would be faster, or was at least “cleaner” than simply forking off `grep`, and piping to it. The reality is that modern `grep` implementations are so optimized that writing something that was as efficient would probably exceed the complexity of his entire project. I have never understood why many programmers seem to have an irrational dislike against forking off POSIX utilities when they target such platforms, and piping through them, which are often far more optimized than anything they've ever written.
- mhh__ 6y agoI'm a little suspect of the "Language x is faster than language y" talk - it seems too prone to programmer culture to test scientifically, beyond being able to prove that you can or can't end up with the same machine code from multiple languages.
- Sohcahtoa82 6y agoAnd you can almost always write a program that executes faster in a "slower" language than a "faster" one.
- nwallin 6y ago> Rust + LLVM will already handily beat a naive bare bones C or C++ compiler that isn't loaded with sophisticated optimization tricks. Well - sure. LLVM is loaded with sophisticated optimization tricks. If one compiler does sophisticated optimization tricks and the other compiler doesn't do sophisticated optimization tricks, the compiler with the sophisticated optimization tricks will be faster. Tangent: Ten years ago or so, LLVM/Clang was touted as being head and shoulders better than GCC, the big new thing, the bees knees. Some of how it was better was obvious to everyone- readable error messages are pretty awesome. (GCC stole that idea pretty quickly) But the big thing that the LLVM/Clang people talked about was how blazingly fast compilation was compared to GCC. It was normal to take 1/10th as long to compile something. The code didn't run as fast as the code generated by GCC, maybe 50% of the performance, but that was a problem that they would eventually fix with more sophisticated optimizers. But compilation was fast! Here we are ten years later, and LLVM/Clang generates code that runs almost as quickly as GCC. What did it cost, besides ten years of incrementally making the optimizer more and more sophisticated, a little bit better one little bit at a time? Well, it takes just as long to compile something with LLVM's sophisticated optimizer as it does to compile something with GCC's sophisticated optimizer. The point is, there's a lot of yak shaving that will have to go into making Rust+LLVM work together better. And LLVM is already well acquainted with the barber. The low hanging fruit you're looking for has already been plucked.
- throwaway894345 6y agoIt’s been a a bit since I was a C++ developer, but didn’t LLVM spur GCC on to improve significantly? Maybe LLVM and GCC are pretty comparable today with respect to build time and performance, but I think the more interesting question is how LLVM compares to GCC ten years ago (or more precisely, where GCC would be today were it not for competition from LLVM). Personally I’m glad there are multiple options, and people seem to prefer using LLVM for a language backend more than GCC for whatever reason, so it seems like a significant contribution to our digital society.
- nwallin 6y agoHard to say. In some places it's clear: LLVM's error messages were head and shoulders better than GCC's, and it was immediately obvious to everyone that GCC had to improve. And they're much better now. But I don't believe GCC has made substantial improvements to its compilation speed since LLVM was introduced. In fact I believe it to be the opposite; as a Gentoo user I generally notice that compilation performance gets worse with every major GCC update. It's only due to hardware upgrades that compilation gets shorter. LLVM is inherently much more modular than GCC is, which makes it a very attractive target for a language backend. It's a very large amount of work to shoehorn a language into GCC. The modular nature of LLVM is quite useful for lots of purposes, it is the back end for the syntax highlighting and error highlighting module I use in emacs. clang-format is a godsend for me, and unlike most other autoformatters, it formats based on semantics instead of syntax, which is a huge boon. The static analyzer and llvm-mca are also closely tied to the modularity of LLVM. It's not immediately obvious how one might implement these features based on GCC. So yes, I 100% agree that LLVM is a hugely beneficial contribution to our digital society, even though it's not my first choice for a compiler.