Boost logo

Boost :

Subject: Re: [boost] [compute] Some remarks
From: Hartmut Kaiser (hartmut.kaiser_at_[hidden])
Date: 2015-01-03 08:15:50


> Thomas Heller <thom.heller <at> gmail.com> writes:
>
> > Well, that's exactly what I am trying to say ... The current design of
> the
> > library completely disregards the research that has been done to support
> > asynchronous operations. We have std::future (which is almost equivalent
> to a
> > OpenCL event), why not use the same mechanisms here?

First of all, I fully support Thomas here. Futures (and the extensions
proposed in the 'Concurrency TS') are a wonderful concept allowing
asynchronous computation. Those go beyond 'classical' futures, which just
represent a result which has not computed yet. These futures allow for
continuation style coding as you can attach continuations and compose new
futures based on logical operations on others.

> This is something Joel tries to convince me of but I'm resisting. Could
> you
> shed some light on how events are almost equivalent to futures? Futures
> store the result of the asynchronous computation. Events are markers that
> can be queried to find out an operation finished and can be blocked on
> until
> an operation is finished. The data however is stored somewhere else.
> Futures
> are in this sense safer abstractions as they prevent users from accessing
> results that are not yet finished. That is my understanding of futures, I
> might be wrong here, please correct me if I am.
>
> So I consider futures and events orthogonal concepts. One can be, with
> some
> effort and loss of expressiveness, changed to the other concept and vice
> versa. But I'm not sure if the code makes sense after the change. Consider
> these examples:
>
> future<void> f = copy_async(src, dst);
> fill_async(dst, 42.);
>
> This does not work, a dependency or dataflow graph has to be created
> between
> copy and fill, so:
>
> future<void> f = copy_async(src, dst);
> fill_async(dst, 42., f);

What about:

    future<void> f = copy_async(src, dst);
    f.then([](future<void>&& f) { fill_async(dst, 42.); })

or (assuming await will be available, which almost all of the committee
thinks is something we need):

    await copy_async(src, dst);
    fill_async(dst, 42.);

i.e. the code looks 'normal' but is fully asynchronous thanks to await and
futures.

> But that is not a future, that is an event. How to write this with
> futures?
>
> I think it should be this but I might be wrong:
>
> future<dst::iterator> f = copy_async(src, dst);
> fill_async(f, 42);

You're right that an event is separating the fact that data is available
from the data itself. Well, the opencl guys decided that this is the right
way of doing things. I really hope that we know better. Just because the
underlying opencl API exposes the trigger and the data separately does not
imply that we have to do the same thing in the API exposed from our
libraries. At the same time and as you already mentioned, future<void> is
perfectly well usable for representing even this use case.

> Is this correct? Now everything is a future, is it not? Another
> alternative
> is to hide futures in the containers/ranges/iterators and let the do the
> right thing implicitly. This is what NT2 [0] does afaik.

Joel adopted this in NT2 based on ideas from HPX [1], btw.

> In my library [1] I have feed (equivalent to command_queues) and mark
> (equivalent to events) types so I can write code like this:
>
> device d(0);
> feed f1(d);
> feed f2(d);
> mark m1(f1);
> mark m2(f2);
> wait_for(m1); // block calling thread
> f1.continue_when(m2); // block feed until other feed reached mark
>
> and I'm trying to get rid of this and use futures. But it makes no sense
> without making everything a future.

What do you mean by 'making everything a future'? Having all functions
return futures? If so - then yes - if you want to make a function
asynchronously callable, let it return a future. There is nothing wrong with
that (well, except that std::future is utterly bulky and slow as it is
usually tied to std::sthread which in turn is usually representing kernel
threads - for a proposed solution see my talk at MeetingC++ 2014 [2]).

[1] https://github.com/STEllAR-GROUP/hpx
[2] https://www.youtube.com/watch?v=4OCUEgSNIAY

Regards Hartmut
---------------
http://boost-spirit.com
http://stellar.cct.lsu.edu


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk