5 ms·
Why is calling my asm function from Rust slower than calling it from C?
- dmitrygr 10mo agoFor example, before we had something like: top: *const FFISafe<WithOffset<&'a u8>> We can change that to: top: WithOffset<*const FFISafe<&'a u8>> rust, you were meant to replace c++, not join it...
- saghm 10mo agoThe point of Rust is ostensibly to provide a safer version of C++-like semantics, not necessarily to avoid the same level of complexity. Especially if you're directly using unsafe code (which is necessary in some cases, like FFI), it's not really clear to me that Rust was "meant" to be doing something wildly different here. The large majority of the code not needing to use unsafe will still be better off even if this type of thing is necessary in some places. (To preempt any potential explanations about this: yes, I understand the reference being made with that quote. I just don't think it actually applies here at all)
- zephen 10mo agoThis is all well and good, but "zero cost abstractions" implies, well, that you're crawling _up_ the abstraction pyramid, not lost in twisty little side passages.
- cardiffspaceman 10mo agoTo me it implies abstraction such as a constructor, but with no overhead compared to the same steps done in some other way.
- zephen 10mo agoSure, but languages and the problems we solve with them are both multifaceted, so simply pointing to one tool and saying "this is better than the one you have in your toolbox" is fine, but the plural in "zero cost abstractions" kind of implies that most or all the tools are at parity or better.
- saghm 10mo agoIt sounds like you're saying that you consider seeing this single instance of someone writing a library with a costly abstraction to be indicative of the entire language ecosystem not fitting the paradigm. This is kind of hard to take seriously; it's not like C++ doesn't have some costly abstractions as well way more embedded into the language itself (e.g. exceptions).
- zephen 10mo ago> someone writing a library with a costly abstraction That's not what happened here. > it's not like C++ doesn't have some costly abstractions This is simultaneously both completely orthogonal to my observation that the Rust FFI is borked, and a great example of a problem that wouldn't happen in C++, because in C++ you could completely ignore the costly abstractions if necessary.
- saghm 10mo ago> > someone writing a library with a costly abstraction > That's not what happened here. Yes it is. Where do you think the `FFISafe` type that they used came from? It's not anything inherent to how Rust does FFI; it's a type someone wrote in an attempt to try to provide an abstraction, and that abstraction happened to have a cost. There's absolutely no reason anyone has to use it in order to do FFI in Rust.
- zephen 10mo agoThe extra time was being taken up in the identical assembly language function. Fixing it took wizardry.
- saghm 10mo agoI've never understood that to mean that every possible abstraction would be zero cost, but that the language itself provides abstractions that are zero cost. I'm not sure how you could avoid having external libraries ever implement an abstraction with a cost. I honestly can't tell from this article alone what library the type `FFISafe` is from, but it's not from std. (As an side someone whose spent a lot of time in the ecosystem might be able to infer this is likely a third-party library just from the fact that the capitalization is not in the typical format that official things use; if it were in std, I'd expect it to be FfiSafe, similar to how IoSlice[1], Arc[2], Shl[3], TypeId[4] etc. don't treat separate parts of an abbreviation/acronym/initialism as word breaks). [1]: https://doc.rust-lang.org/std/io/struct.IoSlice.html https://doc.rust-lang.org/std/io/struct.IoSlice.html [2]: https://doc.rust-lang.org/std/sync/struct.Arc.html https://doc.rust-lang.org/std/sync/struct.Arc.html [3]: https://doc.rust-lang.org/std/ops/trait.Shl.html https://doc.rust-lang.org/std/ops/trait.Shl.html [4]: https://doc.rust-lang.org/std/any/struct.TypeId.html https://doc.rust-lang.org/std/any/struct.TypeId.html
- zephen 10mo ago> I've never understood that to mean that every possible abstraction would be zero cost, but that the language itself provides abstractions that are zero cost. To me, "zero cost abstractions" means that you should use the language, because even the fancy abstractions it provides are free. Which presupposes that the language designers _believe_ that abstractions _and_ performance are both _important_. Judging by all the puff pieces on the language, I don't think I'm alone in this belief of what the average Rustacean holds to be true. > I'm not sure how you could avoid having external libraries ever implement an abstraction with a cost. But the point is that the exact same external library code has a _lower_ cost if called from the non-abstract horror of a language C, and the (partial) fix for that is really ugly looking low-level Rust crap that that took a _long_ time to figure out and is the exact opposite of an abstraction, and the full fix is not even known yet. Yes, we all know that abstractions sometimes obscure what is really going on, but the tradeoff is that the code is shorter and prettier, and easier to understand at a higher level. That's... not what is going on here.
- 10mo ago
- Aurornis 10mo ago> but "zero cost abstractions" implies, well, that you're crawling _up_ the abstraction pyramid, not lost in twisty little side passages The zero cost refers to the runtime cost, not the programming complexity.
- kelseyfrog 10mo agoWhat's a language with zero complexity-cost abstractions?
- eptcyka 10mo agoNatural language. It's a language interpreted by LLMs. It is really high level.
- bigstrat2003 10mo agoEven that has lots and lots of abstractions which add complexity. For example, figures of speech such as "shooting fish in a barrel".
- saghm 10mo agoIf anything, the fact that it's hard to come up with an example of a language like this is even more evidence that this probably isn't what anyone has ever meant by that term.
- cyco130 10mo agoNatural languages are much more complex. Complex for humans: I can learn a new programming language in an afternoon and be reasonably productive in it within a week or two. I wish I could say the same for natural languages. Complex for computers: We’ve had good compilers since the 50s. Satisfactory language models are less than five years old.
- pizza234 10mo ago"Zero cost abstractions" refers to some features of the language that provide functionalities with no runtime cost, e.g. (safe) iterators, not to a presumed simplicity of the whole language. Therefore, this is not mutually exclusive with the fact that certain concepts in Rust require more complexity than their counterpart in other languages (after all, the complexities of the borrow checker don't exist in C). In general, and it applies to the referenced article, programming with a high level of control over the implementation is complex, and there's no way around it. This article explains the concept: https://matklad.github.io/2023/01/26/rusts-ugly-syntax.html https://matklad.github.io/2023/01/26/rusts-ugly-syntax.html.
- zephen 10mo ago> "Zero cost abstractions" refers to some features of the language that provide functionalities with no runtime cost... In that case, all languages provide zero cost abstractions. > programming with a high level of control over the implementation is complex, > (after all, the complexities of the borrow checker don't exist in C). The point of an abstraction is to _hide_ complexity. > This article explains the concept The article is only half-right. People complain both about the semantics and the syntax, because Rust's implementation of both presents (in some cases) a huge cognitive load that simply doesn't exist in other languages.
- vlovich123 10mo agoFrom this thread it's pretty clear: 1. You've come up with your own unique definition of "zero cost" which isn't what the term means, at least as popularized by C++ where the concept of "zero cost abstractions" comes from. It means zero runtime cost, not zero cognitive cost. 2. Rust generally has more "zero cost abstractions" than C++ in terms of shifting traditional runtime checks into compile-time checks (e.g. while unique_ptr exists in Rust as Box, it's far more rarely used because ownership is easier to transfer). 3. Rust generally has faster defaults in the standard library so the abstractions are lower-cost than equivalents in C++ (e.g. C++ took forever to add a hash table via unordered_map and then proceeded to really fuck up the definition to inhibit high performance designs despite this being raised during standardization & haven't since revisited the issue). 4. Rust offers far more opportunities for "zero cost abstractions" than C++. Notably it's ownership rules prevent aliasing which allows the compiler to do more aggressive optimizations that can't generally be done in C++. It provides abstractions like NonNullPointer and NonZero so that unused bit patterns can be leveraged for enums (e.g. Option<NonNullPointer> is the size of a raw pointer but in C++ it's harder to pull off). Functional style and iterators are implemented to be aggressively inlined and overheads like bounds checking elided by the compiler, whereas C++ can't elide as easily and various bounds checks have to be inserted. Could go on and on. Anyway, Rust as the base language vs C++ has simpler cognitive abstractions, it has more zero cost abstractions, and it has more efficient abstractions overall, both in the language and the standard library.
- mpyne 10mo ago> rust, you were meant to replace c++, not join it... Turns out that not all of the C++ noise people make fun of is due to C++, sometimes the problems you want to solve with Rust or C++ is just hard to express simply to the compiler.
- bnolsen 10mo agoAnd then zig shows up...
- Aurornis 10mo agoFYI to non-Rust devs wondering what's going on with this code: Those two abstractions (FFISafe and WithOffset) are not standard Rust abstractions. They're something the author is building within their own library: https://github.com/memorysafety/rav1d/blob/25e5574/src/ffi_safe.rs#L11 https://github.com/memorysafety/rav1d/blob/25e5574/src/ffi_s... So for all of the complaining about Rust abstractions and syntax in this thread, keep in mind that these particular abstractions that caused this problem are not standard. If you just want to call an extern "C" function you can do so directly in an unsafe block. The article should be read as the author debugging their Rust wrapper types, not as a generic article about calling C functions from Rust.
- saghm 10mo agoNot related to the topic, but seeing this tidbit in the article took me by surprise; > PSA: if you don’t see syntax highlighting, disable the 1Password extension. This linked to the following discussion that's been ongoing for over a week (with acknowledgement from 1password that they're looking into it but as far as can tell no ETA on the fix or explanation for why it's happening in the first place): https://www.1password.community/discussions/developers/1password-chrome-extension-is-incorrectly-manipulating--blocks/165639 https://www.1password.community/discussions/developers/1pass... I know that browser extensions are in general a pretty terrible ecosystem in terms of security, but am I off-base for thinking this is not a great look for 1password? Maybe I'm just underestimating how hard this is to solve generally, but my expectation would be that it shouldn't be that hard to keep track of which circumstances you're loading entire external scripts to manipulate the DOM and not do it accidentally in places you have no need for it.
- Chilinot 10mo agoYea i think this discussion was quite interesting as well. And i can also verify that this issue exists in Zen (firefox based) as well.
- robocat 10mo agoFrom link: It looks [like the 1password extension] is using prism.js to try to add syntax highlighting to <code> blocks on the entire page. Jesus that comment contains so many red flags for a extension managing passwords!
- toxik 10mo agoInteresting deep dive. Can't say I understand the nuances really, and some of the Rust syntax looks incredibly arcane to me as an outsider.
- ohr 10mo ago(Author here) thanks! Even as an experienced Rust developer, this is a lot of syntax which is part of what makes it archaic I think. As usual with Rust most of it is due to inherent complexity: for example, when you deal with raw pointers, you need to specify if they are const or mut, and you must have a syntax that’s not &, and not too wordy: so * is a good choice (might be changed to &raw in the future!). And if you want to say that something is generic and the generic parameter is a pointer… you just end up with a lot of syntax.
- neuroelectron 10mo agoSo rust isn't just a clever name.
- belter 10mo agoAre you proposing a new language named WD40 ?
- patrick451 10mo agoI would call it it POR-15
- effnorwood 10mo agoabout 40 years
- baobun 10mo agoTitle reminded me of something completely unrelated: FFI overhead is not to be neglected sometimes. I've seen cases where replacing a python or js lib with an in isolation much faster native Rust or C lib with bindings had the end result being a decrease in real-world performance due to it being in a hot path or loop and the overhead being more significant than the savings were. There is no substitute for real-world benchmarks.
- ohr 10mo ago(Author here) yes! I also wrote about this (specifically in Python->Rust FFI) in another article: https://ohadravid.github.io/posts/2023-03-rusty-python/#v2---rewrite-even-more-in-rust https://ohadravid.github.io/posts/2023-03-rusty-python/#v2--...