On Sun, Dec 21, 2014 at 5:33 PM, Niall Douglas
On 21 Dec 2014 at 11:39, Kyle Lutz wrote:
Yes, I've split the blocking and non-blocking memory copy operations into separate functions. Personally, I've never been fond of APIs which drastically change behavior based on a single boolean flag. Also, this is more in line with the API provided by other libraries like Boost.ASIO (e.g. boost::asio::read() vs. boost::asio::async_read()).
I'll also definitely work on improving the documentation for these functions.
b) why your version lacks the last event argument entirely, I have no idea. Anything that can be done with it in the C / C++ API (e.g. OpenCL runtime-level profiling; controlling an out-of-order command-queue / another commmand-queue) seems to be undoable.
My main motivation for returning "void" was to prevent users from attempting to build asynchronous pipelines but accidentally using an event object returned from a synchronous API function causing the whole thing to become synchronous. But I see your point that there may be legitimate uses for event objects associated with synchronous operations. It should be relatively easy to update these APIs (return void -> return event). I'll look into this.
c) error handling: I'd much prefer some policy setting which specifies if an exception is thrown on error (the usual custom in C++) or an error code is returned by the function (the usual OpenCL behaviour).
I won't have the time to contribute a review as I am in the rural United States until the 29th.But I will say this: if your library is sufficiently header implemented, I'd look into the async_result infrastructure used by ASIO.
I'd be very interested in hearing your feedback, even if it is after the formal review period. And I also looked into trying to integrate Boost.Compute with ASIO a while back but didn't make much progress. From what I could tell, it seemed like asynchronous operations are handled via file descriptors (which I guess is required to pass them to select()/epoll()) which doesn't match up with what the OpenCL API makes available (essentially a blocking wait() API or a callback-based API). However, I'm not nearly as knowledgeable about ASIO internals as I'd like to be, any pointers/examples/guidance in this area would be very helpful (I'll definitely look into the async_result infrastructure that you mentioned).
Using async_result lets the caller of your API specify how that API should (a) be async or sync (b) how to return errors (exception or code or anything else) (c) if async, then what kind of operation token object (e.g. a std::future, a boost::future, a compute::future) to return. You'd probably still provide sync versions of APIs for convenience, but these would simply thunk into the async API with the appropriate async_result inputs.
If your library isn't sufficiently header implemented (like AFIO which maintains a stable ABI in addition to API, and therefore async_result cannot pass through that ABI), then if you can wait until summer 2015 I should have my non-allocating basic_future infrastructure working for AFIO. This more generic future mash up toolkit lets you roll futures which return error codes rather than exceptions (thanks to expected
, you simply supply error_code as type E). They should perfectly close the gap between the flexibility of ASIO's async_result and futures and the functional programming idioms of Hana and Expected in an ABI stable solution.
Very interesting. I'll keep my eye on this. Thanks! -kyle