1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
10
11 #define BOOST_TEST_MODULE TestEvent
12 #include <boost/test/unit_test.hpp>
13
14 #include <vector>
15
16 #ifdef BOOST_COMPUTE_USE_CPP11
17 #include <mutex>
18 #include <future>
19 #endif // BOOST_COMPUTE_USE_CPP11
20
21 #include <boost/compute/async/future.hpp>
22 #include <boost/compute/event.hpp>
23
24 #include "context_setup.hpp"
25
BOOST_AUTO_TEST_CASE(null_event)26 BOOST_AUTO_TEST_CASE(null_event)
27 {
28 boost::compute::event null;
29 BOOST_CHECK(null.get() == cl_event());
30 }
31
32 #if defined(BOOST_COMPUTE_CL_VERSION_1_1) && defined(BOOST_COMPUTE_USE_CPP11)
33 std::mutex callback_mutex;
34 std::condition_variable callback_condition_variable;
35 static bool callback_invoked = false;
36
37 static void BOOST_COMPUTE_CL_CALLBACK
callback(cl_event event,cl_int status,void * user_data)38 callback(cl_event event, cl_int status, void *user_data)
39 {
40 std::lock_guard<std::mutex> lock(callback_mutex);
41 callback_invoked = true;
42 callback_condition_variable.notify_one();
43 }
44
BOOST_AUTO_TEST_CASE(event_callback)45 BOOST_AUTO_TEST_CASE(event_callback)
46 {
47 REQUIRES_OPENCL_VERSION(1,2);
48
49 // ensure callback has not yet been executed
50 BOOST_CHECK_EQUAL(callback_invoked, false);
51
52 // enqueue marker and set callback to be invoked
53 boost::compute::event marker = queue.enqueue_marker();
54 marker.set_callback(callback);
55 marker.wait();
56
57 // wait up to one second for the callback to be executed
58 std::unique_lock<std::mutex> lock(callback_mutex);
59 callback_condition_variable.wait_for(
60 lock, std::chrono::seconds(1), [&](){ return callback_invoked; }
61 );
62
63 // ensure callback has been executed
64 BOOST_CHECK_EQUAL(callback_invoked, true);
65 }
66
BOOST_AUTO_TEST_CASE(lambda_callback)67 BOOST_AUTO_TEST_CASE(lambda_callback)
68 {
69 REQUIRES_OPENCL_VERSION(1,2);
70
71 bool lambda_invoked = false;
72
73 boost::compute::event marker = queue.enqueue_marker();
74 marker.set_callback([&](){
75 std::lock_guard<std::mutex> lock(callback_mutex);
76 lambda_invoked = true;
77 callback_condition_variable.notify_one();
78 });
79 marker.wait();
80
81 // wait up to one second for the callback to be executed
82 std::unique_lock<std::mutex> lock(callback_mutex);
83 callback_condition_variable.wait_for(
84 lock, std::chrono::seconds(1), [&](){ return lambda_invoked; }
85 );
86 BOOST_CHECK_EQUAL(lambda_invoked, true);
87 }
88
BOOST_AUTO_TEST_CASE(future_then_callback)89 BOOST_AUTO_TEST_CASE(future_then_callback)
90 {
91 REQUIRES_OPENCL_VERSION(1,2);
92
93 bool callback_invoked = false;
94
95 boost::compute::future<void> future(queue.enqueue_marker());
96 future.then([&](){
97 std::lock_guard<std::mutex> lock(callback_mutex);
98 callback_invoked = true;
99 callback_condition_variable.notify_one();
100 });
101 future.wait();
102
103 // wait up to one second for the callback to be executed
104 std::unique_lock<std::mutex> lock(callback_mutex);
105 callback_condition_variable.wait_for(
106 lock, std::chrono::seconds(1), [&](){ return callback_invoked; }
107 );
108 BOOST_CHECK_EQUAL(callback_invoked, true);
109 }
110
111 void BOOST_COMPUTE_CL_CALLBACK
event_promise_fulfiller_callback(cl_event event,cl_int status,void * user_data)112 event_promise_fulfiller_callback(cl_event event, cl_int status, void *user_data)
113 {
114 auto *promise = static_cast<std::promise<void> *>(user_data);
115 promise->set_value();
116 delete promise;
117 }
118
BOOST_AUTO_TEST_CASE(event_to_std_future)119 BOOST_AUTO_TEST_CASE(event_to_std_future)
120 {
121 REQUIRES_OPENCL_VERSION(1,2);
122
123 // enqueue an asynchronous copy to the device
124 std::vector<float> vector(1000, 3.14f);
125 boost::compute::buffer buffer(context, 1000 * sizeof(float));
126 auto event = queue.enqueue_write_buffer_async(
127 buffer, 0, 1000 * sizeof(float), vector.data()
128 );
129
130 // create a promise and future to be set by the callback
131 auto *promise = new std::promise<void>;
132 std::future<void> future = promise->get_future();
133 event.set_callback(event_promise_fulfiller_callback, CL_COMPLETE, promise);
134
135 // ensure commands are submitted to the device before waiting
136 queue.flush();
137
138 // wait for future to become ready
139 future.wait();
140 }
141 #endif // BOOST_COMPUTE_CL_VERSION_1_1
142
143 BOOST_AUTO_TEST_SUITE_END()
144