Commit 881a492d authored by Dominik Charousset's avatar Dominik Charousset

Properly modularize metainfo init code

parent 44bf5bab
...@@ -19,11 +19,65 @@ ...@@ -19,11 +19,65 @@
#include "caf/opencl/opencl_metainfo.hpp" #include "caf/opencl/opencl_metainfo.hpp"
using namespace std; #define CAF_CLF(funname) #funname , funname
namespace caf { namespace caf {
namespace opencl { namespace opencl {
namespace {
void throwcl(const char* fname, cl_int err) {
if (err != CL_SUCCESS) {
std::string errstr = fname;
errstr += ": ";
errstr += get_opencl_error(err);
throw std::runtime_error(std::move(errstr));
}
}
// call convention for simply calling a function, not using the last argument
template <class F, class... Ts>
void callcl(const char* fname, F f, Ts&&... vs) {
throwcl(fname, f(std::forward<Ts>(vs)..., nullptr));
}
// call convention with `result` argument at the end returning `err`, not
// using the second last argument (set to nullptr) nor the one before (set to 0)
template <class R, class F, class... Ts>
R v1get(const char* fname, F f, Ts&&... vs) {
R result;
throwcl(fname, f(std::forward<Ts>(vs)..., cl_uint{0}, nullptr, &result));
return result;
}
// call convention with `err` argument at the end returning `result`
template <class F, class... Ts>
auto v2get(const char* fname, F f, Ts&&... vs)
-> decltype(f(std::forward<Ts>(vs)..., nullptr)) {
cl_int err;
auto result = f(std::forward<Ts>(vs)..., &err);
throwcl(fname, err);
return result;
}
// call convention with `result` argument at second last position (preceeded by
// its size) followed by an ingored void* argument (nullptr) returning `err`
template <class R, class F, class... Ts>
R v3get(const char* fname, F f, Ts&&... vs) {
R result;
throwcl(fname, f(std::forward<Ts>(vs)..., sizeof(R), &result, nullptr));
return result;
}
void pfn_notify(const char* errinfo, const void*, size_t, void*) {
CAF_LOGC_ERROR("caf::opencl::opencl_metainfo", "initialize",
"\n##### Error message via pfn_notify #####\n"
<< errinfo <<
"\n########################################");
}
} // namespace <anonymous>
opencl_metainfo* opencl_metainfo::instance() { opencl_metainfo* opencl_metainfo::instance() {
auto sid = detail::singletons::opencl_plugin_id; auto sid = detail::singletons::opencl_plugin_id;
auto fac = [] { return new opencl_metainfo; }; auto fac = [] { return new opencl_metainfo; };
...@@ -36,131 +90,64 @@ const std::vector<device_info> opencl_metainfo::get_devices() const { ...@@ -36,131 +90,64 @@ const std::vector<device_info> opencl_metainfo::get_devices() const {
} }
void opencl_metainfo::initialize() { void opencl_metainfo::initialize() {
cl_int err{0};
// get number of available platforms // get number of available platforms
cl_uint number_of_platforms; auto num_platforms = v1get<cl_uint>(CAF_CLF(clGetPlatformIDs));
err = clGetPlatformIDs(0, nullptr, &number_of_platforms);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetPlatformIDs (getting number of platforms): "
<< get_opencl_error(err);
CAF_LOGMF(CAF_ERROR, oss.str());
throw logic_error(oss.str());
}
// get platform ids // get platform ids
vector<cl_platform_id> ids(number_of_platforms); std::vector<cl_platform_id> platforms(num_platforms);
err = clGetPlatformIDs(ids.size(), ids.data(), nullptr); callcl(CAF_CLF(clGetPlatformIDs), num_platforms, platforms.data());
if (err != CL_SUCCESS) { if (platforms.empty()) {
ostringstream oss; throw std::runtime_error("no OpenCL platform found");
oss << "clGetPlatformIDs (getting platform ids): " << get_opencl_error(err);
CAF_LOGMF(CAF_ERROR, oss.str());
throw logic_error(oss.str());
} }
// find gpu devices on our platform // support multiple platforms -> "for (auto platform : platforms)"?
int pid{0}; auto platform = platforms.front();
cl_uint num_devices{0}; // detect how many devices we got
cl_device_type dev_type{CL_DEVICE_TYPE_GPU}; cl_uint num_devs = 0;
err = clGetDeviceIDs(ids[pid], dev_type, 0, nullptr, &num_devices); cl_device_type dev_type = CL_DEVICE_TYPE_GPU;
if (err == CL_DEVICE_NOT_FOUND) { // try get some GPU devices and try falling back to CPU devices on error
CAF_LOG_TRACE("No gpu devices found. Looking for cpu devices."); try {
cout << "No gpu devices found. Looking for cpu devices." << endl; num_devs = v1get<cl_uint>(CAF_CLF(clGetDeviceIDs), platform, dev_type);
dev_type = CL_DEVICE_TYPE_CPU;
err = clGetDeviceIDs(ids[pid], dev_type, 0, nullptr, &num_devices);
}
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetDeviceIDs: " << get_opencl_error(err);
CAF_LOGMF(CAF_ERROR, oss.str());
throw runtime_error(oss.str());
} }
vector<cl_device_id> devices(num_devices); catch (std::runtime_error&) {
err = dev_type = CL_DEVICE_TYPE_CPU;
clGetDeviceIDs(ids[pid], dev_type, num_devices, devices.data(), nullptr); num_devs = v1get<cl_uint>(CAF_CLF(clGetDeviceIDs), platform, dev_type);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetDeviceIDs: " << get_opencl_error(err);
CAF_LOGMF(CAF_ERROR, oss.str());
throw runtime_error(oss.str());
} }
auto pfn_notify = [](const char* errinfo, const void*, size_t, void*) { // get available devices
CAF_LOGC_ERROR("caf::opencl::opencl_metainfo", "initialize", std::vector<cl_device_id> ds(num_devs);
"\n##### Error message via pfn_notify #####\n" + callcl(CAF_CLF(clGetDeviceIDs), platform, dev_type, num_devs, ds.data());
string(errinfo) + std::vector<device_ptr> devices(num_devs);
"\n########################################"); // lift raw pointer as returned by OpenCL to C++ smart pointers
}; auto lift = [](cl_device_id ptr) { return device_ptr{ptr, false}; };
std::transform(ds.begin(), ds.end(), devices.begin(), lift);
// create a context // create a context
m_context.adopt(clCreateContext(0, devices.size(), devices.data(), pfn_notify, m_context.adopt(v2get(CAF_CLF(clCreateContext), nullptr, num_devs, ds.data(),
nullptr, &err)); pfn_notify, nullptr));
if (err != CL_SUCCESS) { for (auto& device : devices) {
ostringstream oss; CAF_LOG_DEBUG("creating command queue for device(s)");
oss << "clCreateContext: " << get_opencl_error(err);
CAF_LOGMF(CAF_ERROR, oss.str());
throw runtime_error(oss.str());
}
for (auto& d : devices) {
CAF_LOG_TRACE("Creating command queue for device(s).");
device_ptr device;
device.adopt(d);
size_t return_size{0};
static constexpr size_t buf_size = 128;
char buf[buf_size];
err = clGetDeviceInfo(device.get(), CL_DEVICE_NAME, buf_size, buf,
&return_size);
if (err != CL_SUCCESS) {
CAF_LOGMF(CAF_ERROR,
"clGetDeviceInfo (CL_DEVICE_NAME): " << get_opencl_error(err));
fill(buf, buf + buf_size, 0);
}
command_queue_ptr cmd_queue; command_queue_ptr cmd_queue;
cmd_queue.adopt(clCreateCommandQueue(m_context.get(), device.get(), try {
CL_QUEUE_PROFILING_ENABLE, &err)); cmd_queue.adopt(v2get(CAF_CLF(clCreateCommandQueue), m_context.get(),
if (err != CL_SUCCESS) { device.get(), CL_QUEUE_PROFILING_ENABLE));
CAF_LOGMF(CAF_DEBUG, "Could not create command queue for device " }
<< buf << ": " << get_opencl_error(err)); catch (std::runtime_error&) {
} else { CAF_LOG_DEBUG("unable to create command queue for device");
size_t max_work_group_size{0}; }
err = clGetDeviceInfo(device.get(), CL_DEVICE_MAX_WORK_GROUP_SIZE, if (cmd_queue) {
sizeof(size_t), &max_work_group_size, &return_size); auto max_wgs = v3get<size_t>(CAF_CLF(clGetDeviceInfo), device.get(),
if (err != CL_SUCCESS) { CL_DEVICE_MAX_WORK_GROUP_SIZE);
ostringstream oss; auto max_wid = v3get<cl_uint>(CAF_CLF(clGetDeviceInfo), device.get(),
oss << "clGetDeviceInfo (" CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS);
<< "CL_DEVICE_MAX_WORK_GROUP_SIZE): " << get_opencl_error(err); dim_vec max_wi_per_dim(max_wid);
CAF_LOGMF(CAF_ERROR, oss.str()); callcl(CAF_CLF(clGetDeviceInfo), device.get(),
throw runtime_error(oss.str()); CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t) * max_wid,
} max_wi_per_dim.data());
cl_uint max_work_item_dimensions = 0; m_devices.push_back(device_info{std::move(device), std::move(cmd_queue),
err = clGetDeviceInfo(device.get(), CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, max_wgs, max_wid, max_wi_per_dim});
sizeof(cl_uint), &max_work_item_dimensions,
&return_size);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetDeviceInfo ("
<< "CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS): " << get_opencl_error(err);
CAF_LOGMF(CAF_ERROR, oss.str());
throw runtime_error(oss.str());
}
dim_vec max_work_items_per_dim(max_work_item_dimensions);
err = clGetDeviceInfo(device.get(), CL_DEVICE_MAX_WORK_ITEM_SIZES,
sizeof(size_t) * max_work_item_dimensions,
max_work_items_per_dim.data(), &return_size);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetDeviceInfo ("
<< "CL_DEVICE_MAX_WORK_ITEM_SIZES): " << get_opencl_error(err);
CAF_LOGMF(CAF_ERROR, oss.str());
throw runtime_error(oss.str());
}
device_info dev_info{device, cmd_queue, max_work_group_size,
max_work_item_dimensions, max_work_items_per_dim};
m_devices.push_back(move(dev_info));
} }
} }
if (m_devices.empty()) { if (m_devices.empty()) {
ostringstream oss; std::string errstr = "could not create a command queue for any device";
oss << "Could not create a command queue for " CAF_LOG_ERROR(errstr);
<< "any present device."; throw std::runtime_error(std::move(errstr));
CAF_LOGMF(CAF_ERROR, oss.str());
throw runtime_error(oss.str());
} }
} }
...@@ -169,7 +156,7 @@ void opencl_metainfo::dispose() { ...@@ -169,7 +156,7 @@ void opencl_metainfo::dispose() {
} }
void opencl_metainfo::stop() { void opencl_metainfo::stop() {
// noop // nop
} }
} // namespace opencl } // namespace opencl
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment