21#include <boost/function_types/function_arity.hpp>
22#include <boost/function_types/parameter_types.hpp>
23#include <boost/function.hpp>
24#include <boost/mpl/begin.hpp>
25#include <boost/mpl/next.hpp>
26#include <boost/mpl/deref.hpp>
28#include "depspawn/fixed_defines.h"
32#error Only the Blitz++ version released with DepSpawn can be used with DepSpawn
36#ifdef DEPSPAWN_USE_TBB
41#include "depspawn/TaskPool.h"
44#ifndef DEPSPAWN_SCALABLE_POOL
46#define DEPSPAWN_SCALABLE_POOL false
55#ifdef DEPSPAWN_DUMMY_POOL
56#include "depspawn/DummyLinkedListPool.h"
58#include "depspawn/LinkedListPool.h"
103 void *
addr()
const {
return (
void *)&t_; }
119#ifdef DEPSPAWN_DUMMY_POOL
120 template<
typename T,
bool SCALABLE>
121 using Pool_t = DummyLinkedListPool<T, SCALABLE>;
123 template<
typename T,
bool SCALABLE>
124 using Pool_t = LinkedListPool<T, true, SCALABLE>;
133 template<
typename MembFuncPtr>
134 struct memb_func_traits
137 template<
typename ClassT,
typename R,
typename... Arg>
138 struct memb_func_traits<R ClassT::* (Arg...)>
140 typedef ClassT class_type;
141 typedef R signature (Arg...);
144 template<
typename ClassT,
typename R,
typename... Arg>
145 struct memb_func_traits<R (ClassT::*) (Arg...) const>
147 typedef ClassT class_type;
148 typedef R signature (Arg...);
152 struct function_type {
153 typedef typename memb_func_traits<
decltype(&F::operator())>::signature signature;
154 typedef std::function<signature> type;
159 template<
typename ClassT,
typename R,
typename... Arg>
160 struct function_type<R (ClassT::*) (Arg...)> {
161 typedef R signature (ClassT&, Arg...);
162 typedef std::function<signature> type;
167 template<
typename ClassT,
typename R,
typename... Arg>
168 struct function_type<R (ClassT::*) (Arg...) const> {
169 typedef R signature (
const ClassT&, Arg...);
170 typedef std::function<signature> type;
174 typename function_type<F>::type make_function(F && f)
176 typedef typename function_type<F>::type result_type;
177 return result_type(std::forward<F>(f));
185 struct is_function_object :
public std::false_type {};
188 struct is_function_object<std::function<T>> :
public std::true_type {};
191 struct is_function_object<boost::function<T>> :
public std::true_type {};
202 template <
typename T>
203 struct ParameterTypes {
204 using intl_type =
typename function_type<T>::signature;
205 using type =
typename ParameterTypes<intl_type>::type;
208 template <
typename T>
209 struct ParameterTypes<T&> {
210 using type =
typename ParameterTypes<T>::type;
213 template<
typename R,
typename... Types>
214 struct ParameterTypes<R(Types...)> {
215 using type = boost::function_types::parameter_types<R(Types...)>;
218 template<
typename Function>
219 struct ParameterTypes<std::function<Function>> {
220 using type = boost::function_types::parameter_types<Function>;
223 template<
typename Function>
224 struct ParameterTypes<boost::function<Function>> {
225 using type = boost::function_types::parameter_types<Function>;
228 template<
typename R,
typename... Types>
229 struct ParameterTypes<R (&) (Types...)> {
230 using type = boost::function_types::parameter_types<R(Types...)>;
233 template <
typename R,
typename C,
typename... Types>
234 struct ParameterTypes<R (C::*)(Types...)> {
235 using type = boost::function_types::parameter_types<R(C&, Types...)>;
238 template <
typename R,
typename C,
typename... Types>
239 struct ParameterTypes<R (C::*)(Types...) const> {
240 using type = boost::function_types::parameter_types<R(C&, Types...)>;
246 typedef size_t value_t;
249 typedef std::pair<int, int> array_range_t;
253 struct is_blitz_array :
public std::false_type {};
259 array_range_t* array_range;
265 void insert_in_arglist(arg_info*& args);
268 void solve_overlap(arg_info *other);
272 bool overlap_array(
const arg_info *other)
const;
276 bool is_contained_array(
const arg_info *other)
const;
279 bool is_array()
const {
return rank != 0; }
284 inline typename std::enable_if< is_blitz_array<T>::value >::type fill_in_array(
const T& a) {
285 addr = (value_t)a.block();
286 const auto& storage = a.storage();
287 rank = storage.originalDims();
288 array_range =
new array_range_t[rank];
289 const blitz::TinyVector<int, 2> *
const extent = storage.extent();
290 for(
int i = 0; i < rank; i++) {
291 array_range[i] = std::make_pair(extent[i][0], extent[i][1]);
298 inline typename std::enable_if< ! is_blitz_array<T>::value >::type fill_in_array(
const T& a) {
301 array_range =
nullptr;
305 static Pool_t<arg_info, DEPSPAWN_SCALABLE_POOL> Pool;
315 static inline auto make(T& t) ->
decltype(std::ref(t)) {
322 static inline T& make(T& t) {
329 struct ref<Ignore<T>&&> {
330 static inline auto make(Ignore<T>& t) ->
decltype(std::ref((T&)t)) {
331 return std::ref((T&)t);
336 template<
typename type,
int dim>
337 struct ref<blitz::Array<type, dim>&&> {
338 static inline blitz::Array<type, dim> make(blitz::Array<type, dim>& __t) {
343 template<
typename type,
int dim>
344 struct ref<blitz::Array<type, dim>&> {
345 static inline blitz::Array<type, dim> make(blitz::Array<type, dim>& __t) {
350 template<
typename type,
int dim>
351 struct ref<const blitz::Array<type, dim>&> {
352 static inline const blitz::Array<type, dim> make(
const blitz::Array<type, dim>& __t) {
357 template<
typename type,
int dim>
358 struct ref<const blitz::Array<type, dim>> {
359 static inline const blitz::Array<type, dim> make(
const blitz::Array<type, dim>& __t) {
371 static const bool value =
false;
375 struct is_ignored<Ignore<T>&&> {
376 static const bool value =
true;
381#ifdef DEPSPAWN_USE_TBB
383 extern tbb::task*
volatile master_task;
385 struct AbstractBoxedFunction;
386 struct AbstractRunner;
388 extern TaskPool *
volatile TP;
389 using AbstractRunner = TaskPool::Task;
393 extern bool EnqueueTasks;
400#include "depspawn/workitem.h"
407 extern thread_local Workitem * enum_thr_spec_father;
410 extern void start_master();
413 extern void common_wait_for(arg_info *pargs,
int nargs);
415#ifdef DEPSPAWN_USE_TBB
418 struct AbstractBoxedFunction {
424 AbstractBoxedFunction(Workitem* ctx)
428 void run_in_env(
bool from_wait);
430 virtual ~AbstractBoxedFunction() {}
435 virtual void run() = 0;
439 template<
typename Function>
440 struct BoxedFunction :
public AbstractBoxedFunction {
447 BoxedFunction(Workitem* ctx, Function&& f)
448 : AbstractBoxedFunction(ctx), f_(std::move(f))
451 virtual ~BoxedFunction() {}
463 struct AbstractRunner :
public tbb::task {
465 std::atomic<Workitem *> ctx_;
469 AbstractRunner(Workitem * ctx)
474 virtual AbstractBoxedFunction * steal(Workitem *ctx) = 0;
476 virtual ~AbstractRunner() {}
480 template<
typename Function>
481 struct runner :
public AbstractRunner {
489 template<
typename InputFunction,
typename... Args>
490 runner(Workitem* ctx,
const InputFunction& f, Args&&... args)
491 : AbstractRunner(ctx), f_(std::bind(f, internal::ref<Args&&>::make(args)...))
495 AbstractBoxedFunction * steal(Workitem *ctx)
final {
498 return new BoxedFunction<Function>(ctx, std::move(f_));
504 Workitem *
const ctx_copy = ctx_.exchange(
nullptr);
506 if (ctx_copy !=
nullptr) {
508 if (!ctx_copy->guard_.fetch_add(1)) {
510 ctx_copy->status = Workitem::Status_t::Running;
512 Workitem *& ref_father_lcl = enum_thr_spec_father;
513 ref_father_lcl = ctx_copy;
519 ref_father_lcl =
nullptr;
521 ctx_copy->finish_execution();
524 while (ctx_copy->guard_ < 3) { }
525 ctx_copy->guard_ = 4;
541 template<
typename T_it>
542 int fill_args(arg_info*&) {
return 0; }
545 template<
typename T_it,
typename Head,
typename... Tail>
546 int fill_args(arg_info*& args, Head&& h, Tail&&... t) {
547 typedef typename boost::mpl::deref<T_it>::type curr_t;
548 constexpr bool is_reference = std::is_reference<curr_t>::value;
549 typedef typename std::remove_reference<curr_t>::type deref_t;
550 constexpr bool is_const = std::is_const<deref_t>::value;
551 constexpr bool is_writable = is_reference && !is_const;
552 constexpr bool is_barray = is_blitz_array<typename std::remove_const<typename std::remove_reference<Head>::type>::type>::value;
553 constexpr int process_argument =
554 !is_ignored<curr_t&&>::value &&
555 !is_ignored<Head&&>::value &&
556 !(std::is_rvalue_reference<Head&&>::value && !is_barray);
558 if(process_argument) {
560 arg_info* n = arg_info::Pool.malloc();
561 n->size =
sizeof(Head);
567 n->insert_in_arglist(args);
570 return process_argument + fill_args<typename boost::mpl::next<T_it>::type>(args, std::forward<Tail>(t)...);
574typedef void spawn_ret_t;
607#ifdef SEQUENTIAL_DEPSPAWN
609#define spawn(f, ...) f(__VA_ARGS__)
613 template<
typename Function,
typename... Args>
614 inline internal::spawn_ret_t spawn(
const Function& f, Args&&... args) {
615 using parameter_types =
typename internal::ParameterTypes<Function>::type;
617 internal::arg_info *pargs =
nullptr;
618 const int nargs = internal::fill_args<typename boost::mpl::begin<parameter_types>::type>(pargs, std::forward<Args>(args)...);
620#ifdef DEPSPAWN_USE_TBB
621 if(!internal::master_task)
622 internal::start_master();
624 internal::Workitem* w = internal::Workitem::Pool.malloc(pargs, nargs);
625 w->insert_in_worklist(
new (tbb::task::allocate_additional_child_of(*internal::master_task)) internal::runner<
decltype(std::bind(f, internal::ref<Args&&>::make(args)...))>(w, f, std::forward<Args>(args)...));
627 if(!internal::TP || !internal::TP->is_running())
628 internal::start_master();
630 internal::Workitem* w = internal::Workitem::Pool.malloc(pargs, nargs);
631 w->insert_in_worklist(internal::TP->build_task(w, f, internal::ref<Args&&>::make(args)...));
636 template<
typename T,
typename... Args>
637 typename std::enable_if< std::is_reference<T>::value &&
638 ! std::is_member_function_pointer<typename std::remove_reference<T>::type>::value &&
639 ! std::is_function<typename std::remove_reference<T>::type>::value &&
640 ! internal::is_function_object<typename std::remove_reference<T>::type>::value,
641 internal::spawn_ret_t >::type
642 spawn(T&& functor, Args&&... args) {
643 using base_type =
typename std::remove_reference<T>::type;
644 return spawn(& base_type::operator(), std::forward<T>(functor), std::forward<Args>(args)...);
664 template<
typename... Args>
667#ifdef DEPSPAWN_USE_TBB
668 if(!internal::master_task)
670 if(!internal::TP || !internal::TP->is_running())
674 typedef void Function(
const Args&... args);
676 typedef boost::function_types::parameter_types<Function> parameter_types;
677 internal::arg_info *pargs =
nullptr;
678 const int nargs = internal::fill_args<typename boost::mpl::begin<parameter_types>::type>(pargs, args...);
680 internal::common_wait_for(pargs, nargs);
696 internal::Workitem *
const limit_;
699 internal::Workitem *
const cur_father_;
702 const bool priority_;
709 Observer(
bool priority, internal::Workitem *w);
730#define depspawnBottomTOKENPASTE(x, y) x ## y
731#define depspawnTOKENPASTE(x, y) depspawnBottomTOKENPASTE(x, y)
734#define depspawn_sync(...) { depspawn::Observer depspawnTOKENPASTE(__depspawn_temporary, __LINE__);\
744 void for_range(
const blitz::Range& r,
const F& f,
int bs = -1) {
747 if(bs == -1) bs = (r.length() + num_threads - 1) / (num_threads);
750 for(i = r.first(); i < r.last(); i+=bs) {
751 lbs = r.last() -i +1 <= bs ? r.last() -i +1 : bs;
752 f(blitz::Range(i, i+lbs-1));
763 void for_range(
const blitz::Range& r1,
const blitz::Range& r2,
const F& f,
int bs1 = -1,
int bs2 = -1) {
767 bs1 = (r1.length() + num_threads - 1) / (num_threads);
770 bs2 = (r2.length() + num_threads - 1) / (num_threads);
774 for(i = r1.first(); i < r1.last(); i+=bs1) {
775 lbs1 = r1.last() -i +1 <= bs1 ? r1.last() -i +1 : bs1;
776 for(j = r2.first(); j < r2.last(); j+=bs2) {
777 lbs2 = r2.last() -j +1 <= bs2 ? r2.last() -j +1 : bs2;
778 f(blitz::Range(i, i+lbs1-1), blitz::Range(j, j+lbs2-1));
790#define DEFINE_NEW_ARRAY_TYPE(type, dim) \
791namespace depspawn { \
792 namespace internal { \
794 struct is_blitz_array<blitz::Array<type, dim>> : public std::true_type {}; \
798DEFINE_NEW_ARRAY_TYPE(
int, 1);
799DEFINE_NEW_ARRAY_TYPE(
int, 2);
800DEFINE_NEW_ARRAY_TYPE(
int, 3);
801DEFINE_NEW_ARRAY_TYPE(
int, 4);
802DEFINE_NEW_ARRAY_TYPE(
unsigned int, 1);
803DEFINE_NEW_ARRAY_TYPE(
unsigned int, 2);
804DEFINE_NEW_ARRAY_TYPE(
unsigned int, 3);
805DEFINE_NEW_ARRAY_TYPE(
unsigned int, 4);
806DEFINE_NEW_ARRAY_TYPE(
unsigned long long, 1);
807DEFINE_NEW_ARRAY_TYPE(
unsigned long long, 2);
808DEFINE_NEW_ARRAY_TYPE(
unsigned long long, 3);
809DEFINE_NEW_ARRAY_TYPE(
unsigned long long, 4);
810DEFINE_NEW_ARRAY_TYPE(
long long, 1);
811DEFINE_NEW_ARRAY_TYPE(
long long, 2);
812DEFINE_NEW_ARRAY_TYPE(
long long, 3);
813DEFINE_NEW_ARRAY_TYPE(
long long, 4);
814DEFINE_NEW_ARRAY_TYPE(
float, 1);
815DEFINE_NEW_ARRAY_TYPE(
float, 2);
816DEFINE_NEW_ARRAY_TYPE(
float, 3);
817DEFINE_NEW_ARRAY_TYPE(
float, 4);
818DEFINE_NEW_ARRAY_TYPE(
double, 1);
819DEFINE_NEW_ARRAY_TYPE(
double, 2);
820DEFINE_NEW_ARRAY_TYPE(
double, 3);
821DEFINE_NEW_ARRAY_TYPE(
double, 4);
822DEFINE_NEW_ARRAY_TYPE(
long double, 1);
823DEFINE_NEW_ARRAY_TYPE(
long double, 2);
824DEFINE_NEW_ARRAY_TYPE(
long double, 3);
825DEFINE_NEW_ARRAY_TYPE(
long double, 4);
Class for ignoring arguments when doing dependency analysis.
Definition: depspawn.h:69
Ignore(T &t)
Constructor.
Definition: depspawn.h:76
Ignore< T > operator=(const T &other)
Assignment.
Definition: depspawn.h:81
void * addr() const
For debugging.
Definition: depspawn.h:103
When destroyed, it makes sure that all the tasks spawned by the current thread since its creation hav...
Definition: depspawn.h:693
Observer(bool priority=true)
friend void wait_for_subtasks(bool priority)
Public library API.
Definition: main.dox:1
internal::TaskPool & get_task_pool()
Ignore< T > ignore(T &&t)
Traits for arguments or parameters that should be ignored.
Definition: depspawn.h:108
int get_num_threads() noexcept
Retrieve number of threads currently in use.
void wait_for_all()
Waits for all tasks to finish.
void wait_for(const Args &... args)
Wait for a specific group of variables to be written.
Definition: depspawn.h:665
void set_task_queue_limit(int limit) noexcept
void wait_for_subtasks(bool priority=true)
void set_threads(int nthreads=-1)
int get_task_queue_limit() noexcept