These are chat archives for rust-lang/rust

22nd
Dec 2017
Michal 'vorner' Vaner
@vorner
Dec 22 2017 08:26
Good morning. I know Rust doesn't have exceptions and I myself believe it was a good decision. But I believe there must have been some conscious and well-though decision why they are not included. Is that reason written down somewhere, as an explanation? I couldn't find it.
Aleksey Kladov
@matklad
Dec 22 2017 08:43
@vorner looks like Result + non-recoverable unwinding was in the language from the start http://venge.net/graydon/talks/intro-talk-2.pdf (slice 15)
Also I am almost sure you've see this link, but it's so good I can't resist posting it :) http://joeduffyblog.com/2016/02/07/the-error-model/
Michal 'vorner' Vaner
@vorner
Dec 22 2017 08:53
I probably did, but I don't remember the details, maybe time to read it again
Alkis Evlogimenos
@alkis
Dec 22 2017 20:28
is there some documentation/story on why rust's green threads failed, what was tried, what worked, what didn't work, etc?
The fundamental reason is that green threading is incompatible with zero-overhead philosophy: you'll have to pay the price for the user-space scheduler and do some non-trivial wrapping when calling into C code.
Alkis Evlogimenos
@alkis
Dec 22 2017 20:38
THanks Andrey and Aleksey, reading now.
Alkis Evlogimenos
@alkis
Dec 22 2017 20:46
and I see @vorner is hacking on corona. What's the status of that? :-)
Michal 'vorner' Vaner
@vorner
Dec 22 2017 20:48
I think it is in a workable state. I didn't do much about it lately, but I also don't see any big things to improve ‒ at least not until someone else tries to use it. Like, there's always the documentation to improve, write more examples, but this wasn't exactly high on the agenda.
It can do some nice things that futures-async can't. Like wait for futures that contain non-'static data, or iterate over borrowed streams.
Alkis Evlogimenos
@alkis
Dec 22 2017 20:50
Yes I saw the examples, they definitely look a lot nicer than futures-async.
Michal 'vorner' Vaner
@vorner
Dec 22 2017 20:53
And it works on stable. The downside is you can't move the coroutines between threads, it needs to allocate a stack for each and it likely won't work on all the targets rustc can compile for.
But if you have ideas what to improve, please, open issues or something :-)
Alkis Evlogimenos
@alkis
Dec 22 2017 20:56
I am reading a lot about coros, work stealing, etc. So far my understanding is: Cilk++ fork-join is really nice when it fits what you want to do. It has some limitations 1) can't express a DAG of computation, just a tree and 2) it doesn't compose well (cilk functions are different than normal functions). The problems seem to be the same as libgreen: keeping stuff alive across coro calls, in other words, making stack frames for each coro gets expensive and the costs outweight the benefits.
Aleksey Kladov
@matklad
Dec 22 2017 20:58
@alkis there's also this interesting perspective that the whole M:N idea is basically a hack to work around the lack of cooperative multithreading support in modern OSes. See this twitter thread and presentation: https://twitter.com/pcwalton/status/877674915863814144 https://www.youtube.com/watch?v=KXuZi9aeGTw
Alkis Evlogimenos
@alkis
Dec 22 2017 21:00
Also I went through the generators implementation in rust (what async/await builds on): if I understood it correctly it does not use llvm's intrinsics for coros so it can't make new stacks at all. Also resuming generators is not like resuming a coro but more like calling a stateful function (going into a switch and figuring out where to jump to at runtime). Is that correct?
@matklad giong to watch that.
Michal 'vorner' Vaner
@vorner
Dec 22 2017 21:01
@alkis Generators are just richer closures that can get suspended and then continue from the same place, instead of running from the beginning again. They don't have their own stacks.
Alkis Evlogimenos
@alkis
Dec 22 2017 21:03
@vorner do they actually suspend? To me suspend means I save the context and return a value along with a pc and resume is restore context and jump to that address. IIRC this is not what generators are in rust right now.
Michal 'vorner' Vaner
@vorner
Dec 22 2017 21:04
The idea in corona is to make it friendly to use, but not necessarily suitable for high number of the coroutines. If you want to do a little of network communication, but the bottleneck lies somewhere else, you don't need to coordinate threads so much (it's often easier with just async stuff, like futures) ‒ and corona plays well with futures.
Well, it's stack-less coroutine. So only the top-most coroutine is suspended, not the frames under it.
They carry the relevant context and local variables in a hidden struct, like a closure does (well, closure doesn't store the locals). Or, that's how I understand them from some explanation on the web, and that works as a mental model for me.
Alkis Evlogimenos
@alkis
Dec 22 2017 21:06
Also they do a match (suspension point) { ... } on every entry
and decide which "state" they are in, and use the hidden struct for that state and continue
so on every resume they go through dispatch -> hardly zero cost :-)
Denis Lisov
@tanriol
Dec 22 2017 21:10
I'd guess this dispatch may be cheaper that restoring a full set of registers...
Alkis Evlogimenos
@alkis
Dec 22 2017 21:11
depends how big the stuff is inside the "coro"
Now, back on the topic of coro stacks, I was thinking that one could stitch together stacks using both the frame pointer and the stack pointer and after some googling, it looks like someone already did: http://chaoran.me/assets/pdf/ws-spaa16.pdf. What is really nice about this approach is that it composes coros and normal functions seamlessly and you only pay overhead when you have coros.
Do you know if anyone tried something similar with rust green threads?
Michal 'vorner' Vaner
@vorner
Dec 22 2017 21:14
Why would it depend on the size of the coroutine? I think the compiler will optimise not to take the variables out of the structure, place it on stack and then return it… it'd just access them directly inside the structure.
Alkis Evlogimenos
@alkis
Dec 22 2017 21:20
Assume a coro with 1000 states: would it be faster to jump to the right place through a pointer or going through a jump table?
Michal 'vorner' Vaner
@vorner
Dec 22 2017 21:22
Ah, so you mean size in number of states, not how many or large local variables are. I guess a jump table. But having a function this big will probably already slow things down anyway, I guess. And it still might be cheaper than the function call itself ‒ but that'd have to be measured and I think this is really one of these small costs you almost never have to care about.
Alkis Evlogimenos
@alkis
Dec 22 2017 21:23
Depends on how pervasively you use coros :-). In a world where coros are super cheap I can see implementing a looot of things on top of them
@matklad ok this talk is about google fibers and how great they are :-). I can tell you from experience that they are a huge improvement to the status quo but they still have a lot to be desired.
Aleksey Kladov
@matklad
Dec 22 2017 21:31
@alkis were they actually shipped anywhere? I haven't seen any information about cooperative usermode scheduling in Linux more modern than then presentation.
Alkis Evlogimenos
@alkis
Dec 22 2017 21:32
No they are not open source.
Alkis Evlogimenos
@alkis
Dec 22 2017 21:43
@vorner when coros resume through indirect jumps the size of functions becomes less relevant. Imagine this function was generated because we called a ton resumable functions (and composed them together). Every time we yield pass a continuation and when we resume we jump back exactly where we left. So if for example the top level coro is an HTML parser, only few parts of the huge function body will be hot. We will be threading through the huge function much like a threaded interpreter.
Denis Lisov
@tanriol
Dec 22 2017 21:49
Does this actually conflict with the switch?
Alkis Evlogimenos
@alkis
Dec 22 2017 21:53
@tanriol what do you mean conflict?
Denis Lisov
@tanriol
Dec 22 2017 21:54
If you have a PC, you can just jump to it. If you have a resume point index, I'd assume, you can just load the target PC from some table and jump to it, no?
Alkis Evlogimenos
@alkis
Dec 22 2017 21:56
Isn't that twice the work?
Alkis Evlogimenos
@alkis
Dec 22 2017 22:03
When the coros are doing I/O this won't matter. But if they are used to express computation and you start using them everywhere this could easily be large overhead. Another advantage of resuming through a PC is that the wait queues become cheaper to implement (at least this is what Cilk devs say about it) because you need just 2 pointers to store a resumption point.