1 // Copyright (c) 2007-2017 Hartmut Kaiser 2 // Copyright (c) 2011 Bryce Lelbach 3 // Copyright (c) 2011-2016 Thomas Heller 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See accompanying 6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 8 /// \file transfer_action.hpp 9 10 #ifndef HPX_RUNTIME_ACTIONS_TRANSFER_BASE_ACTION_HPP 11 #define HPX_RUNTIME_ACTIONS_TRANSFER_BASE_ACTION_HPP 12 13 #include <hpx/runtime/actions_fwd.hpp> 14 15 #include <hpx/runtime/actions/action_support.hpp> 16 #include <hpx/runtime/actions/base_action.hpp> 17 #include <hpx/runtime/actions/detail/invocation_count_registry.hpp> 18 #include <hpx/runtime/components/pinned_ptr.hpp> 19 #include <hpx/runtime/serialization/input_archive.hpp> 20 #include <hpx/runtime/serialization/output_archive.hpp> 21 #include <hpx/runtime/serialization/unique_ptr.hpp> 22 #include <hpx/traits/action_does_termination_detection.hpp> 23 #include <hpx/traits/action_message_handler.hpp> 24 #include <hpx/traits/action_priority.hpp> 25 #include <hpx/traits/action_schedule_thread.hpp> 26 #include <hpx/traits/action_serialization_filter.hpp> 27 #include <hpx/traits/action_stacksize.hpp> 28 #include <hpx/traits/action_was_object_migrated.hpp> 29 #include <hpx/util/assert.hpp> 30 #include <hpx/util/get_and_reset_value.hpp> 31 #include <hpx/util/serialize_exception.hpp> 32 #include <hpx/util/tuple.hpp> 33 #if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX) 34 #include <hpx/util/itt_notify.hpp> 35 #endif 36 37 #include <atomic> 38 #include <cstddef> 39 #include <cstdint> 40 #include <memory> 41 #include <type_traits> 42 #include <utility> 43 44 namespace hpx { namespace actions 45 { 46 /////////////////////////////////////////////////////////////////////////// 47 // If one or more arguments of the action are non-default-constructible, 48 // the transfer_action does not store the argument tuple directly but a 49 // unique_ptr to the tuple instead. 50 namespace detail 51 { 52 template <typename Args> 53 struct argument_holder 54 { 55 argument_holder() = default; 56 argument_holderhpx::actions::detail::argument_holder57 explicit argument_holder(Args && args) 58 : data_(new Args(std::move(args))) 59 {} 60 61 template <typename ... Ts> argument_holderhpx::actions::detail::argument_holder62 argument_holder(Ts && ... ts) 63 : data_(new Args(std::forward<Ts>(ts)...)) 64 {} 65 66 template <typename Archive> serializehpx::actions::detail::argument_holder67 void serialize(Archive& ar, unsigned int const) 68 { 69 ar & data_; 70 } 71 72 HPX_HOST_DEVICE HPX_FORCEINLINE datahpx::actions::detail::argument_holder73 Args& data() 74 { 75 HPX_ASSERT(!!data_); 76 return *data_; 77 } 78 79 #if defined(HPX_DISABLE_ASSERTS) || defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG) 80 HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE datahpx::actions::detail::argument_holder81 Args const& data() const 82 { 83 return *data_; 84 } 85 #else 86 HPX_HOST_DEVICE HPX_FORCEINLINE datahpx::actions::detail::argument_holder87 Args const& data() const 88 { 89 HPX_ASSERT(!!data_); 90 return *data_; 91 } 92 #endif 93 94 private: 95 std::unique_ptr<Args> data_; 96 }; 97 } 98 }} 99 100 namespace hpx { namespace util 101 { 102 template <std::size_t I, typename Args> 103 HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE 104 typename util::tuple_element<I, Args>::type& get(hpx::actions::detail::argument_holder<Args> & t)105 get(hpx::actions::detail::argument_holder<Args>& t) 106 { 107 return util::tuple_element<I, Args>::get(t.data()); 108 } 109 110 template <std::size_t I, typename Args> 111 HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE 112 typename util::tuple_element<I, Args>::type const& get(hpx::actions::detail::argument_holder<Args> const & t)113 get(hpx::actions::detail::argument_holder<Args> const& t) 114 { 115 return util::tuple_element<I, Args>::get(t.data()); 116 } 117 118 template <std::size_t I, typename Args> 119 HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE 120 typename util::tuple_element<I, Args>::type&& get(hpx::actions::detail::argument_holder<Args> && t)121 get(hpx::actions::detail::argument_holder<Args>&& t) 122 { 123 return std::forward<typename util::tuple_element<I, Args>::type>( 124 util::get<I>(t.data())); 125 } 126 127 template <std::size_t I, typename Args> 128 HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE 129 typename util::tuple_element<I, Args>::type const&& get(hpx::actions::detail::argument_holder<Args> const && t)130 get(hpx::actions::detail::argument_holder<Args> const&& t) 131 { 132 return std::forward< 133 typename util::tuple_element<I, Args>::type const 134 >(util::get<I>(t.data())); 135 } 136 }} 137 138 namespace hpx { namespace actions 139 { 140 /////////////////////////////////////////////////////////////////////////// 141 template <typename Action> 142 struct transfer_base_action : base_action_data 143 { 144 public: 145 HPX_NON_COPYABLE(transfer_base_action); 146 147 public: 148 typedef typename Action::component_type component_type; 149 typedef typename Action::derived_type derived_type; 150 typedef typename Action::result_type result_type; 151 typedef typename Action::arguments_type arguments_base_type; 152 typedef typename std::conditional< 153 std::is_constructible<arguments_base_type>::value, 154 arguments_base_type, 155 detail::argument_holder<arguments_base_type> 156 >::type arguments_type; 157 typedef typename Action::continuation_type continuation_type; 158 159 // This is the priority value this action has been instantiated with 160 // (statically). This value might be different from the priority member 161 // holding the runtime value an action has been created with 162 HPX_STATIC_CONSTEXPR std::uint32_t priority_value = 163 traits::action_priority<Action>::value; 164 165 // This is the stacksize value this action has been instantiated with 166 // (statically). This value might be different from the stacksize member 167 // holding the runtime value an action has been created with 168 HPX_STATIC_CONSTEXPR std::uint32_t stacksize_value = 169 traits::action_stacksize<Action>::value; 170 171 typedef typename Action::direct_execution direct_execution; 172 173 // construct an empty transfer_action to avoid serialization overhead 174 transfer_base_action() = default; 175 176 // construct an action from its arguments 177 template <typename... Ts> transfer_base_actionhpx::actions::transfer_base_action178 explicit transfer_base_action(Ts&&... vs) 179 : base_action_data( 180 detail::thread_priority<static_cast<threads::thread_priority>( 181 priority_value)>::call(threads::thread_priority_default), 182 detail::thread_stacksize<static_cast<threads::thread_stacksize>( 183 stacksize_value)>::call(threads::thread_stacksize_default)) 184 , arguments_(std::forward<Ts>(vs)...) 185 {} 186 187 template <typename ...Ts> transfer_base_actionhpx::actions::transfer_base_action188 transfer_base_action(threads::thread_priority priority, Ts&&... vs) 189 : base_action_data( 190 detail::thread_priority<static_cast<threads::thread_priority>( 191 priority_value)>::call(priority), 192 detail::thread_stacksize<static_cast<threads::thread_stacksize>( 193 stacksize_value)>::call(threads::thread_stacksize_default)) 194 , arguments_(std::forward<Ts>(vs)...) 195 {} 196 197 // ~transfer_base_actionhpx::actions::transfer_base_action198 ~transfer_base_action() noexcept override 199 { 200 detail::register_action<derived_type>::instance.instantiate(); 201 } 202 203 public: 204 /// retrieve component type get_static_component_typehpx::actions::transfer_base_action205 static int get_static_component_type() 206 { 207 return derived_type::get_component_type(); 208 } 209 210 private: 211 /// The function \a get_component_type returns the \a component_type 212 /// of the component this action belongs to. get_component_typehpx::actions::transfer_base_action213 int get_component_type() const override 214 { 215 return derived_type::get_component_type(); 216 } 217 218 /// The function \a get_action_name returns the name of this action 219 /// (mainly used for debugging and logging purposes). get_action_namehpx::actions::transfer_base_action220 char const* get_action_name() const override 221 { 222 return detail::get_action_name<derived_type>(); 223 } 224 225 /// The function \a get_serialization_id returns the id which has been 226 /// associated with this action (mainly used for serialization purposes). get_action_idhpx::actions::transfer_base_action227 std::uint32_t get_action_id() const override 228 { 229 return detail::get_action_id<derived_type>(); 230 } 231 232 #if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX) 233 /// The function \a get_action_name_itt returns the name of this action 234 /// as a ITT string_handle get_action_name_itthpx::actions::transfer_base_action235 util::itt::string_handle const& get_action_name_itt() const override 236 { 237 return detail::get_action_name_itt<derived_type>(); 238 } 239 #endif 240 241 /// The function \a get_action_type returns whether this action needs 242 /// to be executed in a new thread or directly. get_action_typehpx::actions::transfer_base_action243 action_type get_action_type() const override 244 { 245 return derived_type::get_action_type(); 246 } 247 248 /// Return whether the embedded action is part of termination detection does_termination_detectionhpx::actions::transfer_base_action249 bool does_termination_detection() const override 250 { 251 return traits::action_does_termination_detection<derived_type>::call(); 252 } 253 254 /// Return whether the given object was migrated 255 std::pair<bool, components::pinned_ptr> was_object_migratedhpx::actions::transfer_base_action256 was_object_migrated(hpx::naming::gid_type const& id, 257 naming::address::address_type lva) override 258 { 259 return traits::action_was_object_migrated<derived_type>::call(id, lva); 260 } 261 262 /// Return a pointer to the filter to be used while serializing an 263 /// instance of this action type. get_serialization_filterhpx::actions::transfer_base_action264 serialization::binary_filter* get_serialization_filter( 265 parcelset::parcel const& p) const override 266 { 267 return traits::action_serialization_filter<derived_type>::call(p); 268 } 269 270 /// Return a pointer to the message handler to be used for this action. get_message_handlerhpx::actions::transfer_base_action271 parcelset::policies::message_handler* get_message_handler( 272 parcelset::parcelhandler* ph, parcelset::locality const& loc, 273 parcelset::parcel const& p) const override 274 { 275 return traits::action_message_handler<derived_type>:: 276 call(ph, loc, p); 277 } 278 279 public: 280 /// retrieve the N's argument 281 template <std::size_t N> 282 HPX_CONSTEXPR inline 283 typename util::tuple_element<N, arguments_type>::type const& gethpx::actions::transfer_base_action284 get() const 285 { 286 return util::get<N>(arguments_); 287 } 288 289 /// Extract the current invocation count for this action get_invocation_counthpx::actions::transfer_base_action290 static std::int64_t get_invocation_count(bool reset) 291 { 292 return util::get_and_reset_value(invocation_count_, reset); 293 } 294 295 // serialization support 296 // loading ... load_basehpx::actions::transfer_base_action297 void load_base(hpx::serialization::input_archive & ar) 298 { 299 ar >> arguments_; 300 this->base_action_data::load_base(ar); 301 } 302 303 // saving ... save_basehpx::actions::transfer_base_action304 void save_base(hpx::serialization::output_archive & ar) 305 { 306 ar << arguments_; 307 this->base_action_data::save_base(ar); 308 } 309 310 protected: 311 arguments_type arguments_; 312 313 private: 314 static std::atomic<std::int64_t> invocation_count_; 315 316 protected: increment_invocation_counthpx::actions::transfer_base_action317 static void increment_invocation_count() 318 { 319 ++invocation_count_; 320 } 321 }; 322 323 template <typename Action> 324 std::atomic<std::int64_t> 325 transfer_base_action<Action>::invocation_count_(0); 326 327 namespace detail 328 { 329 template <typename Action> register_remote_action_invocation_count(invocation_count_registry & registry)330 void register_remote_action_invocation_count( 331 invocation_count_registry& registry) 332 { 333 registry.register_class( 334 hpx::actions::detail::get_action_name<Action>(), 335 &transfer_base_action<Action>::get_invocation_count 336 ); 337 } 338 } 339 340 /////////////////////////////////////////////////////////////////////////// 341 template <std::size_t N, typename Action> 342 HPX_CONSTEXPR inline typename util::tuple_element< 343 N, typename transfer_action<Action>::arguments_type get(transfer_base_action<Action> const & args)344 >::type const& get(transfer_base_action<Action> const& args) 345 { 346 return args.template get<N>(); 347 } 348 }} 349 350 #if defined(HPX_HAVE_PARCELPORT_ACTION_COUNTERS) 351 #include <hpx/runtime/parcelset/detail/per_action_data_counter_registry.hpp> 352 353 namespace hpx { namespace parcelset { namespace detail 354 { 355 /// \cond NOINTERNAL 356 template <typename Action> register_per_action_data_counter_types(per_action_data_counter_registry & registry)357 void register_per_action_data_counter_types( 358 per_action_data_counter_registry& registry) 359 { 360 registry.register_class( 361 hpx::actions::detail::get_action_name<Action>() 362 ); 363 } 364 /// \endcond 365 }}} 366 #endif 367 368 #endif 369