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

[hpx::execution] Added forwarding_scheduler_query #5865

Merged
merged 6 commits into from Jun 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -13,6 +13,77 @@

namespace hpx::execution::experimental {

// [exec.sched_queries.forwarding_scheduler_query]
// 1. `execution::forwarding_scheduler_query` is used to ask a
// customization point object whether it is a scheduler query that
// should be forwarded through scheduler adaptors.
// 2. The name `execution::forwarding_scheduler_query` denotes a
// customization point object. For some subexpression `t`,
// `execution::forwarding_scheduler_query(t)` is expression
// equivalent to:
// 1. `tag_invoke(execution::forwarding_scheduler_query, t)`,
// contextually converted to bool, if the tag_invoke expression is
// well formed.
// Mandates: The tag_invoke expression is indeed
// contextually convertible to bool, that expression and
// the contextual conversion are not potentially-throwing
// and are core constant expressions if t is a core
// constant expression.
// 2. Otherwise, false.
HPX_HOST_DEVICE_INLINE_CONSTEXPR_VARIABLE struct
forwarding_scheduler_query_t final
: hpx::functional::detail::tag_fallback<forwarding_scheduler_query_t>
{
private:
template <typename T>
friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(
forwarding_scheduler_query_t, T&&) noexcept
{
return false;
}
} forwarding_scheduler_query{};

enum class forward_progress_guarantee
{
concurrent,
parallel,
weakly_parallel
};

// 1. `execution::get_forward_progress_guarantee` is used to ask a scheduler about
// the forward progress guarantees of execution agents created by that
// scheduler.
// 2. The name `execution::get_forward_progress_guarantee` denotes a
// customization point object. For some subexpression s, let S be decltype((s)).
// If S does not satisfy execution::scheduler,
// execution::get_forward_progress_guarantee is ill-formed. Otherwise,
// execution::get_forward_progress_guarantee(s) is expression equivalent to:
// 2. `tag_invoke(execution::get_forward_progress_guarantee, as_const(s))`,
// if this expression is well formed.
// Mandates: The tag_invoke expression above is not
// potentially throwing and its type is
// execution::forward_progress_guarantee.
// Otherwise, execution::forward_progress_guarantee::weakly_parallel.
// 3. If `execution::get_forward_progress_guarantee(s)` for some scheduler s returns
// `execution::forward_progress_guarantee::concurrent`, all execution agents
// created by that scheduler shall provide the concurrent forward progress
// guarantee. If it returns `execution::forward_progress_guarantee::parallel`, all
// execution agents created by that scheduler shall provide at least the
// parallel forward progress guarantee.
HPX_HOST_DEVICE_INLINE_CONSTEXPR_VARIABLE struct
get_forward_progress_guarantee_t final
: hpx::functional::detail::tag_fallback_noexcept<
get_forward_progress_guarantee_t>
{
template <typename T>
friend constexpr HPX_FORCEINLINE forward_progress_guarantee
tag_fallback_invoke(get_forward_progress_guarantee_t,
const hpx::util::unwrap_reference<T>&) noexcept
{
return forward_progress_guarantee::weakly_parallel;
}
} get_forward_progress_guarantee{};

// 1. execution::get_scheduler is used to ask an object for its associated
// scheduler.
//
Expand Down
2 changes: 2 additions & 0 deletions libs/core/execution/tests/unit/CMakeLists.txt
Expand Up @@ -28,10 +28,12 @@ set(tests
executor_parameters_dispatching
executor_parameters_timer_hooks
forwarding_env_query
forwarding_scheduler_query
future_then_executor
minimal_async_executor
minimal_sync_executor
persistent_executor_parameters
forward_progress_guarantee
)

set(future_then_executor_PARAMETERS THREADS_PER_LOCALITY 4)
Expand Down
61 changes: 61 additions & 0 deletions libs/core/execution/tests/unit/forward_progress_guarantee.cpp
@@ -0,0 +1,61 @@
// Copyright (c) 2022 Shreyas Atre
//
// SPDX-License-Identifier: BSL-1.0
// 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)

#include <hpx/execution/queries/get_scheduler.hpp>
#include <hpx/execution_base/completion_scheduler.hpp>
#include <hpx/modules/testing.hpp>

#include <exception>
#include <utility>

namespace mylib {

// CPO
struct inline_scheduler_0
{
constexpr friend HPX_FORCEINLINE auto tag_invoke(
hpx::execution::experimental::get_forward_progress_guarantee_t,
const inline_scheduler_0&) noexcept
{
return hpx::execution::experimental::forward_progress_guarantee::
concurrent;
}

} scheduler{};

// CPO
struct inline_scheduler_1
{
/// With the same user-defined tag_invoke overload, the user-defined
/// overload will now be used if it is a match even if it isn't an exact
/// match.
/// This is because tag_fallback will dispatch to tag_fallback_invoke only
/// if there are no matching tag_invoke overloads.
constexpr friend auto tag_invoke(
hpx::execution::experimental::get_forward_progress_guarantee_t,
inline_scheduler_1) noexcept
{
return true;
}
} scheduler_custom{};

} // namespace mylib

int main()
{
using namespace mylib;
static_assert(hpx::execution::experimental::get_forward_progress_guarantee(
scheduler) ==
hpx::execution::experimental::forward_progress_guarantee::
concurrent,
"forward_progress_guarantee should return concurrent");

static_assert(hpx::execution::experimental::get_forward_progress_guarantee(
scheduler_custom),
"CPO should invoke user tag_invoke");

return hpx::util::report_errors();
}
12 changes: 6 additions & 6 deletions libs/core/execution/tests/unit/forwarding_env_query.cpp
Expand Up @@ -23,21 +23,21 @@ namespace mylib {
hpx::execution::experimental::forwarding_env_query_t,
non_query_t) noexcept
{
return false;
return true;
}
} non_query{};

} // namespace mylib

