Live data from Hacker News

Is Rust stack-efficient yet?

arewestackefficientyet.com

61–70 of 111 posts

Re: Is Rust stack-efficient yet?

#61

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.

You can access C#'s GC metrics through `System.GC.GetTotalAllocatedBytes` and similar APIs. Maybe you can make a benchmark and tracker for it yourself!

Re: Is Rust stack-efficient yet?

#62

Earlier quoted context omitted.

I guess what they mean is that the Vec would allocate heap space, and you could steal the allocation for your object to make the Box? You'd need to create this MyType manually and then tell Box what you made unsafely with like Box::from_raw() It feels like a better way to do that directly with Box is Box:: ::new_zeroed() which will make you a Box > full of zero bytes. If MyType is definitely valid when made entirely…

I think the commenter made a guess that I was boxing an array, which is a good guess, it just happens to be wrong in this case. Maybe that will work in the future—I don’t use nightly Rust, so for now, new_zeroed() won’t work. The basic problem is “I want to allocate something large on the heap” and it doesn’t seem like I should need to use nightly builds or unsafe{} to do it.

> I don’t use nightly Rust, so for now, new_zeroed() won’t work

That's a completely fair observation. The main thing I want stabilised is a single niche for custom types. I would take more if offered but experience says that every extra little thing doubles the discussion time, so, one niche is all I need, and Rust guarantees this exists in some form so even if a later mechanism does - say - fancy non-contiguous niches, I just want one value ASAP.

https://github.com/rust-lang/rfcs/pull/3334

> “I want to allocate something large on the heap” and it doesn’t seem like I should need to use nightly builds or unsafe{} to do it.

The former makes sense to me, the latter (a requirement to use unsafe) I can see there can be cases where the compiler has to do a lot of contortions to safely but optimally mint the type in place in the heap and just writing the unsafe case is reasonable. I don't know anything about your type so I can't judge.

Re: Is Rust stack-efficient yet?

#63

This affects the way you write code, too. I was writing something in Rust and I wanted to create a new boxed object. Box::new(...) Boom! Program crashes. The object I’m putting in the heap is too large for the stack. Rustc does this by instantiating the object on the stack, and then copying it to the box. I don’t really want to fuss with nightly or stuff like Box::new_uninit just to deal with this. C++ has both regul…

There's some ugly hacks that may or may not help here:

https://www.reddit.com/r/rust/comments/xxhp3s/perhaps_not_a_...

    r#box!(make_my_elem())
This crate is marked as deprecated because apparently upstream rust optimises its use-case now, but you never know:

https://github.com/kvark/copyless

    Box::alloc().init(make_my_elem())

Re: Is Rust stack-efficient yet?

#64
For easy to miss context:

This seems to be mainly about measuring the change of stack efficiency of rust compared to a C++ base line.

Given who the author is I'm pretty sure they know that e.g. having more stack movement can be better then having more heap allocations.

But there is a list of ways you can reduce stack memory movement as compiler optimizations without allocating heap memory, and AFIK rust doesn't yet fully take advantage of many of them.

Additionally sometimes trading a lot of stack movements with a single allocation can be quite a bit faster, e.g. why anyhow does a thin-pointer + inlined vtable optimization.

So I think the side is mainly for tracking improvements in compiler code generation and secondary if rustc uses some thin-pointer optimizations in places where it does yield some benefits.

Re: Is Rust stack-efficient yet?

#65

Earlier quoted context omitted.

That’s not what -ffold-simple-inlines does. The -ffold-simple-inlines flag simply removes debugging information for certain inlined functions. It doesn’t affect whether the function is inlined in the first place. The result is that debug builds may have a smaller amount of debug information, but the code will be the same.

That's not my reading of the docs, which explicitly talk about folding. Also simple tests shows that it does indeed inline the call even in debug mode. In addition to inlining it also does also remove debug info.

You may be right—I was reading the release notes, and the actual docs go into more detail about what the flag does.

Re: Is Rust stack-efficient yet?

#66

We need &out and &in, so we can safely write this stuff by hand. Then we can worry about the compiler automatically optimizing to use &out behind the scenes (using ABI flexibility). Trying to skip that first step, so the compiler just does unverified shit behind the scenes, I think will just end up with inflexibility and disappointment. Be the tortoise not the hare.

