Commit be771f52 authored by Dominik Charousset's avatar Dominik Charousset

Remove OpenCL binding from core library

The OpenCL binding will be moved to its own repository.
parent 5c242b5f
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_ACTOR_FACADE_HPP
#define CPPA_OPENCL_ACTOR_FACADE_HPP
#include <ostream>
#include <iostream>
#include <algorithm>
#include <stdexcept>
#include "cppa/cppa.hpp"
#include "cppa/channel.hpp"
#include "cppa/to_string.hpp"
#include "cppa/tuple_cast.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/detail/int_list.hpp"
#include "cppa/detail/type_list.hpp"
#include "cppa/detail/make_counted.hpp"
#include "cppa/detail/limited_vector.hpp"
#include "cppa/opencl/global.hpp"
#include "cppa/opencl/command.hpp"
#include "cppa/opencl/program.hpp"
#include "cppa/opencl/smart_ptr.hpp"
namespace cppa {
namespace opencl {
class opencl_metainfo;
template<typename Signature>
class actor_facade;
template<typename Ret, typename... Args>
class actor_facade<Ret(Args...)> : public abstract_actor {
friend class command<actor_facade, Ret>;
public:
using args_tuple = cow_tuple<typename detail::rm_const_and_ref<Args>::type...>;
using arg_mapping = std::function<optional<args_tuple>(message)>;
using result_mapping = std::function<message(Ret&)>;
static intrusive_ptr<actor_facade>
create(const program& prog, const char* kernel_name,
arg_mapping map_args, result_mapping map_result,
const dim_vec& global_dims, const dim_vec& offsets,
const dim_vec& local_dims, size_t result_size) {
if (global_dims.empty()) {
auto str = "OpenCL kernel needs at least 1 global dimension.";
CPPA_LOGM_ERROR(detail::demangle(typeid(actor_facade)).c_str(),
str);
throw std::runtime_error(str);
}
auto check_vec = [&](const dim_vec& vec, const char* name) {
if (!vec.empty() && vec.size() != global_dims.size()) {
std::ostringstream oss;
oss << name << " vector is not empty, but "
<< "its size differs from global dimensions vector's size";
CPPA_LOGM_ERROR(detail::demangle<actor_facade>().c_str(),
oss.str());
throw std::runtime_error(oss.str());
}
};
check_vec(offsets, "offsets");
check_vec(local_dims, "local dimensions");
cl_int err{ 0 };
kernel_ptr kernel;
kernel.adopt(clCreateKernel(prog.m_program.get(), kernel_name, &err));
if (err != CL_SUCCESS) {
std::ostringstream oss;
oss << "clCreateKernel: " << get_opencl_error(err);
CPPA_LOGM_ERROR(detail::demangle<actor_facade>().c_str(),
oss.str());
throw std::runtime_error(oss.str());
}
if (result_size == 0) {
result_size = std::accumulate(global_dims.begin(),
global_dims.end(),
1,
std::multiplies<size_t>{});
}
return new actor_facade<Ret (Args...)>{
prog , kernel , global_dims , offsets,
local_dims, std::move(map_args), std::move(map_result), result_size
};
}
void enqueue(const actor_addr& sender, message_id mid,
message msg, execution_unit*) override {
CPPA_LOG_TRACE("");
typename detail::il_indices<detail::type_list<Args...>>::type indices;
enqueue_impl(sender, std::move(msg), mid, indices);
}
private:
using evnt_vec = std::vector<cl_event>;
using args_vec = std::vector<mem_ptr>;
actor_facade(const program& prog, kernel_ptr kernel,
const dim_vec& global_dimensions,
const dim_vec& global_offsets,
const dim_vec& local_dimensions,
arg_mapping map_args, result_mapping map_result,
size_t result_size)
: m_kernel(kernel) , m_program(prog.m_program)
, m_context(prog.m_context) , m_queue(prog.m_queue)
, m_global_dimensions(global_dimensions)
, m_global_offsets(global_offsets)
, m_local_dimensions(local_dimensions)
, m_map_args(std::move(map_args))
, m_map_result(std::move(map_result))
, m_result_size(result_size)
{
CPPA_LOG_TRACE("id: " << this->id());
}
template<long... Is>
void enqueue_impl(const actor_addr& sender, message msg, message_id id,
detail::int_list<Is...>) {
auto opt = m_map_args(std::move(msg));
if (opt) {
response_promise handle{this->address(), sender, id.response_id()};
evnt_vec events;
args_vec arguments;
add_arguments_to_kernel<Ret>(events, arguments, m_result_size,
get_ref<Is>(*opt)...);
auto cmd = detail::make_counted<command<actor_facade, Ret>>(
handle, this,
std::move(events), std::move(arguments),
m_result_size, *opt
);
cmd->enqueue();
} else {
CPPA_LOGMF(CPPA_ERROR, "actor_facade::enqueue() tuple_cast failed.");
}
}
kernel_ptr m_kernel;
program_ptr m_program;
context_ptr m_context;
command_queue_ptr m_queue;
dim_vec m_global_dimensions;
dim_vec m_global_offsets;
dim_vec m_local_dimensions;
arg_mapping m_map_args;
result_mapping m_map_result;
size_t m_result_size;
void add_arguments_to_kernel_rec(evnt_vec&, args_vec& arguments) {
cl_int err{0};
// rotate left (output buffer to the end)
rotate(begin(arguments), begin(arguments) + 1, end(arguments));
for(size_t i = 0; i < arguments.size(); ++i) {
err = clSetKernelArg(m_kernel.get(), i, sizeof(cl_mem),
static_cast<void*>(&arguments[i]));
CPPA_LOG_ERROR_IF(err != CL_SUCCESS,
"clSetKernelArg: " << get_opencl_error(err));
}
clFlush(m_queue.get());
}
template<typename T0, typename... Ts>
void add_arguments_to_kernel_rec(evnt_vec& events, args_vec& arguments,
T0& arg0, Ts&... args) {
cl_int err{0};
size_t buffer_size = sizeof(typename T0::value_type) * arg0.size();
auto buffer = clCreateBuffer(m_context.get(),
CL_MEM_READ_ONLY,
buffer_size,
nullptr,
&err);
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, "clCreateBuffer: " << get_opencl_error(err));
return;
}
cl_event event;
err = clEnqueueWriteBuffer(m_queue.get(), buffer, CL_FALSE, 0,
buffer_size, arg0.data(),
0, nullptr, &event);
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, "clEnqueueWriteBuffer: "
<< get_opencl_error(err));
return;
}
events.push_back(std::move(event));
mem_ptr tmp;
tmp.adopt(std::move(buffer));
arguments.push_back(tmp);
add_arguments_to_kernel_rec(events, arguments, args...);
}
template<typename R, typename... Ts>
void add_arguments_to_kernel(evnt_vec& events, args_vec& arguments,
size_t ret_size, Ts&&... args) {
arguments.clear();
cl_int err{ 0 };
auto buf = clCreateBuffer(m_context.get(), CL_MEM_WRITE_ONLY,
sizeof(typename R::value_type) * ret_size,
nullptr, &err);
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, "clCreateBuffer: " << get_opencl_error(err));
return;
}
mem_ptr tmp;
tmp.adopt(std::move(buf));
arguments.push_back(tmp);
add_arguments_to_kernel_rec(events, arguments, std::forward<Ts>(args)...);
}
};
} // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_ACTOR_FACADE_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_COMMAND_HPP
#define CPPA_OPENCL_COMMAND_HPP
#include <vector>
#include <numeric>
#include <algorithm>
#include <functional>
#include "cppa/opencl/global.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/response_promise.hpp"
#include "cppa/opencl/smart_ptr.hpp"
#include "cppa/detail/logging.hpp"
#include "cppa/detail/scope_guard.hpp"
namespace cppa {
namespace opencl {
template<typename T, typename R>
class command : public ref_counted {
public:
command(response_promise handle,
intrusive_ptr<T> actor_facade,
std::vector<cl_event> events,
std::vector<mem_ptr> arguments,
size_t result_size,
message msg)
: m_result_size(result_size)
, m_handle(handle)
, m_actor_facade(actor_facade)
, m_queue(actor_facade->m_queue)
, m_events(std::move(events))
, m_arguments(std::move(arguments))
, m_result(m_result_size)
, m_msg(msg) { }
~command() {
cl_int err{0};
for(auto& e : m_events) {
err = clReleaseEvent(e);
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, "clReleaseEvent: "
<< get_opencl_error(err));
}
}
}
void enqueue () {
CPPA_LOG_TRACE("command::enqueue()");
this->ref(); // reference held by the OpenCL comand queue
cl_int err{0};
cl_event event_k;
auto data_or_nullptr = [](const dim_vec& vec) {
return vec.empty() ? nullptr : vec.data();
};
err = clEnqueueNDRangeKernel(m_queue.get(),
m_actor_facade->m_kernel.get(),
m_actor_facade->m_global_dimensions.size(),
data_or_nullptr(m_actor_facade->m_global_offsets),
data_or_nullptr(m_actor_facade->m_global_dimensions),
data_or_nullptr(m_actor_facade->m_local_dimensions),
m_events.size(),
(m_events.empty() ? nullptr : m_events.data()),
&event_k);
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, "clEnqueueNDRangeKernel: "
<< get_opencl_error(err));
this->deref(); // or can anything actually happen?
return;
}
else {
cl_event event_r;
err = clEnqueueReadBuffer(m_queue.get(),
m_arguments.back().get(),
CL_FALSE,
0,
sizeof(typename R::value_type) * m_result_size,
m_result.data(),
1,
&event_k,
&event_r);
if (err != CL_SUCCESS) {
throw std::runtime_error("clEnqueueReadBuffer: "
+ get_opencl_error(err));
this->deref(); // failed to enqueue command
return;
}
err = clSetEventCallback(event_r,
CL_COMPLETE,
[](cl_event, cl_int, void* data) {
auto cmd = reinterpret_cast<command*>(data);
cmd->handle_results();
cmd->deref();
},
this);
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, "clSetEventCallback: "
<< get_opencl_error(err));
this->deref(); // callback is not set
return;
}
err = clFlush(m_queue.get());
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, "clFlush: " << get_opencl_error(err));
}
m_events.push_back(std::move(event_k));
m_events.push_back(std::move(event_r));
}
}
private:
int m_result_size;
response_promise m_handle;
intrusive_ptr<T> m_actor_facade;
command_queue_ptr m_queue;
std::vector<cl_event> m_events;
std::vector<mem_ptr> m_arguments;
R m_result;
message m_msg; // required to keep the argument buffers alive (for async copy)
void handle_results () {
m_handle.deliver(m_actor_facade->m_map_result(m_result));
}
};
} // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_COMMAND_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_DEVICE_INFO_HPP
#define CPPA_OPENCL_DEVICE_INFO_HPP
#include "cppa/opencl/global.hpp"
#include "cppa/opencl/program.hpp"
#include "cppa/opencl/smart_ptr.hpp"
namespace cppa {
namespace opencl {
class device_info {
friend class program;
public:
device_info(device_ptr device,
command_queue_ptr queue,
size_t work_group_size,
cl_uint dimensons,
const dim_vec& items_per_dimension)
: m_max_work_group_size(work_group_size)
, m_max_dimensions(dimensons)
, m_max_work_items_per_dim(items_per_dimension)
, m_device(device)
, m_cmd_queue(queue) { }
inline size_t get_max_work_group_size();
inline cl_uint get_max_dimensions();
inline dim_vec get_max_work_items_per_dim();
private:
size_t m_max_work_group_size;
cl_uint m_max_dimensions;
dim_vec m_max_work_items_per_dim;
device_ptr m_device;
command_queue_ptr m_cmd_queue;
};
/******************************************************************************\
* implementation of inline member functions *
\******************************************************************************/
inline size_t device_info::get_max_work_group_size() {
return m_max_work_group_size;
}
inline cl_uint device_info::get_max_dimensions() {
return m_max_dimensions;
}
inline dim_vec device_info::get_max_work_items_per_dim() {
return m_max_work_items_per_dim;
}
} // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_DEVICE_INFO_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_GLOBAL_HPP
#define CPPA_OPENCL_GLOBAL_HPP
#include <string>
#include "cppa/detail/limited_vector.hpp"
#if defined __APPLE__ || defined(MACOSX)
#include <OpenCL/opencl.h>
#else
#include <CL/opencl.h>
#endif
namespace cppa {
namespace opencl {
/**
* @brief A vector of up to three elements used for OpenCL dimensions.
*/
using dim_vec = detail::limited_vector<size_t, 3>;
std::string get_opencl_error(cl_int err);
cl_int clReleaseDeviceDummy (cl_device_id);
cl_int clRetainDeviceDummy (cl_device_id);
} // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_GLOBAL_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_METAINFO_HPP
#define CPPA_OPENCL_METAINFO_HPP
#include <atomic>
#include <vector>
#include <algorithm>
#include <functional>
#include "cppa/cppa.hpp"
#include "cppa/opencl/global.hpp"
#include "cppa/opencl/program.hpp"
#include "cppa/opencl/smart_ptr.hpp"
#include "cppa/opencl/device_info.hpp"
#include "cppa/opencl/actor_facade.hpp"
#include "cppa/detail/singleton_mixin.hpp"
#include "cppa/detail/singleton_manager.hpp"
namespace cppa {
namespace opencl {
class opencl_metainfo {
friend class program;
friend class detail::singleton_manager;
friend command_queue_ptr get_command_queue(uint32_t id);
public:
const std::vector<device_info> get_devices() const;
private:
static inline opencl_metainfo* create_singleton() {
return new opencl_metainfo;
}
void initialize();
void dispose();
void stop();
context_ptr m_context;
std::vector<device_info> m_devices;
};
opencl_metainfo* get_opencl_metainfo();
} // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_METAINFO_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_PROGRAM_HPP
#define CPPA_OPENCL_PROGRAM_HPP
#include <memory>
#include "cppa/opencl/global.hpp"
#include "cppa/opencl/smart_ptr.hpp"
namespace cppa {
namespace opencl {
template<typename Signature>
class actor_facade;
/**
* @brief A wrapper for OpenCL's cl_program.
*/
class program {
template<typename Signature>
friend class actor_facade;
public:
/**
* @brief Factory method, that creates a cppa::opencl::program
* from a given @p kernel_source.
* @returns A program object.
*/
static program create(const char* kernel_source, const char* options = nullptr, uint32_t device_id = 0);
private:
program(context_ptr context, command_queue_ptr queue, program_ptr program);
context_ptr m_context;
program_ptr m_program;
command_queue_ptr m_queue;
};
} // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_PROGRAM_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_SMART_PTR_HPP
#define CPPA_OPENCL_SMART_PTR_HPP
#include <memory>
#include <algorithm>
#include <type_traits>
namespace cppa {
namespace opencl {
template<typename T, cl_int (*ref)(T), cl_int (*deref)(T)>
class smart_ptr {
using element_type = typename std::remove_pointer<T>::type;
using pointer = element_type* ;
using reference = element_type& ;
using const_pointer = const element_type*;
using const_reference = const element_type&;
public:
smart_ptr(pointer ptr = nullptr) : m_ptr(ptr) {
if (m_ptr) ref(m_ptr);
}
~smart_ptr() { reset(); }
smart_ptr(const smart_ptr& other) : m_ptr(other.m_ptr) {
if (m_ptr) ref(m_ptr);
}
smart_ptr(smart_ptr&& other) : m_ptr(other.m_ptr) {
other.m_ptr = nullptr;
}
smart_ptr& operator=(pointer ptr) {
reset(ptr);
return *this;
}
smart_ptr& operator=(smart_ptr&& other) {
std::swap(m_ptr, other.m_ptr);
return *this;
}
smart_ptr& operator=(const smart_ptr& other) {
smart_ptr tmp{other};
std::swap(m_ptr, tmp.m_ptr);
return *this;
}
inline void reset(pointer ptr = nullptr) {
if (m_ptr) deref(m_ptr);
m_ptr = ptr;
if (ptr) ref(ptr);
}
// does not modify reference count of ptr
inline void adopt(pointer ptr) {
reset();
m_ptr = ptr;
}
inline pointer get() const { return m_ptr; }
inline pointer operator->() const { return m_ptr; }
inline reference operator*() const { return *m_ptr; }
inline bool operator!() const { return m_ptr == nullptr; }
inline explicit operator bool() const { return m_ptr != nullptr; }
private:
pointer m_ptr;
};
using mem_ptr = smart_ptr<cl_mem, clRetainMemObject, clReleaseMemObject>;
using event_ptr = smart_ptr<cl_event, clRetainEvent, clReleaseEvent> ;
using kernel_ptr = smart_ptr<cl_kernel, clRetainKernel, clReleaseKernel> ;
using context_ptr = smart_ptr<cl_context, clRetainContext, clReleaseContext>;
using program_ptr = smart_ptr<cl_program, clRetainProgram, clReleaseProgram>;
typedef smart_ptr<cl_device_id, clRetainDeviceDummy, clReleaseDeviceDummy>
device_ptr;
typedef smart_ptr<cl_command_queue, clRetainCommandQueue, clReleaseCommandQueue>
command_queue_ptr;
} // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_SMART_PTR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include "cppa/opencl/global.hpp"
namespace cppa {
namespace opencl {
std::string get_opencl_error(cl_int err) {
switch (err) {
case CL_SUCCESS:
return "CL_SUCCESS";
case CL_DEVICE_NOT_FOUND:
return "CL_DEVICE_NOT_FOUND";
case CL_DEVICE_NOT_AVAILABLE:
return "CL_DEVICE_NOT_AVAILABLE";
case CL_COMPILER_NOT_AVAILABLE:
return "CL_COMPILER_NOT_AVAILABLE";
case CL_MEM_OBJECT_ALLOCATION_FAILURE:
return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
case CL_OUT_OF_RESOURCES:
return "CL_OUT_OF_RESOURCES";
case CL_OUT_OF_HOST_MEMORY:
return "CL_OUT_OF_HOST_MEMORY";
case CL_PROFILING_INFO_NOT_AVAILABLE:
return "CL_PROFILING_INFO_NOT_AVAILABLE";
case CL_MEM_COPY_OVERLAP:
return "CL_MEM_COPY_OVERLAP";
case CL_IMAGE_FORMAT_MISMATCH:
return "CL_IMAGE_FORMAT_MISMATCH";
case CL_IMAGE_FORMAT_NOT_SUPPORTED:
return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
case CL_BUILD_PROGRAM_FAILURE:
return "CL_BUILD_PROGRAM_FAILURE";
case CL_MAP_FAILURE:
return "CL_MAP_FAILURE";
case CL_INVALID_VALUE:
return "CL_INVALID_VALUE";
case CL_INVALID_DEVICE_TYPE:
return "CL_INVALID_DEVICE_TYPE";
case CL_INVALID_PLATFORM:
return "CL_INVALID_PLATFORM";
case CL_INVALID_DEVICE:
return "CL_INVALID_DEVICE";
case CL_INVALID_CONTEXT:
return "CL_INVALID_CONTEXT";
case CL_INVALID_QUEUE_PROPERTIES:
return "CL_INVALID_QUEUE_PROPERTIES";
case CL_INVALID_COMMAND_QUEUE:
return "CL_INVALID_COMMAND_QUEUE";
case CL_INVALID_HOST_PTR:
return "CL_INVALID_HOST_PTR";
case CL_INVALID_MEM_OBJECT:
return "CL_INVALID_MEM_OBJECT";
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:
return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
case CL_INVALID_IMAGE_SIZE:
return "CL_INVALID_IMAGE_SIZE";
case CL_INVALID_SAMPLER:
return "CL_INVALID_SAMPLER";
case CL_INVALID_BINARY:
return "CL_INVALID_BINARY";
case CL_INVALID_BUILD_OPTIONS:
return "CL_INVALID_BUILD_OPTIONS";
case CL_INVALID_PROGRAM:
return "CL_INVALID_PROGRAM";
case CL_INVALID_PROGRAM_EXECUTABLE:
return "CL_INVALID_PROGRAM_EXECUTABLE";
case CL_INVALID_KERNEL_NAME:
return "CL_INVALID_KERNEL_NAME";
case CL_INVALID_KERNEL_DEFINITION:
return "CL_INVALID_KERNEL_DEFINITION";
case CL_INVALID_KERNEL:
return "CL_INVALID_KERNEL";
case CL_INVALID_ARG_INDEX:
return "CL_INVALID_ARG_INDEX";
case CL_INVALID_ARG_VALUE:
return "CL_INVALID_ARG_VALUE";
case CL_INVALID_ARG_SIZE:
return "CL_INVALID_ARG_SIZE";
case CL_INVALID_KERNEL_ARGS:
return "CL_INVALID_KERNEL_ARGS";
case CL_INVALID_WORK_DIMENSION:
return "CL_INVALID_WORK_DIMENSION";
case CL_INVALID_WORK_GROUP_SIZE:
return "CL_INVALID_WORK_GROUP_SIZE";
case CL_INVALID_WORK_ITEM_SIZE:
return "CL_INVALID_WORK_ITEM_SIZE";
case CL_INVALID_GLOBAL_OFFSET:
return "CL_INVALID_GLOBAL_OFFSET";
case CL_INVALID_EVENT_WAIT_LIST:
return "CL_INVALID_EVENT_WAIT_LIST";
case CL_INVALID_EVENT:
return "CL_INVALID_EVENT";
case CL_INVALID_OPERATION:
return "CL_INVALID_OPERATION";
case CL_INVALID_GL_OBJECT:
return "CL_INVALID_GL_OBJECT";
case CL_INVALID_BUFFER_SIZE:
return "CL_INVALID_BUFFER_SIZE";
case CL_INVALID_MIP_LEVEL:
return "CL_INVALID_MIP_LEVEL";
case CL_INVALID_GLOBAL_WORK_SIZE:
return "CL_INVALID_GLOBAL_WORK_SIZE";
default: return "UNKNOWN_ERROR";
}
}
cl_int clReleaseDeviceDummy (cl_device_id) { return 0; }
cl_int clRetainDeviceDummy (cl_device_id) { return 0; }
} // namespace opencl
} // namespace cppa
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include "cppa/opencl/opencl_metainfo.hpp"
using namespace std;
namespace cppa {
namespace opencl {
const std::vector<device_info> opencl_metainfo::get_devices() const {
return m_devices;
}
void opencl_metainfo::initialize() {
cl_int err{0};
// get number of available platforms
cl_uint number_of_platforms;
err = clGetPlatformIDs(0, nullptr, &number_of_platforms);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetPlatformIDs (getting number of platforms): "
<< get_opencl_error(err);
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw logic_error(oss.str());
}
// get platform ids
vector<cl_platform_id> ids(number_of_platforms);
err = clGetPlatformIDs(ids.size(), ids.data(), nullptr);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetPlatformIDs (getting platform ids): "
<< get_opencl_error(err);
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw logic_error(oss.str());
}
// find gpu devices on our platform
int pid{0};
cl_uint num_devices{0};
cl_device_type dev_type{CL_DEVICE_TYPE_GPU};
err = clGetDeviceIDs(ids[pid], dev_type, 0, nullptr, &num_devices);
if (err == CL_DEVICE_NOT_FOUND) {
CPPA_LOG_TRACE("No gpu devices found. Looking for cpu devices.");
cout << "No gpu devices found. Looking for cpu devices." << endl;
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);
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw runtime_error(oss.str());
}
vector<cl_device_id> devices(num_devices);
err = clGetDeviceIDs(ids[pid], dev_type, num_devices, devices.data(), nullptr);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetDeviceIDs: " << get_opencl_error(err);
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw runtime_error(oss.str());
}
// create a context
m_context.adopt(clCreateContext(0,
devices.size(),
devices.data(),
nullptr,
nullptr,
&err));
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clCreateContext: " << get_opencl_error(err);
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw runtime_error(oss.str());
}
// create command queues
for (auto& d : devices) {
CPPA_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) {
CPPA_LOGMF(CPPA_ERROR, "clGetDeviceInfo (CL_DEVICE_NAME): "
<< get_opencl_error(err));
fill(buf, buf+buf_size, 0);
}
command_queue_ptr cmd_queue;
cmd_queue.adopt(clCreateCommandQueue(m_context.get(),
device.get(),
CL_QUEUE_PROFILING_ENABLE,
&err));
if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_DEBUG, "Could not create command queue for device "
<< buf << ": " << get_opencl_error(err));
}
else {
size_t max_work_group_size{0};
err = clGetDeviceInfo(device.get(),
CL_DEVICE_MAX_WORK_GROUP_SIZE,
sizeof(size_t),
&max_work_group_size,
&return_size);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetDeviceInfo ("
<< "CL_DEVICE_MAX_WORK_GROUP_SIZE): "
<< get_opencl_error(err);
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw runtime_error(oss.str());
}
cl_uint max_work_item_dimensions = 0;
err = clGetDeviceInfo(device.get(),
CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS,
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);
CPPA_LOGMF(CPPA_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);
CPPA_LOGMF(CPPA_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()) {
ostringstream oss;
oss << "Could not create a command queue for "
<< "any present device.";
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw runtime_error(oss.str());
}
}
void opencl_metainfo::destroy() {
delete this;
}
void opencl_metainfo::dispose() {
delete this;
}
opencl_metainfo* get_opencl_metainfo() {
return detail::singleton_manager::get_opencl_metainfo();
}
} // namespace opencl
} // namespace cppa
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
#include "cppa/config.hpp"
#include "cppa/opencl/program.hpp"
#include "cppa/opencl/opencl_metainfo.hpp"
#include "cppa/detail/singletons.hpp"
using namespace std;
namespace cppa {
namespace opencl {
program::program(context_ptr context, command_queue_ptr queue, program_ptr program)
: m_context(move(context)), m_program(move(program)), m_queue(move(queue)) { }
program program::create(const char* kernel_source, const char* options, uint32_t device_id) {
auto metainfo = get_opencl_metainfo();
auto devices = metainfo->get_devices();
auto context = metainfo->m_context;
if (devices.size() <= device_id) {
ostringstream oss;
oss << "Device id " << device_id
<< " is not a vaild device. Maximum id is: "
<< (devices.size() -1) << ".";
CPPA_LOGM_ERROR(detail::demangle<program>().c_str(), oss.str());
throw runtime_error(oss.str());
}
cl_int err{0};
// create program object from kernel source
size_t kernel_source_length = strlen(kernel_source);
program_ptr pptr;
pptr.adopt(clCreateProgramWithSource(context.get(),
1,
&kernel_source,
&kernel_source_length,
&err));
if (err != CL_SUCCESS) {
throw runtime_error("clCreateProgramWithSource: "
+ get_opencl_error(err));
}
// build programm from program object
auto dev_tmp = devices[device_id].m_device.get();
err = clBuildProgram(pptr.get(), 1, &dev_tmp, options, nullptr, nullptr);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clBuildProgram: " << get_opencl_error(err);
// get the build log
if (err == CL_BUILD_PROGRAM_FAILURE) {
size_t buildlog_buffer_size = 0;
// get the log length
clGetProgramBuildInfo(pptr.get(),
dev_tmp,
CL_PROGRAM_BUILD_LOG,
sizeof(buildlog_buffer_size),
nullptr,
&buildlog_buffer_size);
vector<char> buffer(buildlog_buffer_size);
// fill the buffer with buildlog informations
clGetProgramBuildInfo(pptr.get(),
dev_tmp,
CL_PROGRAM_BUILD_LOG,
sizeof(buffer[0]) * buildlog_buffer_size,
buffer.data(),
nullptr);
// make sure string is null terminated
buffer.push_back('\0');
cerr << "OpenCL build error log: "
<< endl
<< buffer.data()
<< endl;
}
throw runtime_error(oss.str());
}
return {context, devices[device_id].m_cmd_queue, pptr};
}
} // namespace opencl
} // namespace cppa
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