Commit efe644a0 authored by CARDOSI Paul's avatar CARDOSI Paul
Browse files

Add interface support for gpu callables.

Patition and check task method call arguments for both tasks created by the user and tasks created internally by the runtime.
Replace index_sequence unpacking logic with a foreach_in_tuple template function.
Restructure SpRuntime source file.
Use g++-8 for ci tests.
parent b90adddb
......@@ -4,7 +4,7 @@ FROM ubuntu:18.04
RUN apt-get update \
&& apt-get install -y apt-transport-https \
&& apt-get install -y wget \
&& apt-get install -y g++-7 \
&& apt-get install -y g++-8 \
&& apt-get install -y git \
&& apt-get install -y make \
&& wget https://github.com/Kitware/CMake/releases/download/v3.15.6/cmake-3.15.6-Linux-x86_64.sh && chmod +x cmake-3.15.6-Linux-x86_64.sh \
......
......@@ -6,7 +6,7 @@ spetabaru:
script:
- mkdir build
- cd build
- VERBOSE=1 CXX=g++-7 cmake -DUSE_ADVANCE_TESTING=ON ..
- VERBOSE=1 CXX=g++-8 cmake -DUSE_ADVANCE_TESTING=ON ..
- make
- CTEST_OUTPUT_ON_FAILURE=TRUE make test
......@@ -17,7 +17,7 @@ spetabaru-debug:
script:
- mkdir build
- cd build
- VERBOSE=1 CXX=g++-7 cmake -DCMAKE_BUILD_TYPE=DEBUG -DUSE_ADVANCE_TESTING=ON ..
- VERBOSE=1 CXX=g++-8 cmake -DCMAKE_BUILD_TYPE=DEBUG -DUSE_ADVANCE_TESTING=ON ..
- make
- CTEST_OUTPUT_ON_FAILURE=TRUE make test
......@@ -49,7 +49,7 @@ spetabaru-debug-coverage:
script:
- mkdir build
- cd build
- VERBOSE=1 CXX=g++-7 cmake -DCMAKE_BUILD_TYPE=DEBUG -DSPETABARU_USE_COVERAGE=ON ..
- VERBOSE=1 CXX=g++-8 cmake -DCMAKE_BUILD_TYPE=DEBUG -DSPETABARU_USE_COVERAGE=ON ..
- make
- CTEST_OUTPUT_ON_FAILURE=TRUE make test
- lcov --directory ./ -c -o coverage-rapport.info
......
......@@ -122,6 +122,8 @@ if(NOT SPETABARU_AS_SUBPROJECT)
set(SPETABARU_CXX_FLAGS "${SPETABARU_CXX_FLAGS} -m64")
endif()
OPTION(SPETABARU_COMPILE_WITH_CUDA "Set to on to compile tasks with GPU callables" OFF)
OPTION( SPETABARU_ATTACHE_SOURCE "Set to on to add -g flag" OFF )
if( SPETABARU_ATTACHE_SOURCE )
set(SPETABARU_CXX_FLAGS "${SPETABARU_CXX_FLAGS} -g")
......@@ -136,8 +138,8 @@ endif()
#===========================================================================
# Generate config
#===========================================================================
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Src/SPETABARUConfig.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/Src/SPETABARUConfig.h )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Src/Config/SpConfig.hpp.cmake
${CMAKE_CURRENT_BINARY_DIR}/Src/Config/SpConfig.hpp )
#===========================================================================
# Build lib
......
......@@ -2,12 +2,21 @@
// SPETABARU - Berenger Bramas MPCDF - 2016
// Under LGPL Licence, please you must read the LICENCE file.
///////////////////////////////////////////////////////////////////////////
#ifndef SPETABARUCONFIG_H
#define SPETABARUCONFIG_H
#ifndef SPCONFIG_H
#define SPCONFIG_H
// Define all macros (ADD-NEW-HERE)
// #cmakedefine SPETABARU_USE_X
// @SPETABARU_X@
#cmakedefine SPETABARU_COMPILE_WITH_CUDA
namespace SpConfig {
#ifdef SPETABARU_COMPILE_WITH_CUDA
inline constexpr bool CompileWithCuda = true;
#else
inline constexpr bool CompileWithCuda = false;
#endif
}
#endif
This diff is collapsed.
......@@ -117,6 +117,7 @@ public:
virtual bool hasMode(const SpDataAccessMode inMode) const = 0;
virtual small_vector<std::pair<SpDataHandle*,SpDataAccessMode>> getDataHandles() const = 0;
virtual void executeCallback() = 0;
virtual bool hasCallableOfType(const SpCallableType sct) const = 0;
virtual std::string getTaskBodyString() = 0;
void useDependences() {
......@@ -333,6 +334,10 @@ public:
target->setOriginalTask(inOriginal);
}
bool hasCallableOfType(const SpCallableType sct) const {
return target->hasCallableOfType(sct);
}
friend SpAbstractTaskWithReturn;
};
private:
......@@ -433,6 +438,10 @@ public:
void setOriginalTask(SpAbstractTask* inOriginal){// For speculation
target->setOriginalTask(inOriginal);
}
bool hasCallableOfType(const SpCallableType sct) const {
return target->hasCallableOfType(sct);
}
friend SpAbstractTaskWithReturn;
};
......
......@@ -17,23 +17,19 @@
#include <cxxabi.h>
#endif
template <class TaskFuncType, class RetType, class ... Params>
template <class RetType, class DataDependencyTupleTy, class CallableTupleTy>
class SpTask : public SpAbstractTaskWithReturn<RetType> {
using Parent = SpAbstractTask;
using ParentReturn = SpAbstractTaskWithReturn<RetType>;
using TupleParamsType = std::tuple<Params...>;
//! Number of parameters in the task function prototype
static const long int NbParams = sizeof...(Params);
static const long int NbParams = std::tuple_size<DataDependencyTupleTy>::value;
//! Internal value for undefined dependences
static constexpr long int UndefinedKey(){
return -1;
}
//! Function to call
TaskFuncType taskCallback;
//! Data handles
std::array<SpDataHandle*,NbParams> dataHandles;
//! Dependences' keys for each handle
......@@ -44,45 +40,49 @@ class SpTask : public SpAbstractTaskWithReturn<RetType> {
//! Extra handles's dependences keys
small_vector<long int> dataHandlesKeysExtra;
//! Params (inside data mode)
TupleParamsType tupleParams;
//! DataDependency objects
DataDependencyTupleTy tupleParams;
//! Callables
CallableTupleTy callables;
///////////////////////////////////////////////////////////////////////////////
/// Methods to call the task function with a conversion from handle to data
///////////////////////////////////////////////////////////////////////////////
//! Expand the tuple with the index and call getView
template <std::size_t... Is>
static RetType SpTaskCoreWrapper(TaskFuncType& taskCallback, TupleParamsType& params, std::index_sequence<Is...>){
return taskCallback( std::get<Is>(params).getView() ... );
template <class CallableTy, std::size_t... Is>
static RetType SpTaskCoreWrapper(CallableTy &callable, DataDependencyTupleTy &dataDep, std::index_sequence<Is...>){
return std::invoke(callable.getCallableRef(), std::get<Is>(dataDep).getView()...);
}
//! Dispatch use if RetType is not void (will set parent value with the return from function)
template <class SRetType>
static void executeCore(SpAbstractTaskWithReturn<SRetType>* taskObject, TaskFuncType& taskCallback, TupleParamsType& params) {
taskObject->setValue(SpTaskCoreWrapper(taskCallback, params, std::make_index_sequence<std::tuple_size<TupleParamsType>::value>{}));
template <class SRetType, class CallableTy>
static void executeCore(SpAbstractTaskWithReturn<SRetType>* taskObject, CallableTy &callable, DataDependencyTupleTy &dataDep) {
taskObject->setValue(SpTaskCoreWrapper(callable, dataDep, std::make_index_sequence<std::tuple_size<DataDependencyTupleTy>::value>{}));
}
//! Dispatch use if RetType is void (will not set parent value with the return from function)
static void executeCore(SpAbstractTaskWithReturn<void>* /*taskObject*/, TaskFuncType& taskCallback, TupleParamsType& params) {
SpTaskCoreWrapper(taskCallback, params, std::make_index_sequence<std::tuple_size<TupleParamsType>::value>{});
template <class CallableTy>
static void executeCore(SpAbstractTaskWithReturn<void>* /*taskObject*/, CallableTy &callable, DataDependencyTupleTy &dataDep) {
SpTaskCoreWrapper(callable, dataDep, std::make_index_sequence<NbParams>{});
}
//! Called by parent abstract task class
void executeCore() final {
//Equivalent to ParentReturn::setValue(SpTaskCoreWrapper(taskCallback, dataHandles.data()));
executeCore(this, taskCallback, tupleParams);
executeCore(this, std::get<0>(callables), tupleParams);
}
public:
//! Constructor from a task function
template <class TaskFuncTypeCstr, typename... T>
explicit SpTask(TaskFuncTypeCstr&& inTaskCallback, const SpTaskActivation initialActivationState,
const SpPriority& inPriority,
TupleParamsType&& inTupleParams, T... t)
template <typename... T>
explicit SpTask(const SpTaskActivation initialActivationState,
const SpPriority &inPriority,
DataDependencyTupleTy &&inDataDepTuple,
CallableTupleTy &&inCallableTuple, T... t)
: SpAbstractTaskWithReturn<RetType>(initialActivationState, inPriority),
taskCallback(std::forward<TaskFuncTypeCstr>(inTaskCallback)),
tupleParams(inTupleParams){
tupleParams(inDataDepTuple),
callables(std::move(inCallableTuple)) {
((void) t, ...);
std::fill_n(dataHandles.data(), NbParams, nullptr);
std::fill_n(dataHandlesKeys.data(), NbParams, UndefinedKey());
......@@ -90,14 +90,18 @@ public:
#ifdef __GNUG__
// if GCC then we ask for a clean type as default task name
int status;
char *demangledName = abi::__cxa_demangle(typeid(TaskFuncType).name(), 0, 0, &status);
char *demangledName = abi::__cxa_demangle(typeid(std::remove_reference_t<decltype(std::get<0>(callables))>).name(), 0, 0, &status);
Parent::setTaskName(demangledName);
free(demangledName);
#else
Parent::setTaskName(typeid(TaskFuncType).name());
Parent::setTaskName(typeid(std::remove_reference_t<decltype(std::get<0>(callables))>).name());
#endif
}
DataDependencyTupleTy& getDataDependencyTupleRef() {
return tupleParams;
}
//! Set the dependence at position HandleIdx in the prototype
template <long int HandleIdx>
void setDataHandle(SpDataHandle* inData, const long int inHandleKey){
......@@ -332,6 +336,14 @@ public:
return true;
}
bool hasCallableOfType([[maybe_unused]] const SpCallableType sct) const override final {
if constexpr(std::tuple_size_v<CallableTupleTy> == 1) {
return std::tuple_element_t<0, CallableTupleTy>::callable_type == sct;
} else {
return true;
}
}
std::string getTaskBodyString() override {
......@@ -348,22 +360,21 @@ public:
}
};
template <class TaskFuncType, class RetType, class ... Params>
class SpSelectTask : public SpTask<TaskFuncType, RetType, Params...>
template <class RetType, class DataDependencyTupleTy, class CallableTupleTy>
class SpSelectTask : public SpTask<RetType, DataDependencyTupleTy, CallableTupleTy>
{
using Parent = SpTask<TaskFuncType, RetType, Params...>;
using TupleParamsType = std::tuple<Params...>;
using Parent = SpTask<RetType, DataDependencyTupleTy, CallableTupleTy>;
// flag indicating if the select task is carrying surely written values over
bool isCarrSurWrittValuesOver;
public:
template <class TaskFuncTypeCstr, typename... T>
explicit SpSelectTask(TaskFuncTypeCstr&& inTaskCallback, const SpTaskActivation initialActivationState,
explicit SpSelectTask(const SpTaskActivation initialActivationState,
const SpPriority& inPriority,
TupleParamsType&& inTupleParams, bool iCSWVO)
: Parent(std::forward<TaskFuncTypeCstr>(inTaskCallback), initialActivationState, inPriority,
std::forward<TupleParamsType>(inTupleParams)), isCarrSurWrittValuesOver(iCSWVO) {}
DataDependencyTupleTy &&inDataDepTuple,
CallableTupleTy &&inCallableTuple, bool iCSWVO)
: Parent(initialActivationState, inPriority,
std::move(inDataDepTuple), std::move(inCallableTuple)), isCarrSurWrittValuesOver(iCSWVO) {}
void setEnabledDelegate(const SpTaskActivation inIsEnable) override final {
if((inIsEnable == SpTaskActivation::DISABLE && !isCarrSurWrittValuesOver)
......
......@@ -8,6 +8,7 @@
#include <type_traits>
#include <array>
#include "Config/SpConfig.hpp"
#include "SpArrayView.hpp"
#include "SpDebug.hpp"
#include "Data/SpDataDuplicator.hpp"
......@@ -286,4 +287,67 @@ struct has_getAllData : std::false_type {};
template<class T>
struct has_getAllData<T, void_t<decltype(std::declval<T>().getAllData())>> : std::true_type {};
template <SpDataAccessMode dam1, SpDataAccessMode dam2>
struct access_modes_are_equal_internal : std::conditional_t<dam1==dam2, std::true_type, std::false_type> {};
template<SpDataAccessMode dam1, typename T, typename = std::void_t<>>
struct access_modes_are_equal : std::false_type {};
template <SpDataAccessMode dam1, typename T>
struct access_modes_are_equal<dam1, T, std::void_t<decltype(T::AccessMode)>> : access_modes_are_equal_internal<dam1, T::AccessMode> {};
enum class SpCallableType {
CPU=0,
GPU
};
template <bool compileWithCuda, class T, SpCallableType ct>
class SpCallableWrapper {
private:
using CallableTy = std::remove_reference_t<T>;
CallableTy callable;
public:
static constexpr auto callable_type = ct;
template <typename T2, typename=std::enable_if_t<std::is_same<std::remove_reference_t<T2>, CallableTy>::value>>
SpCallableWrapper(T2 &&inCallable) : callable(std::forward<T2>(inCallable)) {}
CallableTy& getCallableRef() {
return callable;
}
};
template <class T, SpCallableType ct>
class SpCallableWrapper<false, T, ct> {
public:
template<typename T2>
SpCallableWrapper(T2&&) {}
};
template <class T>
auto SpCpu(T &&callable) {
return SpCallableWrapper<true, T, SpCallableType::CPU>(std::forward<T>(callable));
}
template <class T>
auto SpGpu(T &&callable) {
return SpCallableWrapper<SpConfig::CompileWithCuda, T, SpCallableType::GPU>(std::forward<T>(callable));
}
template <class T0>
struct is_instantiation_of_callable_wrapper : std::false_type {};
template <bool b, class T0, SpCallableType ct>
struct is_instantiation_of_callable_wrapper<SpCallableWrapper<b, T0, ct>> : std::true_type {};
template <class T0, SpCallableType callableType0>
struct is_instantiation_of_callable_wrapper_with_type : std::false_type {};
template <bool b, class T0, SpCallableType callableType0, SpCallableType callableType1>
struct is_instantiation_of_callable_wrapper_with_type<SpCallableWrapper<b, T0, callableType1>, callableType0> :
std::conditional_t<callableType0==callableType1, std::true_type, std::false_type> {};
template <class T, SpCallableType callableType>
inline constexpr bool is_instantiation_of_callable_wrapper_with_type_v = is_instantiation_of_callable_wrapper_with_type<T, callableType>::value;
#endif
......@@ -9,6 +9,7 @@
#include <string>
#include <sstream>
#include <cstring>
#include <functional>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
......@@ -113,12 +114,40 @@ namespace SpUtils{
exit(-1);
}
}
template <typename CallableTy, typename TupleTy, std::size_t... Is,
std::enable_if_t<std::conjunction_v<std::is_invocable<CallableTy, std::tuple_element_t<Is, std::remove_reference_t<TupleTy>>>...>, int> = 0>
static void foreach_in_tuple_impl(CallableTy &&c, TupleTy &&t, std::index_sequence<Is...>) {
if constexpr(sizeof...(Is) > 0) {
using RetTy = std::invoke_result_t<CallableTy, std::tuple_element_t<0, std::remove_reference_t<TupleTy>>>;
if constexpr(std::is_same_v<RetTy, bool>) {
(std::invoke(std::forward<CallableTy>(c), std::get<Is>(std::forward<TupleTy>(t))) || ...);
} else {
(static_cast<void>(std::invoke(std::forward<CallableTy>(c), std::get<Is>(std::forward<TupleTy>(t)))),...);
}
}
}
template <template <typename...> typename Template, typename T>
struct is_instantiation_of : std::false_type {};
template <template <typename...> typename Template, typename... Args>
struct is_instantiation_of<Template, Template<Args...> > : std::true_type {};
template <typename CallableTy, typename TupleTy, std::size_t... Is,
std::enable_if_t<std::conjunction_v<std::is_invocable<CallableTy, std::integral_constant<size_t, Is>,
std::tuple_element_t<Is, std::remove_reference_t<TupleTy>>>...>, int> = 0>
static void foreach_in_tuple_impl(CallableTy &&c, TupleTy &&t, std::index_sequence<Is...>) {
if constexpr(sizeof...(Is) > 0) {
using RetTy = std::invoke_result_t<CallableTy, std::integral_constant<size_t, 0>, std::tuple_element_t<0, std::remove_reference_t<TupleTy>>>;
if constexpr(std::is_same_v<RetTy, bool>) {
(std::invoke(std::forward<CallableTy>(c), std::integral_constant<size_t, Is>{}, std::get<Is>(std::forward<TupleTy>(t))) || ...);
} else {
(static_cast<void>(std::invoke(std::forward<CallableTy>(c), std::integral_constant<size_t, Is>{}, std::get<Is>(std::forward<TupleTy>(t)))),...);
}
}
}
template <typename CallableTy, typename TupleTy>
static void foreach_in_tuple(CallableTy &&c, TupleTy &&t) {
foreach_in_tuple_impl(std::forward<CallableTy>(c), std::forward<TupleTy>(t), std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<TupleTy>>>{});
}
}
#define spetabaru_xstr(s) spetabaru_str(s)
......
///////////////////////////////////////////////////////////////////////////
// Spetabaru - Berenger Bramas MPCDF - 2017
// Under LGPL Licence, please you must read the LICENCE file.
///////////////////////////////////////////////////////////////////////////
#include "Config/SpConfig.hpp"
#include "Utils/SpModes.hpp"
#include "Utils/SpUtils.hpp"
#include "Tasks/SpTask.hpp"
#include "Runtimes/SpRuntime.hpp"
// @NBTESTS = 5
int main(){
const int NumThreads = SpUtils::DefaultNumThreads();
SpRuntime runtime(NumThreads);
const double initVal = 1.0;
double writeVal = 0.0;
#ifdef TEST1
runtime.task(SpRead(initVal),
[]([[maybe_unused]] const double& initValParam){},
[]([[maybe_unused]] const double& initValParam){});
#endif
#ifdef TEST2
runtime.task(SpRead(initVal),
SpCpu([]([[maybe_unused]] const double& initValParam){}),
SpCpu([]([[maybe_unused]] const double& initValParam){}));
#endif
#ifdef TEST3
runtime.task(SpRead(initVal),
SpGpu([]([[maybe_unused]] const double& initValParam){})
SpGpu([]([[maybe_unused]] const double& initValParam){}));
#endif
#ifdef TEST4
if constexpr(!SpConfig::CompileWithCuda) {
runtime.task(SpRead(initVal),
SpGpu([]([[maybe_unused]] const double& initValParam){}));
} else {
static_assert(false, "Force wrongPrototypeExtended-4 to fail.");
}
#endif
#ifdef TEST5
runtime.task(SpProbability(0.25), SpRead(initVal), SpWrite(writeVal),
SpCpu([]([[maybe_unused]] const double& initValParam, double& writeValParam) {
writeValParam = 42;
}));
#endif
runtime.waitAllTasks();
runtime.stopAllThreads();
}
///////////////////////////////////////////////////////////////////////////
// Spetabaru - Berenger Bramas MPCDF - 2017
// Under LGPL Licence, please you must read the LICENCE file.
///////////////////////////////////////////////////////////////////////////
#include "UTester.hpp"
#include "utestUtils.hpp"
#include "Utils/SpModes.hpp"
#include "Utils/SpUtils.hpp"
#include "Utils/SpArrayView.hpp"
#include "Utils/SpArrayAccessor.hpp"
#include "Tasks/SpTask.hpp"
#include "Runtimes/SpRuntime.hpp"
class TestCallableWrappers : public UTester< TestCallableWrappers > {
using Parent = UTester< TestCallableWrappers >;
template <SpSpeculativeModel Spm>
void Test(){
SpRuntime<Spm> runtime;
runtime.setSpeculationTest([](const int /*inNbReadyTasks*/, const SpProbability& /*inProbability*/) -> bool{
return true;
});
int a=0;
runtime.task(SpWrite(a), [](int& param_a){
param_a++;
});
runtime.task(SpWrite(a), SpCpu([](int& param_a){
param_a++;
}));
runtime.task(SpWrite(a),
[](int& param_a){
param_a++;
},
SpGpu([](int& param_a){
param_a++;
}));
runtime.task(SpWrite(a),
SpCpu([](int& param_a){
param_a++;
}),
SpGpu([](int& param_a){
param_a++;
}));
runtime.task(SpWrite(a),
SpGpu([](int& param_a){
param_a++;
}),
[](int& param_a){
param_a++;
});
runtime.task(SpWrite(a),
SpGpu([](int& param_a){
param_a++;
}),
SpCpu([](int& param_a){
param_a++;
}));
runtime.waitAllTasks();
runtime.stopAllThreads();
UASSERTETRUE(a == 6);
}
void Test1() { Test<SpSpeculativeModel::SP_MODEL_1>(); }
void SetTests() {
Parent::AddTest(&TestCallableWrappers::Test1, "Test callable wrappers.");
}
};
// You must do this
TestClass(TestCallableWrappers)
......@@ -24,8 +24,8 @@ class MethodTest : public UTester< MethodTest > {
class C_constint{
public:
C_constint() = default;
C_constint(const C_constint&) = delete;
C_constint& operator=(const C_constint&) = delete;
C_constint(const C_constint&) = default;
C_constint& operator=(const C_constint&) = default;
C_constint(C_constint&&) = default;
C_constint& operator=(C_constint&&) = default;
......@@ -43,8 +43,8 @@ class MethodTest : public UTester< MethodTest > {
class C_constint_intref{
public:
C_constint_intref() = default;
C_constint_intref(const C_constint_intref&) = delete;
C_constint_intref& operator=(const C_constint_intref&) = delete;
C_constint_intref(const C_constint_intref&) = default;
C_constint_intref& operator=(const C_constint_intref&) = default;
C_constint_intref(C_constint_intref&&) = default;
C_constint_intref& operator=(C_constint_intref&&) = default;
......@@ -63,8 +63,8 @@ class MethodTest : public UTester< MethodTest > {
class C_intref{
public:
C_intref() = default;
C_intref(const C_intref&) = delete;
C_intref& operator=(const C_intref&) = delete;
C_intref(const C_intref&) = default;
C_intref& operator=(const C_intref&) = default;
C_intref(C_intref&&) = default;
C_intref& operator=(C_intref&&) = default;
......
Supports Markdown
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