int main()
{
static_assert(
!hpx::execution::experimental::forwarding_env_query(mylib::non_query),
"non_query is not an environmental query");
static_assert(hpx::execution::experimental::forwarding_env_query(
mylib::non_query) == true,
"non_query CPO is user implemented that returns true");

static_assert(hpx::execution::experimental::forwarding_env_query(
hpx::execution::experimental::get_scheduler),
"get_scheduler is an environmental query");
hpx::execution::experimental::get_scheduler) == false,
"environmental query falls back to false");

return hpx::util::report_errors();
}
42 changes: 42 additions & 0 deletions libs/core/execution/tests/unit/forwarding_scheduler_query.cpp
@@ -0,0 +1,42 @@
// Copyright (c) 2022 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// 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)

#include <hpx/execution/queries/get_scheduler.hpp>
#include <hpx/functional/tag_invoke.hpp>
#include <hpx/modules/testing.hpp>

#include <exception>
#include <string>
#include <type_traits>
#include <utility>

namespace mylib {

inline constexpr struct non_query_t final
: hpx::functional::tag<non_query_t>
{
friend constexpr auto tag_invoke(
hpx::execution::experimental::forwarding_scheduler_query_t,
non_query_t) noexcept
{
return true;
}
} non_query{};

} // namespace mylib

int main()
{
static_assert(hpx::execution::experimental::forwarding_scheduler_query(
mylib::non_query) == true,
"non_query CPO is user implemented to return true");

static_assert(hpx::execution::experimental::forwarding_scheduler_query(
hpx::execution::experimental::get_scheduler) == false,
"invokes tag_fallback which returns false by default");

return hpx::util::report_errors();
}
Expand Up @@ -176,7 +176,7 @@ namespace hpx::execution::experimental {
friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(
forwarding_env_query_t, T&&) noexcept
{
return true;
return false;
}

} forwarding_env_query{};
Expand Down
Expand Up @@ -11,6 +11,8 @@
#include <hpx/execution_base/agent_base.hpp>
#include <hpx/execution_base/agent_ref.hpp>
#include <hpx/execution_base/detail/spinlock_deadlock_detection.hpp>
#include <hpx/functional/detail/tag_fallback_invoke.hpp>
#include <hpx/modules/type_support.hpp>
#include <hpx/timing/high_resolution_timer.hpp>
#include <hpx/timing/steady_clock.hpp>

Expand Down Expand Up @@ -68,6 +70,39 @@ namespace hpx { namespace execution_base {
{
agent().sleep_until(sleep_time, desc);
}

// [exec.sched_queries.execute_may_block_caller]
// 1. `this_thread::execute_may_block_caller` is used to ask a scheduler s
// whether a call `execution::execute(s, f)` with any invocable f
// may block the thread where such a call occurs.
//
// 2. The name `this_thread::execute_may_block_caller` denotes a
// customization point object. For some subexpression s, let S be decltype((s)).
// If S does not satisfy `execution::scheduler`,
// `this_thread::execute_may_block_caller` is ill-formed. Otherwise,
// `this_thread::execute_may_block_caller(s)` is expression equivalent to:
// 1. `tag_invoke(this_thread::execute_may_block_caller, as_const(s))`,
// if this expression is well formed.
// -- Mandates: The tag_invoke expression above is not
// potentially throwing and its type is bool.
// 2. Otherwise, true.
//
// 3. If `this_thread::execute_may_block_caller(s)` for some scheduler s
// returns false, no execution::execute(s, f) call with some invocable f
// shall block the calling thread.
HPX_HOST_DEVICE_INLINE_CONSTEXPR_VARIABLE struct
execute_may_block_caller_t final
: hpx::functional::detail::tag_fallback_noexcept<
execute_may_block_caller_t>
{
template <typename T>
friend constexpr HPX_FORCEINLINE bool tag_fallback_invoke(
execute_may_block_caller_t,
const hpx::util::unwrap_reference<T>&) noexcept
{
return true;
}
} execute_may_block_caller{};
} // namespace this_thread
}} // namespace hpx::execution_base

Expand Down
1 change: 1 addition & 0 deletions libs/core/execution_base/tests/unit/CMakeLists.txt
Expand Up @@ -14,6 +14,7 @@ set(tests
completion_signatures
execution_context
get_env
execute_may_block_caller
)

foreach(test ${tests})
Expand Down
@@ -0,0 +1,31 @@
// Copyright (c) 2022 Shreyas Atre
//
// SPDX-License-Identifier: BSL-1.0
// 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)

#include <hpx/modules/execution_base.hpp>
#include <hpx/modules/testing.hpp>

struct scheduler
{
friend constexpr bool tag_invoke(
hpx::execution_base::this_thread::execute_may_block_caller_t,
const scheduler&) noexcept
{
return false;
}
};

int main()
{
{
scheduler s1;
static_assert(
hpx::execution_base::this_thread::execute_may_block_caller(s1) ==
false,
"CPO returns false");
}

return hpx::util::report_errors();
}