News for hackers. Stuff that matters.
Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @03:19PM (#12270911)
> So wondering if Rust provides any ability to add that kind of an N:M threading approach. Perhaps via an extension, macro or some other mechanism.

I don't want M:N threading as Go implements it. It's a big loss of performance for marginal benefit over futures. In particular the libmill approach was tried in Rust and the results were far worse than 1:1.

However, assuming this takes off I would like to see async/await style syntactic sugar over futures down the road to make it easier to write code that looks blocking but actually isn't. Crucially, this sugar would maintain the zero-cost nature of futures. With that approach, we'd have the ergonomics of languages like Erlang and Go without the significant performance tax associated with M:N.

Re:Zero-cost futures in Rust by sebcat on Thursday August 11, 2016 @03:58PM (#12271162)
> I don't want M:N threading as Go implements it.

As someone who writes code for enterpricey businesses doing a lot of I/O bound stuff, golang style M:N threading is a godsend over Java's standard library, and other common platforms in that space. Being able to express your code in a sequential manor and still gain the performance offered by implicit fiber,goroutine,w/e scheduling is pretty awesome. With futures, there's still some language semantic overhead from the point of view of the developer.

In my problem space, M:N threading is simply worth it. And if I need anything better performing, I can still switch to C for specific use cases.

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @04:09PM (#12271244)
> Being able to express your code in a sequential manor and still gain the performance offered by implicit fiber,goroutine,w/e scheduling is pretty awesome.

You don't gain as much performance. On Linux, you don't actually gain that much if anything over 1:1 threading. Most of the benefits of goroutines actually comes from the small stacks, which don't have anything to do with M:N and 1:1 to begin with—they're a feature of GC.

As the blog post states, our end goal is to achieve the ergonomics of Go-style M:N without sacrificing nginx levels of performance. With this futures library, we've established the foundations. It would make no sense to give up before even trying.

> And if I need anything better performing, I can still switch to C for specific use cases.

Why would you write networking code in C in 2016, when there are better alternatives available (like this one)?

Rust's philosophy is to have both performance and ergonomics. It rejects the idea that optimal performance requires a cumbersome programming model. I'm not about to give up on that.

Re:Zero-cost futures in Rust by gravypod on Friday August 12, 2016 @09:06AM (#12275259)
> Why would you write networking code in C in 2016, when there are better alternatives available (like this one)?

As someone who's done a bit of game development in the past I can easily say that you'll fall flat on your face in some fields if you don't write your own protocols. There are simply no protocols that operate well in every use case and there are also use-cases without standardized protocols.

For extremely high performance operations you NEED to use a custom protocol in some case to squeeze every bit of power out of your applications.

From a game development perspective you need to handle two types of content: content that isn't really ordered by time occurrence and content that needs to happen sequentially.

Because of this you can correctly optimize your networking stack for those needs and get your networking system really fast.

Some people have taken to using TCP with a JSON message passing system and that just doesn't work large scale. You'll have huge latency issues and with a big enough game you have to do some serious bit-packing to make it cost effective to host servers for.

Now I'm speaking generally and this is just from my experience but there is definitely still a reason to write your own network code.

Re:Zero-cost futures in Rust by kibwen on Friday August 12, 2016 @10:46AM (#12276092)
I believe pcwalton agrees that the ability to write one's own networking code is important. The quoted line is simply questioning why you'd write such code in C (which, if you're a game developer, means that "platform support" is a perfectly valid answer).
Re:Zero-cost futures in Rust by pcwalton on Friday August 12, 2016 @11:53AM (#12276615)
Sure, there are valid reasons to write your own network code. The question is whether you should write it in C. :)
Re:Zero-cost futures in Rust by derefr on Thursday August 11, 2016 @04:27PM (#12271332)
> On Linux, you don't actually gain that much if anything over 1:1 threading.

You use green threads instead of native threads because native threads have space overhead, not because they have time overhead. Attempting to spawn 100k OS threads will do strange things to most kernel scheduling algorithms; they're not optimized for that use-case.

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @04:37PM (#12271400)
> You use green threads instead of native threads because native threads have space overhead, not because they have time overhead.

The main overhead of a thread, green or native, is the stack. The size of the stack is independent of whether you use native or green threads. Go's small stacks are actually made possible by its GC, not its choice of 1:1 or M:N. In musl, for example, you can have 2KB stacks [1] with 1:1.

I haven't seen a benchmark of huge numbers of native threads vs. a userland scheduler, but I have a hard time imagining that a userland scheduler will beat the kernel's scheduler. The kernel scheduler has a much more global picture of the system compared to userland.

[1]: https://github.com/rofl0r/musl/blob/d05aaedaabd4f5472c233dbb...

Re:Zero-cost futures in Rust by derefr on Thursday August 11, 2016 @04:46PM (#12271441)
> The kernel scheduler has a much more global picture of the system compared to userland.

In most of the comparisons I've seen (usually for Erlang), worst-case latency was the important factor, so interaction with the kernel scheduler was avoided as much as possible. In the Erlang runtime, you can pass a switch to cause the userland scheduler-threads to each get bound to a particular processor core, and to cause the kernel scheduler to avoid scheduling anything on those cores. Effectively, this partitions the processor into a set of cores the OS scheduler entirely manages, and a set of cores that the userland scheduler entirely manages.

Re:Zero-cost futures in Rust by eridius on Thursday August 11, 2016 @10:22PM (#12273061)
If the kernel scheduler completely hands control of the core over to the program, doesn't that mean you can only run one or two programs on the entire machine at once without running out of cores? Surely the kernel still schedules other threads on that core too.
Re:Zero-cost futures in Rust by derefr on Thursday August 11, 2016 @11:45PM (#12273284)
Yes, that's rather the point: we're talking about highly-multicore server machines (e.g. 16/32 cores, or perhaps far more) entirely dedicated to running your extremely-concurrent application. You want all but one or two of those cores just running the app and nothing else. You leave one or two cores for the "control plane" or "supervisor"—the OS—to schedule all the rest of its tasks on.

It's a lot like a machine running a hypervisor with a single VM on it set to consume 100% of available resources—but actually slightly more efficient than that, since a guest can intelligently pin allocate cores to itself and pin its scheduler-threads to them and then just stop thinking about the pinning, while a hypervisor-host is stuck constantly thinking about whether its vCPUs-to-pCPU mapping is currently optimal, with what's basically a black box consuming those vCPUs.

Re:Zero-cost futures in Rust by bluejekyll on Friday August 12, 2016 @11:53AM (#12276610)
Is this something Erlang supports, or is it something that you get merely because you've pinned threads to a specific core?

I know with cgroups in Linux you can pin processes to cores pretty easily. Just curious how Erlang makes this easier.

Re:Zero-cost futures in Rust by derefr on Friday August 12, 2016 @03:25PM (#12278127)
If you mean that in terms of "can you ask Erlang itself to do this for you", then yes: http://erlang.org/doc/man/erl.html#+sbt

If you mean that in terms of "does the Erlang runtime intelligently take advantage of the fact that its schedulers are pinned to cores to do things you don't get from plain OS-level pinning", I'm not sure.

I think it might, though. This is my impression from reading, a year or so back, the same docs I just linked; you can read them for yourself and form your own opinion if you think this sounds crazy:

It seems like ERTS (the Erlang runtime: BEAM VM + associated processes like epmd and heart) has a pool of "async IO" threads, separate from the regular scheduler threads, that just get blocking syscalls scheduled onto them. Erlang will, if-and-only-if it knows it has pinned schedulers, attempt to "pair" async IO threads with scheduler threads, so that Erlang processes that cause syscalls schedule those syscalls onto "their" async IO threads, and the completion events can go directly back to the scheduler-thread that should contain the Erlang process that wants to unblock in response to them.†

In the default case, if you don't tell ERTS any different, it'll assume you've got one (UMA) CPU with N cores, and will try to pin async IO threads to the same cores as their paired scheduler-threads. This has context-switching overhead, but not much, since 1. the async IO thread is mostly doing kernel select() polling and racing to sleep, and 2. the two threads are in a producer-consumer relationship, like a Unix pipeline, where both can progress independently without needing to synchronize.

If you want, though, you can further optimize by feeding ERTS a CPU map, describing how the cores in your machine are grouped into CPU packages, and how the CPU packages are further grouped into NUMA memory-access groups. ERTS will then attempt to schedule its async IO threads onto a separate core of the same CPU package, or if not possible, the same NUMA group* as the scheduler-thread, to decrease IPC memory-barrier flushing overhead. (The IPC message is still forced to dump from a given core's cache-lines into the CPU or to NUMA local memory, but it doesn't have to go all the way to main memory.)

ERTS will also, when fed a CPU map, penalize the choice in its scheduling algorithm to move an Erlang process to a different CPU package or NUMA group. (It will still do it, but only if it has no other choice.)

---

† This is in contrast to a runtime without "native" green-threads, like the JVM, where even if you've got an async IO pool, it just sees an opaque pool of runtime threads and sends its completion events to one at random, and then it's the job of a framework like Quasar to take time out of the job of each of its JVM runtime threads to catch those messages and route them to a scheduler running on one of said runtime threads.

The same is true of an HVM hypervisor: without both OS support (paravirtualization) plus core pinning inside each VM, a hardware interrupt will just "arrive at" the same pCPU that asked to be interrupted, even if the vCPU that was scheduled on that pCPU when it made the hypercall is now somewhere else. This is why SR-IOV is so important: it effectively gives VMs their own named channels for hardware to address messages to, so they don't get delayed by misdelivery.

Re:Zero-cost futures in Rust by DblPlusUngood on Thursday August 11, 2016 @05:12PM (#12271582)
The space overhead is significantly worse for native threading in the presence of many threads since each thread needs both a user and kernel stack.

For M:N, there are N kernel stacks.

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @05:44PM (#12271801)
Fair enough, but kernel stacks are 8K. 10K user + kernel size is a far cry from the 2MB default pthread stack size people usually talk about when they talk about 1:1.

I don't know of any benchmark comparing Go vs. a 1:1 implementation with 2K pthread stack sizes, but I would be surprised if the performance difference is large at all.

Re:Zero-cost futures in Rust by JoshTriplett on Thursday August 11, 2016 @05:48PM (#12271828)
> Fair enough, but kernel stacks are 8K.

And getting even cheaper than that, with the effort to make kernel stacks use virtual memory. As I understand it, once kernel stacks use virtual memory, they'll start out at a single 4k page.

Re:Zero-cost futures in Rust by kibwen on Friday August 12, 2016 @10:48AM (#12276112)
Is there a writeup somewhere of the progress towards this, or a prospective timeline?
Re:Zero-cost futures in Rust by sciurus on Friday August 12, 2016 @02:25PM (#12277703)
Re:Zero-cost futures in Rust by ansible on Thursday August 11, 2016 @05:09PM (#12271551)
I haven't seen a benchmark of huge numbers of native threads vs. a userland scheduler, but I have a hard time imagining that a userland scheduler will beat the kernel's scheduler. The kernel scheduler has a much more global picture of the system compared to userland.

Doesn't using kernel threads imply lots of context switches? Doesn't that tend to be expensive in terms of time on modern architectures?

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @05:31PM (#12271702)
> Doesn't using kernel threads imply lots of context switches?

No, it's actually fewer context switches. That's because each I/O completion event goes straight from the kernel to the code that was waiting on it (1 context switch), not from the kernel to the userland dispatcher to the code that was waiting on it (2 context switches).

Re:Zero-cost futures in Rust by wbl on Thursday August 11, 2016 @08:16PM (#12272683)
This is not quite right. The userland dispatcher to run next thread is not a context switch: the TLB doesn't need to get flushed for instance. Furthermore many userland threads can be woken at once, and don't incur context switches when they suspend, prompting the next runnable thread to run.

If you're willing to put in a lot of compiler work userland thread switching is a function call, literally. I don't 1:1 threads with small stack are going to compete with that.

Re:Zero-cost futures in Rust by naasking on Thursday August 11, 2016 @10:28PM (#12273075)
The real cost of a true "context switch" is the transition from user level to kernel level, which takes thousands of cycles. This cost isn't incurred on a userland context switch, so those costs aren't comparable.
Re:Zero-cost futures in Rust by kijiki on Thursday August 11, 2016 @11:15PM (#12273198)
Thousands of cycles for a SYSCALL/SYSRET on a reasonably modern Intel/AMD CPU? I think you should try to measure that.
Re:Zero-cost futures in Rust by DblPlusUngood on Friday August 12, 2016 @12:32PM (#12276923)
"Thousands of cycles" is definitely not true on modern CPUs. SYSENTER/SYSEXIT takes 150 cycles on my Xeon X3460.
Re:Zero-cost futures in Rust by derefr on Friday August 12, 2016 @04:33PM (#12278591)
Given the kind of "cloud"-backed startups most of HN are working on, I think the more practical measurement would be the overhead of a ring 0/3 separation in a VM, plus hypercalls, plus a ring 0/3 separation in the hypervisor (for paravirtualized syscalls); averaged against a ring 0/3 separation in a VM, plus SR-IOV virtualization (for HVM-backed syscalls.)

Yeah, this doesn't apply for context-switches that happen because of plain old pre-emption, but it does happen if the context-switch is because e.g. a network packet wants to arrive at another process in your VM than the one that's currently running.

I would imagine that there's a reason bare-metal IaaS providers have a business model. :)

Re:Zero-cost futures in Rust by naasking on Friday August 12, 2016 @02:02PM (#12277549)
My knowledge of current timings are admittedly a little out of date since my microkernel days are behind me. Even the 150 cycles another poster suggested is still a significant cost over a userland context switch.
Re:Zero-cost futures in Rust by anonymousDan on Thursday August 11, 2016 @06:05PM (#12271953)
What if you have async system calls (e.g. FlexSC)?
Re:Zero-cost futures in Rust by openasocket on Thursday August 11, 2016 @05:34PM (#12271723)
Well, one advantage the Go runtime has is the green threads are cooperatively scheduled, so switches are a lot more lightweight.
Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @05:38PM (#12271748)
> Well, one advantage the Go runtime has is the green threads are cooperatively scheduled, so switches are a lot more lightweight.

Switches occur on timeouts (which involve a round trip through the kernel), on I/O events (which also involve a round trip through the kernel), or on goroutine message passing. So in every case except goroutine message sends, the switches don't actually save you a trip through the kernel.

Re:Zero-cost futures in Rust by saynsedit on Thursday August 11, 2016 @08:00PM (#12272620)
System call context switching is cheaper than and different from thread/scheduler context switching.
Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @08:23PM (#12272713)
OK, but that's irrelevant in this context because Go has to context switch either way.
Re:Zero-cost futures in Rust by zeeboo on Friday August 12, 2016 @12:00AM (#12273320)
It can also switch on memory allocations and function calls as well. I'd expect a large fraction of the context switches come from those events and don't go through the kernel.
Re:Zero-cost futures in Rust by gpderetta on Thursday August 11, 2016 @05:44PM (#12271793)
Except when the IO doesn't go though the kernel in the first place of course.
Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @05:48PM (#12271832)
What I/O doesn't go through the kernel?
Re:Zero-cost futures in Rust by Matthias247 on Friday August 12, 2016 @05:53AM (#12274355)
For I/O you can buffer inside the application whether the respective file is readable/writeable or not. If it's not readable you can directly switch to another goroutine without invoking a syscall. The scheduler will later get notified by select/epoll that the file is readable/writeable, adjust the buffered status and reschedule the goroutine.

But ok, for reading you might often have a buffered state of readable while in reality it's not and you only get this information through EAGAIN on read, so you won't avoid the syscall there. For writing you most likely always would.

Re:Zero-cost futures in Rust by gpderetta on Thursday August 11, 2016 @06:11PM (#12271995)
For the example if you are using kernel bypass of the network stack, which is increasingly common in high throughput/low latency applications.
Re:Zero-cost futures in Rust by haimez on Thursday August 11, 2016 @10:03PM (#12273003)
If you're going to bypass the kernel network stack for performance, you're definitely not going to write the rest of your code in go. The garbage collector, goroutine scheduler, and conservative compile time optimizations will totally undermine the end goal.

If you're in that world, you're using C, C++, or That if you're feeling dangerous.

Re:Zero-cost futures in Rust by pjmlp on Friday August 12, 2016 @03:02AM (#12273793)
The JVM is used a lot in Fintech.

Of course it isn't the OpenJDK, rather specialized JVMs like Azul or they code using C style coding with the GC out of the out paths, having profiled the applications with tools like Java Mission Control.

These are the customers driving Oracles effort for value types, AOT compilation and JNI replacement.

Why not just use C and C++, one might ask?

In spite of all these tricks and required knowledge, salaries are lower than for C and C++ developers and overall project costs are anyway lower due to shorter development times for the other tools not available in C and C++.

Hence why Fintech nowadays is looking into languages like Pony, because they don't want to wait for Java 10, if possible.

So an area where Rust might eventually earn some friends.

Re:Zero-cost futures in Rust by kasey_junk on Thursday August 11, 2016 @11:01PM (#12273159)
I've done kernel bypass work on the JVM.
Re:Zero-cost futures in Rust by gpderetta on Friday August 12, 2016 @09:37AM (#12275486)
FWIW, I wasn't thinking bout go.
Re:Zero-cost futures in Rust by saosebastiao on Thursday August 11, 2016 @07:23PM (#12272419)
Is anybody doing kernel bypass networking in go?
Re:Zero-cost futures in Rust by tomp on Thursday August 11, 2016 @07:45PM (#12272532)
Couldn't you switch on timeout using some kind of CPU counter, e.g. RDTSC?
Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @08:37PM (#12272774)
Then you're polling the system clock all the time, which is a large unnecessary throughput loss.
Re:Zero-cost futures in Rust by tomp on Friday August 12, 2016 @06:13AM (#12274402)
But that's just one instruction, highly paralelisable (I assume), as opposed to going through the kernel... Anyways, I haven't measured it, it's just an idea I had!
Re:Zero-cost futures in Rust by lightcatcher on Thursday August 11, 2016 @05:31PM (#12271701)
> Why would you write networking code in C in 2016, when there are better alternatives available (like this one)?

Support for kernel bypass networking libraries like ibverbs, DPDK (has an old unmaintained Rust wrapper) and other IO kernel bypass libraries such as SPDK and IOAT.

If Rust supported these libraries, I'd much prefer the future based Rust code to a massive event loop in C.

Re:Zero-cost futures in Rust by benlwalker on Friday August 12, 2016 @03:05AM (#12273807)
I'm one of the authors of SPDK (which includes an NVMe driver and an IOAT driver). If the community wants to add rust bindings to those two components I'd be very supportive.
Re:Zero-cost futures in Rust by JoshTriplett on Thursday August 11, 2016 @05:46PM (#12271812)
The article mentioned that the authors would love to help make futures-based wrappers for C libraries. You might ask if they could help with wrappers for ibverbs, DPDK, SPDK, and IOAT.
Re:Zero-cost futures in Rust by bluejekyll on Thursday August 11, 2016 @06:21PM (#12272058)
It's all open-source, this is an area that if it matters this much to you, you could help support. The Rust community is hugely welcoming to people coming on and helping.
Re:Zero-cost futures in Rust by apendleton on Thursday August 11, 2016 @04:37PM (#12271405)
> In my problem space, M:N threading is simply worth it. And if I need anything better performing, I can still switch to C for specific use cases.

It maybe sounds like you should just use Go, which (as you point out) makes exactly those tradeoffs. I think Rust is aiming for a different market segment, with customers that want to make a different set of tradeoffs. Seems ideal to have both options. In particular, I don't think switching to C will ever be something Rust will want to require of its users.

Re:Zero-cost futures in Rust by steveklabnik on Thursday August 11, 2016 @04:07PM (#12271235)
Well, one of the problems with M:N threading is that the "switch into C for that part" gets a lot more expensive, negating the speed increase.
Re:Zero-cost futures in Rust by serge2k on Thursday August 11, 2016 @08:09PM (#12272653)
> I can still switch to C for specific use cases.

So use go and switch to rust for specific use cases.

Re:Zero-cost futures in Rust by rdtsc on Thursday August 11, 2016 @04:24PM (#12271319)
> sugar over futures down the road to make it easier to write code that looks blocking but actually isn't.

Yes! That is basically what I am after.

Currently using Erlang so having to give up cheap isolated processes and message passing to do concurrency would be hard. But I understand that is a different level of abstraction as well (a VM, multi-machine clusters, etc vs almost raw C speed).

But in general bringing Rust and Erlang together seems like a swell idea. Both are focused on safety, which I like. Been keeping my eye on https://github.com/hansihe/Rustler

Re:Zero-cost futures in Rust by yawaramin on Thursday August 11, 2016 @07:53PM (#12272586)
> ... I would like to see async/await style syntactic sugar over futures down the road to make it easier to write code that looks blocking but actually isn't....

Would a Scala-style 'for' comprehension achieve the same thing while also being more generally applicable? Scala achieves this by using instance methods 'map', 'flatMap' and 'withFilter'. Personally I think Rust should just lift the sugar wholesale :-)

Re:Zero-cost futures in Rust by stshine on Friday August 12, 2016 @02:19AM (#12273675)
Simply comparing M:N threading with futures is not correct. In my experience using futures in Javascript, it does not support control flow at all. The goroutine's equivalent is async/await, which transform the cps of asynchronous I/O back to sync form, but it may impose more overheads than M:N threading since it stores the stack structure in its parameter.
Re:Zero-cost futures in Rust by saynsedit on Thursday August 11, 2016 @03:44PM (#12271074)
Are libmill and Go's approach the same? I.e. Holding concurrent state in multiple stack frames? What causes that to have degraded performance?

Is this new approach different because instead of stack frames you just have dynamically allocated callback state?

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @04:02PM (#12271194)
> Are libmill and Go's approach the same? I.e. Holding concurrent state in multiple stack frames? What causes that to have degraded performance?

In the M:N approach you have to allocate stack space for each goroutine that you spawn. This requires that you either know the size of the stack up front (generally not possible without being conservative and requesting a large allocation) or that you start small and grow (resulting in a lot of memory traffic and pauses in the growth case, and much harder to do in C).

By contrast, with the zero-cost futures approach we statically know exactly how much per-goroutine size we will ever need, and we can allocate precisely that amount. Furthermore, we only save the data that's absolutely needed across blocking calls. This results in much smaller per-connection state, and as a result it's quicker to allocate.

It's the difference between static and dynamic control flow. Full M:N requires us to give up static knowledge of what a goroutine will do and try to do the best we can at runtime. With futures, we have a lot more static knowledge, and as a result we can optimize more aggressively.

Re:Zero-cost futures in Rust by mindslight on Thursday August 11, 2016 @08:30PM (#12272742)
> This requires that you either know the size of the stack up front ... generally not possible without being conservative

Well, you are writing the compiler. Sure you'd be up against the halting problem, but relatively few functions are (non-tail) recursive.

Perhaps the unwieldiness of a large stack is better attributed to the feature of unbounded recursion (and FFI into "uncharted territory") than the feature of green threads.

I appreciate that Rust has already been down the road of lightweight threads. This statement just struck me as an assumption that deserved to be questioned.

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @08:41PM (#12272783)
It would require higher order control flow analysis like k-CFA, which would certainly fail to produce a bounded stack size on any nontrivial program.

The futures library is the control flow analysis. Because it uses the type system instead of higher order control flow analysis, it actually achieves precision.

Re:Zero-cost futures in Rust by DannyBee on Friday August 12, 2016 @02:31PM (#12277759)
"It would require higher order control flow analysis like k-CFA, which would certainly fail to produce a bounded stack size on any nontrivial program."

You can actually do a pretty good job without k-CFA.

First, and i know you know this, when you say "fail to produce a bounded stack size", you really mean "a reasonable bounded stack size".

A bounded stack size of easy, and does not require context sensitive analysis: The stack size is just max sum of stack sizes of of meet over all paths in an acyclic graph :)

The cycles, you either can statically calculate the recurrence count or you can't.

Bounded heap size is pretty much impossible, but stack size is pretty easy.

Recursion is also not hard. You form strongly connected components. You try to prove how often the component is cycled. If you can, victory. If you can't, you can bound it unless it's truly dynamic.

More to the point, here's a paper on doing it with ADA in GCC in 2009 (IE with sticks and fire):

http://www.adacore.com/uploads/technical-papers/Stack_Analys...

Note they are within 2% on most cases, and can detect whether it's statically knowable, bounded, or dynamically changing.

Re:Zero-cost futures in Rust by fmap on Friday August 12, 2016 @10:10AM (#12275749)
Are you sure about that? First, many higher-order constructs boil down to simple first-order control flow after partial evaluation (see e.g. AnyDSL https://anydsl.github.io/#publications). Inferring stack size bounds in the presence of higher-order programming features is also possible, and was implemented (as the "static region optimization") in MLkit.

But the main point is that code in a high-level programming language looks very different from C or even Rust code. Sparks in Haskell, or processes in Erlang, or even individual goroutines in Go, are typically executing comparatively tiny programs. If the call graph of the program in question is acyclic, then it should be easy to get a bound on the maximum stack size.

To be clear, I agree with you that a 1:1 threading model is the better design for Rust, simply because it's the only design where you can guarantee zero overhead and don't need a complicated runtime. What I don't agree with is that the M:N threading model is inherently inferior. Especially for a high-level programming language, I would assume that you can reduce the overhead significantly through static analysis and a good implementation.

Re:Zero-cost futures in Rust by saynsedit on Friday August 12, 2016 @10:30AM (#12275939)
You can't get around page fault blocking with user-space M:N threading. It will be approximate until there is a way to do that.
Re:Zero-cost futures in Rust by mindslight on Thursday August 11, 2016 @09:11PM (#12272867)
I was thinking of a much lighter analysis, based on some optional restrictions. If a function:

- is not recursive

- does not call function pointers (ie trait objects)

- allocates only fixed-sized objects on the stack

- only calls functions with known stack requirements

then its stack requirement should be known, no? It feels like with these requirements, one can still write many programs (threads, really). And if one goes beyond the restrictions, then they just pay the cost of having to guess a large stack size.

Stack size analysis would be helpful for other applications as well, like embedded platforms.

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @11:55PM (#12273310)
No program beyond the most trivial will meet these requirements. The moment you call any function indirectly you lose.
Re:Zero-cost futures in Rust by mindslight on Friday August 12, 2016 @12:04AM (#12273331)
Yes, but indirectly means "&Fn", but not "&F where F: Fn".

And a whole program doesn't need to conform, only individual threads. Presumably the ones you want to make a lot of.

(And if a little dynamicism was required, its expense could be paid for at the use, by creating a fresh necessary-sized stack at that point. But I'm probably opening up old split-stack wounds, sorry)

Re:Zero-cost futures in Rust by jroesch on Friday August 12, 2016 @01:06PM (#12277156)
The problem with an optimization like this is that the current approach always gives you a guarantee on runtime cost. Heuristic based optimizations make performance harder to ensure, not to mention recovering performance when you fall outside the valid subset much more difficult. You can obviously provide another static analysis to warn you about violations, but this seems is more complex, and less flexible then the current approach.
Re:Zero-cost futures in Rust by mindslight on Friday August 12, 2016 @02:29PM (#12277741)
Actually the "current approach" gives you no bound on the stack size. You guess, hope, and test (or do this analysis manually).

While your general objection is good to always keep in mind, it is a tradeoff. There is no perfect solution when you're up against the halting problem (unless you're proposing to change the language to only bounded recursion).

What I'm arguing for here is for more than the single problem the OP is solving, so it's not a case of choosing one or the other and calling it a day.

Re:Zero-cost futures in Rust by Matthias247 on Friday August 12, 2016 @06:09AM (#12274390)
libmill only uses a single kernel thread so it's a little bit simpler here than Go, but otherwise they should be comparable.

Regarding stack vs. dynamically allocated state (in a future) I'm not convinced what's better. Yes, the allocated stack most likely has an overhead. But at least the data will be stored there in linear fashion and accessing the state will be super cheap once the stack is loaded. In case of futures that hold dynamically allocated data the state might be spread over much more memory locations, so it might be slower to access. I however haven't any more scientific data on this.

In my real-world applications I'm getting about the same performance from a Go based and a boost asio (uses no futures but dynamically allocated callback closures for storing state) networking application. However the programming style is completely different.

Re:Zero-cost futures in Rust by saynsedit on Friday August 12, 2016 @10:35AM (#12275985)
With Rust zero cost futures, only one memory allocation is done for the entire chain of futures. It's not doing an allocation for every callback.

This makes it comparable to using a stack. In an M:N solution, the stack is usually (but not always) allocated similarly (e.g. using malloc).

Re:Zero-cost futures in Rust by ngrilly on Saturday August 13, 2016 @02:00PM (#12282357)
> With that approach, we'd have the ergonomics of languages like Erlang and Go without the significant performance tax associated with M:N.

Can you quantify the "performance tax associated with M:N"?

Re:Zero-cost futures in Rust by Thaxll on Thursday August 11, 2016 @04:40PM (#12271415)
What is the "significant performance tax" in Go? Do you have any numbers about this implementation?

When I look at the benchmark of your minihttp vs Go fasthttp, Rust is supposed to be 3x time faster without any GC and yet minihttp pulls 2M req/sec VS 1.5 for Go which is a small margin when you know how Go works and is GC.

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @04:48PM (#12271446)
> What is the "significant performance tax" in Go?

I explain in this sibling comment: https://news.ycombinator.com/item?id=12271194

> Do you have any numbers about this implementation?

See the blog post.

Re:Zero-cost futures in Rust by Thaxll on Thursday August 11, 2016 @04:55PM (#12271476)
I did edit my first question after seeing the numbers.
Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @05:07PM (#12271536)
Arguing about whether a 30% difference is "significant" isn't really interesting.
Re:Zero-cost futures in Rust by Thaxll on Thursday August 11, 2016 @05:46PM (#12271811)
You're talking about using a language where you have to manually manage the memory, is significantly harder to use than Go, have less built-in concurrent patterns, inferior standard library, so yes 30% seems a very small benefit.

I didn't had look into the benchmark but my guess is that it's waiting on the I/O so any language with good concurrent model will have the same numbers.

The benchmark would have been more interesting if it was more CPU intensive, that would have definitely favored Rust.

it's not about Rust Vs Go, it's just that 30% seems very low when you know how fast Rust is vs Go in some scenarios.

Re:Zero-cost futures in Rust by pcwalton on Thursday August 11, 2016 @05:50PM (#12271846)
> You're talking about using a language where you have to manually manage the memory, is significantly harder to use than Go, have less built-in concurrent patterns, inferior standard library so yes 30% seems a very small as a benefit.

Naturally I disagree with all of those items, but I'm also equally uninterested in starting a Rust vs. Go war.

Re:Zero-cost futures in Rust by stuartd on Thursday August 11, 2016 @04:12PM (#12271268)
> ergonomics of languages like Erlang and Go

My brain read that as "ergolangmics"