Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sequential task execution policy #1273

Merged
merged 10 commits into from Sep 23, 2014
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
2 changes: 2 additions & 0 deletions docs/manual/build_system/cmake_variables.qbk
Expand Up @@ -29,6 +29,7 @@ The options are split into these categories:
* [link build_system.cmake_variables.HPX_AUTOMATIC_PREPROCESSING HPX_AUTOMATIC_PREPROCESSING]
* [link build_system.cmake_variables.HPX_AUTOMATIC_SERIALIZATION_REGISTRATION HPX_AUTOMATIC_SERIALIZATION_REGISTRATION]
* [link build_system.cmake_variables.HPX_BENCHMARK_SCRIPTS_PATH HPX_BENCHMARK_SCRIPTS_PATH]
* [link build_system.cmake_variables.HPX_BUILD_WITH_INSTALL_PREFIX HPX_BUILD_WITH_INSTALL_PREFIX]
* [link build_system.cmake_variables.HPX_COMPILER_WARNINGS HPX_COMPILER_WARNINGS]
* [link build_system.cmake_variables.HPX_FULL_RPATH HPX_FULL_RPATH]
* [link build_system.cmake_variables.HPX_GCC_VERSION_CHECK HPX_GCC_VERSION_CHECK]
Expand All @@ -55,6 +56,7 @@ The options are split into these categories:
[[[#build_system.cmake_variables.HPX_AUTOMATIC_PREPROCESSING] `HPX_AUTOMATIC_PREPROCESSING:BOOL`][True if the automatic header preprocessing target should be created (default: OFF).]]
[[[#build_system.cmake_variables.HPX_AUTOMATIC_SERIALIZATION_REGISTRATION] `HPX_AUTOMATIC_SERIALIZATION_REGISTRATION:BOOL`][Use automatic serialization registration for actions and functions. This affects compatibility between HPX applications compiled with different compilers (default ON)]]
[[[#build_system.cmake_variables.HPX_BENCHMARK_SCRIPTS_PATH] `HPX_BENCHMARK_SCRIPTS_PATH:PATH`][Directory to place batch scripts in]]
[[[#build_system.cmake_variables.HPX_BUILD_WITH_INSTALL_PREFIX] `HPX_BUILD_WITH_INSTALL_PREFIX:BOOL`][Always set the HPX_PREFIX default to the install directory (default: OFF)]]
[[[#build_system.cmake_variables.HPX_COMPILER_WARNINGS] `HPX_COMPILER_WARNINGS:BOOL`][Enable compiler warnings (default: ON)]]
[[[#build_system.cmake_variables.HPX_FULL_RPATH] `HPX_FULL_RPATH:BOOL`][Build and link HPX libraries and executables with full RPATHs (default: ON)]]
[[[#build_system.cmake_variables.HPX_GCC_VERSION_CHECK] `HPX_GCC_VERSION_CHECK:BOOL`][Ignore version reported by gcc (default: ON)]]
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