[HN Gopher] Why is calling my asm function from Rust slower than...
___________________________________________________________________
Why is calling my asm function from Rust slower than calling it
from C?
Author : gavide
Score : 90 points
Date : 2025-12-27 14:13 UTC (2 days ago)
(HTM) web link (ohadravid.github.io)
(TXT) w3m dump (ohadravid.github.io)
| dmitrygr wrote:
| For 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 wrote:
| The 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 wrote:
| This 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 wrote:
| To me it implies abstraction such as a constructor, but
| with no overhead compared to the same steps done in some
| other way.
| zephen wrote:
| Sure, 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 wrote:
| It 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 wrote:
| > 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 wrote:
| > > 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 wrote:
| The extra time was being taken up in the identical
| assembly language function.
|
| Fixing it took wizardry.
| Aurornis wrote:
| > That's not what happened here.
|
| Yes, it's what happened here. The article is about
| debugging the author's own abstraction types that had
| some incorrect assumptions.
|
| You do not need these wrapper types to call C functions.
| If the author had removed the complex extractions and
| called the extern "C" function directly (as is standard
| in Rust) there would not be the additional overhead.
| saghm wrote:
| 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. 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
| [2]: https://doc.rust-lang.org/std/sync/struct.Arc.html
| [3]: https://doc.rust-lang.org/std/ops/trait.Shl.html [4]:
| https://doc.rust-lang.org/std/any/struct.TypeId.html
| zephen wrote:
| > 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.
| saghm wrote:
| > 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.
|
| No, it's not the exact same external library. There's an
| additional Rust library in between that they used, which
| provides the `FFISafe` type, and that has overhead. This
| is not a standard Rust library, or even one that I'm able
| to find within a few minutes of googling despite having
| used Rust for over a decade. It's not clear to me why you
| think this is necessarily representative of Rust rather
| than one specific library; someone could just as easily
| wrap a C library in another C library in a way that adds
| overhead, and it would be equally nonsensical to cite
| that as an argument that C isn't efficient.
|
| Your argument seems to boil down to "Rust claims to be
| efficient, but it's possible for someone to write
| inefficient code, and for me to use that code, so
| therefore those claims are wrong".
| zephen wrote:
| > No, it's not the exact same external library.
|
| It uses the exact same assembly language.
|
| > There's an additional Rust library in between that they
| used, which provides the `FFISafe` type, and that has
| overhead.
|
| Look, I wrote " But the point is that the exact same
| external library code has a _lower_ cost if called [from
| C]" and that remains a true statement. It's pretty
| obvious that I was referring to the shared code,
| otherwise, it wouldn't have ever been called from C,
| right?
|
| The profiler showed that the identical assembly language
| itself was taking more cycles when called from C.
|
| > There's an additional Rust library in between that they
| used, which provides the `FFISafe` type, and that has
| overhead. This is not a standard Rust library, or even
| one that I'm able to find within a few minutes of
| googling despite having used Rust for over a decade.
|
| The point is that they did the absolute normal expected
| thing in Rust, and it slowed down the external assembly
| language library, and after a _lot_ of digging and
| debugging, they changed the Rust code to be a lot less
| flexible and more convoluted, and now the assembly
| language is almost as fast as when it is called from C.
|
| > Your argument seems to boil down to "Rust claims to be
| efficient, but it's possible for someone to write
| inefficient code, and for me to use that code, so
| therefore those claims are wrong".
|
| No, that's not my argument at all. Look, the people doing
| this _obviously_ know Rust, and it took them a _long_
| time, and some _really_ ugly concrete low-level concrete
| code, to take external code and make it perform almost as
| well as if it had been called from C++.
|
| To me, that looks like a high-cost non-abstraction.
| Aurornis wrote:
| > Look, I wrote " But the point is that the exact same
| external library code has a _lower_ cost if called [from
| C]" and that remains a true statement.
|
| I don't think you've understood the article at all.
|
| The overhead came from the author's own abstractions that
| were designed to accommodate both the assembly version or
| the Rust fallback. The assumption was that they take the
| same types and therefore the abstraction would be zero-
| cost, but in practice the Rust version had different
| types and therefore there was extra overhead in the way
| they were called.
|
| If the author had simply done an extern "C" of the
| function and called it from Rust there wouldn't be
| overhead.
|
| > To me, that looks like a high-cost non-abstraction.
|
| The abstractions that caused this probably were not
| standard Rust library abstractions. The author wrote them
| as part of the library.
|
| You don't need an abstraction at all to just call C
| functions from Rust. It's build right into the language.
|
| If you think the problems in this article are a common
| Rust failure mode, you haven't understood the article at
| all. The unique method of calling C functions was
| something the author wrote, not a standard Rust practice.
| Aurornis wrote:
| > 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,
|
| In case it's not clear, the FFISafe abstraction is not a
| Rust standard library feature. It's a wrapper type that
| the author created within their library to bypass some
| compiler warnings:
|
| https://github.com/memorysafety/rav1d/blob/25e5574/src/ff
| i_s...
|
| If you want to call C functions from Rust it's as simple
| as writing an extern block and then calling the function,
| though you'll have to put the call in an unsafe block
| because obviously the Rust compiler can't make safety
| guarantees across that boundary.
|
| The Rust docs for extern are concise: https://doc.rust-
| lang.org/std/keyword.extern.html
| Aurornis wrote:
| > 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 wrote:
| What's a language with zero complexity-cost abstractions?
| eptcyka wrote:
| Natural language. It's a language interpreted by LLMs. It
| is _really_ high level.
| bigstrat2003 wrote:
| Even that has lots and lots of abstractions which add
| complexity. For example, figures of speech such as
| "shooting fish in a barrel".
| pizza234 wrote:
| "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.
| vlovich123 wrote:
| From 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 wrote:
| > 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.
| Aurornis wrote:
| FYI 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_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 wrote:
| Not 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/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 wrote:
| Yea i think this discussion was quite interesting as well. And
| i can also verify that this issue exists in Zen (firefox based)
| as well.
| toxik wrote:
| Interesting deep dive. Can't say I understand the nuances really,
| and some of the Rust syntax looks incredibly arcane to me as an
| outsider.
| neuroelectron wrote:
| So rust isn't just a clever name.
| belter wrote:
| Are you proposing a new language named WD40 ?
| patrick451 wrote:
| I would call it it POR-15
___________________________________________________________________
(page generated 2025-12-29 23:00 UTC)