On Tuesday, January 06, 2015 09:13:57 Niall Douglas wrote:
On 5 Jan 2015 at 12:49, Thomas Heller wrote:
I don't think it's that easy because really it comes down to commonality of kernel wait object, or rather, whether one has access to the true underlying kernel wait object or not.
You make the assumption that you only ever synchronize on kernel space objects. This is not at all required nor necessary.
I make the assumption that one _eventually_ synchronises on kernel wait objects, and I also assume that you usually need the ability to fall back onto a kernel wait in most potential wait scenarios (e.g. if no coroutine work is pending, and there is nothing better to do but sleep now). One could I suppose simply call yield() all the time, but that is battery murder for portable devices.
That's, IMHO, a implementation detail of one specific future island, or to be more precise of the way the tasks are scheduled. This has nothing to do how you suspend a user level task, for example.
What is missing on POSIX is a portable universal kernel wait object used by everything in the system. It is correct to claim you can easily roll your own with a condition variable and an atomic, the problem comes in when one library (e.g. OpenCL) has one kernel wait object and another library has a slightly different one, and the two cannot be readily composed into a single wait_for_all() or wait_for_any() which accepts all wait object types, including non-kernel wait object types.
Exactly, this could be easily achieved by defining an appropriate API for the shared state of asynchronous operations, the wait functions would then just use the async result objects, which in turn use to wait the functionality as implemented in the shared state. A portable, universal kernel wait object is not really necessary for that. Not everyone wants to pay for the cost of a kernel transition. This is an implementation detail of a specific future island, IMHO. Aside from that, i don't want to limit myself to POSIX. <snip>
On 5 Jan 2015 at 13:49, Thomas Heller wrote:
No it isn't. Current futures require the compiler to generate the code for handling exception throws irrespective of whether it could ever happen or not. As a relative weight to something like a SHA round which is fundamentally noexcept, this isn't a trivial overhead especially when it's completely unnecessary.
Ok. Hands down: What's the associated overhead you are talking about? Do you have exact numbers?
I gave you exact numbers: a 13% overhead for a SHA256 round.
To quote your earlier mail: "The best I could get it to is 17 cycles a byte, with the scheduling (mostly future setup and teardown) consuming 2 cycles a byte, or a 13% overhead which I feel is unacceptable." So which of these "mostly future setup and teardown" is related to exception handling? Please read http://www.open-std.org/Jtc1/sc22/wg21/docs/TR18015.pdf from page 32 onwards. I was under the impression that we left the "exceptions are slow" discussion way behind us :/ <snip>
1. Release BindLib based AFIO to stable branch (ETA: end of January). 2. Get BindLib up to Boost quality, and submit for Boost review (ETA: March/April). Just a minor very unrelated remark. I find the name "BindLib" very confusing.
<snip>
I might add that BindLib lets the library end user choose what kind of future the external API of the library uses. Indeed BindLib based AFIO lets you choose between std::future and boost::future, and moreover you can use both configurations of AFIO in the same translation unit and it "just works". I could very easily - almost trivially - add support for a hpx::future in there, though AFIO by design needs kernel threads because it's the only way of generating parallelism in non-microkernel operating system kernels (indeed, the whole point of AFIO is to abstract that detail away for end users).
*shiver* I wouldn't want to maintain such a library. This sounds very dangerous and limiting. Note that both boost::future and hpx::future are far more capable than the current std::future with different performance characteristics.