Skip to content

Commit

Permalink
Merge pull request #1273 from hkaiser/sequential_task_execution_policy
Browse files Browse the repository at this point in the history
Sequential task execution policy
  • Loading branch information
hkaiser committed Sep 23, 2014
2 parents 9998b72 + 2077639 commit eebdead
Show file tree
Hide file tree
Showing 73 changed files with 2,460 additions and 1,538 deletions.
1 change: 1 addition & 0 deletions docs/CMakeLists.txt
Expand Up @@ -45,6 +45,7 @@ set(doxygen_dependencies
"${hpx_SOURCE_DIR}/hpx/parallel/execution_policy.hpp"
"${hpx_SOURCE_DIR}/hpx/parallel/algorithm.hpp"
"${hpx_SOURCE_DIR}/hpx/parallel/task_region.hpp"
"${hpx_SOURCE_DIR}/hpx/parallel/detail/adjacent_find.hpp"
"${hpx_SOURCE_DIR}/hpx/parallel/detail/all_any_none.hpp"
"${hpx_SOURCE_DIR}/hpx/parallel/detail/copy.hpp"
"${hpx_SOURCE_DIR}/hpx/parallel/detail/count.hpp"
Expand Down
4 changes: 3 additions & 1 deletion docs/hpx.idx
Expand Up @@ -57,6 +57,9 @@ is_parallel_execution_policy "" "hpx\.parallel\.v1\.is_parallel_executi
is_sequential_execution_policy "" "hpx\.parallel\.v1\.is_sequential_execution_policy.*"


# hpx/parallel/detail/adjacent_find.hpp
parallel::adjacent_find "adjacent_find" "hpx\.parallel\.v1\.adjacent_find.*"

# hpx/parallel/detail/all_any_none.hpp
parallel::all_of "all_of" "hpx\.parallel\.v1\.all_of.*"
parallel::any_of "any_of" "hpx\.parallel\.v1\.any_of.*"
Expand All @@ -83,7 +86,6 @@ parallel::find_if "find_if" "hpx\.parallel\.v1\.find_if$"
parallel::find_if_not "find_if_not" "hpx\.parallel\.v1\.find_if_not.*"
parallel::find_end "find_end" "hpx\.parallel\.v1\.find_end.*"
parallel::find_first_of "find_first_of" "hpx\.parallel\.v1\.find_first_of.*"
parallel::adjacent_find "adjacent_find" "hpx\.parallel\.v1\.adjacent_find.*"

# hpx/parallel/detail/for_each.hpp
parallel::for_each "for_each" "hpx\.parallel\.v1\.for_each$"
Expand Down
17 changes: 10 additions & 7 deletions docs/manual/parallel_algorithms.qbk
Expand Up @@ -21,9 +21,10 @@ Extensions for Parallelism) and __cpp11_n4088__ (Task Regions).
[section:parallel_algorithms Using Parallel Algorithms]

[def __sequential_execution_policy__ [classref hpx::parallel::v1::sequential_execution_policy `sequential_execution_policy`]]
[def __sequential_task_execution_policy__ [classref hpx::parallel::v1::sequential_task_execution_policy `sequential_task_execution_policy`]]
[def __parallel_execution_policy__ [classref hpx::parallel::v1::parallel_execution_policy `parallel_execution_policy`]]
[def __parallel_vector_execution_policy__ [classref hpx::parallel::v1::parallel_vector_execution_policy `parallel_vector_execution_policy`]]
[def __task_execution_policy__ [classref hpx::parallel::v1::task_execution_policy `task_execution_policy`]]
[def __parallel_task_execution_policy__ [classref hpx::parallel::v1::parallel_task_execution_policy `parallel_task_execution_policy`]]
[def __execution_policy__ [classref hpx::parallel::v1::execution_policy `execution_policy`]]

