Live data from Hacker News

Is Rust stack-efficient yet?

arewestackefficientyet.com

11–20 of 111 posts

Re: Is Rust stack-efficient yet?

#11
I would love to see this for C#. Avoiding heap allocations was something I had to tackle as part of a simulation software. C# has a handful of GC generations, and GC gen1 is very fast, but it's still faster to pool things ahead of time.

Re: Is Rust stack-efficient yet?

#12

I don’t understand the point of this. Is there a trade off in being stack efficient and speed?

The main goal is removing replacing pointless stack-to-stack copies with simply mutating in-place on the stack correctly in the first place. Due to some mix of: * Rust code relying more on copies than C++ (for esample, harder to make something uninitialized and fill it in) * LLVM missing optimizations that rust relies on heavier than C++ * No real guarantees around RVO / NRVO Rust code often will put something on the…

> No real guarantees around RVO / NRVO

Shouldn’t Rust in theory have a lot more freedom in defining its calling conventions than C++ has? I wonder if there’s anything that prevents doing RVO by default, or if just hadn’t been a priority yet.

Re: Is Rust stack-efficient yet?

#13
post #5

It would be more informative if the stack metrics were paired with heap metrics. You can trivially avoid stack to stack copies by allocating on the heap and passing pointers / references. But that is often actually slower, because heap allocation is more costly than copying data within the stack.

This is not about a heap-vs-stack tradeoff, this is about the compiler routinely generating very inefficient code that copies data around on stack for no good reason.

For an example I've seen myself: using a custom GC pointer library, calling `Gc::allocate(SomeBigStruct{...})` constructed the SomeBigStruct on stack and copied it around using memcpy 4 times before it actually landed in the allocated heap memory. The equivalent code compiled with a C++ compiler would have probably optimized the program enough to fill the struct in-place on heap without any issues.

(this example is from over a year ago; it's not as bad anymore, but it still generates suboptimal assembly with too much copying)

Re: Is Rust stack-efficient yet?

#14
I noticed in one of my crates that Rust often cannot optimize "moves" away. I was in the unusual situation where I had to move around a very large stack buffer(typically in Rust they live on the heap). Instead of passing it back and forth between moving functions as I originally designed, I had to redesign it to use macros which significantly improved my benchmarks. Further attention to optimizations here would be very welcome.

Re: Is Rust stack-efficient yet?

#15
post #9

I've run into frustrating stack overflows in seemingly trivial non-recursive code, so I appreciate this effort! I wonder if it might be simpler to track stack sizes statically instead of using runtime instrumentation. What I mean is, for example on x86_64, the function prologue has a stack reservation in the form of `sub rbp, 0x168`. So we can easily tell that the function uses 0x168 bytes of stack space. Just add th…

It's not clear to me how this would track stackstack and memorystack copies. Can you explain?

Re: Is Rust stack-efficient yet?

#17
post #5

It would be more informative if the stack metrics were paired with heap metrics. You can trivially avoid stack to stack copies by allocating on the heap and passing pointers / references. But that is often actually slower, because heap allocation is more costly than copying data within the stack.

This is not about a heap-vs-stack tradeoff, this is about the compiler routinely generating very inefficient code that copies data around on stack for no good reason. For an example I've seen myself: using a custom GC pointer library, calling `Gc::allocate(SomeBigStruct{...})` constructed the SomeBigStruct on stack and copied it around using memcpy 4 times before it actually landed in the allocated heap memory. The e…

Most likely these kinds of things are the cause but this data does not actually show that assumption because it lacks the other information. It’s also possible rust has more copies on each which would be useful to track anyways.

Re: Is Rust stack-efficient yet?

#18
post #9

I've run into frustrating stack overflows in seemingly trivial non-recursive code, so I appreciate this effort! I wonder if it might be simpler to track stack sizes statically instead of using runtime instrumentation. What I mean is, for example on x86_64, the function prologue has a stack reservation in the form of `sub rbp, 0x168`. So we can easily tell that the function uses 0x168 bytes of stack space. Just add th…

I like tracking this or at least having a way to track this. It's incredibly common that you only discover a crash too late in production due to running out of stack size and at least knowing a histogram over some test runs about how close something went to the (configured) limit would already be incredibly helpful for service stability.

Re: Is Rust stack-efficient yet?

#19
post #15
post #9

I've run into frustrating stack overflows in seemingly trivial non-recursive code, so I appreciate this effort! I wonder if it might be simpler to track stack sizes statically instead of using runtime instrumentation. What I mean is, for example on x86_64, the function prologue has a stack reservation in the form of `sub rbp, 0x168`. So we can easily tell that the function uses 0x168 bytes of stack space. Just add th…

It's not clear to me how this would track stack stack and memory stack copies. Can you explain?

If you copy between stack regions, you need more stack memory, so the stack allocation should be larger. Of course, this would undercount cases that copy to the same region many times which seems likely.

Re: Is Rust stack-efficient yet?

#20
This looks like a good metric to track. Looking at some generated asm when I was optimising a no_std program for size, I was surprised how much stack shuffling was going on. Also iirc it had runs of load/store where it seemed like a loop might be better.

Shrinking the size of my library's Error struct seemed to help a lot - I wonder if it's because an error "E" smaller than the Result's "T" can be returned in-place, but a larger one needs a copy...?

Post reply on HN