9 ms·
> These algorithms use the data received from userspace in order to index into a lot of arrays and thus benefit from Rust's memory safety. If everything is don
by cyber_kinetist 3y ago
> These algorithms use the data received from userspace in
order to index into a lot of arrays and thus benefit from Rust's memory safety.
If everything is done with arrays and indices (apparently from looking at the code: (https://gitlab.collabora.com/dwlsalmeida/for-upstream/-/blob/7681609641fb9c94a0b5d827dc2e7290401689c3/rust/kernel/media/v4l2_core/vp9.rs https://gitlab.collabora.com/dwlsalmeida/for-upstream/-/blob...) it seems like Rust's borrow checker doesn't really help at all, and the only thing Rust really does for you is just bounds checks on arrays (with additional runtime overhead)... So I'm not sure how this can really improve the state of things compared to C with the equivalent bounds checks.
- woodruffw 3y ago> So I'm not sure how this can really improve the state of things compared to C with the equivalent bounds checks. The simplest answer here is that a compiler-introduced bounds check is almost always better than a human one. Humans make bounds errors, compilers generally don't. The longer answer is that the current state of the code does not guarantee its future state. The fact that bounds checks constitute the current majority of safety guardrails does not mean that future refactors won't benefit from Rust's temporal memory safety guarantees. Or more abstractly: it's easier to perform safe refactors when your safety properties compose natively, rather than having to bolt another layer of checks onto pre-existing language that doesn't support them natively. Edit: Forgot to mention: another benefit of bounds checking in the language itself is optimization: when humans bounds-check, the compiler needs to recognize human patterns to safety remove or merge redundant bounds checks. When the language specifies its own bounds checks, the compiler knows exactly what they'll look like and can optimize accordingly. Modern optimizing compilers are very good at detecting human-written bounds, but a fully compiler-controlled optimization is going to beat a human-augmented optimization >95% of the time.
- hulitu 3y ago> Humans make bounds errors, compilers generally don't. I think i saw this in a movie. It didn't turned well. /s
- jhoechtl 3y ago[flagged]
- shakow 3y agoShhh, why would you comment without any actual data-supported opinion or personal experience regarding bound checking performance impact? This is HN!
- pton_xd 3y ago> If everything is done with arrays and indices (apparently from looking at the code: (https://gitlab.collabora.com/dwlsalmeida/for-upstream/-/blob https://gitlab.collabora.com/dwlsalmeida/for-upstream/-/blob...) it seems like Rust's borrow checker doesn't really help at all That's the Rust "secret" in many high-performance computing applications, like games. You write everything using arenas and handles, which effectively side-steps the borrow checker. Everyone sane has been doing that for decades in C and C++. Obviously Rust has far better guarantees in general, but the pervasive usage of this borrow checker anti-pattern suggests that perhaps we need a more comprehensive way to guarantee memory safety.
- giovannibonetti 3y agoI remember Zig is able to convert arrays of struct to struct to arrays in compile time [1], which effectively sidesteps all the need for the user to worry about array indices and having them in the right range. https://zig.news/kristoff/struct-of-arrays-soa-in-zig-easy-in-userland-40m0 https://zig.news/kristoff/struct-of-arrays-soa-in-zig-easy-i...
- aw1621107 3y ago> which effectively sidesteps all the need for the user to worry about array indices and having them in the right range. How does converting AoS to SoA eliminate the need to worry about array indices? If you have an array of structs with N entities and convert that to a struct of arrays each array would also have N entities, so out-of-bounds accesses in one would be equally out-of-bounds in the other.
- giovannibonetti 3y agoYou can use iterators and skip over indices completely.
- aw1621107 3y agoWouldn't that apply to both AoS and SoA, though?
- HackerThemAll 3y ago> So I'm not sure Then sit back and watch others try it out. Let's see what comes out of it, the Rust code can always be discarded if it turns out to be inferior to the current implementation. It's not like breaking a glass, we can reverse it.
- pjc50 3y agoOh, they're not afraid of this failing, they're afraid of it succeeding.
- gattr 3y agoAs already mentioned, bounds checks won't necessarily cause that much overhead. When I rewrote my small image processing library from C to Rust ([1]), I only had to use unchecked array access in one hot loop to get overall performance equivalent to C code. [1] https://github.com/GreatAttractor/libskry_r https://github.com/GreatAttractor/libskry_r
- pornel 3y agoVulnerabilities are where programmers thought the bounds checks were redundant, and they weren't. This overprotectiveness by default turns out to be useful: https://github.com/rust-fuzz/trophy-case https://github.com/rust-fuzz/trophy-case Look how many of the crashes are panics and unwraps that could have been buffer overflows or wild pointer derferences otherwise. And there are plenty of arithmetic overflows that are much less dangerous when they can't cause out of bounds access. The code in this particular codec seems to be a direct translation of C code. Idiomatic Rust code would use iterators more, which work better for optimizing out redundant checks. It's easily fixable.
- lionkor 3y ago> with additional runtime overhead Hate to be the optimization nerd, but that's not really how any of this works. It's likely that this overhead is two instructions in the likely case (compare and jump), and there's absolutely no profiling being done here to show if this causes a measurable performance difference. It's quite likely that nobody here is profiling this, and is just guessing based on "more code = slower", but there is really no way to predict this in such a general sense. It may be that these bounds checks even cause the compiler to do optimizations later since it can make more assumptions. At the same time, if performance turns out to he a problem, there is probably bigger fish to fry than removing guardrails (maybe memory layout, maybe access patterns, maybe reordering things.
- Kab1r 3y agoYou would be surprised how much impact the additional instructions can incur. I found UB in a dependency of a popular video encoder. My fix involved adding compare and branches. I thought it wouldn't be significant but then I was instructed to benchmark it and it was significantly slower.
- bayindirh 3y agoI also don't think that we should be writing everything in Rust blindly. If you can guarantee that you won't be accessing outside of an array before entering a critical section, not having bounds checking is actually a plus. I have a similar code where I can guarantee that I won't be ever accessing outside the boundaries of arrays and vectors, and that gives me great performance boost.
- __s 3y agoYou can skip bounds checks in Rust using `unsafe`
- ParetoOptimal 3y ago> If you can guarantee that you won't be accessing outside of an array before entering a critical section That is a huge IF though. People getting those things wrong either initially or a refactor invalidating this invariant is a huge source of bugs.
- bayindirh 3y agoYes, I'm aware. However in most cases I know the size of the array in the beginning and it's not modified by any means (which is guarded by const correctness throughout the code). If I can't guarantee that, I use vectors and ".at()", which does bound checking at runtime. Generally I'm developing solo, so people mucking what I do is very rare, however I don't blindly believe myself either.
- mlsu 3y agoIt makes sense that you don't see the value of Rust if you spend most of your time developing solo. The value of these checks is not just to reduce bugs in production code. It's nice that that happens, but that's not even the primary value of the borrow checker. The primary value is that having these checks (lifetimes, bounds checks, -- everything that makes Rust annoying to write) makes refactoring on a shared codebase significantly easier. This means that you are not introducing bugs in a refactor, so you can refactor faster, which means you can ditch bad architectures sooner, which compounds and saves enormous amounts of developer time and $$. And it's a knock-on effect that increases in value as the team grows larger. Keeping track of lifetimes and bounds for a solo dev is quite easy as you say. Keeping track of lifetimes and bounds for the other dozen devs on my team? In all external dependencies? Extremely difficult. Impossible in a large codebase, actually, given the number of mem safety bugs that appear even in mature C codebases. It's collaboration that is the source of these bugs, that these checks work to mitigate. I sort of wondered why C did not have a package management system, until I started working on a large C codebase. There is a reason Rust has cargo and C does not; it has nothing to do with whether or not someone decided to write cargo and everything to do with Rust's language features.
- phkahler 3y ago>> So I'm not sure how this can really improve the state of things compared to C with the equivalent bounds checks. [emphasis added] Like all things Rust, you can do the same thing in C but that requires extra effort and more source code. If Rust will add bounds checking for you automatically, that's a step up from C.
- bayindirh 3y agoIf you don't need to do bounds checking, and doing it anyway, then that's a step down from C.
- mcfedr 3y agoBut isn't the point that the number of times a c programmer thought they didn't need bounds checks and reality are very different. Also off by one errors and such. Rust won't let you make these mistakes
- bayindirh 3y agoI personally don't think that a programming language should save me from myself unless I explicitly ask for it. For every case I first prove to myself that I can get away without bounds checking, otherwise if I'm in doubt, I put it in and profile. I think Rust is a nice language, but when it's presented as an "antidote" to "evils of C/C++", and is "indeed made to kill those" I lose my interest. Also, while I think learning Rust is worthwhile, I think promoting Rust's barriers as saviors are funny. We say that Apple's against general purpose computing with all its walled gardens. Then Rust is against "General purpose programming". I want to be able to write programs which crash and burn like meteors entering the atmosphere, because this allows me to understand the hardware under me. Promoting a walled programming language as "the one and only" is wrong. Why should I embrace a programming language as one and only if that doesn't allow me to do what I want with my computer? Edit: No, unsafe doesn't count, because it doesn't remove all checks.
- chatmasta 3y ago
- tinco 3y agoThe bounds checks in Rust are implicit (i.e. part of the std implementation), and get removed by the compiler if they're unnecessary. I think that's a pretty great improvement over the state of things in C. And if you are convinced you don't need a bounds check and the compiler does not remove it you can explicitly remove the bounds check, provided you mark the access as unsafe. So Rust is a strict improvement over C in this regard.
- faitswulff 3y agoshnatsel wrote a post on bounds checking performance implications in Rust. Money quote: > The real-world performance impact of bounds checks is surprisingly low. > The greatest impact I’ve ever seen on real-world code from removing bounds checks alone was *15%,* but the typical gains are in *1% to 3% range,* and even that only happens in code that does a lot of number crunching. > You can occasionally see greater impact (as we’ll see soon!) if removing bounds checks allows the compiler to perform other optimizations. > Still, performance of code that’s not doing large amounts of number crunching will probably [not be impacted by bounds checks](https://blog.readyset.io/bounds-checks/ https://blog.readyset.io/bounds-checks/) at all. It is, of course, not universally applicable, so read the post for full details: https://shnatsel.medium.com/how-to-avoid-bounds-checks-in-rust-without-unsafe-f65e618b4c1e https://shnatsel.medium.com/how-to-avoid-bounds-checks-in-ru...
- bayindirh 3y agoAsking because of interest: How compiler decides that it needs BC or not?
- tinco 3y agoThrough value tracking. It's actually LLVM that does this, GCC probably does it as well, so in theory explicit bounds checks in regular C code would also be removed by the compiler. How it works exactly I don't know, and apparently it's so complex that it requires over 9000 lines of C++ to express: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/ValueTracking.cpp https://github.com/llvm/llvm-project/blob/main/llvm/lib/Anal...