[def __exception_list__ [classref hpx::exception_list `exception_list`]]
Expand Down Expand Up @@ -53,7 +54,7 @@ sequential order in the calling thread.

The applications of function objects in parallel algorithms invoked with an
execution policy object of type __parallel_execution_policy__ or
__task_execution_policy__ are permitted to execute in an unordered fashion in
__parallel_task_execution_policy__ are permitted to execute in an unordered fashion in
unspecified threads, and indeterminately sequenced within each thread.

[important It is the caller's responsibility to ensure correctness, for example
Expand All @@ -66,10 +67,11 @@ equivalent to the use of the execution policy __parallel_execution_policy__.
Algorithms invoked with an execution policy object of type __execution_policy__
execute internally as if invoked with the contained execution policy object.
An exception is when an __execution_policy__ contains an execution policy of
type __task_execution_policy__ (which normally turns the algorithm into its
asynchronous version). In this case the execution is semantically equivalent to
the case of passing a __parallel_execution_policy__ contained in the
__execution_policy__ object.
type __sequential_task_execution_policy__ or __parallel_task_execution_policy__
(which normally turn the algorithm into its asynchronous version). In this case
the execution is semantically equivalent to the case of passing a
__sequential_execution_policy__ or __parallel_execution_policy__ contained in the
__execution_policy__ object respectively.


[heading Parallel Exceptions]
Expand All @@ -87,7 +89,8 @@ the algorithm:
[funcref hpx::terminate] shall be called.

* If the execution policy object is of type __sequential_execution_policy__,
__parallel_execution_policy__, or __task_execution_policy__ the execution of
__sequential_task_execution_policy__, __parallel_execution_policy__, or
__parallel_task_execution_policy__ the execution of
the algorithm terminates with an __exception_list__ exception. All
uncaught exceptions thrown during the application of user-provided
function objects shall be contained in the __exception_list__.
Expand Down
13 changes: 13 additions & 0 deletions hpx/include/parallel_adjacent_find.hpp
@@ -0,0 +1,13 @@
// Copyright (c) 2007-2014 Hartmut Kaiser
// Copyright (c) 2014 Grant Mercer
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#if !defined(HPX_PARALLEL_ADJACENT_FIND_SEP_20_2014_0732PM)
#define HPX_PARALLEL_ADJACENT_FIND_SEP_20_2014_0732PM

#include <hpx/parallel/detail/adjacent_find.hpp>

#endif

1 change: 1 addition & 0 deletions hpx/parallel/algorithm.hpp
Expand Up @@ -12,6 +12,7 @@
/// See N4071: 1.3/3
#include <algorithm>

#include <hpx/parallel/detail/adjacent_find.hpp>
#include <hpx/parallel/detail/all_any_none.hpp>
#include <hpx/parallel/detail/copy.hpp>
#include <hpx/parallel/detail/count.hpp>
Expand Down
246 changes: 246 additions & 0 deletions hpx/parallel/detail/adjacent_find.hpp
@@ -0,0 +1,246 @@
// Copyright (c) 2014 Grant Mercer
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/// \file parallel/detail/adjacent_find.hpp

#if !defined(HPX_PARALLEL_DETAIL_ADJACENT_FIND_SEP_20_2014_0731PM)
#define HPX_PARALLEL_DETAIL_ADJACENT_FIND_SEP_20_2014_0731PM

#include <hpx/hpx_fwd.hpp>
#include <hpx/parallel/execution_policy.hpp>
#include <hpx/parallel/detail/algorithm_result.hpp>
#include <hpx/parallel/detail/predicates.hpp>
#include <hpx/parallel/detail/dispatch.hpp>
#include <hpx/parallel/util/partitioner.hpp>
#include <hpx/parallel/util/loop.hpp>

#include <algorithm>
#include <iterator>

#include <boost/static_assert.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>

namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1)
{
///////////////////////////////////////////////////////////////////////////
// adjacent_find
namespace detail
{
/// \cond NOINTERNAL
template <typename FwdIter>
struct adjacent_find
: public detail::algorithm<adjacent_find<FwdIter>, FwdIter>
{
adjacent_find()
: adjacent_find::algorithm("adjacent_find")
{}

template <typename ExPolicy, typename Pred>
static FwdIter
sequential(ExPolicy const&, FwdIter first, FwdIter last, Pred && op)
{
return std::adjacent_find(first, last, op);
}

template <typename ExPolicy, typename Pred>
static typename detail::algorithm_result<ExPolicy, FwdIter>::type
parallel(ExPolicy const& policy, FwdIter first, FwdIter last,
Pred && op)
{
typedef hpx::util::zip_iterator<FwdIter, FwdIter> zip_iterator;
typedef typename zip_iterator::reference reference;
typedef typename std::iterator_traits<FwdIter>::difference_type
difference_type;

if(first == last)
{
return detail::algorithm_result<ExPolicy, FwdIter>::get(
std::move(last));
}

FwdIter next = first;
++next;
difference_type count = std::distance(first,last);
util::cancellation_token<difference_type> tok(count);

return util::partitioner<ExPolicy, FwdIter, void>::call_with_index(
policy, hpx::util::make_zip_iterator(first,next), count-1,
[op, tok](std::size_t base_idx, zip_iterator it,
std::size_t part_size) mutable
{
util::loop_idx_n(
base_idx, it, part_size, tok,
[&op, &tok](reference t, std::size_t i)
{
if(op(hpx::util::get<0>(t), hpx::util::get<1>(t)))
tok.cancel(i);
});
},
[=](std::vector<hpx::future<void> > &&) mutable -> FwdIter
{
difference_type adj_find_res = tok.get_data();
if(adj_find_res != count)
std::advance(first, adj_find_res);
else
first = last;

return std::move(first);
});
}
};
/// \endcond
}

/// Searches the range [first, last) for two consecutive identical elements.
/// This version uses operator== to compare the elements
///
/// \note Complexity: Exactly the smaller of (result - first) + 1 and
/// (last - first) - 1 applications of operator==
/// where \a result is the return value
///
/// \tparam ExPolicy The type of the execution policy to use (deduced).
/// It describes the manner in which the execution
/// of the algorithm may be parallelized and the manner
/// in which it executes the assignments.
/// \tparam FwdIter The type of the source iterators used for the
/// range (deduced).
/// This iterator type must meet the requirements of an
/// forward iterator.
///
/// \param policy The execution policy to use for the scheduling of
/// the iterations.
/// \param first Refers to the beginning of the sequence of elements
/// of the range the algorithm will be applied to.
/// \param last Refers to the end of the sequence of elements of
/// the range the algorithm will be applied to.
///
/// The comparison operations in the parallel \a adjacent_find algorithm invoked
/// with an execution policy object of type \a sequential_execution_policy
/// execute in sequential order in the calling thread.
///
/// The comparison operations in the parallel \a adjacent_find algorithm invoked
/// with an execution policy object of type \a parallel_execution_policy
/// or \a parallel_task_execution_policy are permitted to execute in an unordered
/// fashion in unspecified threads, and indeterminately sequenced
/// within each thread.
///
/// \returns The \a adjacent_find algorithm returns a \a hpx::future<FwdIter> if the
/// execution policy is of type
/// \a sequential_task_execution_policy or
/// \a parallel_task_execution_policy and
/// returns \a FwdIter otherwise.
/// The \a adjacent_find algorithm returns an iterator to first of the
/// identical elements. If no such elements are found,\a last is returned
///
template <typename ExPolicy, typename FwdIter>
inline typename boost::enable_if<
is_execution_policy<ExPolicy>,
typename detail::algorithm_result<ExPolicy, FwdIter>::type
>::type
adjacent_find(ExPolicy && policy, FwdIter first, FwdIter last)
{
typedef typename std::iterator_traits<FwdIter>::iterator_category
iterator_category;

BOOST_STATIC_ASSERT_MSG(
(boost::is_base_of<
std::forward_iterator_tag, iterator_category
>::value),
"Requires at least forward iterator");

typedef is_sequential_execution_policy<ExPolicy> is_seq;

return detail::adjacent_find<FwdIter>().call(
std::forward<ExPolicy>(policy),
first, last, detail::equal_to(),
is_seq());
}

/// Searches the range [first, last) for two consecutive identical elements.
/// This version uses the given binary predicate op
///
/// \note Complexity: Exactly the smaller of (result - first) + 1 and
/// (last - first) - 1 application of the predicate
/// where \a result is the value returned
///
/// \tparam ExPolicy The type of the execution policy to use (deduced).
/// It describes the manner in which the execution
/// of the algorithm may be parallelized and the manner
/// in which it executes the assignments.
/// \tparam FwdIter The type of the source iterators used for the
/// range (deduced).
/// This iterator type must meet the requirements of an
/// forward iterator.
/// \tparam Pred The type of the function/function object to use
/// (deduced). Unlike its sequential form, the parallel
/// overload of \a adjacent_find requires \a Pred to meet the
/// requirements of \a CopyConstructible.
///
/// \param policy The execution policy to use for the scheduling of
/// the iterations.
/// \param first Refers to the beginning of the sequence of elements
/// of the range the algorithm will be applied to.
/// \param last Refers to the end of the sequence of elements of
/// the range the algorithm will be applied to.
/// \param op The binary predicate which returns \a true
/// if the elements should be treated as equal. The signature
/// should be equivalent to the following:
/// \code
/// bool pred(const Type1 &a, const Type2 &b);
/// \endcode \n
/// The signature does not need to have const &, but
/// the function must not modify the objects passed to
/// it. The types \a Type1 and \a Type2 must be such
/// that objects of types \a FwdIter1 and \a FwdIter2
/// can be dereferenced and then implicitly converted
/// to \a Type1 and \a Type2 respectively.
///
/// The comparison operations in the parallel \a adjacent_find invoked
/// with an execution policy object of type \a sequential_execution_policy
/// execute in sequential order in the calling thread.
///
/// The comparison operations in the parallel \a adjacent_find invoked
/// with an execution policy object of type \a parallel_execution_policy
/// or \a parallel_task_execution_policy are permitted to execute in an unordered
/// fashion in unspecified threads, and indeterminately sequenced
/// within each thread.
///
/// \returns The \a adjacent_find algorithm returns a \a hpx::future<InIter> if the
/// execution policy is of type
/// \a sequential_task_execution_policy or
/// \a parallel_task_execution_policy and
/// returns \a InIter otherwise.
/// The \a adjacent_find algorithm returns an iterator to the first of the
/// identical elements. If no such elements are found, \a last is returned.
///
/// This overload of \a adjacent_find is available if the user decides to
/// provide their algorithm their own binary predicate \a op.
///
template <typename ExPolicy, typename FwdIter, typename Pred>
inline typename boost::enable_if<
is_execution_policy<ExPolicy>,
typename detail::algorithm_result<ExPolicy, FwdIter>::type
>::type
adjacent_find(ExPolicy && policy, FwdIter first, FwdIter last, Pred && op)
{
typedef typename std::iterator_traits<FwdIter>::iterator_category
iterator_category;

BOOST_STATIC_ASSERT_MSG(
(boost::is_base_of<
std::forward_iterator_tag, iterator_category
>::value),
"Requires at least forward iterator");

typedef is_sequential_execution_policy<ExPolicy> is_seq;

return detail::adjacent_find<FwdIter>().call(
std::forward<ExPolicy>(policy),
first, last, op, is_seq());
}
}}}

#endif

0 comments on commit eebdead

Please sign in to comment.