Live data from Hacker News

How much does Rust's bounds checking cost?

blog.readyset.io

61–70 of 195 posts

Re: How much does Rust's bounds checking cost?

#61
post #46

Earlier quoted context omitted.

Not too long, did read : The benchmark went from 28.5ms to 32.9ms. That as a percentage is 15% and is huge, it’s not noise. The test is flawed in some way, the article is disappointing in that the author didn’t investigate further.

MySQL is a huge amount of code doing a variety of things in each query -- networking, parsing, IO, locking, etc. Each of those can easily have significant and hard to predict latencies. Benchmarking that needs special care, and planning for whatever it is you want to measure. A million trivial queries and a dozen very heavy queries are going to do significantly different things, and have different tradeoffs and perfo…

The benchmark was specifically testing the hot path of a cached query in their MySQL caching proxy. MySQL wasn’t involved at all.

I agree completely that benchmarks need care, hence my point that the article is disappointing.

The author missed the chance to investigate why removing bounds checks seemed to regress performance by 15%, and instead wrote it off as “close enough.”

It would have been really interesting to find out why, even if it did end up being measurement noise.

Re: How much does Rust's bounds checking cost?

#62
post #45

Always amuses me that it's current year and people think about turning off checks, even when they're pretty much free in modern* (since 1993 Pentium, which got like 80% accuracy with its primitive branch prediction?) CPUs... "Around Easter 1961, a course on ALGOL 60 was offered … After the ALGOL course in Brighton, Roger Cook was driving me and my colleagues back to London when he suddenly asked, "Instead of designin…

> I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law.

Here we are, 42 years later, and bounds checks are still not the default in some languages. Because performance, or something. And our computers are literally 1000x as fast as they were in 1980. So instead of paying 2% in bounds checks and getting a merge 980x faster, we get 2-3x more CVEs, costing the economy billions upon billions of dollars a year.

Re: How much does Rust's bounds checking cost?

#63

What if a compiler were to only allow an array access when it can prove that it's in bounds? Wherever it can't you'd have to wrap the array access in an if, or otherwise refactor your code to help the compiler. Then you'd have no panicking at least and more predictable performance.

That's how WUFFS (Wrangling Untrusted File Formats Safely) works:

https://github.com/google/wuffs#what-does-compile-time-check...

Re: How much does Rust's bounds checking cost?

#64
post #49

The reason performance decreased when he removed bounds checking is because asserting bounds is very useful to a compiler. Essentially, the compiler emits code like this: 1. if (x >= 0) && (x The compiler deduces that at line 5 0 1. get element from array index x 2. do more stuff So the compiler doesn't know anything about x, which is bad. The solution which apparently is not implemented in Rust (or LLVM, idk) is to…

I'm not sure I follow: where is abs(x)?

Re: How much does Rust's bounds checking cost?

#65
For Virgil, there is a switch to turn off bounds checking, for the only reason to measure their cost. (It's not expected that anyone ever do this for production code). Bounds checks do not appear to slow down any program that matters (TM) by more than 2%. That's partly because so many loops automatically have bounds checks removed by analysis. But still. It's negligible.

Re: How much does Rust's bounds checking cost?

#66
One technique is to add asserts before a block of code to hoist the checks out. The compiler is usually smart enough to know which conditions have already been checked. Here's a simple example: https://rust.godbolt.org/z/GPMcYd371

This can make a big difference if you can hoist bounds checks out of an inner loop. You get the performance without adding any unsafe {}.

Re: How much does Rust's bounds checking cost?

#67
post #49

The reason performance decreased when he removed bounds checking is because asserting bounds is very useful to a compiler. Essentially, the compiler emits code like this: 1. if (x >= 0) && (x The compiler deduces that at line 5 0 1. get element from array index x 2. do more stuff So the compiler doesn't know anything about x, which is bad. The solution which apparently is not implemented in Rust (or LLVM, idk) is to…

Interesting observation. So one should instead do the comparison with something like:

    1. if (x >= 0) && (x 
Where unreachable_unchecked transmits precisely such information to the optimizer: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unc...

Re: How much does Rust's bounds checking cost?

#68
post #44

Earlier quoted context omitted.

In Rust at least, once you instantiate the iterator, the array it's iterating over can't be mutated until the iterator is dropped, and that can be statically guaranteed at compile time. So you don't need to bounds-check at every access; you can decide at the outset how many iterations there are going to be, and doing that number of iterations will be known not to walk past the end.

I don't think that's always possible in practice: consider Vec , whose size is only known at runtime. A Vec 's iterator can only do runtime bounds checking to avoid walking past the end. That said, this is unavoidable in C/C++ too.

I think we're suffering from some fuzziness about what bounds checks we're referring to. Even in your example, you only need to check the size of the Vec when you instantiate the iterator, not each time the iterator accesses an element, because at the time the iterator over the Vec's contents is instantiated, the Vec's size is known, and it can't change over the life of the iterator (because mutation is disallowed when there's an outstanding borrow). With a regular for-loop:

    for i in 0..v.len() {
        println!("{:?}", v[i]);
    }
you check the length at the top (the `v.len()`) and also for each `v[i]`. The first is unavoidable, but the second can be skipped when using an iterator instead, because it can be statically guaranteed that, even if you don't know at compile time what concretely the length is, whatever it ends up being, the index will never exceed it. Rust specifically differs from C++ in this respect, because nothing in that language prevents the underlying vector's length from changing while the iterator exists, so without per-access bounds checks it's still possible for an iterator to walk past the end.

Re: How much does Rust's bounds checking cost?

#69
post #66

One technique is to add asserts before a block of code to hoist the checks out. The compiler is usually smart enough to know which conditions have already been checked. Here's a simple example: https://rust.godbolt.org/z/GPMcYd371 This can make a big difference if you can hoist bounds checks out of an inner loop. You get the performance without adding any unsafe {}.

Yeah this is because the error message printed contains the location of the error as well as the attempted index. Thus, there are differences between the bounds failures and the optimizer can't hoist the check out (plus probably some concerns due to side effects of opaque functions).

Re: How much does Rust's bounds checking cost?

#70
post #44

Earlier quoted context omitted.

In Rust at least, once you instantiate the iterator, the array it's iterating over can't be mutated until the iterator is dropped, and that can be statically guaranteed at compile time. So you don't need to bounds-check at every access; you can decide at the outset how many iterations there are going to be, and doing that number of iterations will be known not to walk past the end.

I don't think that's always possible in practice: consider Vec , whose size is only known at runtime. A Vec 's iterator can only do runtime bounds checking to avoid walking past the end. That said, this is unavoidable in C/C++ too.

The Rust compiler guarantees that the memory location and size of the iterated array do not change during the operation. So the iterator can be a pointer that iterates until it points to the end of the array. There is no need to do bounds checks: the pointer only goes over the valid range.

In C/C++, the array can change. It might be moved, de-allocated or resized in the current or a synchronous thread. So the pointer that iterates until it is equal to the end pointer, might point to invalid data if the size, location or existence of the vector changes.

Post reply on HN