This tutorial shows how to use ViennaCL with multiple threads, one thread per GPU. The use of one thread per context (host, CUDA, OpenCL) is supported. However, using more than one thread per context is not fully covered by the OpenCL standard. It is, however, perfectly fine to use multiple OpenCL contexts simultaneously, each using one thread.
We start with including the necessary headers:
#ifndef VIENNACL_WITH_OPENCL
#define VIENNACL_WITH_OPENCL
#endif
#include <iostream>
#include <boost/thread.hpp>
Each thread runs a separate task, for which we provide the following functor. For each thread, vector operations and a vector norm gets computed.
template<typename NumericT>
class worker
{
public:
worker(std::size_t tid) : thread_id_(tid) {}
void operator()()
{
std::size_t N = 6;
u += v;
std::stringstream ss;
ss <<
"Result of thread " << thread_id_ <<
" on device " <<
viennacl::ocl::get_context(static_cast<long>(thread_id_)).
devices()[0].name() <<
": " << result << std::endl;
ss << " A: " << A << std::endl;
ss << " x: " << x << std::endl;
message_ = ss.str();
}
std::string message() const { return message_; }
private:
std::string message_;
std::size_t thread_id_;
};
In the main routine we create two OpenCL contexts and then use one thread per context to run the operations in the functor defined above.
{
{
std::cerr << "Error: No platform found!" << std::endl;
return EXIT_FAILURE;
}
Part 1: Setup first device for first context, second device for second context:
std::vector<viennacl::ocl::device>
const & devices = pf.
devices();
if (devices.size() > 1)
else
Part 2: Now let two threads operate on two GPUs in parallel.
worker<ScalarType> work_functor0(0);
worker<ScalarType> work_functor1(1);
boost::thread worker_thread_0(boost::ref(work_functor0));
boost::thread worker_thread_1(boost::ref(work_functor1));
worker_thread_0.join();
worker_thread_1.join();
std::cout << work_functor0.message() << std::endl;
std::cout << work_functor1.message() << std::endl;
We're done - print a success message.
std::cout << "!!!! TUTORIAL COMPLETED SUCCESSFULLY !!!!" << std::endl;
return EXIT_SUCCESS;
}
Full Example Code
#ifndef VIENNACL_WITH_OPENCL
#define VIENNACL_WITH_OPENCL
#endif
#include <iostream>
#include <boost/thread.hpp>
template<typename NumericT>
class worker
{
public:
worker(std::size_t tid) : thread_id_(tid) {}
void operator()()
{
std::size_t N = 6;
u += v;
std::stringstream ss;
ss <<
"Result of thread " << thread_id_ <<
" on device " <<
viennacl::ocl::get_context(static_cast<long>(thread_id_)).
devices()[0].name() <<
": " << result << std::endl;
ss << " A: " << A << std::endl;
ss << " x: " << x << std::endl;
message_ = ss.str();
}
std::string message() const { return message_; }
private:
std::string message_;
std::size_t thread_id_;
};
{
{
std::cerr << "Error: No platform found!" << std::endl;
return EXIT_FAILURE;
}
std::vector<viennacl::ocl::device>
const & devices = pf.
devices();
if (devices.size() > 1)
else
worker<ScalarType> work_functor0(0);
worker<ScalarType> work_functor1(1);
boost::thread worker_thread_0(boost::ref(work_functor0));
boost::thread worker_thread_1(boost::ref(work_functor1));
worker_thread_0.join();
worker_thread_1.join();
std::cout << work_functor0.message() << std::endl;
std::cout << work_functor1.message() << std::endl;
std::cout << "!!!! TUTORIAL COMPLETED SUCCESSFULLY !!!!" << std::endl;
return EXIT_SUCCESS;
}