[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)