Easier said than done. You can already have:

    unsafe fn new_in_place(out: &mut MaybeUninit)
But you require unsafe code both to implement it (to project MaybeUninit) and to call it.

For it to be safe to call the type system would have to encode the invariant that &out is initialised after the call. It becomes even more complicated if the operation can fail.

Re: Is Rust stack-efficient yet?

#67
post #36

That's why I like AVR8 assembly better than C for Arduino. You have this big register file and the one C wants to use the most is the stack pointer.

That's not the optimization in question here, though. C uses the stack pointer a lot if you use a lot of stack-local variables. Mark all your stuff "static" and it will use immediate addresses instead (which may or may not help you -- putting all the "local" stuff in a block referenced by one pointer is usually a good thing!). What's happening here is that C++ is the inheritor of decades of ponderous analysis about h…

> C uses the stack pointer a lot if you use a lot of stack-local variables. Mark all your stuff "static" and it will use immediate addresses instead

Yes, but optimizing compilers are decently good at using registers instead, which is unfortunately not true for less popular targets (which usually means anything other than amd64 and arm64). I think that's what GP was referring to.

Re: Is Rust stack-efficient yet?

#68
post #52

Earlier quoted context omitted.

Having been bitten by that exact problem in C++, I think the original sin is to treat stuff like copy elision as a mere optimization, instead of a semantic guarantee.

The C++ committee recognized this problem. As of C++17, copy elision is mandatory. Several forms of it, at least.

Rust has also recognized the problem from a very early stage one.

For example this is why there was a `box` operator in early rust.

And e.g. placement-in like APIs had been in the works for years, it's just that no satisfying and sound solution has been found (but multiple solutions which initially seems sound).

Which is why we currently are in a "hope the optimizer does the right thing" situations (through it is pretty much guaranteed to do the right thing for a lot of cases around Box).

But then it also isn't the highest priority as it turns out a log of "big" data structures (lists, maps, etc.) tend to grow on the heap anyway, the the situation that someone run into debug builds crashing because of a big data-structure is pretty rare, and it also crashing of release build is even rarer. Some of the most likeliest ways to have a too-big data-structure on the stack is: Having some very deep type nesting. But then such types are (in the rust ecosystem) often seen as an abuse of the type system and an anti-pattern anyway. Through it can be a fun puzzel, and some people are obsessed which bending the type system to their will to create DSLs or encode everything possible in the type system. But I have yet to see commercial projects with mixed skill level team members where using such libraries didn't lead to productivity reduction on the long run (independent of programming language).

Re: Is Rust stack-efficient yet?

#69
post #43

Earlier quoted context omitted.

Box::new allocating on the stack and moving is only true in debug builds, in release builds it directly allocates on the heap. Not apologizing, just explaining. It is being fixed, the interim solution is to use a Vec.

There’s a broader problem here, which also applies to the C++ ecosystem, which is that debug builds are far less usable than they should be. C++ compilers in common debug configurations will emit a function call for std::move(), which is not in any way useful for typical debugging tasks and can make the program significantly slower. I don’t want to rely on compiler optimizations to make my code work. Or alternatively…

> The idea of using a Vec would be nice—if only the boxed item were an array! It’s a struct, you see…

Vectors of length 1 are still vectors :)

Re: Is Rust stack-efficient yet?

#70

Earlier quoted context omitted.

I guess what they mean is that the Vec would allocate heap space, and you could steal the allocation for your object to make the Box? You'd need to create this MyType manually and then tell Box what you made unsafely with like Box::from_raw() It feels like a better way to do that directly with Box is Box:: ::new_zeroed() which will make you a Box > full of zero bytes. If MyType is definitely valid when made entirely…

I think the commenter made a guess that I was boxing an array, which is a good guess, it just happens to be wrong in this case. Maybe that will work in the future—I don’t use nightly Rust, so for now, new_zeroed() won’t work. The basic problem is “I want to allocate something large on the heap” and it doesn’t seem like I should need to use nightly builds or unsafe{} to do it.

    let heap_value = vec![the_struct];
Based on another comment addressing this, I don't think the original commentor was making assumptions about the shape of your data.
Post reply on HN