diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d99f98bae..27aafa5af 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -64,6 +64,7 @@ add_vexcl_test(reduce_by_key reduce_by_key.cpp) add_vexcl_test(logical logical.cpp) add_vexcl_test(threads threads.cpp) add_vexcl_test(svm svm.cpp) +add_vexcl_test(events events.cpp) add_vexcl_test(multiple_objects "dummy1.cpp;dummy2.cpp") if (NOT DEFINED ENV{APPVEYOR}) diff --git a/tests/events.cpp b/tests/events.cpp new file mode 100644 index 000000000..ffa43f1cd --- /dev/null +++ b/tests/events.cpp @@ -0,0 +1,29 @@ +#define BOOST_TEST_MODULE Let +#include +#include +#include +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(let_vector_expr) +{ + const size_t n = 16 * 1024; + + std::vector q1(1, ctx.queue(0)); + std::vector q2(1, vex::backend::duplicate_queue(ctx.queue(0))); + + vex::vector x(q1, n); + vex::vector y(q2, n); + + vex::Reductor count(q2); + + x = 1; + q1[0].finish(); + + x = 2; + y = x; + + BOOST_CHECK_EQUAL(count(y != 2), 0); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/vexcl/backend/compute.hpp b/vexcl/backend/compute.hpp index e783b921b..b2cf0d7b3 100644 --- a/vexcl/backend/compute.hpp +++ b/vexcl/backend/compute.hpp @@ -55,5 +55,6 @@ namespace vex { #include #include +#include #endif diff --git a/vexcl/backend/compute/event.hpp b/vexcl/backend/compute/event.hpp new file mode 100644 index 000000000..4afd8943d --- /dev/null +++ b/vexcl/backend/compute/event.hpp @@ -0,0 +1,123 @@ +#ifndef VEXCL_BACKEND_COMPUTE_EVENT_HPP +#define VEXCL_BACKEND_COMPUTE_EVENT_HPP + +/* +The MIT License + +Copyright (c) 2012-2016 Denis Demidov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** + * \file vexcl/backend/compute/event.hpp + * \author Denis Demidov + * \brief Bring Boost.Compute events into vex::backend::compute namespace. + */ + +#include +#include + +namespace vex { +namespace backend { +namespace compute { + +using boost::compute::event; +using boost::compute::wait_list; + +/// Append event to wait list +inline void wait_list_append(wait_list &dst, const event &e) { + dst.insert(e); +} + +/// Append wait list to wait list +inline void wait_list_append(wait_list &dst, const wait_list &src) { + for(size_t i = 0; i < src.size(); ++i) + dst.insert(src[i]); +} + +/// Get id of the context the event was submitted into +inline context_id get_context_id(const event &e) { + return e.get_info(); +} + +/// Enqueue marker (with wait list) into the queue +inline event enqueue_marker(command_queue &q, + const wait_list &events = wait_list()) +{ + event e; + +#ifdef CL_VERSION_1_2 + if(q.get_device().check_version(1, 2)) { + context_id ctx = get_context_id(q); + wait_list my_events; + + std::copy_if(events.begin(), events.end(), + std::back_inserter(my_events), + [=](const event &e){ return ctx == get_context_id(e); }); + + e = q.enqueue_marker(my_events); + } else +#else + e = q.enqueue_marker(); +#endif + return e; +} + +/// Enqueue barrier (with wait list) into the queue +inline event enqueue_barrier(command_queue &q, + const wait_list &events = wait_list()) +{ + event e; + +#ifdef CL_VERSION_1_2 + if(q.get_device().check_version(1, 2)) { + context_id ctx = get_context_id(q); + wait_list my_events; + + std::copy_if(events.begin(), events.end(), + std::back_inserter(my_events), + [=](const event &e){ return ctx == get_context_id(e); }); + + e = q.enqueue_barrier(my_events); + } else +#else + e = q.enqueue_barrier(); +#endif + return e; +} + +/// Wait for events in the list +inline void wait_for_events(const wait_list &events) { + std::map by_context; + + for(auto e = events.begin(); e != events.end(); ++e) { + context_id ctx = get_context_id(*e); + by_context[ctx].insert(*e); + } + + for(auto c = by_context.begin(); c != by_context.end(); ++c) + c->second.wait(); +} + +} // namespace compute +} // namespace backend +} // namespace vex + +#endif diff --git a/vexcl/backend/cuda.hpp b/vexcl/backend/cuda.hpp index 856bd747e..3cafd603e 100644 --- a/vexcl/backend/cuda.hpp +++ b/vexcl/backend/cuda.hpp @@ -44,5 +44,6 @@ THE SOFTWARE. #include #include #include +#include #endif diff --git a/vexcl/backend/cuda/event.hpp b/vexcl/backend/cuda/event.hpp new file mode 100644 index 000000000..344a22299 --- /dev/null +++ b/vexcl/backend/cuda/event.hpp @@ -0,0 +1,131 @@ +#ifndef VEXCL_BACKEND_CUDA_EVENT_HPP +#define VEXCL_BACKEND_CUDA_EVENT_HPP + +/* +The MIT License + +Copyright (c) 2012-2016 Denis Demidov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** + * \file vexcl/backend/compute/event.hpp + * \author Denis Demidov + * \brief Bring Boost.Compute events into vex::backend::compute namespace. + */ + +#include + +namespace vex { +namespace backend { +namespace cuda { + +namespace detail { + +template <> +struct deleter_impl { + static void dispose(CUevent e) { + cuda_check( cuEventDestroy(e) ); + } +}; + +} // namespace detail + +class event { + public: + event(const command_queue &q) + : q(q), e( create(q), detail::deleter(q.context().raw()) ) { } + + CUevent raw() const { return e.get(); } + + operator CUevent() const { return e.get(); } + + void wait() const { + cuda_check( cuStreamWaitEvent(q.raw(), e.get(), 0) ); + } + + vex::backend::context context() const { + return q.context(); + } + private: + context c; + command_queue q; + std::shared_ptr::type> e; + + static CUevent create(const command_queue &q) { + CUevent e; + q.context().set_current(); + + cuda_check( cuEventCreate(&e, CU_EVENT_DEFAULT) ); + cuda_check( cuEventRecord(e, q.raw()) ); + + return e; + } +}; + +typedef std::vector wait_list; + +/// Append event to wait list +inline void wait_list_append(wait_list &dst, const event &e) { + dst.push_back(e); +} + +/// Append wait list to wait list +inline void wait_list_append(wait_list &dst, const wait_list &src) { + dst.insert(dst.begin(), src.begin(), src.end()); +} + +/// Get id of the context the event was submitted into +inline context_id get_context_id(const event &e) { + return e.context().raw(); +} + +/// Enqueue marker (with wait list) into the queue +inline event enqueue_marker(const command_queue &q, const wait_list &events = wait_list()) { + context_id ctx = q.context().raw(); + + q.context().set_current(); + + for(auto e = events.begin(); e != events.end(); ++e) + if (get_context_id(*e) == ctx) + cuda_check( cuEventSynchronize(e->raw()) ); + + return event(q); +} + +/// Enqueue barrier (with wait list) into the queue +inline event enqueue_barrier(command_queue &q, + const wait_list &events = wait_list()) +{ + return enqueue_marker(q, events); +} + +/// Wait for events in the list +inline void wait_for_events(const wait_list &events) { + for(auto e = events.begin(); e != events.end(); ++e) + e->wait(); +} + +} // namespace cuda +} // namespace backend +} // namespace vex + + +#endif diff --git a/vexcl/backend/opencl.hpp b/vexcl/backend/opencl.hpp index e1fdd1707..90f61993b 100644 --- a/vexcl/backend/opencl.hpp +++ b/vexcl/backend/opencl.hpp @@ -45,5 +45,6 @@ THE SOFTWARE. #include #include #include +#include #endif diff --git a/vexcl/backend/opencl/event.hpp b/vexcl/backend/opencl/event.hpp new file mode 100644 index 000000000..b145c3974 --- /dev/null +++ b/vexcl/backend/opencl/event.hpp @@ -0,0 +1,126 @@ +#ifndef VEXCL_BACKEND_OPENCL_EVENT_HPP +#define VEXCL_BACKEND_OPENCL_EVENT_HPP + +/* +The MIT License + +Copyright (c) 2012-2016 Denis Demidov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** + * \file vexcl/backend/opencl/event.hpp + * \author Denis Demidov + * \brief Bring OpenCL events into vex::backend::opencl namespace. + */ + +#include + +#include +#include + +#include + +namespace vex { +namespace backend { +namespace opencl { + +typedef cl::Event event; +typedef std::vector wait_list; + +/// Append event to wait list +inline void wait_list_append(wait_list &dst, const event &e) { + dst.push_back(e); +} + +/// Append wait list to wait list +inline void wait_list_append(wait_list &dst, const wait_list &src) { + dst.insert(dst.begin(), src.begin(), src.end()); +} + +/// Get id of the context the event was submitted into +inline context_id get_context_id(const event &e) { + return e.getInfo()(); +} + +/// Enqueue marker (with wait list) into the queue +inline event enqueue_marker(command_queue &q, + const wait_list &events = wait_list()) +{ + event e; + +#ifdef CL_VERSION_1_2 + if ( Filter::CLVersion(1,2)( q.getInfo() ) ) { + context_id ctx = get_context_id(q); + wait_list my_events; + + std::copy_if(events.begin(), events.end(), + std::back_inserter(my_events), + [=](const event &e){ return ctx == get_context_id(e); }); + + q.enqueueMarkerWithWaitList(&my_events, &e); + } else +#else + q.enqueueMarker(&e); +#endif + return e; +} + +/// Enqueue barrier (with wait list) into the queue +inline event enqueue_barrier(command_queue &q, + const wait_list &events = wait_list()) +{ + event e; + +#ifdef CL_VERSION_1_2 + if ( Filter::CLVersion(1,2)( q.getInfo() ) ) { + context_id ctx = get_context_id(q); + wait_list my_events; + + std::copy_if(events.begin(), events.end(), + std::back_inserter(my_events), + [=](const event &e){ return ctx == get_context_id(e); }); + + q.enqueueBarrierWithWaitList(&my_events, &e); + } else +#else + q.enqueueBarrier(&e); +#endif + return e; +} + +/// Wait for events in the list +inline void wait_for_events(const wait_list &events) { + std::map by_context; + + for(auto e = events.begin(); e != events.end(); ++e) { + context_id ctx = get_context_id(*e); + by_context[ctx].push_back(*e); + } + + for(auto c = by_context.begin(); c != by_context.end(); ++c) + cl::Event::waitForEvents(c->second); +} + +} // namespace opencl +} // namespace backend +} // namespace vex + +#endif