Commit 9b3c07ad authored by Dominik Charousset's avatar Dominik Charousset

Merge pull request #581

parents e520075d 2b699267
[submodule "libcaf_opencl"]
path = libcaf_opencl
url = ../opencl.git
[submodule "libcaf_python/third_party/pybind"]
path = libcaf_python/third_party/pybind
url = https://github.com/pybind/pybind11.git
Subproject commit cc4e4ef5ad92e3ee78e2f2897027e5f48cbc8e93
cmake_minimum_required(VERSION 2.8)
project(caf_opencl C CXX)
# get header files; only needed by CMake generators,
# e.g., for creating proper Xcode projects
file(GLOB_RECURSE LIBCAF_OPENCL_HDRS "caf/*.hpp")
add_custom_target(libcaf_opencl)
# list cpp files excluding platform-dependent files
set (LIBCAF_OPENCL_SRCS
src/global.cpp
src/manager.cpp
src/program.cpp
src/opencl_err.cpp
src/platform.cpp
src/device.cpp)
# build shared library if not compiling static only
if(NOT CAF_BUILD_STATIC_ONLY)
add_library(libcaf_opencl_shared SHARED ${LIBCAF_OPENCL_SRCS}
${LIBCAF_OPENCL_HDRS} ${OpenCL_INCLUDE_DIRS})
target_link_libraries(libcaf_opencl_shared ${LD_FLAGS}
${CAF_LIBRARY_CORE}
${OpenCL_LIBRARIES})
set_target_properties(libcaf_opencl_shared
PROPERTIES
SOVERSION "${CAF_VERSION}"
VERSION "${CAF_VERSION}"
OUTPUT_NAME caf_opencl)
if(NOT WIN32)
install(TARGETS libcaf_opencl_shared LIBRARY DESTINATION lib)
endif()
endif()
# build static library only if --build-static or --build-static-only was set
if(CAF_BUILD_STATIC_ONLY OR CAF_BUILD_STATIC)
add_library(libcaf_opencl_static STATIC ${LIBCAF_OPENCL_HDRS} ${LIBCAF_OPENCL_SRCS})
target_link_libraries(libcaf_opencl_static ${LD_FLAGS}
${CAF_LIBRARY_CORE_STATIC}
${OpenCL_LIBRARIES})
set_target_properties(libcaf_opencl_static PROPERTIES OUTPUT_NAME caf_opencl_static)
install(TARGETS libcaf_opencl_static ARCHIVE DESTINATION lib)
endif()
link_directories(${LD_DIRS})
include_directories(. ${INCLUDE_DIRS})
# install includes
install(DIRECTORY caf/ DESTINATION include/caf FILES_MATCHING PATTERN "*.hpp")
OpenCL Actors
=============
This module eases the use of OpenCL with CAF. See our [Wiki page](https://github.com/actor-framework/actor-framework/wiki/OpenCL-Actors) for details.
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_ALL_HPP
#define CAF_OPENCL_ALL_HPP
#include "caf/opencl/manager.hpp"
#endif // CAF_OPENCL_ALL_HPP
This diff is collapsed.
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_DETAIL_COMMAND_HELPER_HPP
#define CAF_OPENCL_DETAIL_COMMAND_HELPER_HPP
#include "caf/detail/type_list.hpp"
#include "caf/opencl/arguments.hpp"
namespace caf {
namespace opencl {
namespace detail {
// signature for the function that is applied to output arguments
template <class List>
struct output_function_sig;
template <class... Ts>
struct output_function_sig<detail::type_list<Ts...>> {
using type = std::function<message (Ts&...)>;
};
// derive signature of the command that handles the kernel execution
template <class T, class List>
struct command_sig;
template <class T, class... Ts>
struct command_sig<T, detail::type_list<Ts...>> {
using type = command<T, Ts...>;
};
// derive type for a tuple matching the arguments as mem_refs
template <class List>
struct tuple_type_of;
template <class... Ts>
struct tuple_type_of<detail::type_list<Ts...>> {
using type = std::tuple<Ts...>;
};
} // namespace detail
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_DETAIL_COMMAND_HELPER_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_CORE_HPP
#define CAF_OPENCL_CORE_HPP
namespace caf {
namespace detail {
} // namespace detail
namespace opencl {
namespace detail {
using namespace caf::detail;
} // namespace detail
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_CORE_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_SMART_PTR_HPP
#define CAF_OPENCL_SMART_PTR_HPP
#include <memory>
#include <algorithm>
#include <type_traits>
#include "caf/intrusive_ptr.hpp"
#include "caf/opencl/global.hpp"
#define CAF_OPENCL_PTR_ALIAS(aliasname, cltype, claddref, clrelease) \
inline void intrusive_ptr_add_ref(cltype ptr) { claddref(ptr); } \
inline void intrusive_ptr_release(cltype ptr) { clrelease(ptr); } \
namespace caf { \
namespace opencl { \
namespace detail { \
using aliasname = intrusive_ptr<std::remove_pointer<cltype>::type>; \
} /* namespace detail */ \
} /* namespace opencl */ \
} // namespace caf
CAF_OPENCL_PTR_ALIAS(raw_mem_ptr, cl_mem, clRetainMemObject, clReleaseMemObject)
CAF_OPENCL_PTR_ALIAS(raw_event_ptr, cl_event, clRetainEvent, clReleaseEvent)
CAF_OPENCL_PTR_ALIAS(raw_kernel_ptr, cl_kernel, clRetainKernel, clReleaseKernel)
CAF_OPENCL_PTR_ALIAS(raw_context_ptr, cl_context,
clRetainContext, clReleaseContext)
CAF_OPENCL_PTR_ALIAS(raw_program_ptr, cl_program,
clRetainProgram, clReleaseProgram)
CAF_OPENCL_PTR_ALIAS(raw_device_ptr, cl_device_id,
clRetainDeviceDummy, clReleaseDeviceDummy)
CAF_OPENCL_PTR_ALIAS(raw_command_queue_ptr, cl_command_queue,
clRetainCommandQueue, clReleaseCommandQueue)
#endif // CAF_OPENCL_SMART_PTR_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_DETAIL_SPAWN_HELPER_HPP
#define CAF_OPENCL_DETAIL_SPAWN_HELPER_HPP
#include "caf/opencl/actor_facade.hpp"
namespace caf {
namespace opencl {
namespace detail {
struct tuple_construct { };
template <bool PassConfig, class... Ts>
struct cl_spawn_helper {
using impl = opencl::actor_facade<PassConfig, Ts...>;
using map_in_fun = typename impl::input_mapping;
using map_out_fun = typename impl::output_mapping;
actor operator()(actor_config actor_cfg, const opencl::program_ptr p,
const char* fn, const opencl::nd_range& range,
Ts&&... xs) const {
return actor_cast<actor>(impl::create(std::move(actor_cfg),
p, fn, range,
map_in_fun{}, map_out_fun{},
std::forward<Ts>(xs)...));
}
actor operator()(actor_config actor_cfg, const opencl::program_ptr p,
const char* fn, const opencl::nd_range& range,
map_in_fun map_input, Ts&&... xs) const {
return actor_cast<actor>(impl::create(std::move(actor_cfg),
p, fn, range,
std::move(map_input),
map_out_fun{},
std::forward<Ts>(xs)...));
}
actor operator()(actor_config actor_cfg, const opencl::program_ptr p,
const char* fn, const opencl::nd_range& range,
map_in_fun map_input, map_out_fun map_output,
Ts&&... xs) const {
return actor_cast<actor>(impl::create(std::move(actor_cfg),
p, fn, range,
std::move(map_input),
std::move(map_output),
std::forward<Ts>(xs)...));
}
};
} // namespace detail
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_DETAIL_SPAWN_HELPER_HPP
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_GLOBAL_HPP
#define CAF_OPENCL_GLOBAL_HPP
#include <string>
#include <iostream>
#include "caf/config.hpp"
#include "caf/detail/limited_vector.hpp"
#if defined(CAF_MACOS) || defined(CAF_IOS)
# include <OpenCL/opencl.h>
#else
# include <CL/opencl.h>
#endif
// needed for OpenCL 1.0 compatibility (works around missing clReleaseDevice)
extern "C" {
cl_int clReleaseDeviceDummy(cl_device_id);
cl_int clRetainDeviceDummy(cl_device_id);
} // extern "C"
namespace caf {
namespace opencl {
enum device_type {
def = CL_DEVICE_TYPE_DEFAULT,
cpu = CL_DEVICE_TYPE_CPU,
gpu = CL_DEVICE_TYPE_GPU,
accelerator = CL_DEVICE_TYPE_ACCELERATOR,
custom = CL_DEVICE_TYPE_CUSTOM,
all = CL_DEVICE_TYPE_ALL
};
/// Default values to create OpenCL buffers
enum buffer_type : cl_mem_flags {
input = CL_MEM_READ_WRITE | CL_MEM_HOST_WRITE_ONLY,
input_output = CL_MEM_READ_WRITE,
output = CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
scratch_space = CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS
};
std::ostream& operator<<(std::ostream& os, device_type dev);
device_type device_type_from_ulong(cl_ulong dev);
/// A vector of up to three elements used for OpenCL dimensions.
using dim_vec = detail::limited_vector<size_t, 3>;
std::string opencl_error(cl_int err);
std::string event_status(cl_event event);
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_GLOBAL_HPP
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_MEM_REF_HPP
#define CAF_OPENCL_MEM_REF_HPP
#include <ios>
#include <vector>
#include "caf/sec.hpp"
#include "caf/optional.hpp"
#include "caf/ref_counted.hpp"
#include "caf/opencl/detail/core.hpp"
#include "caf/opencl/detail/raw_ptr.hpp"
namespace caf {
namespace opencl {
/// Updates the reference types in a message with a given event.
struct msg_adding_event {
msg_adding_event(detail::raw_event_ptr event) : event_(event) {
// nop
}
template <class T, class... Ts>
message operator()(T& x, Ts&... xs) {
return make_message(add_event(std::move(x)), add_event(std::move(xs))...);
}
template <class... Ts>
message operator()(std::tuple<Ts...>& values) {
return apply_args(*this, detail::get_indices(values), values);
}
template <class T>
mem_ref<T> add_event(mem_ref<T> ref) {
ref.set_event(event_);
return std::move(ref);
}
detail::raw_event_ptr event_;
};
// Tag to separate mem_refs from other types in messages.
struct ref_tag {};
class device;
/// A reference type for buffers on a OpenCL devive. Access is not thread safe.
/// Hence, a mem_ref should only be passed to actors sequentially.
template <class T>
class mem_ref : ref_tag {
public:
using value_type = T;
friend struct msg_adding_event;
template <bool PassConfig, class... Ts>
friend class actor_facade;
friend class device;
expected<std::vector<T>> data(optional<size_t> result_size = none) {
if (!memory_)
return make_error(sec::runtime_error, "No memory assigned.");
if (0 != (access_ & CL_MEM_HOST_NO_ACCESS))
return make_error(sec::runtime_error, "No memory access.");
if (result_size && *result_size > num_elements_)
return make_error(sec::runtime_error, "Buffer has less elements.");
auto num_elements = (result_size ? *result_size : num_elements_);
auto buffer_size = sizeof(T) * num_elements;
std::vector<T> buffer(num_elements);
std::vector<cl_event> prev_events;
if (event_)
prev_events.push_back(event_.get());
cl_event event;
auto err = clEnqueueReadBuffer(queue_.get(), memory_.get(), CL_TRUE,
0, buffer_size, buffer.data(),
static_cast<cl_uint>(prev_events.size()),
prev_events.data(), &event);
if (err != CL_SUCCESS)
return make_error(sec::runtime_error, opencl_error(err));
// decrements the previous event we used for waiting above
event_.reset(event, false);
return buffer;
}
void reset() {
num_elements_ = 0;
access_ = CL_MEM_HOST_NO_ACCESS;
memory_.reset();
access_ = 0;
event_.reset();
}
inline const detail::raw_mem_ptr& get() const {
return memory_;
}
inline size_t size() const {
return num_elements_;
}
inline cl_mem_flags access() const {
return access_;
}
mem_ref()
: num_elements_{0},
access_{CL_MEM_HOST_NO_ACCESS},
queue_{nullptr},
event_{nullptr},
memory_{nullptr} {
// nop
}
mem_ref(size_t num_elements, detail::raw_command_queue_ptr queue,
detail::raw_mem_ptr memory, cl_mem_flags access,
detail::raw_event_ptr event)
: num_elements_{num_elements},
access_{access},
queue_{queue},
event_{event},
memory_{memory} {
// nop
}
mem_ref(size_t num_elements, detail::raw_command_queue_ptr queue,
cl_mem memory, cl_mem_flags access, detail::raw_event_ptr event)
: num_elements_{num_elements},
access_{access},
queue_{queue},
event_{event},
memory_{memory} {
// nop
}
mem_ref(mem_ref&& other) = default;
mem_ref& operator=(mem_ref<T>&& other) = default;
mem_ref(const mem_ref& other) = default;
mem_ref& operator=(const mem_ref& other) = default;
~mem_ref() {
// nop
}
private:
inline void set_event(cl_event e, bool increment_reference = true) {
event_.reset(e, increment_reference);
}
inline void set_event(detail::raw_event_ptr e) {
event_ = std::move(e);
}
inline detail::raw_event_ptr event() {
return event_;
}
inline cl_event take_event() {
return event_.release();
}
size_t num_elements_;
cl_mem_flags access_;
detail::raw_command_queue_ptr queue_;
detail::raw_event_ptr event_;
detail::raw_mem_ptr memory_;
};
} // namespace opencl
template <class T>
struct allowed_unsafe_message_type<opencl::mem_ref<T>> : std::true_type {};
} // namespace caf
#endif // CAF_OPENCL_MEM_REF_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_ND_RANGE_HPP
#define CAF_OPENCL_ND_RANGE_HPP
#include "caf/opencl/global.hpp"
namespace caf {
namespace opencl {
class nd_range {
public:
nd_range(const opencl::dim_vec& dimensions,
const opencl::dim_vec& offsets = {},
const opencl::dim_vec& local_dimensions = {})
: dims_{dimensions},
offset_{offsets},
local_dims_{local_dimensions} {
// nop
}
nd_range(opencl::dim_vec&& dimensions,
opencl::dim_vec&& offsets = {},
opencl::dim_vec&& local_dimensions = {})
: dims_{std::move(dimensions)},
offset_{std::move(offsets)},
local_dims_{std::move(local_dimensions)} {
// nop
}
nd_range(const nd_range&) = default;
nd_range(nd_range&&) = default;
nd_range& operator=(const nd_range&) = default;
nd_range& operator=(nd_range&&) = default;
const opencl::dim_vec& dimensions() const {
return dims_;
}
const opencl::dim_vec& offsets() const {
return offset_;
}
const opencl::dim_vec& local_dimensions() const {
return local_dims_;
}
private:
opencl::dim_vec dims_;
opencl::dim_vec offset_;
opencl::dim_vec local_dims_;
};
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_ND_RANGE_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_OPENCL_ERR_HPP
#define CAF_OPENCL_OPENCL_ERR_HPP
#include "caf/opencl/global.hpp"
#include "caf/logger.hpp"
#define CAF_CLF(funname) #funname , funname
namespace caf {
namespace opencl {
void throwcl(const char* fname, cl_int err);
void pfn_notify(const char* errinfo, const void*, size_t, void*);
// call convention for simply calling a function
template <class F, class... Ts>
void v1callcl(const char* fname, F f, Ts&&... vs) {
throwcl(fname, f(std::forward<Ts>(vs)...));
}
// call convention for simply calling a function, not using the last argument
template <class F, class... Ts>
void v2callcl(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;
}
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_OPENCL_ERR_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_PLATFORM_HPP
#define CAF_OPENCL_PLATFORM_HPP
#include "caf/ref_counted.hpp"
#include "caf/opencl/device.hpp"
namespace caf {
namespace opencl {
class platform;
using platform_ptr = intrusive_ptr<platform>;
class platform : public ref_counted {
public:
friend class program;
template <class T, class... Ts>
friend intrusive_ptr<T> caf::make_counted(Ts&&...);
inline const std::vector<device_ptr>& devices() const;
inline const std::string& name() const;
inline const std::string& vendor() const;
inline const std::string& version() const;
static platform_ptr create(cl_platform_id platform_id, unsigned start_id);
private:
platform(cl_platform_id platform_id, detail::raw_context_ptr context,
std::string name, std::string vendor, std::string version,
std::vector<device_ptr> devices);
~platform();
static std::string platform_info(cl_platform_id platform_id,
unsigned info_flag);
cl_platform_id platform_id_;
detail::raw_context_ptr context_;
std::string name_;
std::string vendor_;
std::string version_;
std::vector<device_ptr> devices_;
};
/******************************************************************************\
* implementation of inline member functions *
\******************************************************************************/
inline const std::vector<device_ptr>& platform::devices() const {
return devices_;
}
inline const std::string& platform::name() const {
return name_;
}
inline const std::string& platform::vendor() const {
return vendor_;
}
inline const std::string& platform::version() const {
return version_;
}
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_PLATFORM_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENCL_PROGRAM_HPP
#define CAF_OPENCL_PROGRAM_HPP
#include <map>
#include <memory>
#include "caf/ref_counted.hpp"
#include "caf/opencl/device.hpp"
#include "caf/opencl/global.hpp"
#include "caf/opencl/detail/raw_ptr.hpp"
namespace caf {
namespace opencl {
class program;
using program_ptr = intrusive_ptr<program>;
/// @brief A wrapper for OpenCL's cl_program.
class program : public ref_counted {
public:
friend class manager;
template <bool PassConfig, class... Ts>
friend class actor_facade;
template <class T, class... Ts>
friend intrusive_ptr<T> caf::make_counted(Ts&&...);
private:
program(detail::raw_context_ptr context, detail::raw_command_queue_ptr queue,
detail::raw_program_ptr prog,
std::map<std::string, detail::raw_kernel_ptr> available_kernels);
~program();
detail::raw_context_ptr context_;
detail::raw_program_ptr program_;
detail::raw_command_queue_ptr queue_;
std::map<std::string, detail::raw_kernel_ptr> available_kernels_;
};
} // namespace opencl
} // namespace caf
#endif // CAF_OPENCL_PROGRAM_HPP
cmake_minimum_required(VERSION 2.8)
project(caf_examples_opencl CXX)
if(OpenCL_LIBRARIES AND NOT CAF_NO_EXAMPLES)
add_custom_target(opencl_examples)
include_directories(${LIBCAF_INCLUDE_DIRS})
if(${CMAKE_SYSTEM_NAME} MATCHES "Window")
set(WSLIB -lws2_32)
else()
set(WSLIB)
endif()
macro(add name folder)
add_executable(${name} ${folder}/${name}.cpp ${ARGN})
target_link_libraries(${name}
${LD_FLAGS}
${CAF_LIBRARIES}
${PTHREAD_LIBRARIES}
${WSLIB}
${OpenCL_LIBRARIES})
add_dependencies(${name} all_examples)
endmacro()
add(proper_matrix .)
add(simple_matrix .)
add(scan .)
endif()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <vector>
#include <iomanip>
#include <numeric>
#include <cassert>
#include <iostream>
#include "caf/all.hpp"
#include "caf/detail/limited_vector.hpp"
#include "caf/opencl/all.hpp"
using namespace std;
using namespace caf;
using namespace caf::opencl;
using caf::detail::limited_vector;
namespace {
using fvec = vector<float>;
constexpr size_t matrix_size = 8;
constexpr const char* kernel_name = "matrix_mult";
// opencl kernel, multiplies matrix1 and matrix2
// last parameter is, by convention, the output parameter
constexpr const char* kernel_source = R"__(
kernel void matrix_mult(global const float* matrix1,
global const float* matrix2,
global float* output) {
// we only use square matrices, hence: width == height
size_t size = get_global_size(0); // == get_global_size_(1);
size_t x = get_global_id(0);
size_t y = get_global_id(1);
float result = 0;
for (size_t idx = 0; idx < size; ++idx)
result += matrix1[idx + y * size] * matrix2[x + idx * size];
output[x+y*size] = result;
}
)__";
} // namespace <anonymous>
template<size_t Size>
class square_matrix {
public:
using value_type = fvec::value_type;
static constexpr size_t num_elements = Size * Size;
// allows serialization
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f,
square_matrix& m) {
return f(meta::type_name("square_matrix"), m.data_);
}
square_matrix(square_matrix&&) = default;
square_matrix(const square_matrix&) = default;
square_matrix& operator=(square_matrix&&) = default;
square_matrix& operator=(const square_matrix&) = default;
square_matrix() : data_(num_elements) { }
explicit square_matrix(fvec d) : data_(move(d)) {
assert(data_.size() == num_elements);
}
inline float& operator()(size_t column, size_t row) {
return data_[column + row * Size];
}
inline const float& operator()(size_t column, size_t row) const {
return data_[column + row * Size];
}
inline void iota_fill() {
iota(data_.begin(), data_.end(), 0);
}
using const_iterator = typename fvec::const_iterator;
const_iterator begin() const { return data_.begin(); }
const_iterator end() const { return data_.end(); }
fvec& data() { return data_; }
const fvec& data() const { return data_; }
private:
fvec data_;
};
template<size_t Size>
string to_string(const square_matrix<Size>& m) {
ostringstream oss;
oss.fill(' ');
for (size_t row = 0; row < Size; ++row) {
for (size_t column = 0; column < Size; ++column)
oss << fixed << setprecision(2) << setw(9) << m(column, row);
oss << '\n';
}
return oss.str();
}
// to annouce the square_matrix to libcaf, we have to define these operators
template<size_t Size>
inline bool operator==(const square_matrix<Size>& lhs,
const square_matrix<Size>& rhs) {
return equal(lhs.begin(), lhs.end(), rhs.begin());
}
template<size_t Size>
inline bool operator!=(const square_matrix<Size>& lhs,
const square_matrix<Size>& rhs) {
return !(lhs == rhs);
}
using matrix_type = square_matrix<matrix_size>;
void multiplier(event_based_actor* self) {
auto& mngr = self->system().opencl_manager();
// create two matrices with ascending values
matrix_type m1;
m1.iota_fill();
auto m2 = m1;
// print "source" matrix
cout << "calculating square of matrix:" << endl
<< to_string(m1) << endl;
auto unbox_args = [](message& msg) -> optional<message> {
return msg.apply([](matrix_type& lhs, matrix_type& rhs) {
return make_message(std::move(lhs.data()), std::move(rhs.data()));
});
};
auto box_res = [] (fvec& result) -> message {
return make_message(matrix_type{move(result)});
};
// spawn an opencl actor
// 1st arg: source code of one or more opencl kernels
// 2nd arg: name of the kernel to use
// 3rd arg: the config specifies how many dimensions the kernel uses and how
// many work items are created, creates matrix_size * matrix_size
// global work items in this case
// 4th arg: the opencl function operates on vectors, this function converts
// a tuple of two matrices to a tuple of vectors; note that this
// function returns an option (an empty results causes the actor to
// ignore the message)
// 5th arg: converts the ouptut vector back to a matrix that is then
// used as response message
// from 6 : a description of the kernel signature using in/out/in_out classes
// with the argument type. Since the actor always expects input
// arguments for global memory to be contained in vectors,
// the vector is omitted here.
auto worker = mngr.spawn(kernel_source, kernel_name,
nd_range{dim_vec{matrix_size, matrix_size}},
unbox_args, box_res,
in<float>{}, in<float>{}, out<float>{});
// send both matrices to the actor and
// wait for results in form of a matrix_type
self->request(worker, chrono::seconds(5), move(m1), move(m2)).then(
[](const matrix_type& result) {
cout << "result:" << endl << to_string(result);
}
);
}
int main() {
// matrix_type ist not a simple type,
// it must be annouced to libcaf
actor_system_config cfg;
cfg.load<opencl::manager>()
.add_message_type<fvec>("float_vector")
.add_message_type<matrix_type>("square_matrix");
actor_system system{cfg};
system.spawn(multiplier);
system.await_all_actors_done();
return 0;
}
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <vector>
#include <iomanip>
#include <numeric>
#include <iostream>
#include "caf/all.hpp"
#include "caf/opencl/all.hpp"
using namespace std;
using namespace caf;
using namespace caf::opencl;
using caf::detail::limited_vector;
namespace {
using fvec = std::vector<float>;
constexpr size_t matrix_size = 8;
constexpr const char* kernel_name = "matrix_mult";
// opencl kernel, multiplies matrix1 and matrix2
// last parameter is, by convention, the output parameter
constexpr const char* kernel_source = R"__(
kernel void matrix_mult(global const float* matrix1,
global const float* matrix2,
global float* output) {
// we only use square matrices, hence: width == height
size_t size = get_global_size(0); // == get_global_size_(1);
size_t x = get_global_id(0);
size_t y = get_global_id(1);
float result = 0;
for (size_t idx = 0; idx < size; ++idx)
result += matrix1[idx + y * size] * matrix2[x + idx * size];
output[x+y*size] = result;
}
)__";
} // namespace <anonymous>
void print_as_matrix(const fvec& matrix) {
for (size_t column = 0; column < matrix_size; ++column) {
for (size_t row = 0; row < matrix_size; ++row) {
cout << fixed << setprecision(2) << setw(9)
<< matrix[row + column * matrix_size];
}
cout << endl;
}
}
void multiplier(event_based_actor* self) {
// the opencl actor only understands vectors
// so these vectors represent the matrices
fvec m1(matrix_size * matrix_size);
fvec m2(matrix_size * matrix_size);
// fill each with ascending values
iota(m1.begin(), m1.end(), 0);
iota(m2.begin(), m2.end(), 0);
// print "source" matrix
cout << "calculating square of matrix:" << endl;
print_as_matrix(m1);
cout << endl;
// spawn an opencl actor
// 1st arg: source code of one or more kernels
// 2nd arg: name of the kernel to use
// 3rd arg: a spawn configuration that includes:
// - the global dimension arguments for opencl's enqueue
// creates matrix_size * matrix_size global work items
// - offsets for global dimensions (optional)
// - local dimensions (optional)
// 4th to Nth arg: the kernel signature described by in/out/in_out classes
// that contain the argument type in their template. Since the actor
// expects its arguments for global memory to be passed in vectors,
// the vector type is omitted for brevity.
auto worker = self->system().opencl_manager().spawn(
kernel_source, kernel_name,
nd_range{dim_vec{matrix_size, matrix_size}},
in<float>{}, in<float>{}, out<float>{}
);
// send both matrices to the actor and wait for a result
self->request(worker, chrono::seconds(5), move(m1), move(m2)).then(
[](const fvec& result) {
cout << "result: " << endl;
print_as_matrix(result);
}
);
}
int main() {
actor_system_config cfg;
cfg.load<opencl::manager>()
.add_message_type<fvec>("float_vector");
actor_system system{cfg};
system.spawn(multiplier);
system.await_all_actors_done();
return 0;
}
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <iostream>
#include <utility>
#include "caf/logger.hpp"
#include "caf/ref_counted.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/opencl/global.hpp"
#include "caf/opencl/device.hpp"
#include "caf/opencl/opencl_err.hpp"
using namespace std;
namespace caf {
namespace opencl {
device_ptr device::create(const detail::raw_context_ptr& context,
const detail::raw_device_ptr& device_id,
unsigned id) {
CAF_LOG_DEBUG("creating device for opencl device with id:" << CAF_ARG(id));
// look up properties we need to create the command queue
auto supported = info<cl_ulong>(device_id, CL_DEVICE_QUEUE_PROPERTIES);
bool profiling = false; // (supported & CL_QUEUE_PROFILING_ENABLE) != 0u;
bool out_of_order = (supported & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) != 0u;
unsigned properties = profiling ? CL_QUEUE_PROFILING_ENABLE : 0;
if (out_of_order)
properties |= CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE;
// create the command queue
detail::raw_command_queue_ptr command_queue{
v2get(CAF_CLF(clCreateCommandQueue),
context.get(), device_id.get(),
properties),
false
};
// create the device
auto dev = make_counted<device>(device_id, std::move(command_queue),
context, id);
//device dev{device_id, std::move(command_queue), context, id};
// look up device properties
dev->address_bits_ = info<cl_uint>(device_id, CL_DEVICE_ADDRESS_BITS);
dev->little_endian_ = info<cl_bool>(device_id, CL_DEVICE_ENDIAN_LITTLE);
dev->global_mem_cache_size_ =
info<cl_ulong>(device_id, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE);
dev->global_mem_cacheline_size_ =
info<cl_uint>(device_id, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE);
dev->global_mem_size_ =
info<cl_ulong >(device_id,CL_DEVICE_GLOBAL_MEM_SIZE);
dev->host_unified_memory_ =
info<cl_bool>(device_id, CL_DEVICE_HOST_UNIFIED_MEMORY);
dev->local_mem_size_ =
info<cl_ulong>(device_id, CL_DEVICE_LOCAL_MEM_SIZE);
dev->local_mem_type_ =
info<cl_uint>(device_id, CL_DEVICE_LOCAL_MEM_TYPE);
dev->max_clock_frequency_ =
info<cl_uint>(device_id, CL_DEVICE_MAX_CLOCK_FREQUENCY);
dev->max_compute_units_ =
info<cl_uint>(device_id, CL_DEVICE_MAX_COMPUTE_UNITS);
dev->max_constant_args_ =
info<cl_uint>(device_id, CL_DEVICE_MAX_CONSTANT_ARGS);
dev->max_constant_buffer_size_ =
info<cl_ulong>(device_id, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE);
dev->max_mem_alloc_size_ =
info<cl_ulong>(device_id, CL_DEVICE_MAX_MEM_ALLOC_SIZE);
dev->max_parameter_size_ =
info<size_t>(device_id, CL_DEVICE_MAX_PARAMETER_SIZE);
dev->max_work_group_size_ =
info<size_t>(device_id, CL_DEVICE_MAX_WORK_GROUP_SIZE);
dev->max_work_item_dimensions_ =
info<cl_uint>(device_id, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS);
dev->profiling_timer_resolution_ =
info<size_t>(device_id, CL_DEVICE_PROFILING_TIMER_RESOLUTION);
dev->max_work_item_sizes_.resize(dev->max_work_item_dimensions_);
clGetDeviceInfo(device_id.get(), CL_DEVICE_MAX_WORK_ITEM_SIZES,
sizeof(size_t) * dev->max_work_item_dimensions_,
dev->max_work_item_sizes_.data(), nullptr);
dev->device_type_ =
device_type_from_ulong(info<cl_ulong>(device_id, CL_DEVICE_TYPE));
string extensions = info_string(device_id, CL_DEVICE_EXTENSIONS);
split(dev->extensions_, extensions, " ", false);
dev->opencl_c_version_ = info_string(device_id, CL_DEVICE_EXTENSIONS);
dev->device_vendor_ = info_string(device_id, CL_DEVICE_VENDOR);
dev->device_version_ = info_string(device_id, CL_DEVICE_VERSION);
dev->name_ = info_string(device_id, CL_DEVICE_NAME);
return dev;
}
void device::synchronize() {
clFinish(queue_.get());
}
string device::info_string(const detail::raw_device_ptr& device_id,
unsigned info_flag) {
size_t size;
clGetDeviceInfo(device_id.get(), info_flag, 0, nullptr, &size);
vector<char> buffer(size);
clGetDeviceInfo(device_id.get(), info_flag, sizeof(char) * size, buffer.data(),
nullptr);
return string(buffer.data());
}
device::device(detail::raw_device_ptr device_id,
detail::raw_command_queue_ptr queue,
detail::raw_context_ptr context,
unsigned id)
: device_id_(std::move(device_id)),
queue_(std::move(queue)),
context_(std::move(context)),
id_(id) {
// nop
}
device::~device() {
// nop
}
} // namespace opencl
} // namespace caf
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <fstream>
#include "caf/detail/type_list.hpp"
#include "caf/opencl/device.hpp"
#include "caf/opencl/manager.hpp"
#include "caf/opencl/platform.hpp"
#include "caf/opencl/opencl_err.hpp"
#include "caf/opencl/detail/raw_ptr.hpp"
using namespace std;
namespace caf {
namespace opencl {
optional<device_ptr> manager::find_device(size_t dev_id) const {
if (platforms_.empty())
return none;
size_t to = 0;
for (auto& pl : platforms_) {
auto from = to;
to += pl->devices().size();
if (dev_id >= from && dev_id < to)
return pl->devices()[dev_id - from];
}
return none;
}
void manager::init(actor_system_config&) {
// get number of available platforms
auto num_platforms = v1get<cl_uint>(CAF_CLF(clGetPlatformIDs));
// get platform ids
std::vector<cl_platform_id> platform_ids(num_platforms);
v2callcl(CAF_CLF(clGetPlatformIDs), num_platforms, platform_ids.data());
if (platform_ids.empty())
throw std::runtime_error("no OpenCL platform found");
// initialize platforms (device discovery)
unsigned current_device_id = 0;
for (auto& pl_id : platform_ids) {
platforms_.push_back(platform::create(pl_id, current_device_id));
current_device_id +=
static_cast<unsigned>(platforms_.back()->devices().size());
}
}
void manager::start() {
// nop
}
void manager::stop() {
// nop
}
actor_system::module::id_t manager::id() const {
return actor_system::module::opencl_manager;
}
void* manager::subtype_ptr() {
return this;
}
actor_system::module* manager::make(actor_system& sys,
caf::detail::type_list<>) {
return new manager{sys};
}
program_ptr manager::create_program_from_file(const char* path,
const char* options,
uint32_t device_id) {
std::ifstream read_source{std::string(path), std::ios::in};
string kernel_source;
if (read_source) {
read_source.seekg(0, std::ios::end);
kernel_source.resize(static_cast<size_t>(read_source.tellg()));
read_source.seekg(0, std::ios::beg);
read_source.read(&kernel_source[0],
static_cast<streamsize>(kernel_source.size()));
read_source.close();
} else {
ostringstream oss;
oss << "No file at '" << path << "' found.";
CAF_LOG_ERROR(CAF_ARG(oss.str()));
throw runtime_error(oss.str());
}
return create_program(kernel_source.c_str(), options, device_id);
}
program_ptr manager::create_program(const char* kernel_source,
const char* options,
uint32_t device_id) {
auto dev = find_device(device_id);
if (!dev) {
ostringstream oss;
oss << "No device with id '" << device_id << "' found.";
CAF_LOG_ERROR(CAF_ARG(oss.str()));
throw runtime_error(oss.str());
}
return create_program(kernel_source, options, *dev);
}
program_ptr manager::create_program_from_file(const char* path,
const char* options,
const device_ptr dev) {
std::ifstream read_source{std::string(path), std::ios::in};
string kernel_source;
if (read_source) {
read_source.seekg(0, std::ios::end);
kernel_source.resize(static_cast<size_t>(read_source.tellg()));
read_source.seekg(0, std::ios::beg);
read_source.read(&kernel_source[0],
static_cast<streamsize>(kernel_source.size()));
read_source.close();
} else {
ostringstream oss;
oss << "No file at '" << path << "' found.";
CAF_LOG_ERROR(CAF_ARG(oss.str()));
throw runtime_error(oss.str());
}
return create_program(kernel_source.c_str(), options, dev);
}
program_ptr manager::create_program(const char* kernel_source,
const char* options,
const device_ptr dev) {
// create program object from kernel source
size_t kernel_source_length = strlen(kernel_source);
detail::raw_program_ptr pptr;
pptr.reset(v2get(CAF_CLF(clCreateProgramWithSource), dev->context_.get(),
1u, &kernel_source, &kernel_source_length),
false);
// build programm from program object
auto dev_tmp = dev->device_id_.get();
auto err = clBuildProgram(pptr.get(), 1, &dev_tmp, options, nullptr, nullptr);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clBuildProgram: " << opencl_error(err);
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,
0, 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(char) * buildlog_buffer_size,
buffer.data(), nullptr);
ostringstream ss;
ss << "############## Build log ##############"
<< endl << string(buffer.data()) << endl
<< "#######################################";
// seems that just apple implemented the
// pfn_notify callback, but we can get
// the build log
#ifndef __APPLE__
CAF_LOG_ERROR(CAF_ARG(ss.str()));
#endif
oss << endl << ss.str();
}
throw runtime_error(oss.str());
}
cl_uint number_of_kernels = 0;
clCreateKernelsInProgram(pptr.get(), 0u, nullptr, &number_of_kernels);
map<string, detail::raw_kernel_ptr> available_kernels;
if (number_of_kernels > 0) {
vector<cl_kernel> kernels(number_of_kernels);
err = clCreateKernelsInProgram(pptr.get(), number_of_kernels,
kernels.data(), nullptr);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clCreateKernelsInProgram: " << opencl_error(err);
throw runtime_error(oss.str());
}
for (cl_uint i = 0; i < number_of_kernels; ++i) {
size_t len;
clGetKernelInfo(kernels[i], CL_KERNEL_FUNCTION_NAME, 0, nullptr, &len);
vector<char> name(len);
err = clGetKernelInfo(kernels[i], CL_KERNEL_FUNCTION_NAME, len,
reinterpret_cast<void*>(name.data()), nullptr);
if (err != CL_SUCCESS) {
ostringstream oss;
oss << "clGetKernelInfo (CL_KERNEL_FUNCTION_NAME): "
<< opencl_error(err);
throw runtime_error(oss.str());
}
detail::raw_kernel_ptr kernel;
kernel.reset(move(kernels[i]));
available_kernels.emplace(string(name.data()), move(kernel));
}
} else {
CAF_LOG_WARNING("Could not built all kernels in program. Since this happens"
" on some platforms, we'll ignore this and try to build"
" each kernel individually by name.");
}
return make_counted<program>(dev->context_, dev->queue_, pptr,
move(available_kernels));
}
manager::manager(actor_system& sys) : system_(sys) {
// nop
}
manager::~manager() {
// nop
}
} // namespace opencl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/opencl/opencl_err.hpp"
namespace caf {
namespace opencl {
void throwcl(const char* fname, cl_int err) {
if (err != CL_SUCCESS) {
std::string errstr = fname;
errstr += ": ";
errstr += opencl_error(err);
throw std::runtime_error(std::move(errstr));
}
}
void pfn_notify(const char* errinfo, const void*, size_t, void*) {
CAF_LOG_ERROR("\n##### Error message via pfn_notify #####\n"
<< errinfo <<
"\n########################################");
static_cast<void>(errinfo); // remove warning
}
} // namespace opencl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <utility>
#include <vector>
#include <iostream>
#include "caf/opencl/platform.hpp"
#include "caf/opencl/opencl_err.hpp"
using namespace std;
namespace caf {
namespace opencl {
platform_ptr platform::create(cl_platform_id platform_id,
unsigned start_id) {
vector<unsigned> device_types = {CL_DEVICE_TYPE_GPU,
CL_DEVICE_TYPE_ACCELERATOR,
CL_DEVICE_TYPE_CPU};
vector<cl_device_id> ids;
for (cl_device_type device_type : device_types) {
auto known = ids.size();
cl_uint discoverd;
auto err = clGetDeviceIDs(platform_id, device_type, 0, nullptr, &discoverd);
if (err == CL_DEVICE_NOT_FOUND) {
continue; // no devices of the type found
} else if (err != CL_SUCCESS) {
throwcl("clGetDeviceIDs", err);
}
ids.resize(known + discoverd);
v2callcl(CAF_CLF(clGetDeviceIDs), platform_id, device_type,
discoverd, (ids.data() + known));
}
vector<detail::raw_device_ptr> devices;
devices.resize(ids.size());
auto lift = [](cl_device_id ptr) {
return detail::raw_device_ptr{ptr, false};
};
transform(ids.begin(), ids.end(), devices.begin(), lift);
detail::raw_context_ptr context;
context.reset(v2get(CAF_CLF(clCreateContext), nullptr,
static_cast<unsigned>(ids.size()),
ids.data(), pfn_notify, nullptr),
false);
vector<device_ptr> device_information;
for (auto& device_id : devices) {
device_information.push_back(device::create(context, device_id,
start_id++));
}
if (device_information.empty()) {
string errstr = "no devices for the platform found";
CAF_LOG_ERROR(CAF_ARG(errstr));
throw runtime_error(move(errstr));
}
auto name = platform_info(platform_id, CL_PLATFORM_NAME);
auto vendor = platform_info(platform_id, CL_PLATFORM_VENDOR);
auto version = platform_info(platform_id, CL_PLATFORM_VERSION);
return make_counted<platform>(platform_id, move(context), move(name),
move(vendor), move(version),
move(device_information));
}
string platform::platform_info(cl_platform_id platform_id,
unsigned info_flag) {
size_t size;
auto err = clGetPlatformInfo(platform_id, info_flag, 0, nullptr,
&size);
throwcl("clGetPlatformInfo", err);
vector<char> buffer(size);
v2callcl(CAF_CLF(clGetPlatformInfo), platform_id, info_flag,
sizeof(char) * size, buffer.data());
return string(buffer.data());
}
platform::platform(cl_platform_id platform_id, detail::raw_context_ptr context,
string name, string vendor, string version,
vector<device_ptr> devices)
: platform_id_(platform_id),
context_(std::move(context)),
name_(move(name)),
vendor_(move(vendor)),
version_(move(version)),
devices_(move(devices)) {
// nop
}
platform::~platform() {
// nop
}
} // namespace opencl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <map>
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
#include "caf/opencl/manager.hpp"
#include "caf/opencl/program.hpp"
#include "caf/opencl/opencl_err.hpp"
using namespace std;
namespace caf {
namespace opencl {
program::program(detail::raw_context_ptr context,
detail::raw_command_queue_ptr queue,
detail::raw_program_ptr prog,
map<string, detail::raw_kernel_ptr> available_kernels)
: context_(move(context)),
program_(move(prog)),
queue_(move(queue)),
available_kernels_(move(available_kernels)) {
// nop
}
program::~program() {
// nop
}
} // namespace opencl
} // namespace caf
This diff is collapsed.
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