Edit: It's also not Rust per se, but the numbers at https://github.com/google/puffs/blob/master/doc/benchmarks.m... shows that, on Puffs' benchmarks, gcc 7.2 noticably outperforms clang/llvm 5.0. I'm sure this is a solvable problem, and not a fundamental flaw with llvm, but fixing that's beyond my llvm knowledge.
> Some of the safe languages (Go, Java, JavaScript, Python, Rust, etc.) are faster than others, but generally speaking, they're not as fast as C/C++. Consider an array indexing expression like "a[i]".
I don't think you'll win any friends in the Rust camp by making broad statements like that. Performance of "unsafe" vs "safe" languages largely boils down to memory access patterns, cache usage and how many levels of indirection you tend to hit. Rust easily matches C/C++ while keeping high level abstractions(bounds checks are done at slice level and not per-element access).
I don't think Mozilla would have used Rust for Servo/Quantum if it was slower than C++. It's certainly held true in all the cases I've used Rust in place of C++.
First, as I said in another comment, Rust is great tech, written by great engineers. Puffs is still different (with different trade-offs).
And, yes, memory access patterns, cache usage, etc. affect performance.
And, yes, in general, Rust performs comparably to C/C++. As I noted elsewhere, Rust with runtime arithmetic overflow checks currently performs worse than Rust without such checks. So, yes, Rust without those checks is as fast as C, and in general, arithmetic overflow isn't the biggest concern.
steveklabnik, a Rust expert, commented on this page that, in the future, "if the runtime checks get cheap enough, we can do them in release mode as well". If so, that's great, I'm happy to be proven wrong. Cheap still isn't zero, though, and see "nanoseconds become milliseconds" at https://groups.google.com/forum/#!topic/puffslang/2z61mNTAMn...
In contrast, Puffs today performs as fast as C, with arithmetic overflow checks. They just happen to be compile time checks. And sometimes overflow is indeed a concern (search for "underflow" in https://blog.chromium.org/2012/05/tale-of-two-pwnies-part-1....).
I'm sorry, but I don't understand what you mean by bounds checks being done at the slice level and not per-element access. A statement like "pixels[y * stride + x] = etc" is per-element, right?
> I'm sorry, but I don't understand what you mean by bounds checks being done at the slice level and not per-element access. A statement like "pixels[y * stride + x] = etc" is per-element, right?
Yes, if you index a slice you have to check each access. However the idiomatic way to work with strides of data in Rust is to use Iterators.
Bounds is checked at the entry of an iteration and the the inner loop is nice and fast. So your example would be:
for pixel in &mut pixels[0..y*stride+x] {
*pixel = etc
}
I tried to do something similar on the playground[1] but it turns out Rust/LLVM is too smart and folded the whole loop down to a constant.
> In contrast, Puffs today performs as fast as C, with arithmetic overflow checks. They just happen to be compile time checks.
I'll grant that's largely true, but as far as I can see it's not entirely true. For example, to quote a comment from one of the example .puffs files:
// Set history_index (modulo 0x8000) to the length of this
// remainder. The &0x7FFF is redundant, but proves to the
// compiler that the conversion to u32 will not overflow.
In this case, the redundant operation is equivalent to a disabled arithmetic overflow check, although it's (commendably) made more explicit.
Similarly, in decode_lzw.puffs, I think (could be wrong) that some of the conditions in 'if' statements, e.g. "(width < 12)", should always be true unless the image is malformed. In a way, this is substituting for a runtime array bounds check and/or overflow check that might be hit if the condition weren't present. Here too, Puffs arguably wins by making the check explicit. If I'm right that the author stuffed in extra conditions where demanded by the compiler, rather than properly considering the consequences of their being false (e.g. should probably result in returning an error), then there's some argument that it would be better to crash than silently misbehave. But even then, at least Puffs makes the problem relatively obvious, whereas in e.g. Rust you just have to trust that your code won't perform any overflows.
Integer overflow is a huge concern in C, but much less of one in memory-safe languages, where a buffer size being miscalculated should result in a controlled panic rather than memory corruption (…at least if you're not interfacing with unsafe code). Still, an overflow is effectively a miscalculation, incorrect behavior, and with any kind of incorrect behavior there's always a chance it will compromise security in some way.
> Similarly on performance, the idiomatic and fast C/C++ way to read a byte of input from a buffered source is "x = src++". But pointer arithmetic is explicitly unsafe in e.g. Go and Rust. Sure, you can hide the unsafe parts as private implementation and provide an unsafe-free public API. Still, as future maintainers edit the code, proof of safety (and the assumptions that they rely upon) are merely comments, not compiler enforced.*
Sure, but that's not the idiomatic way to do that in Rust. The idiomatic way to do that in Rust is to have an iterator over the bytes and call `next()` on it to get the next byte. This means no unsafe code in your codebase, meaning no need to worry about proving that it's safe or about safety not being enforced by the compiler.
Sure, that's not unsafe, but it does require a bounds check, i.e. seeing if you've hit the end of your slice of byte data.
One of the goals of Puffs is to eliminate that runtime bounds check, so it'd be exactly as fast as C/C++'s "x = *src++", even if you're not consuming exactly one byte per iteration, so you can't use Rust's "for val in bytes_iter".
Coincidentally, the word "Puffs" in German is a colloquial expression for "brothels". Not that it matters much in your context, just a piece of trivia...
ingve linked to the github page instead of the announcement e-mail: https://groups.google.com/forum/#!topic/puffslang/2z61mNTAMn...
That announcement has more to say about the comparison to Rust, which is probably the most frequently asked question.
There's also some more words, on Rust and on other related work like Dafny, at https://github.com/google/puffs/blob/master/doc/related-work...
Edit: It's also not Rust per se, but the numbers at https://github.com/google/puffs/blob/master/doc/benchmarks.m... shows that, on Puffs' benchmarks, gcc 7.2 noticably outperforms clang/llvm 5.0. I'm sure this is a solvable problem, and not a fundamental flaw with llvm, but fixing that's beyond my llvm knowledge.