4 ms·
C++ is better for performance because it’s old and tremendous effort has been put into optimizing it. Rust is a very young language. It benefits from the clang
by api 5y ago
C++ is better for performance because it’s old and tremendous effort has been put into optimizing it. Rust is a very young language. It benefits from the clang tool chain and gets some of that optimization for free, but there is a lot of room to make Rust faster.
Unlike GC’d or dynamic languages, there is nothing intrinsic about Rust that makes it a fundamentally harder language to optimize. It’s really like a modern provably safe C++.
It also depends on how you code. If you make heavy use of functional constructs and complex types your Rust code will probably not end up being optimized as well. For tight algorithms it’s good to write “thin” Rust. The exact same is true for C++. You would not want to use a lot of STL or functional stuff in a rendering pipeline core. High performance C++ looks like C.
- gpderetta 5y agoWhich optimizations is the rust compiler missing? A lot of the optimizations required for fast code, like manual layout of custom datastructures are done by the programmers, not by the compiler. I don't doubt that rust can also express this optimizations given the similar low level control provided by the language, but what the OP and the parent are saying is that some of these are not idiomatic in rust and harder or impossible to express in the safe subset of the language. > You would not want to use a lot of STL or functional stuff in a rendering pipeline core. High performance C++ looks like C. FWIW that's not at all my experience.
- BenFrantzDale 5y agoAgreed. My favorite example of C++ vs C performance is C++’s `std::sort` which is intrinsically faster than anything similar in C because C lacks the language features (templates) to support performant code reuse like that.
- volta83 5y agoTBH, while I can think of many layout optimizations that Rust does and C does not, I can't think of any that C or C++ do that Rust does not. In particular when it comes to unions which are heavily used in low-level code, Rust does optimizations that C and C++ can't even dream of (like all the niche optimizations).
- gpderetta 5y agowhich optimizations on unions does rust do?
- volta83 5y agoIn C++, you have `std::optional<T>`. That's a type that either contains a `T` or contains nothing. In C++, sizeof(optional<T>) > sizeof(T) because the discriminat has to be stored somewhere. This is true even if, e.g., you do something like `optional<T&>`. You know that T& is a non-null pointer, and you only have two variants, and one of the variants has no state, so you technically can encode this as 0x0 is the "no reference" variant, and the != 0x0 is the reference variant, and have `optional<T&>` have the same size as `T&`. Rust does these layout optimizations of compressing the discriminant into gaps in the values of discriminated unions automatically. So: enum Option<T> { Some(T), None } for `Option<T&>` has the same size as `T&` in Rust, as opposed to C++. In C, an example would be: struct DU { enum { A, B } discriminant; union { bool A; bool B; } }; You could encode that into 3 bits (i.e. have sizeof(DU) == 1), but instead you'll have at least sizeof(DU) == 2, because you need one byte for the discriminant, and one byte for the payload. It is very easy to create values with gaps in Rust, but C doesn't really support doing this. Another optimization are alignment optimizations. In C, if you write: struct S { uint8_t a; uint32_t b; uint8_t c; }; that ends up being 12 bytes long. In Rust, by default, that gets reordered as uint32_t, uint8_t, uint8_t, so it only ends up being 8 bytes. If you want that instead to be laid out like in C, you can write: #[repr(C)] struct S { a: u8, b: u32, c: u8 } and then you get the same 12 bytes as in C. There are many supported `repr(...)` options supported for algebraic data types, e.g., you can use repr(u32) for the Rust enum above to store the discriminant in a u32, and get the same layout as DU in C.
- gpderetta 5y agoRight, c++ has no builtin discriminated union, and std::optional<T&> is actually not valid in C++ (unfortunately). But discriminant-less custom optionals classes with 'zero' type support via traits are easy to do (and I have done it many times). You do not have to rely on the compiler identifying a safe empty state and you can define any application specific one. For example if for one specific (and common) use case strings are always non null, optional<string, non_null_trait> has an obvious implementation. So, yes, these sorts of optimizations are not done by the compiler has it has no notion of discriminated types (one day maybe...), but can be done generically by the programmer. In fact you could in principle optimize multiple layers of variant<optional<...>,... > and collapse everything in one discriminant,as long as you do not provide reference access to the sub variants; the required metaprogram is not going to be pretty though. One of the advantages of C++ is that it allows this sort of control.
- osigurdson 5y agoRust uses LLVM so optimizations occur at the AST level. Therefore it should be able to take advantage of the same optimizations as Clang C++ which uses the same approach.
- steveklabnik 5y agoThey happen at a lower level than an AST, but you're right that any front end can in theory generate the same IR and therefore get the same optimizations. The trick is if the language semantics allow for it; this bites both ways.
- nuerow 5y ago> Rust is a very young language. It benefits from the clang tool chain and gets some of that optimization for free, but there is a lot of room to make Rust faster. I feel that this sort of belief relies too heavily on a presumption that performance is somehow proportional to the age of a programming language, and in the process ignores the fact that a) it's already using a highly optimized toolchain that benefits from decades of research and development, and b) there is absolutely no suggestion that any potential performance gains are relevant or exclusive to the Rust's front-end.
- api 5y agoThere is always a long tail of optimizations and tweaks that must be done to get a language that last 5% of the way to parity with a language like C. Building on LLVM gets them 95% of the way. BTW Rust has some features that make optimization a lot easier, like the ability to assume strict aliasing in more cases. It’s safety features also make it easier to write zero copy, copy on write, and other optimization patterns without making mistakes. This enables some bold performance optimizations at the code level that would require serious bravery in C. Long term I expect that Rust will be faster in some cases.