diff --git a/cinch b/cinch index 75df645f1..6b837e2c7 160000 --- a/cinch +++ b/cinch @@ -1 +1 @@ -Subproject commit 75df645f1a365410e151c2e1c632a59f0a32942f +Subproject commit 6b837e2c7ab62fb2516efdb517eee095b9741fd7 diff --git a/config/project.cmake b/config/project.cmake index 8d95062e4..89ec98b1d 100644 --- a/config/project.cmake +++ b/config/project.cmake @@ -448,7 +448,8 @@ endif() list(APPEND FLECSI_LIBRARY_DEPENDENCIES ${COLORING_LIBRARIES}) -if(FLECSI_RUNTIME_MODEL STREQUAL "mpi") +if(FLECSI_RUNTIME_MODEL STREQUAL "mpi" OR + FLECSI_RUNTIME_MODEL STREQUAL "hpx") #------------------------------------------------------------------------------# # Use lazy aggregated dense field communication #------------------------------------------------------------------------------# @@ -582,7 +583,7 @@ if (ENABLE_KOKKOS) target_link_libraries( FleCSI PUBLIC ${Kokkos_LIBRARIES} ) - if(ENABLE_FLECSI_TUTORIAL) + if(ENABLE_FLECSI_TUTORIAL) target_link_libraries(FleCSI-Tut PUBLIC ${Kokkos_LIBRARIES}) endif() endif() diff --git a/flecsi/coloring/CMakeLists.txt b/flecsi/coloring/CMakeLists.txt index 7eb46a90e..b879643c9 100644 --- a/flecsi/coloring/CMakeLists.txt +++ b/flecsi/coloring/CMakeLists.txt @@ -37,19 +37,21 @@ set(coloring_HEADERS # runtime specific and can be configured for whichever runtime is active. #------------------------------------------------------------------------------# +set(UNIT_POLICY MPI) + if(FLECSI_RUNTIME_MODEL STREQUAL "serial") - set(UNIT_POLICY SERIAL) +# set(UNIT_POLICY SERIAL) set(RUNTIME_DRIVER ../execution/serial/runtime_driver.cc) elseif(FLECSI_RUNTIME_MODEL STREQUAL "legion") - set(UNIT_POLICY LEGION) +# set(UNIT_POLICY LEGION) set(RUNTIME_DRIVER ../execution/legion/runtime_driver.cc) elseif(FLECSI_RUNTIME_MODEL STREQUAL "mpi") - set(UNIT_POLICY MPI) +# set(UNIT_POLICY MPI) set(RUNTIME_DRIVER ../execution/mpi/runtime_driver.cc) elseif(FLECSI_RUNTIME_MODEL STREQUAL "hpx") @@ -108,7 +110,7 @@ cinch_add_unit(dcrs LIBRARIES ${CINCH_RUNTIME_LIBRARIES} ${COLORING_LIBRARIES} - POLICY MPI + POLICY ${UNIT_POLICY} THREADS 5 ) @@ -117,8 +119,10 @@ cinch_add_devel_target(devel-dcrs INPUTS test/simple2d-8x8.msh test/simple2d-16x16.msh - LIBRARIES ${COLORING_LIBRARIES} - POLICY MPI + LIBRARIES + ${CINCH_RUNTIME_LIBRARIES} + ${COLORING_LIBRARIES} + POLICY ${UNIT_POLICY} THREADS 5 FOLDER "Tests/Coloring/Devel" ) @@ -127,31 +131,33 @@ cinch_add_unit(boxcolor2d SOURCES test/test_simple_box_colorer_2d.cc INPUTS LIBRARIES ${COLORING_LIBRARIES} - POLICY MPI + POLICY ${UNIT_POLICY} THREADS 4 ) cinch_add_unit(boxcolor3d SOURCES test/test_simple_box_colorer_3d.cc INPUTS LIBRARIES ${COLORING_LIBRARIES} - POLICY MPI + POLICY ${UNIT_POLICY} THREADS 4 ) # Both of these tests depend on ParMETIS. # This could change if we add more colorer types. if(ENABLE_PARMETIS) -cinch_add_devel_target(coloring - SOURCES test/coloring.cc - INPUTS - test/simple2d-8x8.msh - test/simple2d-16x16.msh - test/simple2d-32x32.msh - test/simple2d-48x48.msh - LIBRARIES ${COLORING_LIBRARIES} - POLICY MPI - THREADS 5 - FOLDER "Tests/Coloring/Devel" -) + cinch_add_devel_target(coloring + SOURCES test/coloring.cc + INPUTS + test/simple2d-8x8.msh + test/simple2d-16x16.msh + test/simple2d-32x32.msh + test/simple2d-48x48.msh + LIBRARIES + ${CINCH_RUNTIME_LIBRARIES} + ${COLORING_LIBRARIES} + POLICY ${UNIT_POLICY} + THREADS 5 + FOLDER "Tests/Coloring/Devel" + ) -endif() +endif(ENABLE_PARMETIS) diff --git a/flecsi/data/CMakeLists.txt b/flecsi/data/CMakeLists.txt index 34fe54f8d..0aa56ae21 100644 --- a/flecsi/data/CMakeLists.txt +++ b/flecsi/data/CMakeLists.txt @@ -114,18 +114,15 @@ elseif(FLECSI_RUNTIME_MODEL STREQUAL "hpx") set(data_HEADERS ${data_HEADERS} + hpx/color.h hpx/data_client_handle_policy.h hpx/data_handle_policy.h hpx/data_policy.h hpx/dense.h hpx/global.h - hpx/meta_data.h - hpx/registration_wrapper.h - hpx/scoped.h hpx/sparse.h - hpx/storage_policy.h hpx/sparse_data_handle_policy.h - hpx/tuple.h + hpx/storage_policy.h ) set(UNIT_POLICY HPX) @@ -233,7 +230,6 @@ if(ENABLE_PARMETIS) cinch_add_unit(client_registration SOURCES test/client_registration.cc - ../utils/demangle.cc ${DRIVER_INITIALIZATION} ${RUNTIME_DRIVER} DEFINES diff --git a/flecsi/data/client.h b/flecsi/data/client.h index 23963a9a0..36966de13 100644 --- a/flecsi/data/client.h +++ b/flecsi/data/client.h @@ -378,6 +378,15 @@ struct data_client_policy_handler_u> { *ent.ghost_id_updated = false; } #endif +#if FLECSI_RUNTIME_MODEL == FLECSI_RUNTIME_MODEL_hpx + auto ritr = ism.find(ent.index_space); + clog_assert(ritr != ism.end(), "invalid index space " << ei.index_space); + + // make client handle depend on only one of the fields + if(h.future == nullptr) { + h.future = &(ritr->second.future[ent.fid]); + } +#endif ++entity_index; } // for diff --git a/flecsi/data/hpx/color.h b/flecsi/data/hpx/color.h new file mode 100644 index 000000000..4616c71c6 --- /dev/null +++ b/flecsi/data/hpx/color.h @@ -0,0 +1,198 @@ +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2018, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once + +/*! @file */ + +//----------------------------------------------------------------------------// +// POLICY_NAMESPACE must be defined before including storage_class.h!!! +// Using this approach allows us to have only one storage_class_u +// definition that can be used by all data policies -> code reuse... +#define POLICY_NAMESPACE hpx +#include +#undef POLICY_NAMESPACE +//----------------------------------------------------------------------------// + +#include +#include +#include +#include +#include + +#include + +namespace flecsi { +namespace data { +namespace hpx { + +//----------------------------------------------------------------------------// +// Global handle. +//----------------------------------------------------------------------------// + +/*! + The color_handle_u provide an access to color variables that have + been registered in data model + + \tparam T The type of the data variable. If this type is not + consistent with the type used to register the data, bad things + can happen. However, it can be useful to reinterpret the type, + e.g., when writing raw bytes. This class is part of the + low-level \e flecsi interface, so it is assumed that you + know what you are doing... + + @tparam PERMISSIONS The permissions to the handle. + */ + +template +struct color_handle_u : public global_data_handle_u { + + /*! + Type definitions. + */ + + using base_t = global_data_handle_u; + + /*! + Constructor. + */ + + color_handle_u() { + base_t::color = true; + } + + /*! + Destructor. + */ + + ~color_handle_u() {} + + /* + Copy constructor. + */ + + template + color_handle_u(const color_handle_u & a) + : base_t(reinterpret_cast(a)), label_(a.label()), + size_(a.size()) { + static_assert(P2 == 0, "passing mapped handle to task args"); + } + + //--------------------------------------------------------------------------// + // Member data interface. + //--------------------------------------------------------------------------// + + /*! + \brief Return a std::string containing the label of the data variable + reference by this handle. + */ + + const std::string & label() const { + return label_; + } // label + + /*! + \brief Return the index space size of the data variable + referenced by this handle. + */ + + size_t size() const { + return size_; + } // size + + /*! + \brief Test to see if this handle is empty + + \return true if registered. + */ + + operator bool() const { + return base_t::combined_data != nullptr; + } // operator bool + +private: + std::string label_ = ""; + size_t size_ = 1; +}; // struct color_handle_u + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// +// Main type definition. +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// + +//----------------------------------------------------------------------------// +// Global storage type. +//----------------------------------------------------------------------------// + +/*! + FIXME: Global storage type. + */ +template<> +struct storage_class_u { + + /*! + Type definitions. + */ + + template + using handle_t = color_handle_u; + + /*! + Data handles. + */ + + template + static handle_t get_handle( + const data_client_handle & client_handle) { + handle_t h; + auto & context = execution::context_t::instance(); + + auto & field_info = context.get_field_info_from_name( + typeid(typename DATA_CLIENT_TYPE::type_identifier_t).hash_code(), + utils::hash::field_hash(VERSION)); + + auto & registered_field_data = context.registered_field_data(); + auto fieldDataIter = registered_field_data.find(field_info.fid); + if(fieldDataIter == registered_field_data.end()) { + // TODO: deal with VERSION + context.register_field_data(field_info.fid, field_info.size); + } + + auto data = registered_field_data[field_info.fid].data(); + + h.fid = field_info.fid; + h.index_space = field_info.index_space; + h.data_client_hash = field_info.data_client_hash; + + h.combined_data = reinterpret_cast(data); + + h.color = true; + h.state = context.execution_state(); + + auto& registered_field_futures = context.registered_field_futures(); + h.future = ®istered_field_futures[field_info.fid]; + + h.ghost_is_readable = nullptr; + + return h; + } + +}; // struct storage_class_u + +} // namespace hpx +} // namespace data +} // namespace flecsi diff --git a/flecsi/data/hpx/data_client_handle_policy.h b/flecsi/data/hpx/data_client_handle_policy.h index f931db55f..d2094aaad 100644 --- a/flecsi/data/hpx/data_client_handle_policy.h +++ b/flecsi/data/hpx/data_client_handle_policy.h @@ -1,10 +1,7 @@ /*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. *~--------------------------------------------------------------------------~*/ -#ifndef flecsi_data_hpx_data_client_handle_policy_h -#define flecsi_data_hpx_data_client_handle_policy_h +#pragma once #include @@ -13,12 +10,19 @@ //! @date Initial file creation: Jun 21, 2017 //----------------------------------------------------------------------------// +#include +#include +#include + namespace flecsi { + //----------------------------------------------------------------------------// -//! FIXME: Description of class +//! Provides a collection of fields which are populated when traversing the +//! data client entity information which is then passed to the data client +//! handle. //----------------------------------------------------------------------------// + struct data_client_handle_entity_t { - // FIXME check context using field_id_t = std::size_t; data_client_handle_entity_t() @@ -36,11 +40,11 @@ struct data_client_handle_entity_t { field_id_t fid2; field_id_t fid3; field_id_t id_fid; - size_t fid_size; - size_t fid2_size; - size_t fid3_size; - size_t id_fid_size; -}; + std::size_t fid_size; + std::size_t fid2_size; + std::size_t fid3_size; + std::size_t id_fid_size; +}; // struct data_client_handle_entity_t //----------------------------------------------------------------------------// //! Provides a collection of fields which are populated when, in the case of @@ -48,7 +52,6 @@ struct data_client_handle_entity_t { //! which is then passed the data client handle. //----------------------------------------------------------------------------// struct data_client_handle_adjacency_t { - // FIXME check context using field_id_t = std::size_t; std::size_t adj_index_space; @@ -62,56 +65,51 @@ struct data_client_handle_adjacency_t { std::size_t num_indices; field_id_t index_fid; field_id_t offset_fid; - size_t index_fid_size; - size_t offset_fid_size; + std::size_t index_fid_size; + std::size_t offset_fid_size; + std::size_t * offsets_buf; + utils::id_t * indices_buf; }; struct data_client_handle_index_subspace_t { - // FIXME check context using field_id_t = std::size_t; std::size_t index_space; std::size_t index_subspace; field_id_t index_fid; - size_t index_fid_size; + std::size_t index_fid_size; + utils::id_t * indices_buf; std::size_t domain; std::size_t dim; }; -//----------------------------------------------------------------------------// -//! FIXME: Description of class -//----------------------------------------------------------------------------// - struct hpx_data_client_handle_policy_t { // FIXME: This needs to be exposed at a higher level // maximum number of adjacencies to read, this limits the size of the // serialize struct passed to Legion // static constexpr size_t MAX_ADJACENCIES = 32; - static constexpr size_t MAX_ADJACENCIES = 64; + static constexpr std::size_t MAX_ADJACENCIES = 64; // maximum number of handle entities - static constexpr size_t MAX_ENTITIES = 7; + static constexpr std::size_t MAX_ENTITIES = 7; // maximum number of handle index subspaces - static constexpr size_t MAX_INDEX_SUBSPACES = 10; + static constexpr std::size_t MAX_INDEX_SUBSPACES = 10; - size_t num_handle_entities; - size_t num_handle_adjacencies; - size_t num_index_subspaces; + std::size_t num_handle_entities; + std::size_t num_handle_adjacencies; + std::size_t num_index_subspaces; data_client_handle_entity_t handle_entities[MAX_ENTITIES]; data_client_handle_adjacency_t handle_adjacencies[MAX_ADJACENCIES]; data_client_handle_index_subspace_t handle_index_subspaces[MAX_INDEX_SUBSPACES]; - // data_client_handle_index_subspace_t - // handle_index_subspaces[MAX_INDEX_SUBSPACES]; + + execution::hpx_future_u* future = nullptr; + }; // struct data_client_handle_policy_t } // namespace flecsi -#endif // flecsi_data_hpx_data_client_handle_policy_h - /*~-------------------------------------------------------------------------~-* - * Formatting options for vim. - * vim: set tabstop=2 shiftwidth=2 expandtab : *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/data_handle_policy.h b/flecsi/data/hpx/data_handle_policy.h index e3e75fbab..5a4f2abff 100644 --- a/flecsi/data/hpx/data_handle_policy.h +++ b/flecsi/data/hpx/data_handle_policy.h @@ -1,29 +1,35 @@ /*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. *~--------------------------------------------------------------------------~*/ -#ifndef flecsi_data_hpx_data_handle_policy_h -#define flecsi_data_hpx_data_handle_policy_h +#pragma once -/// -/// \file -/// \date Initial file creation: Apr 04, 2017 -/// +//----------------------------------------------------------------------------// +//! @file +//! @date Initial file creation: Apr 04, 2017 +//----------------------------------------------------------------------------// + +#include +#include namespace flecsi { -/// -/// \class hpx_data_handle_policy_t data_handle_policy.h -/// \brief hpx_data_handle_policy_t provides... -/// -struct hpx_data_handle_policy_t {}; // class hpx_data_handle_policy_t +//----------------------------------------------------------------------------// -} // namespace flecsi +struct hpx_data_handle_policy_t { + // +++ The following fields are set from get_handle(), reading + // information from the context which is data that is the same + // across multiple ranks/colors and should be used ONLY as read-only data + + field_id_t fid; + size_t index_space; + size_t data_client_hash; + bool * ghost_is_readable; -#endif // flecsi_data_hpx_data_handle_policy_h + execution::hpx_future_u* future = nullptr; + +}; // class mpi_data_handle_policy_t + +} // namespace flecsi /*~-------------------------------------------------------------------------~-* - * Formatting options for vim. - * vim: set tabstop=2 shiftwidth=2 expandtab : *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/data_policy.h b/flecsi/data/hpx/data_policy.h index 3ae93be75..37319a9eb 100644 --- a/flecsi/data/hpx/data_policy.h +++ b/flecsi/data/hpx/data_policy.h @@ -1,24 +1,21 @@ /*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. *~--------------------------------------------------------------------------~*/ -#ifndef flecsi_data_hpx_data_policy_h -#define flecsi_data_hpx_data_policy_h +#pragma once //----------------------------------------------------------------------------// //! @file //! @date Initial file creation: Jun 21, 2017 //----------------------------------------------------------------------------// -#include "flecsi/data/hpx/registration_wrapper.h" -#include "flecsi/data/storage.h" - -#include "flecsi/data/hpx/dense.h" -#include "flecsi/data/hpx/global.h" -#include "flecsi/data/hpx/scoped.h" -#include "flecsi/data/hpx/sparse.h" -#include "flecsi/data/hpx/tuple.h" +#include +#include +#include +#include +#include +#include +//#include +//#include namespace flecsi { namespace data { @@ -28,37 +25,18 @@ namespace data { //----------------------------------------------------------------------------// struct hpx_data_policy_t { - template - using storage_class_u = hpx::storage_class_u; - - template - using field_wrapper_u = hpx_field_registration_wrapper_u; + //--------------------------------------------------------------------------// + //! The storage_class_u type determines the underlying storage mechanism + //! for the backend runtime. + //--------------------------------------------------------------------------// - template - using client_wrapper_u = hpx_client_registration_wrapper_u; + template + using storage_class_u = hpx::storage_class_u; -}; // class hpx_data_policy_t +}; // class mpi_data_policy_t } // namespace data } // namespace flecsi -#endif // flecsi_data_hpx_data_policy_h - /*~-------------------------------------------------------------------------~-* - * Formatting options for vim. - * vim: set tabstop=2 shiftwidth=2 expandtab : *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/dense.h b/flecsi/data/hpx/dense.h index a349d2932..e4faf5c4c 100644 --- a/flecsi/data/hpx/dense.h +++ b/flecsi/data/hpx/dense.h @@ -1,22 +1,23 @@ -/*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved - *~--------------------------------------------------------------------------~*/ - +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2016, Los Alamos National Security, LLC + All rights reserved. + */ #pragma once +/*! @file */ + //----------------------------------------------------------------------------// -// POLICY_NAMESPACE must be defined before including storage_type.h!!! -// Using this approach allows us to have only one storage_type_t +// POLICY_NAMESPACE must be defined before including storage_class.h!!! +// Using this approach allows us to have only one storage_class_t // definition that can be used by all data policies -> code reuse... #define POLICY_NAMESPACE hpx #include @@ -29,17 +30,16 @@ #include #include #include +#include #include #include -/// -/// \file -/// \date Initial file creation: Apr 7, 2016 -/// +#include -#define np(X) \ - std::cout << __FILE__ << ":" << __LINE__ << ": " << __PRETTY_FUNCTION__ \ - << ": " << #X << " = " << (X) << std::endl +//----------------------------------------------------------------------------// +//! @file +//! @date Initial file creation: Apr 7, 2016 +//----------------------------------------------------------------------------// namespace flecsi { namespace data { @@ -67,7 +67,6 @@ namespace hpx { /// e.g., when writing raw bytes. This class is part of the /// low-level \e flecsi interface, so it is assumed that you /// know what you are doing... -/// \tparam MD The meta data type. /// template struct dense_handle_t : public dense_data_handle_u { @@ -89,276 +88,8 @@ struct dense_handle_t : public dense_data_handle_u { template friend struct dense_handle_t; -}; - -#if 0 - /// - /// Copy constructor. - /// - dense_handle_t(const dense_handle_t & a) : label_(a.label_) {} - - template - dense_handle_t(const dense_handle_t & h) - : label_(h.label_) {} - - //--------------------------------------------------------------------------// - // Member data interface. - //--------------------------------------------------------------------------// - - /// - /// \brief Return a std::string containing the label of the data variable - /// reference by this accessor. - /// - const std::string & label() const { - return label_; - } // label - - /// - /// \brief Return the index space size of the data variable - /// referenced by this accessor. - /// - size_t size() const { - return base::primary_size; - } // size - - /// - // \brief Return the index space size of the data variable - // referenced by this handle. - /// - size_t exclusive_size() const { - return base::exclusive_size; - } // size - - /// - // \brief Return the index space size of the data variable - // referenced by this handle. - /// - size_t shared_size() const { - return base::shared_size; - } // size - - //--------------------------------------------------------------------------// - // Operators. - //--------------------------------------------------------------------------// - - /// - /// \brief Provide logical array-based access to the data for this - /// data variable. This is the const operator version. - /// - /// \tparam E A complex index type. - /// - /// This version of the operator is provided to support use with - /// \e flecsi mesh entity types \ref mesh_entity_base_t. - /// - template - const T & operator[](E * e) const { - return this->operator[](e->template id<0>()); - } // operator [] - - /// - /// \brief Provide logical array-based access to the data for this - /// data variable. This is the const operator version. - /// - /// \tparam E A complex index type. - /// - /// This version of the operator is provided to support use with - /// \e flecsi mesh entity types \ref mesh_entity_base_t. - /// - template - T & operator[](E * e) { - return this->operator[](e->template id<0>()); - } // operator [] - - /// - /// \brief Provide logical array-based access to the data for this - /// data variable. This is the const operator version. - /// - /// \tparam E A complex index type. - /// - /// This version of the operator is provided to support use with - /// \e flecsi mesh entity types \ref mesh_entity_base_t. - /// - template - const T & operator()(E * e) const { - return this->operator[](e->template id<0>()); - } // operator [] - - /// - /// \brief Provide logical array-based access to the data for this - /// data variable. This is the const operator version. - /// - /// \tparam E A complex index type. - /// - /// This version of the operator is provided to support use with - /// \e flecsi mesh entity types \ref mesh_entity_base_t. - /// - template - T & operator()(E * e) { - return this->operator[](e->template id<0>()); - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - const T & operator[](size_t index) const { - assert(index < base::primary_size && "index out of range"); - return base::primary_data[index]; - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - T & operator[](size_t index) { - assert(index < base::primary_size && "index out of range"); - return base::primary_data[index]; - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - const T & exclusive(size_t index) const { - assert(index < base::exclusive_size && "index out of range"); - return base::exclusive_data[index]; - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - T & exclusive(size_t index) { - assert(index < base::exclusive_size && "index out of range"); - return base::exclusive_data[index]; - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - const T & shared(size_t index) const { - assert(index < base::shared_size && "index out of range"); - return base::shared_data[index]; - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - T & shared(size_t index) { - assert(index < base::shared_size && "index out of range"); - return base::shared_data[index]; - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - const T & ghost(size_t index) const { - assert(index < base::ghost_size && "index out of range"); - return base::ghost_data[index]; - } // operator [] - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - T & ghost(size_t index) { - assert(index < base::ghost_size && "index out of range"); - return base::ghost_data[index]; - } // operator [] - - // /// - // // \brief Provide logical array-based access to the data for this - // // data variable. This is the const operator version. - // // - // // \tparam E A complex index type. - // // - // // This version of the operator is provided to support use with - // // \e flecsi mesh entity types \ref mesh_entity_base_t. - // /// - // template - // const T & - // operator () ( - // E * e - // ) const - // { - // return this->operator()(e->template id<0>()); - // } // operator () - // - // /// - // // \brief Provide logical array-based access to the data for this - // // data variable. This is the const operator version. - // // - // // \tparam E A complex index type. - // // - // // This version of the operator is provided to support use with - // // \e flecsi mesh entity types \ref mesh_entity_base_t. - // /// - // template - // T & - // operator () ( - // E * e - // ) - // { - // return this->operator()(e->template id<0>()); - // } // operator () - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - const T & operator()(size_t index) const { - assert(index < base::primary_size && "index out of range"); - return base::primary_data[index]; - } // operator () - - /// - // \brief Provide logical array-based access to the data for this - // data variable. This is the const operator version. - // - // \param index The index of the data variable to return. - /// - T & operator()(size_t index) { - assert(index < base::primary_size && "index out of range"); - return base::primary_data[index]; - } // operator () - - /// - /// \brief Test to see if this accessor is empty - /// - /// \return true if registered. - /// - operator bool() const { - return base::primary_data != nullptr; - } // operator bool - - template - friend struct dense_handle_t; - -private: - std::string label_ = ""; }; // struct dense_handle_t -#endif + //+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// // Main type definition. //+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// @@ -368,10 +99,10 @@ struct dense_handle_t : public dense_data_handle_u { //----------------------------------------------------------------------------// /// -/// FIXME: Dense storage type. +/// Dense storage type. Provides an interface from obtaining data handles /// template<> -struct storage_class_u { +struct storage_class_u { //--------------------------------------------------------------------------// // Type definitions. //--------------------------------------------------------------------------// @@ -379,6 +110,21 @@ struct storage_class_u { template using handle_t = dense_handle_t; + /*! + Obtain a dense data handle to a field that resides on the specified data + client. + + @param client_handle the data client that owns the field. + + @tparam DATA_CLIENT_TYPE The data client type. + @tparam DATA_TYPE Handle datatype, e.g. double, int, trivially + copyable structs, etc. + @tparam NAMES The namespace key. Namespaces allow separation + of attribute names to avoid collisions. + @tparam NAME The field name. + @tparam VERSION The field version. + @tparam PERMISSIONS The data client permissions. + */ template { static handle_t get_handle( const data_client_t & data_client) { handle_t h; - // FIXME add logic here + + auto & context = execution::context_t::instance(); + + using client_type = typename DATA_CLIENT_TYPE::type_identifier_t; + + // get field_info for this data handle + auto & field_info = context.get_field_info_from_name( + typeid(typename DATA_CLIENT_TYPE::type_identifier_t).hash_code(), + utils::hash::field_hash(VERSION)); + + // get color_info for this field. + auto & color_info = + (context.coloring_info(field_info.index_space)).at(context.color()); + auto & index_coloring = context.coloring(field_info.index_space); + + auto & registered_field_data = context.registered_field_data(); + auto fieldDataIter = registered_field_data.find(field_info.fid); + if(fieldDataIter == registered_field_data.end()) { + size_t size = field_info.size * (color_info.exclusive + + color_info.shared + color_info.ghost); + // TODO: deal with VERSION + context.register_field_data(field_info.fid, size); + } + auto fieldMetaDataIter = + context.registered_field_metadata().find(field_info.fid); + if(fieldMetaDataIter == context.registered_field_metadata().end()) { + context.register_field_metadata( + field_info.fid, color_info, index_coloring); + } + + auto & ism = context.index_space_data_map(); + + auto data = registered_field_data[field_info.fid].data(); + // populate data member of data_handle_t + auto & hb = dynamic_cast &>(h); + + hb.fid = field_info.fid; + hb.index_space = field_info.index_space; + hb.data_client_hash = field_info.data_client_hash; + + hb.exclusive_size = color_info.exclusive; + hb.combined_data = hb.exclusive_buf = hb.exclusive_data = + reinterpret_cast(data); + hb.combined_size = color_info.exclusive; + + hb.shared_size = color_info.shared; + hb.shared_data = hb.shared_buf = hb.exclusive_data + hb.exclusive_size; + hb.combined_size += color_info.shared; + + hb.ghost_size = color_info.ghost; + hb.ghost_data = hb.ghost_buf = hb.shared_data + hb.shared_size; + hb.combined_size += color_info.ghost; + + hb.ghost_is_readable = + &(ism[field_info.index_space].ghost_is_readable[field_info.fid]); + + hb.future = &(ism[field_info.index_space].future[field_info.fid]); + return h; } -}; // struct storage_class_u +}; // struct storage_class_t } // namespace hpx } // namespace data diff --git a/flecsi/data/hpx/global.h b/flecsi/data/hpx/global.h index a39e9ae79..c9769327e 100644 --- a/flecsi/data/hpx/global.h +++ b/flecsi/data/hpx/global.h @@ -1,597 +1,156 @@ -/*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_hpx_global_h -#define flecsi_hpx_global_h +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2018, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once + +/*! @file */ //----------------------------------------------------------------------------// -// POLICY_NAMESPACE must be defined before including storage_type.h!!! -// Using this approach allows us to have only one storage_type_t +// POLICY_NAMESPACE must be defined before including storage_class.h!!! +// Using this approach allows us to have only one storage_class_u // definition that can be used by all data policies -> code reuse... #define POLICY_NAMESPACE hpx -//#include "flecsi/data/storage_type.h" +#include #undef POLICY_NAMESPACE //----------------------------------------------------------------------------// -#include "flecsi/data/data_client.h" -#include "flecsi/data/global_data_handle.h" +#include +#include +#include +#include +#include +#include #include -/// -/// \file -/// \date Initial file creation: Apr 17, 2016 -/// - namespace flecsi { namespace data { namespace hpx { -//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// -// Helper type definitions. -//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// - -#if 0 - //----------------------------------------------------------------------------// -// Scalar accessor. +// Global handle. //----------------------------------------------------------------------------// -/// -/// \brief global_accessor_t provides logically array-based access to data -/// variables that have been registered in the data model. -/// -/// \tparam T The type of the data variable. If this type is not -/// consistent with the type used to register the data, bad things -/// can happen. However, it can be useful to reinterpret the type, -/// e.g., when writing raw bytes. This class is part of the -/// low-level \e flecsi interface, so it is assumed that you -/// know what you are doing... -/// \tparam MD The meta data type. -/// -template -struct global_accessor_t { +/*! + The global_handle_u provide an access to global variables that have + been registered in data model - //--------------------------------------------------------------------------// - // Type definitions. - //--------------------------------------------------------------------------// + \tparam T The type of the data variable. If this type is not + consistent with the type used to register the data, bad things + can happen. However, it can be useful to reinterpret the type, + e.g., when writing raw bytes. This class is part of the + low-level \e flecsi interface, so it is assumed that you + know what you are doing... - using meta_data_t = MD; - using user_meta_data_t = typename meta_data_t::user_meta_data_t; + @tparam PERMISSIONS The permissions to the handle. + */ - //--------------------------------------------------------------------------// - // Constructors. - //--------------------------------------------------------------------------// +template +struct global_handle_u : public global_data_handle_u { + + /*! + Type definitions. + */ + + using base_t = global_data_handle_u; + + /*! + Constructor. + */ + + global_handle_u() { + base_t::global = true; + } + + /*! + Destructor. + */ + + ~global_handle_u() {} - /// Default constructor. - global_accessor_t() = default; - - /// - /// Constructor. - /// - /// \param label The c_str() version of the const_string_t used for - /// this data variable's hash. - /// \param size The size of the associated index space. - /// \param data A pointer to the raw data. - /// \param user_meta_data A reference to the user-defined meta data. - /// - global_accessor_t( - const std::string & label, - T * data, - const user_meta_data_t & user_meta_data, - bitset_t & user_attributes) - : label_(label), data_(data), user_meta_data_(&user_meta_data), - user_attributes_(&user_attributes) {} - - /// - /// Copy constructor. - /// - global_accessor_t(const global_accessor_t & a) - : label_(a.label_), data_(a.data_), user_meta_data_(a.user_meta_data_), - user_attributes_(a.user_attributes_) {} + /* + Copy constructor. + */ + + template + global_handle_u(const global_handle_u & a) + : base_t(reinterpret_cast(a)), label_(a.label()), + size_(a.size()) { + static_assert(P2 == 0, "passing mapped handle to task args"); + } //--------------------------------------------------------------------------// // Member data interface. //--------------------------------------------------------------------------// - /// - /// \brief Return a std::string containing the label of the data variable - /// reference by this accessor. - /// + /*! + \brief Return a std::string containing the label of the data variable + reference by this handle. + */ + const std::string & label() const { return label_; } // label - /// - /// \brief Return the user meta data for this data variable. - /// - const user_meta_data_t & meta_data() const { - return *user_meta_data_; - } // meta_data - - /// - /// - /// - bitset_t & attributes() { - return *user_attributes_; - } // attributes + /*! + \brief Return the index space size of the data variable + referenced by this handle. + */ - const bitset_t & attributes() const { - return *user_attributes_; - } // attributes + size_t size() const { + return size_; + } // size - //--------------------------------------------------------------------------// - // Operators. - //--------------------------------------------------------------------------// - - /// \brief copy operator. - /// \param [in] a The accessor to copy. - /// \return A reference to the new copy. - global_accessor_t & operator=(const global_accessor_t & a) { - label_ = a.label_; - data_ = a.data_; - user_meta_data_ = a.user_meta_data_; - user_attributes_ = a.user_attributes_; - return *this; - } // operator = - - /// - /// - /// - const T * operator->() const { - return data_; - } // operator -> - - /// - /// - /// - T * operator->() { - return data_; - } // operator -> - - /// \brief Provide access to the data for this data variable. - /// \remark This is the const operator version. - const T & operator*() const { - return *data_; - } + /*! + \brief Test to see if this handle is empty - /// \brief Provide access to the data for this data variable. - T & operator*() { - return *data_; - } + \return true if registered. + */ - /// - /// \brief Test to see if this accessor is empty. - /// - /// \return true if registered. - /// operator bool() const { - return data_ != nullptr; + return base_t::combined_data != nullptr; } // operator bool - /// \brief Implicit conversion operator. - /// Using explicit keyword forces users to use static_cast(). But - /// if you dont use this, then it is ambiguous - /// accessor a, b; - /// int c = 2; - /// a = c; // ok, uses assignment - /// b = 3; // ok, uses assignement - /// c = a; // ok for non-explicit cases, uses conversion operator - /// c = static_cast(a); // works for both explicit and implicit cases - /// // which one do you want? accessor/accessor assignement operator or - /// // do you want to convert b to int, then assign int to a? - /// a = b; - /// Making this explicit forces you to have to static cast for all cases, - /// which I think is less ambiguous - /// a = static_cast(b); - /// a = static_cast(c); - explicit operator T() const { - return *data_; - } - private: std::string label_ = ""; - T * data_ = nullptr; - const user_meta_data_t * user_meta_data_ = nullptr; - bitset_t * user_attributes_ = nullptr; - -}; // struct global_accessor_t -#endif - -//----------------------------------------------------------------------------// -// Scalar handle. -//----------------------------------------------------------------------------// - -template -struct global_handle_u : public global_data_handle_u {}; -// struct global_handle_t + size_t size_ = 1; +}; // struct global_handle_u //+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// // Main type definition. //+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// //----------------------------------------------------------------------------// -// Scalar storage type. +// Global storage type. //----------------------------------------------------------------------------// -/// -// FIXME: Scalar storage type. -/// +/*! + FIXME: Global storage type. + */ template<> struct storage_class_u { - //--------------------------------------------------------------------------// - // Type definitions. - //--------------------------------------------------------------------------// - - // using data_store_t = DS; - // using meta_data_t = MD; - - // template - // using accessor_t = global_accessor_t; - - template - using handle_t = global_handle_u; - - // using st_t = storage_class_u; - -#if 0 - //--------------------------------------------------------------------------// - // Data registration. - //--------------------------------------------------------------------------// - - /// - /// \tparam T Data type to register. - /// \tparam NS Namespace. - /// \tparam Args Variadic arguments that are passed to - /// metadata initialization. - /// - /// \param data_store A reference for accessing the low-level data. - /// \param key A const string instance containing the variable name. - /// \param runtime_namespace The runtime namespace to be used. - /// \param The number of variable versions for this datum. - /// - template - static handle_t register_data( - const data_client_t & data_client, - data_store_t & data_store, - const utils::const_string_t & key, - size_t versions, - Args &&... args) { - size_t h = key.hash() ^ data_client.runtime_id(); - - // Runtime assertion that this key is unique. - assert( - data_store[NS].find(h) == data_store[NS].end() && "key already exists"); - - data_store[NS][h].user_data.initialize(std::forward(args)...); - - data_store[NS][h].label = key.c_str(); - data_store[NS][h].size = 1; - data_store[NS][h].type_size = sizeof(T); - data_store[NS][h].versions = versions; - data_store[NS][h].rtti.reset(new - typename meta_data_t::type_info_t(typeid(T))); - - for (size_t i = 0; i < versions; ++i) { - data_store[NS][h].data[i].resize(sizeof(T)); - } // for - - // num_materials is unused for this storage type - data_store[NS][h].num_entries = 0; - - return {}; - } // register_data - - //--------------------------------------------------------------------------// - // Data accessors. - //--------------------------------------------------------------------------// + /*! + Type definitions. + */ - /// \brief Return a global_accessor_t. - /// - /// \param [in] meta_data The meta data to use to build the accessor. - /// \param [in] version The version to select. - /// - /// \remark In this version, the search for meta data was already done. - template - static accessor_t get_accessor(meta_data_t & meta_data, size_t version) { - - // check that the requested version exists - if (version >= meta_data.versions) { - std::cerr << "version out of range" << std::endl; - std::abort(); - } + template + using handle_t = global_handle_u; - // construct an accessor from the meta data - return {meta_data.label, reinterpret_cast(&meta_data.data[version][0]), - meta_data.user_data, meta_data.attributes[version]}; - } + /*! + Data handles. + */ - /// \brief Return a global_accessor_t. - /// - /// \param [in] data_store The data store to search. - /// \param [in] hash The hash to search for. - /// \param [in] version The version to select. - /// - /// \remark In this version, the search for meta data has not been done, - /// but the key has already been hashed. - template - static accessor_t get_accessor( - data_store_t & data_store, - const utils::const_string_t::hash_type_t & hash, - size_t version) { - auto search = data_store[NS].find(hash); - - if (search == data_store[NS].end()) { - return {}; - } else { - return get_accessor(search->second, version); - } // if - } // get_accessor - - /// \brief Return a global_accessor_t. - /// - /// \param [in] data_client The data client to restrict our search to. - /// \param [in] data_store The data store to search. - /// \param [in] key The key to search for. - /// \param [in] version The version to select. - /// - /// \remark In this version, the search for meta data has not been done, - /// and the key is still a string. - template - static accessor_t get_accessor( - const data_client_t & data_client, - data_store_t & data_store, - const utils::const_string_t & key, - size_t version) { - const size_t hash = key.hash() ^ data_client.runtime_id(); - return get_accessor(data_store, hash, version); - } // get_accessor - - /// \brief Return a list of all accessor_t's filtered by a predicate. - /// - /// \param [in] data_client The data client to restrict our search to. - /// \param [in] data_store The data store to search. - /// \param [in] version The version to select. - /// \param [in] predicate If \e predicate(a) returns true, add the accessor - /// to the list. - /// \param [in] sorted If true, sort the results by label lexographically. - /// - /// \remark This version is confined to search within a single namespace - template - static decltype(auto) get_accessors( - const data_client_t & data_client, - data_store_t & data_store, - size_t version, - Predicate && predicate, - bool sorted) { - - std::vector> as; - - // the runtime id - auto runtime_id = data_client.runtime_id(); - - // loop over each key pair - for (auto & entry_pair : data_store[NS]) { - // get the meta data key and label - const auto & meta_data_key = entry_pair.first; - auto & meta_data = entry_pair.second; - // now build the hash for this label - const auto & label = meta_data.label; - auto key_hash = - utils::hash(label, label.size()); - auto hash = key_hash ^ runtime_id; - // filter out the accessors for different data_clients - if (meta_data_key != hash) - continue; - // if the reconstructed hash matches the meta data key, - // then we may want this one - auto a = get_accessor(meta_data, version); - if (a) - if (meta_data.rtti->type_info == typeid(T) && predicate(a)) - as.emplace_back(std::move(a)); - } // for - - // if sorting is requested - if (sorted) - std::sort(as.begin(), as.end(), [](const auto & a, const auto & b) { - return a.label() < b.label(); - }); - - return as; - - } // get_accessor - - /// \brief Return a list of all accessor_t's filtered by a predicate. - /// - /// \param [in] data_client The data client to restrict our search to. - /// \param [in] data_store The data store to search. - /// \param [in] version The version to select. - /// \param [in] predicate If \e predicate(a) returns true, add the accessor - /// to the list. - /// \param [in] sorted If true, sort the results by label lexographically. - /// - /// \remark This version searches all namespaces. - template - static decltype(auto) get_accessors( - const data_client_t & data_client, - data_store_t & data_store, - size_t version, - Predicate && predicate, - bool sorted) { - - std::vector> as; - - // the runtime id - auto runtime_id = data_client.runtime_id(); - - // check each namespace - for (auto & namespace_map : data_store) { - - // the namespace data - auto & namespace_key = namespace_map.first; - auto & namespace_data = namespace_map.second; - - // loop over each key pair - for (auto & entry_pair : namespace_data) { - // get the meta data key and label - const auto & meta_data_key = entry_pair.first; - auto & meta_data = entry_pair.second; - // now build the hash for this label - const auto & label = meta_data.label; - auto key_hash = utils::hash( - label, label.size()); - auto hash = key_hash ^ runtime_id; - // filter out the accessors for different data_clients - if (meta_data_key != hash) - continue; - // if the reconstructed hash matches the meta data key, - // then we may want this one - auto a = get_accessor(meta_data, version); - if (a) - if (meta_data.rtti->type_info == typeid(T) && predicate(a)) - as.emplace_back(std::move(a)); - } // for each key pair - } // for each namespace - - // if sorting is requested - if (sorted) - std::sort(as.begin(), as.end(), [](const auto & a, const auto & b) { - return a.label() < b.label(); - }); - - return as; - - } // get_accessor - - /// \brief Return a list of all accessor_t's. - /// - /// \param [in] data_client The data client to restrict our search to. - /// \param [in] data_store The data store to search. - /// \param [in] version The version to select. - /// \param [in] sorted If true, sort the results by label lexographically. - /// - /// \remark This version is confined to search within a single namespace - template - static decltype(auto) get_accessors( - const data_client_t & data_client, - data_store_t & data_store, - size_t version, - bool sorted) { - - std::vector> as; - - // the runtime id - auto runtime_id = data_client.runtime_id(); - - // loop over each key pair - for (auto & entry_pair : data_store[NS]) { - // get the meta data key and label - const auto & meta_data_key = entry_pair.first; - auto & meta_data = entry_pair.second; - // now build the hash for this label - const auto & label = meta_data.label; - auto key_hash = - utils::hash(label, label.size()); - auto hash = key_hash ^ runtime_id; - // filter out the accessors for different data_clients - if (meta_data_key != hash) - continue; - // if the reconstructed hash matches the meta data key, - // then we may want this one - auto a = get_accessor(meta_data, version); - if (a) - if (meta_data.rtti->type_info == typeid(T)) - as.emplace_back(std::move(a)); - } // for - - // if sorting is requested - if (sorted) - std::sort(as.begin(), as.end(), [](const auto & a, const auto & b) { - return a.label() < b.label(); - }); - - return as; - - } // get_accessor - - /// \brief Return a list of all accessor_t's. - /// - /// \param [in] data_client The data client to restrict our search to. - /// \param [in] data_store The data store to search. - /// \param [in] version The version to select. - /// \param [in] sorted If true, sort the results by label lexographically. - /// - /// \remark This version searches all namespaces. - template - static decltype(auto) get_accessors( - const data_client_t & data_client, - data_store_t & data_store, - size_t version, - bool sorted) { - - std::vector> as; - - // the runtime id - auto runtime_id = data_client.runtime_id(); - - // check each namespace - for (auto & namespace_map : data_store) { - - // the namespace data - auto & namespace_key = namespace_map.first; - auto & namespace_data = namespace_map.second; - - // loop over each key pair - for (auto & entry_pair : namespace_data) { - // get the meta data key and label - const auto & meta_data_key = entry_pair.first; - auto & meta_data = entry_pair.second; - // now build the hash for this label - const auto & label = meta_data.label; - auto key_hash = utils::hash( - label, label.size()); - auto hash = key_hash ^ runtime_id; - // filter out the accessors for different data_clients - if (meta_data_key != hash) - continue; - // if the reconstructed hash matches the meta data key, - // then we may want this one - auto a = get_accessor(meta_data, version); - if (a) - if (meta_data.rtti->type_info == typeid(T)) - as.emplace_back(std::move(a)); - } // for each key pair - } // for each namespace - - // if sorting is requested - if (sorted) - std::sort(as.begin(), as.end(), [](const auto & a, const auto & b) { - return a.label() < b.label(); - }); - - return as; - - } // get_accessor -#endif - //--------------------------------------------------------------------------// - // Data handles. - //--------------------------------------------------------------------------// - - /// - /// - /// template { static handle_t get_handle( const data_client_handle & client_handle) { handle_t h; - return {}; - } // get_handle + auto & context = execution::context_t::instance(); + + auto & field_info = context.get_field_info_from_name( + typeid(typename DATA_CLIENT_TYPE::type_identifier_t).hash_code(), + utils::hash::field_hash(VERSION)); + + auto & registered_field_data = context.registered_field_data(); + auto fieldDataIter = registered_field_data.find(field_info.fid); + if(fieldDataIter == registered_field_data.end()) { + // TODO: deal with VERSION + context.register_field_data(field_info.fid, field_info.size); + } + + auto data = registered_field_data[field_info.fid].data(); + + h.fid = field_info.fid; + h.index_space = field_info.index_space; + h.data_client_hash = field_info.data_client_hash; + + h.combined_data = reinterpret_cast(data); -}; // struct storage_type_t + h.global = true; + h.state = context.execution_state(); + + auto& registered_field_futures = context.registered_field_futures(); + h.future = ®istered_field_futures[field_info.fid]; + + h.ghost_is_readable = nullptr; + + return h; + } + +}; // struct storage_class_u } // namespace hpx } // namespace data } // namespace flecsi - -#endif // flecsi_hpx_global_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/meta_data.h b/flecsi/data/hpx/meta_data.h deleted file mode 100644 index 86531de86..000000000 --- a/flecsi/data/hpx/meta_data.h +++ /dev/null @@ -1,85 +0,0 @@ -/*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_hpx_meta_data_h -#define flecsi_hpx_meta_data_h - -#include -#include -#include -#include - -#include "flecsi/data/common/data_types.h" - -/// -/// \file -/// \date Initial file creation: Apr 15, 2016 -/// - -namespace flecsi { -namespace data { - -//----------------------------------------------------------------------------// -// struct hpx_meta_data_t -//----------------------------------------------------------------------------// - -/// -/// \brief hpx_meta_data_t provides storage for extra information that is -/// used to interpret data variable information at different points -/// in the low-level runtime. -/// -/// \tparam T A user-defined data type that will be carried with the meta data. -/// -template -struct hpx_meta_data_t { - using user_meta_data_t = T; - - std::string label; - user_meta_data_t user_data; - size_t index_space; - size_t size; - size_t type_size; - size_t versions; - - /// - /// \brief type_info_t allows creation of reference information - /// to the user-specified type of the data data. - /// - /// The std::type_info type requires dynamic initialization. The - /// type_info_t type is designed to allow construction without - /// needing a non-trivial default constructor for the - /// hpx_meta_data_t type. - /// - struct type_info_t { - type_info_t(const std::type_info & type_info_) : type_info(type_info_) {} - const std::type_info & type_info; - }; // struct type_info_t - - std::shared_ptr rtti; - - std::unordered_map> data; - std::unordered_map attributes; - size_t num_entries; - -}; // struct hpx_meta_data_t - -} // namespace data -} // namespace flecsi - -#endif // flecsi_hpx_meta_data_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/registration_wrapper.h b/flecsi/data/hpx/registration_wrapper.h deleted file mode 100644 index 25123c5a2..000000000 --- a/flecsi/data/hpx/registration_wrapper.h +++ /dev/null @@ -1,91 +0,0 @@ -/*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_data_hpx_registration_wrapper_h -#define flecsi_data_hpx_registration_wrapper_h - -//----------------------------------------------------------------------------// -//! @file -//! @date Initial file creation: Apr 27, 2017 -//----------------------------------------------------------------------------// - -#include - -#include "flecsi/execution/context.h" -#include "flecsi/topology/mesh_topology.h" - -#include "flecsi/utils/tuple_walker.h" - -namespace flecsi { -namespace data { - -//----------------------------------------------------------------------------// -//! -//----------------------------------------------------------------------------// - -template -struct hpx_field_registration_wrapper_u { - using field_id_t = size_t; - - static void register_callback(field_id_t fid) { - clog(info) << "In register_callback" << std::endl; - // Do stuff - } // register_callback - -}; // class hpx_field_registration_wrapper_t - -/// -/// \class registration_wrapper_t registration_wrapper.h -/// \brief registration_wrapper_t provides... -/// -template -struct hpx_client_registration_wrapper_u { -}; // class hpx_client_registration_wrapper_t - -template -struct hpx_client_registration_wrapper_u< - flecsi::topology::mesh_topology_u, - NAMESPACE_HASH, - NAME_HASH> { - using field_id_t = size_t; - // using mesh_topology_t = flecsi::topology::mesh_topology_t; - - static void register_callback(field_id_t fid) { - clog_tag_guard(registration); - clog(info) << "In client_register_callback" << std::endl; - // Do stuff - } // register_callback - - template - struct type_walker_u - : public flecsi::utils::tuple_walker_u> { - void handle(TUPLE_ENTRY_TYPE const & entry) { - std::cout << "adding with domain: " << std::get<1>(entry) << std::endl; - } // handle - }; // struct type_walker_u - - static void register_data() { - // walk types - type_walker_u type_wakler; - - } // register_data - -}; // struct hpx_client_registration_wrapper_t - -} // namespace data -} // namespace flecsi - -#endif // flecsi_data_hpx_registration_wrapper_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options for vim. - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/scoped.h b/flecsi/data/hpx/scoped.h deleted file mode 100644 index 8bc558034..000000000 --- a/flecsi/data/hpx/scoped.h +++ /dev/null @@ -1,51 +0,0 @@ -/*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_hpx_scoped_h -#define flecsi_hpx_scoped_h - -//----------------------------------------------------------------------------// -// POLICY_NAMESPACE must be defined before including storage_type.h!!! -// Using this approach allows us to have only one storage_type_t -// definintion that can be used by all data policies -> code reuse... -#define POLICY_NAMESPACE hpx -//#include "flecsi/data/storage_type.h" -#undef POLICY_NAMESPACE -//----------------------------------------------------------------------------// - -/// -/// \file -/// \date Initial file creation: Apr 17, 2016 -/// - -namespace flecsi { -namespace data { -namespace hpx { - -/// -// FIXME: Scoped storage type. -/// -template<> -struct storage_class_u {}; // struct storage_class_u - -} // namespace hpx -} // namespace data -} // namespace flecsi - -#endif // flecsi_hpx_scoped_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/sparse.h b/flecsi/data/hpx/sparse.h index 67bfc4f27..f552916b4 100644 --- a/flecsi/data/hpx/sparse.h +++ b/flecsi/data/hpx/sparse.h @@ -1,682 +1,182 @@ /*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved *~--------------------------------------------------------------------------~*/ -#ifndef flecsi_hpx_sparse_h -#define flecsi_hpx_sparse_h - -#include -#include -#include -#include -#include +#pragma once //----------------------------------------------------------------------------// -// POLICY_NAMESPACE must be defined before including storage_type.h!!! -// Using this approach allows us to have only one storage_type_t +// POLICY_NAMESPACE must be defined before including storage_class.h!!! +// Using this approach allows us to have only one storage_class_t // definintion that can be used by all data policies -> code reuse... #define POLICY_NAMESPACE hpx -//#include "flecsi/data/storage_type.h" +#include #undef POLICY_NAMESPACE //----------------------------------------------------------------------------// -#include "flecsi/topology/index_space.h" -#include "flecsi/utils/const_string.h" +#include +#include -#define np(X) \ - std::cout << __FILE__ << ":" << __LINE__ << ": " << __PRETTY_FUNCTION__ \ - << ": " << #X << " = " << (X) << std::endl +#include +#include +#include +#include +#include -/// -/// \file -/// \date Initial file creation: Apr 17, 2016 -/// +#include + +//----------------------------------------------------------------------------// +//! @file +//! @date Initial file creation: Oct 05, 2017 +//----------------------------------------------------------------------------// namespace flecsi { namespace data { namespace hpx { -// FIXME: sparce data was completely refactored in December 2017. -#if 0 - //+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// -// Helper type definitions. +// Main type definition. //+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// //----------------------------------------------------------------------------// -// Sparse accessor. +// Dense storage type. //----------------------------------------------------------------------------// -/// -/// -/// -template -struct entry_value_u { - entry_value_u(size_t entry) : entry(entry) {} - - entry_value_u(size_t entry, T value) : entry(entry), value(value) {} - - entry_value_u() {} - - size_t entry; - T value; -}; // struct entry_value_u - -static constexpr size_t INDICES_FLAG = 1UL << 63; -static constexpr size_t ENTRIES_FLAG = 1UL << 62; - -/// -/// \brief sparse_accessor_t provides logically array-based access to data -/// variables that have been registered in the data model. -/// -/// \tparam T The type of the data variable. If this type is not -/// consistent with the type used to register the data, bad things -/// can happen. However, it can be useful to reinterpret the type, -/// e.g., when writing raw bytes. This class is part of the -/// low-level \e flecsi interface, so it is assumed that you -/// know what you are doing... -/// \tparam MD The meta data type. -/// -template -struct sparse_accessor_t { +/*! + Sparse storage type. Sparse data is partitioned into exclusive, shared, + ghost entries. It allows entries to be allocated sparsely per index. + Within an index, entries are stored in sorted order. A sparse accessor + can read and modify existing entries, but cannot allocate new entries. + The mutator is used for this purpose. A sparse data handle is passed to a + task which is then transformed to an accessor, likewise for a mutator. + */ +template<> +struct storage_class_u { //--------------------------------------------------------------------------// // Type definitions. //--------------------------------------------------------------------------// - using iterator_t = utils::index_space_t::iterator_t; - using meta_data_t = MD; - using user_meta_data_t = typename meta_data_t::user_meta_data_t; - - using entry_value_t = entry_value_u; - - using index_space_ = - topology::index_space, true>; - - //--------------------------------------------------------------------------// - // Constructors. - //--------------------------------------------------------------------------// - - /// - /// - /// - sparse_accessor_t() {} - - /// - /// - /// - sparse_accessor_t(meta_data_t & meta_data, size_t version) - : meta_data_(meta_data), version_(version), num_indices_(meta_data.size), - num_entries_(meta_data_.num_entries) { - auto iitr = meta_data_.data.find(version | INDICES_FLAG); - assert(iitr != meta_data_.data.end()); - - std::vector & raw_indices = - const_cast &>(iitr->second); - - indices_ = reinterpret_cast(&raw_indices[0]); - - auto mitr = meta_data_.data.find(version | ENTRIES_FLAG); - assert(mitr != meta_data_.data.end()); - - std::vector & raw_entries = - const_cast &>(mitr->second); - - entries_ = reinterpret_cast(&raw_entries[0]); - } // sparse_accessor_t - - //--------------------------------------------------------------------------// - // Member data interface. - //--------------------------------------------------------------------------// - - /// - /// - /// - bitset_t & attributes() { - return meta_data_.user_attributes_; - } // attributes - - //--------------------------------------------------------------------------// - // Operators. - //--------------------------------------------------------------------------// - - /// - /// - /// - T & operator()(size_t index, size_t entry) { - assert(index < num_indices_ && "sparse accessor: index out of bounds"); - - entry_value_t * start = entries_ + indices_[index]; - entry_value_t * end = entries_ + indices_[index + 1]; - - entry_value_t * itr = std::lower_bound( - start, end, entry_value_t(entry), - [](const auto & k1, const auto & k2) -> bool { - return k1.entry < k2.entry; - }); - - assert(itr != end && "sparse accessor: unmapped entry"); - - return itr->value; - } // operator () - - index_space_ entries() const { - size_t id = 0; - index_space_ is; - std::unordered_set found; - - for (size_t index = 0; index < num_indices_; ++index) { - entry_value_t * itr = entries_ + indices_[index]; - entry_value_t * end = entries_ + indices_[index + 1]; - - while (itr != end) { - size_t entry = itr->entry; - if (found.find(entry) == found.end()) { - is.push_back({id++, entry}); - found.insert(entry); - } - ++itr; - } - } - - return is; - } - - index_space_ entries(size_t index) const { - assert(index < num_indices_ && "sparse accessor: index out of bounds"); - - entry_value_t * itr = entries_ + indices_[index]; - entry_value_t * end = entries_ + indices_[index + 1]; - - index_space_ is; - - size_t id = 0; - while (itr != end) { - is.push_back({id++, itr->entry}); - ++itr; + template + using handle_u = ragged_data_handle_u; + + template + static handle_u get_handle(const data_client_t & data_client) { + static_assert( + VERSION < utils::hash::field_max_versions, "max field version exceeded"); + + auto & context = execution::context_t::instance(); + + using client_type = typename DATA_CLIENT_TYPE::type_identifier_t; + + // get field_info for this data handle + auto & field_info = context.get_field_info_from_name( + typeid(typename DATA_CLIENT_TYPE::type_identifier_t).hash_code(), + utils::hash::field_hash(VERSION)); + + auto & registered_sparse_field_data = + context.registered_sparse_field_data(); + auto fieldDataIter = registered_sparse_field_data.find(field_info.fid); + if(fieldDataIter == registered_sparse_field_data.end()) { + // get color_info for this field. + auto & color_info = + (context.coloring_info(field_info.index_space)).at(context.color()); + auto & index_coloring = context.coloring(field_info.index_space); + + auto & im = context.sparse_index_space_info_map(); + auto iitr = im.find(field_info.index_space); + clog_assert(iitr != im.end(), + "sparse index space info not registered for index space: " + << field_info.index_space); + + // TODO: these parameters need to be passed in field + // registration, or defined elsewhere + const size_t max_entries_per_index = iitr->second.max_entries_per_index; + + // TODO: deal with VERSION + context.register_sparse_field_data( + field_info.fid, field_info.size, color_info, max_entries_per_index); } - - return is; - } - - index_space_ indices() { - index_space_ is; - size_t id = 0; - - for (size_t i = 0; i < num_indices_; ++i) { - if (indices_[i] != indices_[i + 1]) { - is.push_back({id++, i}); - } + auto fieldMetaDataIter = + context.registered_sparse_field_metadata().find(field_info.fid); + if(fieldMetaDataIter == context.registered_sparse_field_metadata().end()) { + auto & color_info = + (context.coloring_info(field_info.index_space)).at(context.color()); + auto & index_coloring = context.coloring(field_info.index_space); + + context.register_sparse_field_metadata( + field_info.fid, color_info, index_coloring); } - return is; - } - - index_space_ indices(size_t entry) { - index_space_ is; - size_t id = 0; - - for (size_t index = 0; index < num_indices_; ++index) { - entry_value_t * start = entries_ + indices_[index]; - entry_value_t * end = entries_ + indices_[index + 1]; - - if (std::binary_search( - start, end, entry_value_t(entry), - [](const auto & k1, const auto & k2) -> bool { - return k1.entry < k2.entry; - })) { - is.push_back({id++, index}); - } - } + auto & fd = registered_sparse_field_data[field_info.fid]; - return is; - } + handle_u h(fd.max_entries_per_index); + h.init(fd.num_exclusive, fd.num_shared, fd.num_ghost); - /// - /// - /// - void dump() { - for (size_t i = 0; i < num_indices_; ++i) { - size_t start = indices_[i]; - size_t end = indices_[i + 1]; - - std::cout << "+++++ row: " << i << std::endl; - - for (size_t j = start; j < end; ++j) { - entry_value_t & mj = entries_[j]; - std::cout << "++ entry: " << mj.entry << std::endl; - std::cout << "++ value: " << mj.value << std::endl << std::endl; - } // for - } // for - } // dump - - /// - /// - /// - T * data() { - return nullptr; - } // data - -private: - size_t version_; - const meta_data_t & meta_data_ = *(std::make_unique()); - size_t num_indices_; - size_t num_entries_; - size_t * indices_; - entry_value_t * entries_; - -}; // struct sparse_accessor_t - -template -struct sparse_mutator_t { + auto & hb = h; - //--------------------------------------------------------------------------// - // Type definitions. - //--------------------------------------------------------------------------// + hb.fid = field_info.fid; + hb.index_space = field_info.index_space; - using iterator_t = utils::index_space_t::iterator_t; - using meta_data_t = MD; - using user_meta_data_t = typename meta_data_t::user_meta_data_t; + using vector_t = typename ragged_data_handle_u::vector_t; + hb.rows = reinterpret_cast(&fd.rows[0]); - using entry_value_t = entry_value_u; + auto & ism = context.index_space_data_map(); + hb.ghost_is_readable = + &(ism[field_info.index_space].ghost_is_readable[field_info.fid]); - //--------------------------------------------------------------------------// - // Constructors. - //--------------------------------------------------------------------------// + hb.future = &(ism[field_info.index_space].future[field_info.fid]); - /// - /// - /// - sparse_mutator_t() {} - - /// - /// - /// - sparse_mutator_t( - size_t num_slots, - const std::string & label, - size_t version, - meta_data_t & meta_data, - const user_meta_data_t & user_meta_data) - : num_slots_(num_slots), label_(label), version_(version), - meta_data_(meta_data), num_indices_(meta_data_.size), - num_entries_(meta_data_.num_entries), - indices_(new size_t[num_indices_]), - entries_(new entry_value_t[num_indices_ * num_slots_]), - erase_set_(nullptr) { - for (size_t i = 0; i < num_indices_; ++i) { - indices_[i] = 0; - } + return h; } - /// - /// - /// - ~sparse_mutator_t() { - commit(); - } // ~sparse_mutator_t - - T & operator()(size_t index, size_t entry) { - assert(indices_ && "sparse mutator has alread been committed"); - assert(index < num_indices_ && entry < num_entries_); - - size_t n = indices_[index]; - - if (n >= num_slots_) { - return spare_map_.emplace(index, entry_value_t(entry))->second.value; - } // if - - entry_value_t * start = entries_ + index * num_slots_; - entry_value_t * end = start + n; - - entry_value_t * itr = std::lower_bound( - start, end, entry_value_t(entry), - [](const auto & k1, const auto & k2) -> bool { - return k1.entry < k2.entry; - }); - - // if we are creating an that has already been created, just - // over-write the value and exit. No need to increment the - // counters or move data. - if (itr != end && itr->entry == entry) { - return itr->value; - } - - while (end != itr) { - *(end) = *(end - 1); - --end; - } // while - - itr->entry = entry; - - ++indices_[index]; - - return itr->value; - } // operator () - - void erase(size_t index, size_t entry) { - assert(indices_ && "sparse mutator has alread been committed"); - assert(index < num_indices_ && entry < num_entries_); - - if (!erase_set_) { - erase_set_ = new erase_set_t; - } - - erase_set_->emplace(std::make_pair(index, entry)); + template + static handle_u get_mutator(const data_client_t & data_client, + size_t) { + return get_handle( + data_client); } - T * data() { - return nullptr; - } // data - - void commit() { - if (!indices_) { - return; - } // if - - auto iitr = meta_data_.data.find(version_ | INDICES_FLAG); - assert(iitr != meta_data_.data.end()); - - std::vector & raw_indices = - const_cast &>(iitr->second); - - size_t * indices = reinterpret_cast(&raw_indices[0]); - - auto mitr = meta_data_.data.find(version_ | ENTRIES_FLAG); - assert(mitr != meta_data_.data.end()); - - std::vector & raw_entries = - const_cast &>(mitr->second); - - constexpr size_t ev_bytes = sizeof(entry_value_t); - - size_t s = raw_entries.size(); - size_t c = raw_entries.capacity(); - size_t d = (num_indices_ * num_slots_ + spare_map_.size()) * ev_bytes; - - if (c - s < d) { - // raw_entries.reserve(c * ev_bytes + d); - raw_entries.resize(c * ev_bytes + d); - } // if - - entry_value_t * entries = - reinterpret_cast(&raw_entries[0]); - - entry_value_t * entries_end = entries + s / ev_bytes; - - for (size_t i = 0; i < num_indices_; ++i) { - size_t n = indices_[i]; - - size_t pos = indices[i]; - - if (n == 0) { - indices[i + 1] = pos; - continue; - } // if - - auto p = spare_map_.equal_range(i); - - size_t m = distance(p.first, p.second); - - entry_value_t * start = entries_ + i * num_slots_; - entry_value_t * end = start + n; - - auto iitr = entries + pos; - - std::copy(iitr, entries_end, iitr + n + m); - std::copy(start, end, iitr); - entries_end += n + m; - - auto cmp = [](const auto & k1, const auto & k2) -> bool { - return k1.entry < k2.entry; - }; - - auto nitr = iitr + indices[i + 1]; - - std::inplace_merge(iitr, nitr, nitr + n, cmp); - - if (m == 0) { - indices[i + 1] = pos + n; - continue; - } // if - - indices[i + 1] = pos + n + m; - - auto vitr = nitr + n; - - for (auto itr = p.first; itr != p.second; ++itr) { - vitr->entry = itr->second.entry; - vitr->value = itr->second.value; - ++vitr; - } // for - - std::inplace_merge(iitr, nitr + n, nitr + n + m, cmp); - } // for - - delete[] indices_; - indices_ = nullptr; - - delete[] entries_; - entries_ = nullptr; - - if (!erase_set_) { - return; - } - - constexpr size_t erased_marker = std::numeric_limits::max(); - - entry_value_t * start; - entry_value_t * end; - - size_t last = std::numeric_limits::max(); - - size_t num_erased = 0; - - for (auto p : *erase_set_) { - if (p.first != last) { - start = entries + indices[p.first]; - end = entries + indices[p.first + 1]; - last = p.first; - indices[p.first] -= num_erased; - } - - entry_value_t * m = std::lower_bound( - start, end, entry_value_t(p.second), - [](const auto & k1, const auto & k2) -> bool { - return k1.entry < k2.entry; - }); - - m->entry = erased_marker; - start = m + 1; - ++num_erased; - } - - while (last < num_indices_) { - indices[++last] -= num_erased; - } - - std::remove_if(entries, entries_end, [](const auto & k) -> bool { - return k.entry == erased_marker; - }); - - s = raw_entries.size(); - s -= num_erased * ev_bytes; - raw_entries.resize(s); - - delete erase_set_; - erase_set_ = nullptr; - } // commit - -private: - using spare_map_t = std::multimap>; - using erase_set_t = std::set>; - - size_t num_slots_; - std::string label_ = ""; - size_t version_ = 0; - const meta_data_t & meta_data_ = *(std::make_unique()); - - size_t num_indices_; - size_t num_entries_; - size_t * indices_; - entry_value_u * entries_; - spare_map_t spare_map_; - erase_set_t * erase_set_; -}; // struct sparse_accessor_t - -//----------------------------------------------------------------------------// -// Sparse handle. -//----------------------------------------------------------------------------// - -template -struct sparse_handle_t {}; // struct sparse_handle_t - -//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// -// Main type definition. -//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=// - -/// -// FIXME: Sparse storage type. -/// -template -struct storage_type_t { +}; // struct storage_class_t +template<> +struct storage_class_u { //--------------------------------------------------------------------------// // Type definitions. //--------------------------------------------------------------------------// - using data_store_t = DS; - using meta_data_t = MD; - - template - using accessor_t = sparse_accessor_t; - - template - using mutator_t = sparse_mutator_t; - template - using handle_t = sparse_handle_t; - - //--------------------------------------------------------------------------// - // Data registration. - //--------------------------------------------------------------------------// - - template - static handle_t register_data( - const data_client_t & data_client, - data_store_t & data_store, - const flecsi::utils::const_string_t & key, - size_t versions, - size_t index_space, - size_t num_entries, - Args &&... args) { - size_t h = key.hash() ^ data_client.runtime_id(); - - // Runtime assertion that this key is unique - assert( - data_store[NS].find(h) == data_store[NS].end() && "key already exists"); - - meta_data_t & md = data_store[NS][h]; - - md.user_data.initialize(std::forward(args)...); - md.label = key.c_str(); - md.size = data_client.indices(index_space); - md.type_size = sizeof(T); - md.versions = versions; - md.rtti.reset(new typename meta_data_t::type_info_t(typeid(T))); - - md.num_entries = num_entries; - - for (size_t version = 0; version < versions; ++version) { - auto & iv = md.data[version | INDICES_FLAG] = std::vector(); - iv.resize((data_client.indices(index_space) + 1) * sizeof(size_t)); - - md.data[version | ENTRIES_FLAG] = std::vector(); - } + using entry_value_u = data::sparse_entry_value_u; + + template + static auto get_handle(const data_client_t & data_client) { + return storage_class_u::get_handle, NAMESPACE, NAME, VERSION>(data_client); + } - return {}; - } // register_data - - /// - /// - /// - template - static accessor_t get_accessor( - const data_client_t & data_client, - data_store_t & data_store, - const flecsi::utils::const_string_t & key, - size_t version) { - const size_t h = key.hash() ^ data_client.runtime_id(); - auto search = data_store[NS].find(h); - - if (search == data_store[NS].end()) { - return {}; - } else { - auto & meta_data = search->second; - - // check that the requested version exists - assert(meta_data.versions > version && "version out-of-range"); - - return {meta_data, version}; - } // if - } // get_accessor - - /// - /// - /// - template - static mutator_t get_mutator( - const data_client_t & data_client, - data_store_t & data_store, - const flecsi::utils::const_string_t & key, - size_t slots, - size_t version) { - const size_t h = key.hash() ^ data_client.runtime_id(); - auto search = data_store[NS].find(h); - - if (search == data_store[NS].end()) { - return {}; - } else { - auto & meta_data = search->second; - - // check that the requested version exists - assert(meta_data.versions > version && "version out-of-range"); - - return {slots, meta_data.label, version, meta_data, meta_data.user_data}; - } // if - } // get_accessor - - /// - /// - /// - template - static handle_t get_handle( - const data_client_t & data_client, - data_store_t & data_store, - const flecsi::utils::const_string_t & key, - size_t version) { - return {}; - } // get_handle - -}; // struct storage_type_t -#endif + template + static auto get_mutator(const data_client_t & data_client, size_t slots) { + return storage_class_u::get_mutator, NAMESPACE, NAME, VERSION>(data_client, slots); + } +}; // struct storage_class_t } // namespace hpx } // namespace data } // namespace flecsi -#endif // flecsi_hpx_sparse_h - /*~-------------------------------------------------------------------------~-* - * Formatting options - * vim: set tabstop=2 shiftwidth=2 expandtab : *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/sparse_data_handle_policy.h b/flecsi/data/hpx/sparse_data_handle_policy.h index 3c5701268..86f8c1f8e 100644 --- a/flecsi/data/hpx/sparse_data_handle_policy.h +++ b/flecsi/data/hpx/sparse_data_handle_policy.h @@ -3,6 +3,9 @@ #pragma once +#include +#include + //----------------------------------------------------------------------------// //! @file //! @date Initial file creation: Apr 04, 2017 @@ -17,10 +20,11 @@ struct hpx_sparse_data_handle_policy_t { // information from the context which is data that is the same // across multiple ranks/colors and should be used ONLY as read-only data - // field_id_t fid; + field_id_t fid; + bool * ghost_is_readable; + + execution::hpx_future_u* future = nullptr; - size_t reserve; - size_t num_exclusive_entries; }; // class mpi_sparse_data_handle_policy_t } // namespace flecsi diff --git a/flecsi/data/hpx/storage_policy.h b/flecsi/data/hpx/storage_policy.h index c2a9bebde..9092c8055 100644 --- a/flecsi/data/hpx/storage_policy.h +++ b/flecsi/data/hpx/storage_policy.h @@ -1,91 +1,15 @@ /*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved *~--------------------------------------------------------------------------~*/ -#ifndef flecsi_hpx_storage_policy_h -#define flecsi_hpx_storage_policy_h - -#include -#include -#include -#include -#include - -#include "flecsi/data/common/data_hash.h" - -#include "flecsi/data/data_constants.h" -#include "flecsi/data/hpx/meta_data.h" -#include "flecsi/data/hpx/registration_wrapper.h" - -// Include partial specializations -//#include "flecsi/data/hpx/global.h" -#include "flecsi/data/hpx/dense.h" -//#include "flecsi/data/hpx/sparse.h" -//#include "flecsi/data/hpx/scoped.h" -//#include "flecsi/data/hpx/tuple.h" - -/// -/// \file -/// \date Initial file creation: Apr 17, 2016 -/// +#pragma once namespace flecsi { namespace data { -struct hpx_storage_policy_t { - - using field_id_t = size_t; - using registration_function_t = std::function; - using data_value_t = std::pair; - using field_entry_t = std::unordered_map; - - // Field and client registration interfaces are the same for now. - using client_entry_t = field_entry_t; - - bool register_field(size_t client_key, - size_t key, - const registration_function_t & callback) { - // TODO: - return true; - } - - void register_all() { - for(auto & c : field_registry_) { - for(auto & d : c.second) { - d.second.second(d.second.first); - } // for - } // for - } // register_all - - auto const & field_registry() const { - return field_registry_; - } // field_registry - - auto const & client_registry() const { - return client_registry_; - } // client_registry - -private: - std::unordered_map field_registry_; - std::unordered_map client_registry_; -}; // struct hpx_storage_policy_t +struct hpx_storage_policy_t {}; // struct hpx_storage_policy_t } // namespace data } // namespace flecsi -#endif // flecsi_hpx_storage_policy_h - /*~-------------------------------------------------------------------------~-* - * Formatting options - * vim: set tabstop=2 shiftwidth=2 expandtab : *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/data/hpx/tuple.h b/flecsi/data/hpx/tuple.h deleted file mode 100644 index 5d60e900b..000000000 --- a/flecsi/data/hpx/tuple.h +++ /dev/null @@ -1,95 +0,0 @@ -/*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_hpx_tuple_h -#define flecsi_hpx_tuple_h - -//----------------------------------------------------------------------------// -// POLICY_NAMESPACE must be defined before including storage_type.h!!! -// Using this approach allows us to have only one storage_type_t -// definintion that can be used by all data policies -> code reuse... -#define POLICY_NAMESPACE hpx -//#include "flecsi/data/storage_type.h" -#undef POLICY_NAMESPACE -//----------------------------------------------------------------------------// - -/// -// \file hpx/tuple.h -// \authors bergen -// \date Initial file creation: Apr 17, 2016 -/// - -namespace flecsi { -namespace data { -namespace hpx { - -/// -// FIXME: Tuple storage type. -/// -template<> -struct storage_class_u { -#if 0 -/// -// FIXME: Tuple storage type. -/// -template -struct storage_type_t { - - struct tuple_accessor_t {}; // struct tuple_accessor_t - - struct tuple_handle_t {}; // struct tuple_handle_t - - template - static decltype(auto) register_data( - data_store_t & data_store, - uintptr_t runtime_namespace, - const utils::const_string_t & key, - size_t indices, - Args &&... args) {} // register_data - - /// - // - /// - template - static tuple_accessor_t get_accessor( - data_store_t & data_store, - uintptr_t runtime_namespace, - const utils::const_string_t & key) { - return {}; - } // get_accessor - - /// - // - /// - template - static tuple_handle_t get_handle( - data_store_t & data_store, - uintptr_t runtime_namespace, - const utils::const_string_t & key) { - return {}; - } // get_handle -#endif - -}; // struct storage_type_t - -} // namespace hpx -} // namespace data -} // namespace flecsi - -#endif // flecsi_hpx_tuple_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/execution/CMakeLists.txt b/flecsi/execution/CMakeLists.txt index 389e1360a..9a97c9426 100644 --- a/flecsi/execution/CMakeLists.txt +++ b/flecsi/execution/CMakeLists.txt @@ -102,8 +102,12 @@ elseif(FLECSI_RUNTIME_MODEL STREQUAL "hpx") ${execution_HEADERS} hpx/context_policy.h hpx/execution_policy.h + hpx/finalize_handles.h hpx/future.h + hpx/reduction_wrapper.h hpx/runtime_driver.h + hpx/task_epilog.h + hpx/task_prolog.h ) set(execution_SOURCES ${execution_SOURCES} @@ -225,7 +229,6 @@ if (FLECSI_ENABLE_KOKKOS) endif() -if(NOT FLECSI_RUNTIME_MODEL STREQUAL "hpx") # # Test basic task to test future_handle # @@ -363,7 +366,6 @@ if(NOT FLECSI_RUNTIME_MODEL STREQUAL "hpx") THREADS 4 ) - cinch_add_devel_target(concept_coloring SOURCES test/concept_coloring.cc @@ -452,7 +454,7 @@ if(NOT FLECSI_RUNTIME_MODEL STREQUAL "hpx") POLICY ${UNIT_POLICY} THREADS 2 ) - + cinch_add_unit(handle_tuple SOURCES test/handle_tuple.cc @@ -474,7 +476,7 @@ if(NOT FLECSI_RUNTIME_MODEL STREQUAL "hpx") POLICY ${UNIT_POLICY} THREADS 2 ) - + if(FLECSI_RUNTIME_MODEL STREQUAL "mpi") cinch_add_unit(legacy_restart SOURCES @@ -498,8 +500,7 @@ if(NOT FLECSI_RUNTIME_MODEL STREQUAL "hpx") THREADS 2 ) endif() - - + cinch_add_unit(data_handle_task SOURCES test/data_handle_task.cc @@ -906,5 +907,3 @@ if(NOT FLECSI_RUNTIME_MODEL STREQUAL "hpx") endif() # (ENABLE_PARMETIS) endif() # legion - -endif()# not hpx diff --git a/flecsi/execution/execution.h b/flecsi/execution/execution.h index 484c69eb7..f5096ed36 100644 --- a/flecsi/execution/execution.h +++ b/flecsi/execution/execution.h @@ -433,7 +433,7 @@ clog_register_tag(execution); #define flecsi_execute_mpi_task(task, nspace, ...) \ /* MACRO IMPLEMENTATION */ \ \ - flecsi_execute_task(task, nspace, index, ##__VA_ARGS__) + flecsi_execute_task(task, nspace, index, ##__VA_ARGS__).get() //----------------------------------------------------------------------------// // Reduction Interface diff --git a/flecsi/execution/hpx/context_policy.cc b/flecsi/execution/hpx/context_policy.cc index ca1f18b46..737d1748d 100644 --- a/flecsi/execution/hpx/context_policy.cc +++ b/flecsi/execution/hpx/context_policy.cc @@ -1,12 +1,18 @@ -/*~-------------------------------------------------------------------------~~* - * Copyright (c) 2014 Los Alamos National Security, LLC - * All rights reserved. - *~-------------------------------------------------------------------------~~*/ - -//----------------------------------------------------------------------------// -//! @file -//! @date Initial file creation: Jul 26, 2016 -//----------------------------------------------------------------------------// +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2016, Los Alamos National Security, LLC + All rights reserved. + */ + +/*! @file */ #include @@ -18,52 +24,58 @@ #include #include +#include #include #include #include #include -#include - #include +#include namespace flecsi { namespace execution { -hpx_context_policy_t::hpx_context_policy_t() - : min_reduction_{0}, max_reduction_{0} { +//----------------------------------------------------------------------------// +// Implementation of hpx_context_policy_t. +//----------------------------------------------------------------------------// + +hpx_context_policy_t::hpx_context_policy_t() { #if defined(_MSC_VER) hpx::detail::init_winsocket(); #endif -} +} // namespace execution // Return the color for which the context was initialized. size_t hpx_context_policy_t::color() const { - return hpx::get_locality_id(); + return color_; +} + +// Return the number of colors. +size_t +hpx_context_policy_t::colors() const { + return colors_; } // Main HPX thread, does nothing but wait for the application to exit int -hpx_context_policy_t::hpx_main(int (*driver)(int, char *[]), +hpx_context_policy_t::hpx_main(void (*driver)(int, char *[]), int argc, char * argv[]) { - // initialize executors (possible only after runtime is active) - exec_ = flecsi::execution::pool_executor{"default"}; - mpi_exec_ = flecsi::execution::pool_executor{"mpi"}; + MPI_Comm_rank(MPI_COMM_WORLD, &color_); + MPI_Comm_size(MPI_COMM_WORLD, &colors_); // execute user code (driver) - int retval = (*driver)(argc, argv); + (*driver)(argc, argv); // tell the runtime it's ok to exit - hpx::finalize(); - - return retval; + return hpx::finalize(); } int -hpx_context_policy_t::start_hpx(int (*driver)(int, char *[]), +hpx_context_policy_t::start_hpx(void (*driver)(int, char *[]), int argc, char * argv[]) { @@ -77,29 +89,15 @@ hpx_context_policy_t::start_hpx(int (*driver)(int, char *[]), // disable HPX' short options "hpx.commandline.aliasing!=0"}; - auto init_rp = [](hpx::resource::partitioner & rp) { - // Create a thread pool encapsulating the default scheduler - rp.create_thread_pool("default", hpx::resource::local_priority_fifo); - - // Create a thread pool for executing MPI tasks - rp.create_thread_pool("mpi", hpx::resource::static_); - - // Add first core to mpi pool - rp.add_resource(rp.numa_domains()[0].cores()[0].pus()[0], "mpi"); - }; - // Now, initialize and run the HPX runtime, will return when done. #if HPX_VERSION_FULL < 0x010500 - hpx::resource::partitioner rp{ + return hpx::init( hpx::util::bind_front(&hpx_context_policy_t::hpx_main, this, driver), argc, - argv, cfg}; - init_rp(rp); - return hpx::init(); + argv, cfg); #else - // Newer versions of HPX do not allow to explicitly initialice the + // Newer versions of HPX do not allow to explicitly initialize the // resource partitioner anymore hpx::init_params params; - params.rp_callback = init_rp; params.cfg = std::move(cfg); return hpx::init( diff --git a/flecsi/execution/hpx/context_policy.h b/flecsi/execution/hpx/context_policy.h index 3cc0a2c2d..6dbd33061 100644 --- a/flecsi/execution/hpx/context_policy.h +++ b/flecsi/execution/hpx/context_policy.h @@ -1,28 +1,20 @@ -/*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_execution_hpx_context_policy_h -#define flecsi_execution_hpx_context_policy_h - -#include - -#if !defined(FLECSI_ENABLE_HPX) -#error ENABLE_HPX not defined! This file depends on HPX! -#endif - +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2016, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once + +#include #include -#include #include #include @@ -34,121 +26,157 @@ #include #include +#include + +#if !defined(FLECSI_ENABLE_HPX) +#error ENABLE_HPX not defined! This file depends on HPX! +#endif -#include "flecsi/utils/mpi_type_traits.h" +#include + +#include +#include +#include +#include +#include +#include #include #include #include #include +#include #include #include +#include +#include #include -#include - -/// -/// \file hpx/execution_policy.h -/// \authors bergen -/// \date Initial file creation: Nov 15, 2015 -/// - -#if HPX_VERSION_FULL < 0x010500 namespace flecsi { namespace execution { -using pool_executor = hpx::threads::executors::pool_executor; -} // namespace execution -} // namespace flecsi -#else -namespace flecsi { -namespace execution { +/////////////////////////////////////////////////////////////////////////////// +/*! + The hpx_context_policy_t is the backend runtime context policy for HPX. -// newer versions of HPX do not support pool_executor anymore -class pool_executor : public hpx::parallel::execution::thread_pool_executor -{ -public: - explicit pool_executor(std::string const & pool_name = "default") - : hpx::parallel::execution::thread_pool_executor( - &hpx::threads::get_thread_manager().get_pool(pool_name), - hpx::threads::thread_priority_default, - hpx::threads::thread_stacksize_default) {} -}; -} // namespace execution -} // namespace flecsi + @ingroup mpi-execution + */ -namespace hpx { -namespace parallel { -namespace execution { -template<> -struct is_one_way_executor : std::true_type { -}; +struct hpx_context_policy_t { -template<> -struct is_two_way_executor : std::true_type { -}; + /*! + The registration_function_t type defines a function type for + registration callbacks. + */ -template<> -struct is_bulk_two_way_executor - : std::true_type {}; -} // namespace execution -} // namespace parallel -} // namespace hpx -#endif + using registration_function_t = + std::function; -namespace flecsi { -namespace execution { + using task_info_t = std::tuple; -/////////////////////////////////////////////////////////////////////////////// -struct hpx_context_policy_t { + struct sparse_field_data_t { - using field_id_t = size_t; + sparse_field_data_t() {} + + sparse_field_data_t(size_t type_size, + size_t num_exclusive, + size_t num_shared, + size_t num_ghost, + size_t max_entries_per_index) + : type_size(type_size), num_exclusive(num_exclusive), + num_shared(num_shared), num_ghost(num_ghost), + num_total(num_exclusive + num_shared + num_ghost), + max_entries_per_index(max_entries_per_index), + rows(num_total * sizeof(data::row_vector_u)) {} + + std::ostream & write(std::ostream & os, + const data::serdez_untyped_t * serdez) const { + + os.write((char *)&type_size, sizeof(size_t)); + os.write((char *)&num_exclusive, sizeof(size_t)); + os.write((char *)&num_shared, sizeof(size_t)); + os.write((char *)&num_ghost, sizeof(size_t)); + os.write((char *)&num_total, sizeof(size_t)); + os.write((char *)&max_entries_per_index, sizeof(size_t)); + + // use serdez operator to write actual row data + const char * row_ptr = (char *)rows.data(); + for(int i = 0; i < num_total; ++i) { + serdez->serialize(row_ptr, os); + row_ptr += sizeof(data::row_vector_u); + } + return os; + } + + std::istream & read(std::istream & is, + const data::serdez_untyped_t * serdez) { + is.read((char *)&type_size, sizeof(size_t)); + is.read((char *)&num_exclusive, sizeof(size_t)); + is.read((char *)&num_shared, sizeof(size_t)); + is.read((char *)&num_ghost, sizeof(size_t)); + is.read((char *)&num_total, sizeof(size_t)); + is.read((char *)&max_entries_per_index, sizeof(size_t)); + + // use serdez operator to read actual row data + char * row_ptr = (char *)rows.data(); + for(int i = 0; i < num_total; ++i) { + serdez->deserialize(row_ptr, is); + row_ptr += sizeof(data::row_vector_u); + } + return is; + } + + size_t type_size; + + // total # of exclusive, shared, ghost entries + size_t num_exclusive = 0; + size_t num_shared = 0; + size_t num_ghost = 0; + size_t num_total = 0; + + size_t max_entries_per_index; + + std::vector rows; + }; // sparse_field_data_t - //------------------------------------------------------------------------// - // Initialization. - //------------------------------------------------------------------------// + using field_id_t = size_t; FLECSI_EXPORT hpx_context_policy_t(); - /// - /// Initialize the context runtime. The arguments to this method should - /// be passed from the main function. - /// - /// \param argc The number of command-line arguments. - /// \param argv The array of command-line arguments. - /// - /// \return Zero upon clean initialization, non-zero otherwise. - /// + /*! + FleCSI context initialization. This method initializes the FleCSI + runtime using MPI. + + @param argc The command-line argument count passed from main. + @param argv The command-line argument values passed from main. + + @return An integer value with a non-zero error code upon failure, + zero otherwise. + */ int initialize(int argc, char * argv[]) { // start HPX runtime system, execute driver code in the context of HPX return start_hpx(&hpx_runtime_driver, argc, argv); } // hpx_context_policy_t::initialize - /// - /// Return the color for which the context was initialized. - /// + /*! + Return the color for which the context was initialized. + */ FLECSI_EXPORT size_t color() const; /*! Return the number of colors. */ - std::size_t colors() const { - return colors_; - } // color + FLECSI_EXPORT std::size_t colors() const; //--------------------------------------------------------------------------// // Task interface. //--------------------------------------------------------------------------// - /*! - The registration_function_t type defines a function type for - registration callbacks. - */ - - using registration_function_t = - std::function; - /*! The unique_tid_t type create a unique id generator for registering tasks. @@ -165,114 +193,16 @@ struct hpx_context_policy_t { */ //------------------------------------------------------------------------// - // Function registration. + // Function interface. //------------------------------------------------------------------------// - using task_info_t = - std::tuple; - - /// - /// \tparam T The type of the function being registered. - /// - /// \param key A unique function identifier. - /// - /// \return A boolean value that is true if the registration succeeded, - /// false otherwise. - /// - template - bool register_function() { - clog_assert(function_registry_.find(KEY) == function_registry_.end(), - "function has already been registered"); - - clog(info) << "Registering function: " << FUNCTION << std::endl; - - function_registry_[KEY] = reinterpret_cast(FUNCTION); - return true; - } // register_function - - /// - /// Return the function associated with \e key. - /// - /// \param key The unique function identifier. - /// - /// \return A pointer to a std::function that may be cast - /// back to the original function type using reinterpret_cast. - /// - void * function(std::size_t key) { - return function_registry_[key]; - } // function - - /// - /// Register a task with the runtime. - /// - /// \param key The task hash key. - /// \param processor The task processor. - /// \param launch The task launch type. - /// \param name The task name string. - /// - template - bool register_task(processor_type_t processor, - launch_t launch, - std::string const & name) { - clog(info) << "Registering task " << name << " with key " << KEY - << std::endl; - - clog_assert(task_registry_.find(KEY) == task_registry_.end(), - "task key already exists"); - - task_registry_[KEY] = std::make_tuple( - processor, launch, name, reinterpret_cast(FUNCTION)); - - return true; - } // register_task - - /// - /// Return the task associated with \e key. - /// - /// \param key The unique task identifier. - /// - /// \return A pointer to a std::function that may be cast - /// back to the original function type using reinterpret_cast. - /// - template - void * task() const { - - auto it = task_registry_.find(KEY); - - clog_assert(it != task_registry_.end(), "task key does not exists"); - - return std::get<3>(it->second); - } // task - - template - processor_type_t processor_type() const { - auto it = task_registry_.find(KEY); - - clog_assert(it != task_registry_.end(), "task key does not exists"); - - return std::get<0>(it->second); - } - - //-------------------------------------------------------------------- - // Data maps - //-------------------------------------------------------------------- struct index_space_data_t { - // TODO: to be defined. + std::map ghost_is_readable; + std::map> future; }; struct index_subspace_data_t { - std::size_t capacity; - }; - - struct local_index_space_data_t { - std::size_t size; - std::size_t capacity; + size_t capacity; }; auto & index_space_data_map() { @@ -287,155 +217,634 @@ struct hpx_context_policy_t { return index_subspace_data_map_; } - auto & local_index_space_data_map() { - return local_index_space_data_map_; - } + using coloring_info_t = flecsi::coloring::coloring_info_t; + using index_coloring_t = flecsi::coloring::index_coloring_t; + /*! + Field metadata is used maintain MPI information and data types for + MPI windows/one-sided communication to perform ghost copies. + */ struct field_metadata_t { - // TODO: to be defined - }; - struct sparse_field_data_t { - // TODO: to be defined + MPI_Group comm_grp = MPI_GROUP_NULL; + MPI_Group shared_users_grp = MPI_GROUP_NULL; + MPI_Group ghost_owners_grp = MPI_GROUP_NULL; + + std::map origin_types; + std::map target_types; + + MPI_Datatype data_type; + + MPI_Win win = MPI_WIN_NULL; + +#if defined(FLECSI_USE_AGGCOMM) + std::vector>> shared_indices; + std::vector>> ghost_indices; + std::vector shared_field_sizes; + std::vector ghost_field_sizes; + unsigned char * shared_data_buffer; + unsigned char * ghost_data_buffer; +#endif }; + /*! + Field metadata is used maintain MPI information and data types for + MPI windows/one-sided communication to perform ghost copies. + */ struct sparse_field_metadata_t { - // TODO: to be defined + MPI_Group comm_grp = MPI_GROUP_NULL; + MPI_Group shared_users_grp = MPI_GROUP_NULL; + MPI_Group ghost_owners_grp = MPI_GROUP_NULL; + + std::map> compact_origin_lengs; + std::map> compact_origin_disps; + + std::map> compact_target_lengs; + std::map> compact_target_disps; + + std::map origin_types; + std::map target_types; + +#if defined(FLECSI_USE_AGGCOMM) + std::map> shared_indices; + std::map> ghost_indices; + std::vector ghost_row_sizes; +#endif + + MPI_Win win = MPI_WIN_NULL; + + std::function deleter; }; /*! - return max reduction + Create MPI datatypes use for ghost copy by inspecting shared regions, + and ghost owners, to compute origin and target lengths and displacements + for MPI windows. */ + template + void register_field_metadata(const field_id_t fid, + const coloring_info_t & coloring_info, + const index_coloring_t & index_coloring) { +#if !defined(FLECSI_USE_AGGCOMM) + std::map> compact_origin_lengs; + std::map> compact_origin_disps; + + std::map> compact_target_lengs; + std::map> compact_target_disps; + + field_metadata_t metadata; + + register_field_metadata_(metadata, fid, coloring_info, index_coloring, + compact_origin_lengs, compact_origin_disps, compact_target_lengs, + compact_target_disps); + + MPI_Type_contiguous( + static_cast(sizeof(T)), MPI_BYTE, &metadata.data_type); + MPI_Type_commit(&metadata.data_type); + + for(auto owner : coloring_info.ghost_owners) { + int ghost_owner = static_cast(owner); + MPI_Datatype origin_type; + MPI_Datatype target_type; + + MPI_Type_indexed( + static_cast(compact_origin_lengs[ghost_owner].size()), + compact_origin_lengs[ghost_owner].data(), + compact_origin_disps[ghost_owner].data(), metadata.data_type, + &origin_type); + MPI_Type_commit(&origin_type); + metadata.origin_types.insert({ghost_owner, origin_type}); + + MPI_Type_indexed( + static_cast(compact_target_lengs[ghost_owner].size()), + compact_target_lengs[ghost_owner].data(), + compact_target_disps[ghost_owner].data(), metadata.data_type, + &target_type); + MPI_Type_commit(&target_type); + metadata.target_types.insert({ghost_owner, target_type}); + } + + auto data = field_data[fid].data(); + auto shared_data = data + coloring_info.exclusive * sizeof(T); + MPI_Win_create(shared_data, coloring_info.shared * sizeof(T), + static_cast(sizeof(T)), MPI_INFO_NULL, MPI_COMM_WORLD, + &metadata.win); + + field_metadata.insert({fid, metadata}); +#else + field_metadata_t metadata; + int mpiSize; + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); + + // FIXME: Do this per index_space instead of per field id + + metadata.shared_indices.resize(mpiSize); + metadata.ghost_indices.resize(mpiSize); + metadata.ghost_field_sizes.resize(mpiSize); + metadata.shared_field_sizes.resize(mpiSize); + + // indices are stored as vectors of pairs, each pair consisting of: starting + // index, how many consecutive indices + + size_t ghost_cnt = 0; + + for(auto const & ghost : index_coloring.ghost) { + + if(metadata.ghost_indices[ghost.rank].size() == 0 || + ghost_cnt * sizeof(T) != + (metadata.ghost_indices[ghost.rank].back()[0] + + metadata.ghost_indices[ghost.rank].back()[1])) + metadata.ghost_indices[ghost.rank].push_back( + {ghost_cnt * sizeof(T), sizeof(T)}); + else + metadata.ghost_indices[ghost.rank].back()[1] += sizeof(T); + ++ghost_cnt; + } - auto & max_reduction() { - return max_reduction_; + for(auto const & shared : index_coloring.shared) { + + for(auto const & s : shared.shared) { + + if(metadata.shared_indices[s].size() == 0 || + shared.offset * sizeof(T) != (metadata.shared_indices[s].back()[0] + + metadata.shared_indices[s].back()[1])) + + metadata.shared_indices[s].push_back( + {shared.offset * sizeof(T), sizeof(T)}); + + else + + metadata.shared_indices[s].back()[1] += sizeof(T); + } + } + + for(int rank = 0; rank < mpiSize; ++rank) { + for(auto const & ind : metadata.ghost_indices[rank]) + metadata.ghost_field_sizes[rank] += ind[1]; + for(auto const & ind : metadata.shared_indices[rank]) + metadata.shared_field_sizes[rank] += ind[1]; + } + + field_metadata.insert({fid, metadata}); +#endif } /*! - Set max_reduction - - @param double max_reduction + Create MPI datatypes use for ghost copy by inspecting shared regions, + and ghost owners, to compute origin and target lengths and displacements + for MPI windows. */ + template + void register_sparse_field_metadata(const field_id_t fid, + const coloring_info_t & coloring_info, + const index_coloring_t & index_coloring) { + sparse_field_metadata_t metadata; +#if !defined(FLECSI_USE_AGGCOMM) + + register_field_metadata_(metadata, fid, coloring_info, index_coloring, + metadata.compact_origin_lengs, metadata.compact_origin_disps, + metadata.compact_target_lengs, metadata.compact_target_disps); - void set_max_reduction(double max_reduction) { - max_reduction_ = max_reduction; +#else + // compute ghost and shared indicies + size_t ghost_count = 0; + for(auto const & ghost : index_coloring.ghost) { + metadata.ghost_indices[static_cast(ghost.rank)].push_back( + ghost_count); + ++ghost_count; + } + for(auto const & shared : index_coloring.shared) { + for(auto const & s : shared.shared) { + metadata.shared_indices[static_cast(s)].push_back(shared.offset); + } + } + + // allocate ghost_row_sizes + metadata.ghost_row_sizes.resize(index_coloring.ghost.size()); +#endif + + auto it = sparse_field_data.find(fid); + auto rows = &it->second.rows[0]; + auto num_total = &it->second.num_total; + metadata.deleter = [=]() { + using vector_t = typename ragged_data_handle_u::vector_t; + auto vec = reinterpret_cast(rows); + for(size_t i = 0; i < *num_total; ++i) + vec[i].clear(); + }; + + sparse_field_metadata.insert({fid, metadata}); } /*! - Perform reduction for the maximum value type + Compute MPI datatypes, compacted length and displacement for ghost copy + with MPI window. + */ + template + void register_field_metadata_(MD & metadata, + const field_id_t fid, + const coloring_info_t & coloring_info, + const index_coloring_t & index_coloring, + std::map> & compact_origin_lengs, + std::map> & compact_origin_disps, + std::map> & compact_target_lengs, + std::map> & compact_target_disps) { + // The group for MPI_Win_post are the "origin" processes, i.e. + // the peer processes calling MPI_Get to get our shared cells. Thus + // granting access of local window to these processes. This is the set + // coloring_info_t::shared_users + // On the other hand, the group for MPI_Win_start are the 'target' + // processes, i.e. the peer processes this rank is going to get ghost + // cells from. This is the set coloring_info_t::ghost_owners. + // Since both shared_users and ghost_owners are std::set, we have copy + // them to std::vector be passed to MPI. + + // initialize explicitly to avoid integral conversion warnings + std::vector shared_users; + shared_users.reserve(coloring_info.shared_users.size()); + for(auto const v : coloring_info.shared_users) + shared_users.push_back(static_cast(v)); + + std::vector ghost_owners; + ghost_owners.reserve(coloring_info.ghost_owners.size()); + for(auto const v : coloring_info.ghost_owners) + ghost_owners.push_back(static_cast(v)); + + if(metadata.comm_grp == MPI_GROUP_NULL) { + MPI_Comm_group(MPI_COMM_WORLD, &metadata.comm_grp); + + MPI_Group_incl(metadata.comm_grp, static_cast(shared_users.size()), + shared_users.data(), &metadata.shared_users_grp); + MPI_Group_incl(metadata.comm_grp, static_cast(ghost_owners.size()), + ghost_owners.data(), &metadata.ghost_owners_grp); + } + + std::map> origin_lens; + std::map> origin_disps; + std::map> target_lens; + std::map> target_disps; + + for(auto ghost_owner : ghost_owners) { + origin_lens.insert({ghost_owner, {}}); + origin_disps.insert({ghost_owner, {}}); + target_lens.insert({ghost_owner, {}}); + target_disps.insert({ghost_owner, {}}); + } + + int origin_index = 0; + for(const auto & ghost : index_coloring.ghost) { + int rank = static_cast(ghost.rank); + origin_lens[rank].push_back(1); + origin_disps[rank].push_back(origin_index++); + target_lens[rank].push_back(1); + target_disps[rank].push_back(static_cast(ghost.offset)); + } + + int my_color; + MPI_Comm_rank(MPI_COMM_WORLD, &my_color); + +// This should only be uncommented for debugging (outputs info +// during tutorial runs). Consider changing this to use clog +#if 0 + if (my_color == 0) { + for (auto ghost_owner : ghost_owners) { + std::cout << "ghost owner: " << ghost_owner << std::endl; + std::cout << "\torigin length: "; + for(auto len : origin_lens[ghost_owner]) { + std::cout << len << " "; + } + std::cout << std::endl; + std::cout << "\torigin disp: "; + for(auto len : origin_disps[ghost_owner]) { + std::cout << len << " "; + } + std::cout << std::endl; + std::cout << "\ttarget length: "; + for(auto len : target_lens[ghost_owner]) { + std::cout << len << " "; + } + std::cout << std::endl; + + std::cout << "\ttarget disp: "; + for(auto len : target_disps[ghost_owner]) { + std::cout << len << " "; + } + std::cout << std::endl; + } // for + } // if +#endif + + for(auto owner : ghost_owners) { + int ghost_owner = static_cast(owner); + if(origin_disps.size() == 0) + break; + + int count = 0; + compact_origin_lengs[ghost_owner].push_back(1); + compact_origin_disps[ghost_owner].push_back(origin_disps[ghost_owner][0]); + + for(int i = 1; i < origin_disps[ghost_owner].size(); i++) { + if(origin_disps[ghost_owner][i] - origin_disps[ghost_owner][i - 1] == + 1) { + compact_origin_lengs[ghost_owner].back() = + compact_origin_lengs[ghost_owner].back() + 1; + } + else { + compact_origin_lengs[ghost_owner].push_back(1); + compact_origin_disps[ghost_owner].push_back( + origin_disps[ghost_owner][i]); + } + } + } + +#if 0 + if (my_color == 0) { + for (auto ghost_owner : ghost_owners) { + std::cout << "ghost owner: " << ghost_owner << std::endl; + std::cout << "source compacted length: "; + for(auto len : compact_origin_lengs[ghost_owner]) { + std::cout << len << " "; + } + std::cout << std::endl; + std::cout << "source compacted disps: "; + for(auto disp : compact_origin_disps[ghost_owner]) { + std::cout << disp << " "; + } + std::cout << std::endl; + } // for + } // if +#endif - @param + for(auto owner : ghost_owners) { + int ghost_owner = static_cast(owner); + if(target_disps.size() == 0) + break; + + int count = 0; + compact_target_lengs[ghost_owner].push_back(1); + compact_target_disps[ghost_owner].push_back(target_disps[ghost_owner][0]); + + for(int i = 1; i < target_disps[ghost_owner].size(); i++) { + if(target_disps[ghost_owner][i] - target_disps[ghost_owner][i - 1] == + 1) { + compact_target_lengs[ghost_owner].back() = + compact_target_lengs[ghost_owner].back() + 1; + } + else { + compact_target_lengs[ghost_owner].push_back(1); + compact_target_disps[ghost_owner].push_back( + target_disps[ghost_owner][i]); + } + } + } + +#if 0 + if (my_color == 0) { + for (auto ghost_owner : ghost_owners) { + std::cout << "ghost owner: " << ghost_owner << std::endl; + + std::cout << "compacted target length: "; + for(auto len : compact_target_lengs[ghost_owner]) { + std::cout << len << " "; + } + std::cout << std::endl; + std::cout << "compacted target disps: "; + for(auto disp : compact_target_disps[ghost_owner]) { + std::cout << disp << " "; + } + std::cout << std::endl; + } // for + } // if +#endif + } // register_field_metadata_ + + std::map & registered_field_metadata() { + return field_metadata; + }; + + /*! + Register new field data, i.e. allocate a new buffer for the specified field + ID. */ + void register_field_data(field_id_t fid, size_t size) { + // TODO: VERSIONS + auto it = field_data.find(fid); + if(it == field_data.end()) { + field_data.insert({fid, std::vector(size)}); + field_futures.insert({fid, execution::hpx_future_u{}}); + } + else { + it->second.resize(size); + } + } - template - auto reduce_max(hpx::shared_future & local_future) - -> hpx::shared_future { - auto gloabl_max_f = local_future.then( - mpi_exec_, [](hpx::shared_future && local_future) -> T { - T global_max{}; - T local_max = local_future.get(); - MPI_Allreduce(&local_max, &global_max, 1, utils::mpi_type(), MPI_MAX, - MPI_COMM_WORLD); - return global_max; - }); - return gloabl_max_f; + std::map> & registered_field_data() { + return field_data; + } + + std::map> & + registered_field_futures() { + return field_futures; } /*! - return min reduction + Register new sparse field data, i.e. allocate a new buffer for the + specified field ID. Sparse data consists of a buffer of offsets + (start + length) and entry id / value pairs and associated metadata about + this field. */ - auto & min_reduction() { - return min_reduction_; + void register_sparse_field_data(field_id_t fid, + size_t type_size, + const coloring_info_t & coloring_info, + size_t max_entries_per_index) { + // TODO: VERSIONS + sparse_field_data_t new_field(type_size, coloring_info.exclusive, + coloring_info.shared, coloring_info.ghost, max_entries_per_index); + auto it = sparse_field_data.find(fid); + if(it == sparse_field_data.end()) { + sparse_field_data.emplace(fid, std::move(new_field)); + } + else { + it->second = std::move(new_field); + } + } + + std::map & registered_sparse_field_data() { + return sparse_field_data; + } + + std::map & + registered_sparse_field_metadata() { + return sparse_field_metadata; + }; + + std::map & reduction_operations() { + return reduction_ops_; + } // reduction_types + + void finalize() { +#if !defined(FLECSI_USE_AGGCOMM) + for(auto & md : field_metadata) { + for(auto & ty : md.second.origin_types) + MPI_Type_free(&ty.second); + for(auto & ty : md.second.target_types) + MPI_Type_free(&ty.second); + MPI_Type_free(&md.second.data_type); + MPI_Group_free(&md.second.ghost_owners_grp); + MPI_Group_free(&md.second.shared_users_grp); + MPI_Group_free(&md.second.comm_grp); + if(md.second.win != MPI_WIN_NULL) + MPI_Win_free(&md.second.win); + } +#endif + for(auto & md : sparse_field_metadata) { +#if !defined(FLECSI_USE_AGGCOMM) + for(auto & ty : md.second.origin_types) + MPI_Type_free(&ty.second); + for(auto & ty : md.second.target_types) + MPI_Type_free(&ty.second); + MPI_Group_free(&md.second.ghost_owners_grp); + MPI_Group_free(&md.second.shared_users_grp); + MPI_Group_free(&md.second.comm_grp); + if(md.second.win != MPI_WIN_NULL) + MPI_Win_free(&md.second.win); +#endif + md.second.deleter(); + } } + //--------------------------------------------------------------------------// + // Task interface. + //--------------------------------------------------------------------------// + /*! - Set min_reduction + Register a task with the runtime. - @param double min_reduction + @param key The task hash key. + @param name The task name string. + @param callback The registration call back function. */ - void set_min_reduction(double min_reduction) { - min_reduction_ = min_reduction; - } + bool register_task(size_t key, + processor_type_t processor, + launch_t launch, + std::string & name, + const registration_function_t & callback) { + clog(info) << "Registering task callback " << name << " with key " << key + << std::endl; + + clog_assert(task_registry_.find(key) == task_registry_.end(), + "task key already exists"); + + task_registry_[key] = std::make_tuple( + unique_tid_t::instance().next(), processor, launch, name, callback); + + return true; + } // register_task /*! - Perform reduction for the minimum value type + Return the task registration tuple. - @param + @param key The task hash key. */ - template - auto reduce_min(hpx::shared_future & local_future) - -> hpx::shared_future { - auto global_min_f = local_future.then( - mpi_exec_, [](hpx::shared_future && local_future) -> T { - T global_min{}; - T local_min = local_future.get(); - MPI_Allreduce(&local_min, &global_min, 1, utils::mpi_type(), MPI_MAX, - MPI_COMM_WORLD); - return global_min; - }); - return global_min_f; - } + template + task_info_t & task_info() { + auto task_entry = task_registry_.find(KEY); + + clog_assert(task_entry != task_registry_.end(), + "task key " << KEY << " does not exist"); + + return task_entry->second; + } // task_info + + /*! + Return the task registration tuple. + + @param key The task hash key. + */ + + task_info_t & task_info(size_t key) { + auto task_entry = task_registry_.find(key); + + clog_assert(task_entry != task_registry_.end(), + "task key " << key << " does not exist"); + + return task_entry->second; + } // task_info - flecsi::execution::pool_executor & get_default_executor() { - return exec_; +#define task_info_template_method(name, return_type, index) \ + template \ + return_type name() { \ + { \ + clog_tag_guard(context); \ + clog(info) << "Returning " << #name << " for " << KEY << std::endl; \ + } \ + return std::get(task_info()); \ } - flecsi::execution::pool_executor & get_mpi_executor() { - return mpi_exec_; + /*! + FIXME + + @param key The task hash key. + */ + +#define task_info_method(name, return_type, index) \ + return_type name(size_t key) { \ + { \ + clog_tag_guard(context); \ + clog(info) << "Returning " << #name << " for " << key << std::endl; \ + } \ + return std::get(task_info(key)); \ } - int rank; + /*! + FIXME + + @param key The task hash key. + */ + + task_info_template_method(task_id, task_id_t, 0); + task_info_method(task_id, task_id_t, 0); + task_info_template_method(processor_type, processor_type_t, 1); + task_info_method(processor_type, processor_type_t, 1); protected: // Helper function for HPX start-up and shutdown FLECSI_EXPORT int - hpx_main(int (*driver)(int, char *[]), int argc, char * argv[]); + hpx_main(void (*driver)(int, char *[]), int argc, char * argv[]); // Start the HPX runtime system, FLECSI_EXPORT int - start_hpx(int (*driver)(int, char *[]), int argc, char * argv[]); + start_hpx(void (*driver)(int, char *[]), int argc, char * argv[]); -private: - //--------------------------------------------------------------------------// - // Task data members. - //--------------------------------------------------------------------------// +public: + int rank; + // private: + int color_ = 0; int colors_ = 0; - // Map to store task registration callback methods. - std::map task_registry_; - - // Function registry - std::unordered_map function_registry_; - std::map> field_data; std::map field_metadata; + std::map> field_futures; - std::map index_space_data_map_; - std::map local_index_space_data_map_; - std::map index_subspace_data_map_; + std::map index_space_data_map_; + std::map index_subspace_data_map_; std::map sparse_field_data; std::map sparse_field_metadata; - double min_reduction_; - double max_reduction_; + std::map reduction_ops_; -private: - flecsi::execution::pool_executor exec_; - flecsi::execution::pool_executor mpi_exec_; + //--------------------------------------------------------------------------// + // Task data members. + //--------------------------------------------------------------------------// + // Map to store task registration callback methods. + std::map task_registry_; }; // struct hpx_context_policy_t } // namespace execution } // namespace flecsi - -#endif // flecsi_execution_hpx_context_policy_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/execution/hpx/execution_policy.h b/flecsi/execution/hpx/execution_policy.h index 2a0296389..a0c7018c9 100644 --- a/flecsi/execution/hpx/execution_policy.h +++ b/flecsi/execution/hpx/execution_policy.h @@ -1,26 +1,26 @@ -/*~--------------------------------------------------------------------------~* - * @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - * /@@///// /@@ @@////@@ @@////// /@@ - * /@@ /@@ @@@@@ @@ // /@@ /@@ - * /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - * /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - * /@@ /@@/@@//// //@@ @@ /@@/@@ - * /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - * // /// ////// ////// //////// // - * - * Copyright (c) 2016 Los Alamos National Laboratory, LLC - * All rights reserved - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_execution_hpx_execution_policy_h -#define flecsi_execution_hpx_execution_policy_h +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2016, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once + +/*! @file */ #include #include -#include -#include +#include #include +#include #include #include #include @@ -28,42 +28,48 @@ #include #include #include +#include #include -#include -#include -#include - +#include +#include +#include +#include +#include +#include #include - -//#include "flecsi/execution/task.h" - -/// -// \file hpx/execution_policy.h -// \authors bergen -// \date Initial file creation: Nov 15, 2015 -/// +#include +#include namespace flecsi { namespace execution { -//----------------------------------------------------------------------------// -// Future. -//----------------------------------------------------------------------------// +/*! + Executor interface. + */ -/// -/// Executor interface. -/// template struct executor_u { - /// - /// - /// - template - static hpx_future_u - execute(Exec && exec, T fun, A && targs) { - auto user_fun = (reinterpret_cast(fun)); - return hpx::async( - std::forward(exec), std::move(user_fun), std::forward(targs)); + /*! + FIXME documentation + */ + template + static decltype(auto) execute(T function, A && targs) { + auto user_fun = reinterpret_cast(function); + return hpx::make_ready_future( + user_fun(utils::forward_tuple(std::forward(targs)))); + } // execute_task +}; // struct executor_u + +template +struct executor_u { + /*! + FIXME documentation + */ + template + static decltype(auto) execute(T function, A && targs) { + auto user_fun = reinterpret_cast(function); + user_fun(utils::forward_tuple(std::forward(targs))); + return hpx::make_ready_future(); } // execute_task }; // struct executor_u @@ -71,93 +77,182 @@ struct executor_u { // Execution policy. //----------------------------------------------------------------------------// -/// -/// \struct hpx_execution_policy hpx_execution_policy.h -/// \brief hpx_execution_policy provides... -/// +/*! + The hpx_execution_policy_t is the backend runtime execution policy + for HPX. + + @ingroup hpx-execution + */ + struct FLECSI_EXPORT hpx_execution_policy_t { + /*! + The future_u type may be used for explicit synchronization of tasks. + + @tparam RETURN The return type of the task. + */ + template using future_u = hpx_future_u; - //--------------------------------------------------------------------------// - //! The task_wrapper_u type FIXME - //! - //! @tparam RETURN The return type of the task. FIXME - //--------------------------------------------------------------------------// - - template - using functor_task_wrapper_u = - typename flecsi::execution::functor_task_wrapper_u; + /*! + The runtime_state_t type identifies a public type for the high-level + runtime interface to pass state required by the backend. + */ struct runtime_state_t {}; + // using runtime_state_t = hpx_runtime_state_t; + + /*! + Return the runtime state of the calling FleCSI task. + + @param task The calling task. + */ + + static runtime_state_t & runtime_state(void * task); - // static - // runtime_state_t & - // runtime_state( - // void * task - // ) - // { - // return {}; - // } //--------------------------------------------------------------------------// // Task interface. //--------------------------------------------------------------------------// - /// - /// hpx task registration. - /// - /// \tparam R The return type of the task. - /// \tparam A The arguments type of the task. This is a std::tuple of the - /// user task arguments. - /// - template static bool register_task(processor_type_t processor, launch_t launch, std::string name) { +#if defined(ENABLE_CALIPER) return context_t::instance() - .template register_task( - processor, launch, name); + .template register_function(name); +#else + return context_t::instance() + .template register_function(); +#endif } // register_task - /// - /// \tparam R The task return type. - /// \tparam T The user task type. - /// \tparam As The user task argument types. - /// - /// \param key - /// \param user_task_handle - /// \param args - /// + /*! + HPX backend task execution. For documentation on this method, + please see task_u::execute_task. + */ + template static decltype(auto) execute_task(ARGS &&... args) { - context_t & context_ = context_t::instance(); - // Get the function and processor type. - auto fun = context_.task(); +#if defined(ENABLE_CALIPER) + auto tname = context_.function_name(TASK); +#else + /* using a placeholder so we do not have to maintain + function_name_registry when annotations are disabled. */ + std::string tname{""}; +#endif + + using annotation = flecsi::utils::annotation; + + // Make a tuple from the task arguments. + auto task_args = std::forward_as_tuple(args...); + + using decayed_args = utils::convert_tuple_t; + auto decayed_task_args = + decayed_args(std::make_tuple(std::forward(args)...)); + + // collect dependencies from all arguments for this task + annotation::begin(tname); + task_collect_dependencies_t task_collect_dependencies; + task_collect_dependencies.walk(decayed_task_args); + annotation::end(); + + // add this task as a dependency to all arguments, if needed + annotation::begin(tname); + task_add_dependencies_t task_add_dependencies; + task_add_dependencies.walk(task_args, decayed_task_args); + annotation::end(); - auto processor_type = context_.processor_type(); - if(processor_type == processor_type_t::mpi) { - { - clog_tag_guard(execution); - clog(info) << "Executing MPI task: " << KEY << std::endl; + auto func = [tname, function = context_t::instance().function(TASK), + task_args = std::move(decayed_task_args)]( + auto && dependencies) mutable { + // propagate exceptions + for(auto && f : dependencies) { + f.get(); } - return executor_u::execute( - context_t::instance().get_mpi_executor(), std::move(fun), - std::make_tuple(std::forward(args)...)); + context_t & context_ = context_t::instance(); + + annotation::begin(tname); + // run task_prolog to copy ghost cells. + task_prolog_t task_prolog; + task_prolog.walk(task_args); +#if defined(FLECSI_USE_AGGCOMM) + task_prolog.launch_copies(); + task_prolog.launch_sparse_copies(); +#endif + annotation::end(); + + annotation::begin(tname); + auto future = executor_u::execute(function, task_args); + annotation::end(); + + annotation::begin(tname); + task_epilog_t task_epilog; + task_epilog.walk(task_args); + annotation::end(); + + annotation::begin(tname); + finalize_handles_t finalize_handles; + finalize_handles.walk(task_args); + annotation::end(); + + constexpr size_t ZERO = + flecsi::utils::const_string_t{EXPAND_AND_STRINGIFY(0)}.hash(); + + if constexpr(REDUCTION != ZERO) { + + return future.then([](auto && future) { + context_t & context_ = context_t::instance(); + MPI_Datatype datatype = + flecsi::utils::mpi_typetraits_u::type(); + + auto reduction_op = context_.reduction_operations().find(REDUCTION); + + clog_assert(reduction_op != context_.reduction_operations().end(), + "invalid reduction operation"); + + const RETURN sendbuf = future.get(); + RETURN recvbuf; + + MPI_Allreduce(&sendbuf, &recvbuf, 1, datatype, reduction_op->second, + MPI_COMM_WORLD); + + return recvbuf; + }); + } + + return future; + }; + + // force unwrapping of returned future + hpx::future future = hpx::dataflow( + std::move(func), std::move(task_collect_dependencies.dependencies_)); + + // make sure the task dependencies are triggered once this future has + // become ready + if(task_add_dependencies.has_dependencies) { + hpx::traits::detail::get_shared_state(future)->set_on_completed( + [p = std::move(task_add_dependencies.promise)]() mutable { + p.set_value(); + }); } - return executor_u::execute( - context_t::instance().get_default_executor(), std::move(fun), - std::make_tuple(std::forward(args)...)); + return future.share(); } // execute_task //--------------------------------------------------------------------------// @@ -165,46 +260,48 @@ struct FLECSI_EXPORT hpx_execution_policy_t { //--------------------------------------------------------------------------// /*! - MPI backend reduction registration. For documentation on this + HPX backend reduction registration. For documentation on this method please see task_u::register_reduction_operation. */ template static bool register_reduction_operation() { - return true; + using wrapper_t = reduction_wrapper_u; + + return context_t::instance().register_reduction_operation( + NAME, wrapper_t::registration_callback); } // register_reduction_operation //--------------------------------------------------------------------------// // Function interface. //--------------------------------------------------------------------------// - template + RETURN (*DELEGATE)(ARG_TUPLE)> static bool register_function() { return context_t::instance() - .template register_function(); + .template register_function(); } // register_function - /// - /// This method looks up a function from the \e handle argument - /// and executes the associated it with the provided \e args arguments. - /// - /// \param handle The function handle to execute. - /// \param args A variadic argument list of the function parameters. - /// - /// \return The return type of the provided function handle. - /// - template - static decltype(auto) execute_function(FUNCTION_HANDLE & handle, - ARGS &&... args) { + /*! + HPX backend function execution. For documentation on this + method, please see function_u::execute_function. + */ + + template + static decltype(auto) execute_function(HANDLE & handle, ARGS &&... args) { return handle(context_t::instance().function(handle.get_key()), - std::make_tuple(std::forward(args)...)); + std::forward_as_tuple(args...)); } // execute_function }; // struct hpx_execution_policy_t } // namespace execution } // namespace flecsi - -#endif // flecsi_execution_hpx_execution_policy_h diff --git a/flecsi/execution/hpx/finalize_handles.h b/flecsi/execution/hpx/finalize_handles.h new file mode 100644 index 000000000..17ad1baf7 --- /dev/null +++ b/flecsi/execution/hpx/finalize_handles.h @@ -0,0 +1,257 @@ +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2016, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once + +/*! @file */ + +#include +#include +#include + +#include "mpi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace flecsi { +namespace execution { + +struct finalize_handles_t + : public flecsi::utils::tuple_walker_u { + + template + void handle(ragged_mutator & m) { + auto & h = m.handle; + + using value_t = T; + +#if !defined(FLECSI_USE_AGGCOMM) + auto & context = context_t::instance(); + const int my_color = static_cast(context.color()); + auto & my_coloring_info = context.coloring_info(h.index_space).at(my_color); + auto index_coloring = context.coloring(h.index_space); + + auto & sparse_field_metadata = + context.registered_sparse_field_metadata().at(h.fid); + + value_t * shared_data = + new value_t[h.num_shared() * h.max_entries_per_index]; + value_t * ghost_data = new value_t[h.num_ghost() * h.max_entries_per_index]; + + // Load data into shared data buffer + for(int i = 0; i < h.num_shared(); ++i) { + int r = static_cast(h.num_exclusive_ + i); + const auto & row = h.rows[r]; + size_t count = row.size(); + std::memcpy(&shared_data[i * h.max_entries_per_index], row.begin(), + count * sizeof(value_t)); + } // for i + + // Get entry_values + MPI_Datatype shared_ghost_type; + MPI_Type_contiguous(sizeof(value_t), MPI_BYTE, &shared_ghost_type); + MPI_Type_commit(&shared_ghost_type); + + MPI_Win win; + MPI_Win_create(shared_data, + sizeof(value_t) * h.num_shared() * h.max_entries_per_index, + sizeof(value_t), MPI_INFO_NULL, MPI_COMM_WORLD, &win); + + MPI_Win_post(sparse_field_metadata.shared_users_grp, 0, win); + MPI_Win_start(sparse_field_metadata.ghost_owners_grp, 0, win); + + int i = 0; + for(auto & ghost : index_coloring.ghost) { + clog_rank(warn, 0) << "ghost id: " << ghost.id << ", rank: " << ghost.rank + << ", offset: " << ghost.offset << std::endl; + MPI_Get(&ghost_data[i * h.max_entries_per_index], + static_cast(h.max_entries_per_index), shared_ghost_type, + static_cast(ghost.rank), ghost.offset * h.max_entries_per_index, + static_cast(h.max_entries_per_index), shared_ghost_type, win); + i++; + } + + MPI_Win_complete(win); + MPI_Win_wait(win); + + MPI_Win_free(&win); + MPI_Type_free(&shared_ghost_type); + + // for (int i = 0; i < h.num_ghost() * h.max_entries_per_index; i++) + // clog_rank(warn, 0) << "ghost after: " << ghost_data[i].value << + // std::endl; + + int send_count = 0; + for(auto & shared : index_coloring.shared) { + send_count += static_cast(shared.shared.size()); + } + + // Send/Recv counts in entry_values. + std::vector requests(send_count); + std::vector statuses(send_count); + std::vector recv_requests(h.num_ghost()); + std::vector recv_status(h.num_ghost()); + + std::vector send_count_buf; + for(auto & shared : index_coloring.shared) { + for(auto peer : shared.shared) { + send_count_buf.push_back( + h.rows[h.num_exclusive_ + shared.offset].size()); + } + } + + i = 0; + for(auto & shared : index_coloring.shared) { + for(auto peer : shared.shared) { + MPI_Isend(&send_count_buf[i], 1, + flecsi::utils::mpi_typetraits_u::type(), + static_cast(peer), 99, MPI_COMM_WORLD, &requests[i]); + i++; + } + } + + std::vector recv_count_buf(h.num_ghost()); + i = 0; + for(auto & ghost : index_coloring.ghost) { + // MPI_Status status; + MPI_Irecv(&recv_count_buf[i], 1, + flecsi::utils::mpi_typetraits_u::type(), + static_cast(ghost.rank), 99, MPI_COMM_WORLD, &recv_requests[i]); + i++; + } + + MPI_Waitall(send_count, requests.data(), statuses.data()); + MPI_Waitall(static_cast(h.num_ghost()), recv_requests.data(), + recv_status.data()); + + for(int i = 0; i < h.num_ghost(); i++) { + clog_rank(warn, 0) << recv_count_buf[i] << std::endl; + } + + // Unload data from ghost data buffer + for(int i = 0; i < static_cast(h.num_ghost()); i++) { + int r = static_cast(h.num_exclusive_ + h.num_shared() + i); + auto & row = h.rows[r]; + int count = recv_count_buf[i]; + row.resize(count); + std::memcpy(row.begin(), &ghost_data[i * h.max_entries_per_index], + count * sizeof(value_t)); + } + + delete[] shared_data; + delete[] ghost_data; +#else + *(h.ghost_is_readable) = false; +#endif + } // handle + + template + void handle(sparse_mutator & m) { + handle(m.ragged); + } + + /*! + Finalize set topology storage. This inspects index based sizes and + writes out appropriate metadata. + */ + template + typename std::enable_if_t< + std::is_base_of::value> + handle(data_client_handle_u h) { + h.storage.finalize_storage(); + } // handle + + /*! + The finalize_handles_t type can be called to walk task args after task + execution. This allows us to free memory allocated during the task. + + @ingroup execution + */ + + template + typename std::enable_if_t< + std::is_base_of::value> + handle(data_client_handle_u h) { + if(PERMISSIONS == wo || PERMISSIONS == rw) { + auto & context_ = context_t::instance(); + auto & ssm = context_.index_subspace_info(); + + for(size_t i{0}; i < h.num_index_subspaces; ++i) { + data_client_handle_index_subspace_t & iss = h.handle_index_subspaces[i]; + + auto itr = ssm.find(iss.index_subspace); + clog_assert(itr != ssm.end(), "invalid index subspace"); + auto & si = itr->second; + + clog_assert(si.size == 0, "index subspace size already set"); + si.size = h.get_index_subspace_size_(iss.index_subspace); + } // for + } // if + } // handle + + /*! + Handle individual list items + */ + template + typename Container, + typename = + std::enable_if_t::value>> + void handle(Container & list) { + for(auto & item : list) + handle(item); + } + + /*! + * Handle tuple of items + */ + + template + void handle_tuple_items(std::tuple & items, + std::index_sequence) { + (handle(std::get(items)), ...); + } + + template::value>> + void handle(std::tuple & items) { + handle_tuple_items(items, std::make_index_sequence{}); + } + + //-----------------------------------------------------------------------// + // If this is not a data handle, then simply skip it. + //-----------------------------------------------------------------------// + + template + void handle(T &) {} // handle + +}; // struct finalize_handles_t + +} // namespace execution +} // namespace flecsi diff --git a/flecsi/execution/hpx/future.h b/flecsi/execution/hpx/future.h index dd934d939..c9e3c79b5 100644 --- a/flecsi/execution/hpx/future.h +++ b/flecsi/execution/hpx/future.h @@ -29,6 +29,12 @@ namespace execution { // Future concept. //----------------------------------------------------------------------------// +/*! + Abstract interface type for HPX futures. + + @ingroup hpx-execution + */ + template using hpx_future_u = hpx::shared_future; diff --git a/flecsi/execution/hpx/internal_task.h b/flecsi/execution/hpx/internal_task.h deleted file mode 100644 index 5e0e5e29d..000000000 --- a/flecsi/execution/hpx/internal_task.h +++ /dev/null @@ -1,63 +0,0 @@ -/*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. - *~--------------------------------------------------------------------------~*/ - -#pragma once - -//----------------------------------------------------------------------------// -//! @file -//! @date Initial file creation: Mar 31, 2017 -//----------------------------------------------------------------------------// - -#include - -#include -#include -#include - -#include - -//----------------------------------------------------------------------------// -//! @def flecsi_internal_task_key -//! -//! Convenience macro to create a task key from hpx task information. -//! -//! @param task The hpx task to register. -//! @param processor The processor type \ref processor_t. -//! @param single A boolean indicating whether this task can be run as a -//! single task. -//! @param index A boolean indicating whether this task can be run as an -//! index space launch. -//! -//! @ingroup hpx-execution -//----------------------------------------------------------------------------// - -#define flecsi_internal_task_key(task) \ - /* MACRO IMPLEMENTATION */ \ - \ - /* Use const_string_t interface to create the key */ \ - flecsi::utils::const_string_t{EXPAND_AND_STRINGIFY(task)}.hash() - -//----------------------------------------------------------------------------// -//! @def flecsi_internal_register_hpx_task -//! -//! This macro registers an internal hpx task. -//! -//! @param task The hpx task to register. -//! @param processor A processor_mask_t specifying the supported processor -//! types. -//! @param launch A launch_t specifying the launch options. -//! -//! @ingroup hpx-execution -//----------------------------------------------------------------------------// - -#define flecsi_internal_register_hpx_task(task, processor, launch) \ - /* MACRO IMPLEMENTATION */ \ - \ - /* Call the execution policy to register the task */ \ - inline bool task##_task_registered = \ - flecsi::execution::hpx_execution_policy_t::register_hpx_task< \ - flecsi::utils::const_string_t{EXPAND_AND_STRINGIFY(task)}.hash(), \ - typename flecsi::utils::function_traits_u::return_type, \ - task>(processor, launch, {EXPAND_AND_STRINGIFY(task)}) diff --git a/flecsi/execution/hpx/processor_policy.h b/flecsi/execution/hpx/processor_policy.h deleted file mode 100644 index 26194b9a1..000000000 --- a/flecsi/execution/hpx/processor_policy.h +++ /dev/null @@ -1,27 +0,0 @@ -/*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_execution_hpx_processor_policy_h -#define flecsi_execution_hpx_processor_policy_h - -/// -/// \file -/// \date Initial file creation: Apr 12, 2017 -/// - -namespace flecsi { -namespace execution { - -enum class serial_processor_type_t : size_t { loc, toc, mpi }; - -} // namespace execution -} // namespace flecsi - -#endif // flecsi_execution_hpx_processor_policy_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options for vim. - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/execution/hpx/reduction_wrapper.h b/flecsi/execution/hpx/reduction_wrapper.h index 1df5c7b02..a239be4dd 100644 --- a/flecsi/execution/hpx/reduction_wrapper.h +++ b/flecsi/execution/hpx/reduction_wrapper.h @@ -30,13 +30,295 @@ namespace execution { template struct reduction_wrapper_u { + using rhs_t = typename TYPE::RHS; + using lhs_t = typename TYPE::LHS; + + // HPX does not have support for mixed-type reductions + static_assert(std::is_same_v, "type mismatch: LHS != RHS"); + /*! - TODO: Register the user-defined reduction operator with the runtime. + Wrapper to convert the type-erased HPX function to the typed C++ method. */ - static void registration_callback() {} // registration_callback + static void + hpx_wrapper(void * in, void * inout, int * len, MPI_Datatype * dptr) { + + lhs_t * lhs = reinterpret_cast(inout); + rhs_t * rhs = reinterpret_cast(in); + + for(size_t i{0}; i < *len; ++i) { + TYPE::apply(lhs[i], rhs[i]); + } // for + } // hpx_wrapper + + /*! + Register the user-defined reduction operator with the runtime. + */ + + static void registration_callback() { + { + clog_tag_guard(reduction_wrapper); + clog(info) << "Executing reduction wrapper callback for " << HASH + << std::endl; + } // scope + + // Get the runtime context + auto & context_ = context_t::instance(); + + // Get a reference to the operator map + auto & reduction_ops = context_.reduction_operations(); + + // Check if operator has already been registered + clog_assert(reduction_ops.find(HASH) == reduction_ops.end(), + typeid(TYPE).name() << " has already been registered with this name"); + + // Create the operator and register it with the runtime + MPI_Op mpiop; + MPI_Op_create(hpx_wrapper, true, &mpiop); + reduction_ops[HASH] = mpiop; + } // registration_callback }; // struct reduction_wrapper_u +//----------------------------------------------------------------------------// +// Min +//----------------------------------------------------------------------------// + +/*! + Minimum reduction type. + */ + +template +struct min { + + using LHS = T; + using RHS = T; + static constexpr T identity{(std::numeric_limits::max)()}; + + template + static void apply(LHS & lhs, RHS rhs) { + if constexpr(EXCLUSIVE) { + lhs = lhs < rhs ? lhs : rhs; + } + else { + int64_t * target = (int64_t *)&lhs; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = (std::min)(oldval.as_T, rhs); + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + + } // if constexpr + + } // apply + + template + static void fold(RHS & rhs1, RHS rhs2) { + + if constexpr(EXCLUSIVE) { + rhs1 = (std::min)(rhs1, rhs2); + } + else { + int64_t * target = (int64_t *)&rhs1; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = (std::min)(oldval.as_T, rhs2); + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + } // if constexpr + + } // fold + +}; // struct min + +namespace reduction { +//----------------------------------------------------------------------------// +// Max +//----------------------------------------------------------------------------// + +/*! + Maximum reduction type. + */ + +template +struct max { + using LHS = T; + using RHS = T; + static constexpr T identity{(std::numeric_limits::max)()}; + + template + static void apply(LHS & lhs, RHS rhs) { + if constexpr(EXCLUSIVE) { + lhs = lhs > rhs ? lhs : rhs; + } + else { + int64_t * target = (int64_t *)&lhs; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = (std::max)(oldval.as_T, rhs); + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + + } // if constexpr + + } // apply + + template + static void fold(RHS & rhs1, RHS rhs2) { + + if constexpr(EXCLUSIVE) { + rhs1 = (std::max)(rhs1, rhs2); + } + else { + int64_t * target = (int64_t *)&rhs1; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = (std::max)(oldval.as_T, rhs2); + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + } // if constexpr + + } // fold +}; // struct max + +//----------------------------------------------------------------------------// +// Sum +//----------------------------------------------------------------------------// + +/*! + Sum reduction type. + */ + +template +struct sum { + + using LHS = T; + using RHS = T; + static constexpr T identity{}; + + template + static void apply(LHS & lhs, RHS rhs) { + + if constexpr(EXCLUSIVE) { + lhs += rhs; + } + else { + int64_t * target = (int64_t *)&lhs; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = oldval.as_T + rhs; + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + + } // if constexpr + } // apply + + template + static void fold(LHS & lhs, RHS rhs) { + if constexpr(EXCLUSIVE) { + lhs += rhs; + } + else { + int64_t * target = (int64_t *)&lhs; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = oldval.as_T + rhs; + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + } // if constexpr + + } // fold + +}; // struct sum + +/*! + Product reduction type. + */ + +//----------------------------------------------------------------------------// +// Product +//----------------------------------------------------------------------------// + +template +struct product { + using LHS = T; + using RHS = T; + static constexpr T identity{}; + + template + static void apply(LHS & lhs, RHS rhs) { + + if constexpr(EXCLUSIVE) { + lhs *= rhs; + } + else { + int64_t * target = (int64_t *)&lhs; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = oldval.as_T * rhs; + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + + } // if constexpr + } // apply + + template + static void fold(LHS & lhs, RHS rhs) { + if constexpr(EXCLUSIVE) { + lhs *= rhs; + } + else { + int64_t * target = (int64_t *)&lhs; + union + { + int64_t as_int; + T as_T; + } oldval, newval; + do { + oldval.as_int = *target; + newval.as_T = oldval.as_T * rhs; + } while( + !__sync_bool_compare_and_swap(target, oldval.as_int, newval.as_int)); + } // if constexpr + + } // fold +}; // struct product + +} // namespace reduction } // namespace execution } // namespace flecsi diff --git a/flecsi/execution/hpx/runtime_driver.cc b/flecsi/execution/hpx/runtime_driver.cc index c8307ebd8..1655e8030 100644 --- a/flecsi/execution/hpx/runtime_driver.cc +++ b/flecsi/execution/hpx/runtime_driver.cc @@ -1,97 +1,71 @@ -/*~-------------------------------------------------------------------------~~* - * Copyright (c) 2014 Los Alamos National Security, LLC - * All rights reserved. - *~-------------------------------------------------------------------------~~*/ - -//----------------------------------------------------------------------------// -//! @file -//! @date Initial file creation: Aug 01, 2016 -//----------------------------------------------------------------------------// +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2016, Los Alamos National Security, LLC + All rights reserved. + */ +/*! @file */ + +#include // yield_while +#include // get_thread_manager + +#include +#include #include #include #include +#include +#include clog_register_tag(runtime_driver); namespace flecsi { namespace execution { +void +termination_detection() { + auto & tm = hpx::threads::get_thread_manager(); + hpx::util::yield_while( + [&tm]() -> bool { + return tm.get_thread_count() > + std::int64_t(1) + tm.get_background_thread_count(); + }, + "termination_detection"); +} + //----------------------------------------------------------------------------// // Implementation of FleCSI runtime driver task. //----------------------------------------------------------------------------// void -remap_shared_entities() { - // TODO: Is this superseded by index_map/reverse_index_map? - auto & flecsi_context = context_t::instance(); - const int my_color = static_cast(flecsi_context.color()); - - for(auto & coloring_info_pair : flecsi_context.coloring_info_map()) { - auto index_space = coloring_info_pair.first; - auto & coloring_info = coloring_info_pair.second; - - auto & my_coloring_info = - flecsi_context.coloring_info(index_space).at(my_color); - auto & index_coloring = flecsi_context.coloring(index_space); - - std::set new_shared; - - // for (auto& shared : index_coloring.shared) { - // clog_rank(warn, 0) << "myrank: " << my_color - // << " shared id: " << shared.id - // << ", rank: " << shared.rank - // << ", offset: " << shared.offset - // << ", index: " << index << std::endl; - // } - - // FIXME: does this cause deadlock? - size_t index = 0; - for(auto & shared : index_coloring.shared) { - for(auto peer : shared.shared) { - MPI_Send(&index, 1, MPI_UNSIGNED_LONG_LONG, static_cast(peer), 77, - MPI_COMM_WORLD); - } - new_shared.insert(flecsi::coloring::entity_info_t( - shared.id, shared.rank, index, shared.shared)); - index++; - } - context_t::instance().coloring(index_space).shared.swap(new_shared); - - MPI_Status status; - std::set new_ghost; - - for(auto ghost : index_coloring.ghost) { - MPI_Recv(&index, 1, MPI_UNSIGNED_LONG_LONG, static_cast(ghost.rank), - 77, MPI_COMM_WORLD, &status); - new_ghost.insert( - flecsi::coloring::entity_info_t(ghost.id, ghost.rank, index, {})); - } - // for (auto ghost : index_coloring.ghost) { - // clog_rank(warn, 1) << "myrank: " << my_color - // << " old ghost id: " << ghost.id - // << ", rank: " << ghost.rank - // << ", offset: " << ghost.offset - // << std::endl; - // } - // for (auto ghost : new_ghost) { - // clog_rank(warn, 1) << "myrank: " << my_color - // << " new ghost id: " << ghost.id - // << ", rank: " << ghost.rank - // << ", offset: " << ghost.offset - // << std::endl; - // } - context_t::instance().coloring(index_space).ghost.swap(new_ghost); - } -} - -int hpx_runtime_driver(int argc, char ** argv) { { clog_tag_guard(runtime_driver); clog(info) << "In HPX runtime driver" << std::endl; } + auto & context_ = context_t::instance(); + using annotation = flecsi::utils::annotation; + + annotation::begin(); + //--------------------------------------------------------------------------// + // Invoke callbacks for entries in the reduction operation registry. + //--------------------------------------------------------------------------// + + auto & reduction_registry = context_.reduction_registry(); + + for(auto & c : reduction_registry) { + c.second(); + } // for + //--------------------------------------------------------------------------// // Invoke callbacks for entries in the client registry. // @@ -121,19 +95,25 @@ hpx_runtime_driver(int argc, char ** argv) { } // for } // for - auto & flecsi_context = context_t::instance(); - for(auto fi : flecsi_context.registered_fields()) { - flecsi_context.put_field_info(fi); + for(auto fi : context_.registered_fields()) { + context_.put_field_info(fi); } -#if defined FLECSI_ENABLE_SPECIALIZATION_TLT_INIT + annotation::end(); + +#if defined(FLECSI_ENABLE_SPECIALIZATION_TLT_INIT) { clog_tag_guard(runtime_driver); clog(info) << "Executing specialization tlt task" << std::endl; } + annotation::begin(); // Execute the specialization driver. specialization_tlt_init(argc, argv); + annotation::end(); + + // make sure all activity has ceased + termination_detection(); #endif // FLECSI_ENABLE_SPECIALIZATION_TLT_INIT remap_shared_entities(); @@ -143,9 +123,9 @@ hpx_runtime_driver(int argc, char ** argv) { // This depends on the ordering of the BLIS data structure setup. // Currently, this is Exclusive - Shared - Ghost. - for(auto is : flecsi_context.coloring_map()) { + for(auto is : context_.coloring_map()) { std::map _map; - std::size_t counter(0); + size_t counter(0); for(auto index : is.second.exclusive) { _map[counter++] = index.id; @@ -159,29 +139,48 @@ hpx_runtime_driver(int argc, char ** argv) { _map[counter++] = index.id; } // for - flecsi_context.add_index_map(is.first, _map); + context_.add_index_map(is.first, _map); } // for - // Add additional setup. - flecsi_context.advance_state(); +#if defined(FLECSI_USE_AGGCOMM) + auto & ispace_dmap = context_.index_space_data_map(); + for(const auto & fi : context_.registered_fields()) { + auto & ispace_data = ispace_dmap[fi.index_space]; + ispace_data.ghost_is_readable[fi.fid] = true; + } +#endif + +#if defined(FLECSI_ENABLE_DYNAMIC_CONTROL_MODEL) + + // Execute control + if(context_.top_level_driver()) { + context_.top_level_driver()(argc, argv); + } + +#else + + context_.advance_state(); // Call the specialization color initialization function. #if defined(FLECSI_ENABLE_SPECIALIZATION_SPMD_INIT) + annotation::begin(); specialization_spmd_init(argc, argv); + annotation::end(); + + // make sure all activity has ceased + termination_detection(); #endif // FLECSI_ENABLE_SPECIALIZATION_SPMD_INIT - flecsi_context.advance_state(); + context_.advance_state(); + annotation::begin(); // Execute the user driver. driver(argc, argv); + annotation::end(); + +#endif // FLECSI_ENABLE_DYNAMIC_CONTROL_MODEL - return 0; -} // hpx_runtime_driver +} // runtime_driver } // namespace execution } // namespace flecsi - -/*~------------------------------------------------------------------------~--* - * Formatting options for vim. - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~------------------------------------------------------------------------~--*/ diff --git a/flecsi/execution/hpx/runtime_driver.h b/flecsi/execution/hpx/runtime_driver.h index 592e88e8e..4f6565f92 100644 --- a/flecsi/execution/hpx/runtime_driver.h +++ b/flecsi/execution/hpx/runtime_driver.h @@ -1,15 +1,21 @@ -/*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. - *~--------------------------------------------------------------------------~*/ +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // -#ifndef flecsi_execution_hpx_runtime_driver_h -#define flecsi_execution_hpx_runtime_driver_h + Copyright (c) 2016, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once -/// -/// \file -/// \date Initial file creation: Aug 01, 2016 -/// +/*! @file */ + +#include namespace flecsi { namespace execution { @@ -28,7 +34,7 @@ namespace execution { #if defined(FLECSI_ENABLE_SPECIALIZATION_TLT_INIT) void specialization_tlt_init(int argc, char ** argv); -#endif +#endif // FLECSI_ENABLE_SPECIALIZATION_TLT_INIT #if defined(FLECSI_ENABLE_SPECIALIZATION_SPMD_INIT) void specialization_spmd_init(int argc, char ** argv); @@ -47,14 +53,8 @@ void driver(int argc, char ** argv); @ingroup hpx-execution */ -int hpx_runtime_driver(int argc, char ** argv); + +void hpx_runtime_driver(int argc, char ** argv); } // namespace execution } // namespace flecsi - -#endif // flecsi_execution_hpx_runtime_driver_h - -/*~-------------------------------------------------------------------------~-* - * Formatting options for vim. - * vim: set tabstop=2 shiftwidth=2 expandtab : - *~-------------------------------------------------------------------------~-*/ diff --git a/flecsi/execution/hpx/runtime_main.cc b/flecsi/execution/hpx/runtime_main.cc index a7e361b4e..06cf6e800 100644 --- a/flecsi/execution/hpx/runtime_main.cc +++ b/flecsi/execution/hpx/runtime_main.cc @@ -19,6 +19,8 @@ #error FLECSI_ENABLE_MPI not defined! This file depends on MPI! #endif +#include + #include #include @@ -36,10 +38,17 @@ int main(int argc, char ** argv) { // Initialize the MPI runtime - MPI_Init(&argc, &argv); + int provided; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if(provided < MPI_THREAD_MULTIPLE) { + printf("ERROR: Your implementation of MPI does not support " + "MPI_THREAD_MULTIPLE which is required for use of " + "MPI conduit with the HPX-MPI Interop!\n"); + } + assert(provided == MPI_THREAD_MULTIPLE); // get the rank - int rank; + int rank{0}; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //--------------------------------------------------------------------------// @@ -47,14 +56,10 @@ main(int argc, char ** argv) { //--------------------------------------------------------------------------// // Initialize tags to output all tag groups from CLOG - std::string tags("all"); - bool help = false; - - //--------------------------------------------------------------------------// - // Use BOOST Program Options + std::string tags{"all"}; #if defined(FLECSI_ENABLE_BOOST) - options_description desc("Cinch test options"); + options_description desc("FleCSI runtime options"); // Add command-line options desc.add_options()("help,h", "Print this message and exit.")("tags,t", @@ -68,22 +73,19 @@ main(int argc, char ** argv) { notify(vm); - // was help requested - help = vm.count("help"); - if(help) { + if(vm.count("help")) { if(rank == 0) { std::cout << desc << std::endl; } // if - // don't exit, because the user application - // may want to print a usage message too + + return 1; } // if #endif // FLECSI_ENABLE_BOOST - // End BOOST Program Options - //--------------------------------------------------------------------------// + int result{0}; - if(tags == "0" && !help) { + if(tags == "0") { // Output the available tags if(rank == 0) { std::cout << "Available tags (CLOG):" << std::endl; @@ -92,23 +94,18 @@ main(int argc, char ** argv) { std::cout << " " << t.first << std::endl; } // for } // if - // die nicely - MPI_Finalize(); - return 0; } + else { + // Initialize the cinchlog runtime + clog_init(tags); - // Initialize the cinchlog runtime - clog_init(tags); - - //-------------------------------------------------------------------------// - // DONE CLOG INIT - //-------------------------------------------------------------------------// - - // Execute the flecsi runtime. - auto retval = flecsi::execution::context_t::instance().initialize(argc, argv); + // Execute the flecsi runtime. + result = flecsi::execution::context_t::instance().initialize(argc, argv); + flecsi::execution::context_t::instance().finalize(); + } // if // Shutdown the MPI runtime MPI_Finalize(); - return retval; + return result; } // main diff --git a/flecsi/execution/hpx/task_add_dependencies.h b/flecsi/execution/hpx/task_add_dependencies.h new file mode 100644 index 000000000..1a048155c --- /dev/null +++ b/flecsi/execution/hpx/task_add_dependencies.h @@ -0,0 +1,233 @@ +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2020, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once + +/*! @file */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +/*! + @file + @date Initial file creation: November 16, 2020 + */ + +#include +#include +#include + +#include "mpi.h" + +#include +#include +#include +#include + +#include "flecsi/utils/mpi_type_traits.h" +#include +#include + +namespace flecsi { +namespace execution { + +/*! + The task_add_dependencies_t type can be called to walk the task args before + the task has run. This allows to ensure task dependencies be added to the + execution flow. + + @ingroup execution + */ + +struct task_add_dependencies_t + : public flecsi::utils::tuple_walker_u { + + /*! + Construct a task_add_dependencies_t instance. + */ + + task_add_dependencies_t() + : has_dependencies(false), promise(), future(promise.get_future()) {} + + /*! + FIXME: Need a description. + + @tparam T The data type referenced by the handle. + @tparam EXCLUSIVE_PERMISSIONS The permissions required on the exclusive + indices of the index partition. + @tparam SHARED_PERMISSIONS The permissions required on the shared + indices of the index partition. + @tparam GHOST_PERMISSIONS The permissions required on the ghost + indices of the index partition. + + */ + + template + void handle(Dense & a, + dense_accessor &) { + + // Skip Read Only handles + if constexpr((EXCLUSIVE_PERMISSIONS != ro && EXCLUSIVE_PERMISSIONS != na) || + (SHARED_PERMISSIONS != ro && SHARED_PERMISSIONS != na) || + (GHOST_PERMISSIONS != ro && GHOST_PERMISSIONS != na)) { + *a.future = future; + has_dependencies = true; + } + } // handle + + template + void handle(Global & a, global_accessor_u &) { + // Skip Read Only handles + if constexpr(PERMISSIONS != ro && PERMISSIONS != na) { + if(a.future != nullptr) { + *a.future = future; + has_dependencies = true; + } + } + } // handle + + template + void handle(Local & a, color_accessor_u &) { + // Skip Read Only handles + if constexpr(PERMISSIONS != ro && PERMISSIONS != na) { + if(a.future != nullptr) { + *a.future = future; + has_dependencies = true; + } + } + } // handle + + template + void handle(Ragged & a, + ragged_accessor &) { + + // Skip Read Only handles + if constexpr((EXCLUSIVE_PERMISSIONS != ro && EXCLUSIVE_PERMISSIONS != na) || + (SHARED_PERMISSIONS != ro && SHARED_PERMISSIONS != na) || + (GHOST_PERMISSIONS != ro && GHOST_PERMISSIONS != na)) { + *a.future = future; + has_dependencies = true; + } + } // handle + + template + void handle(Sparse & a1, + sparse_accessor & a2) { + handle(a1, a2.ragged); + } // handle + + template + void handle(Ragged & r1, ragged_mutator & r2) { + *r1.future = future; + has_dependencies = true; + } + + template + void handle(Sparse & m1, sparse_mutator & m2) { + *m1.future = future; + has_dependencies = true; + } + + template + void handle(Client & h, data_client_handle_u &) { + + // Skip Read Only handles + if constexpr(PERMISSIONS != ro && PERMISSIONS != na) { + *h.future = future; + has_dependencies = true; + } + } + + /*! + Handle individual list items + */ + template + typename Container1, + template + typename Container2> + void handle(Container1 & list1, Container2 & list2) { + + static_assert(N1 == N2, "list sizes must match"); + auto it2 = list2.begin(); + for(auto it1 = list1.begin(); it1 != list1.end(); ++it1, ++it2) { + handle(*it1, *it2); + } + } + + /*! + * Handle tuple of items + */ + + template + void handle_tuple_items(std::tuple & items1, + std::tuple & items2, + std::index_sequence) { + (handle(std::get(items1), std::get(items2)), ...); + } + + template + void handle(std::tuple & items1, std::tuple & items2) { + handle_tuple_items( + items1, items2, std::make_index_sequence{}); + } + + /*! + This method is called on any task arguments that are not handles, e.g. + scalars or those that did not need any special handling. + */ + template + void handle(T1 &, T2 &) {} // handle + + /*! + This future is used as a dependency for all arguments, if needed + */ + bool has_dependencies; + hpx::lcos::local::promise promise; + hpx_future_u future; + +}; // struct task_add_dependencies_t + +} // namespace execution +} // namespace flecsi diff --git a/flecsi/execution/hpx/task_collect_dependencies.h b/flecsi/execution/hpx/task_collect_dependencies.h new file mode 100644 index 000000000..e998c15b9 --- /dev/null +++ b/flecsi/execution/hpx/task_collect_dependencies.h @@ -0,0 +1,207 @@ +/* + @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ + /@@///// /@@ @@////@@ @@////// /@@ + /@@ /@@ @@@@@ @@ // /@@ /@@ + /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ + /@@//// /@@/@@@@@@@/@@ ////////@@/@@ + /@@ /@@/@@//// //@@ @@ /@@/@@ + /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ + // /// ////// ////// //////// // + + Copyright (c) 2020, Los Alamos National Security, LLC + All rights reserved. + */ +#pragma once + +/*! @file */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +/*! + @file + @date Initial file creation: November 16, 2020 + */ + +#include +#include +#include + +#include "mpi.h" + +#include +#include +#include +#include + +#include "flecsi/utils/mpi_type_traits.h" +#include +#include + +namespace flecsi { +namespace execution { + +/*! + The task_collect_dependencies_t type can be called to walk the task args before + the task has run. This allows to ensure task dependencies be added to the + execution flow. + + @ingroup execution + */ + +struct task_collect_dependencies_t + : public flecsi::utils::tuple_walker_u { + + /*! + Construct a task_collect_dependencies_t instance. + */ + + task_collect_dependencies_t() = default; + + /*! + FIXME: Need a description. + + @tparam T The data type referenced by the handle. + @tparam EXCLUSIVE_PERMISSIONS The permissions required on the exclusive + indices of the index partition. + @tparam SHARED_PERMISSIONS The permissions required on the shared + indices of the index partition. + @tparam GHOST_PERMISSIONS The permissions required on the ghost + indices of the index partition. + + */ + + template + void handle(dense_accessor & a) { + auto & h = a.handle; + + clog_assert(h.future != nullptr, "invalid future handle"); + if(h.future->valid()) { + dependencies_.push_back(*h.future); + } + } // handle + + template + void handle(global_accessor_u & a) { + auto & h = a.handle; + + clog_assert(h.future != nullptr, "invalid future handle"); + if(h.future->valid()) { + dependencies_.push_back(*h.future); + } + } // handle + + template + void handle(color_accessor_u & a) { + auto & h = a.handle; + + clog_assert(h.future != nullptr, "invalid future handle"); + if(h.future->valid()) { + dependencies_.push_back(*h.future); + } + } // handle + + template + void handle(ragged_accessor & a) { + auto & h = a.handle; + + clog_assert(h.future != nullptr, "invalid future handle"); + if(h.future->valid()) { + dependencies_.push_back(*h.future); + } + } // handle + + template + void handle(sparse_accessor & a) { + handle(a.ragged); + } // handle + + template + void handle(ragged_mutator & m) { + handle(m.handle); + } + + template + void handle(sparse_mutator & m) { + handle(m.ragged); + } + + template + void handle(data_client_handle_u h) { + + clog_assert(h.future != nullptr, "invalid future handle"); + if(h.future->valid()) { + dependencies_.push_back(*h.future); + } + } + + /*! + Handle individual list items + */ + template + typename Container> + void handle(Container & list) { + for(auto & item : list) { + handle(item); + } + } + + /*! + * Handle tuple of items + */ + + template + void handle_tuple_items(std::tuple & items, + std::index_sequence) { + (handle(std::get(items)), ...); + } + + template + void handle(std::tuple & items) { + handle_tuple_items(items, std::make_index_sequence{}); + } + + /*! + This method is called on any task arguments that are not handles, e.g. + scalars or those that did not need any special handling. + */ + template + void handle(T &) {} // handle + + /*! + The futures that represent the dependencies of the current task on its + arguments + */ + std::vector> dependencies_; + +}; // struct task_collect_dependencies_t + +} // namespace execution +} // namespace flecsi diff --git a/flecsi/execution/hpx/task_epilog.h b/flecsi/execution/hpx/task_epilog.h index b04335682..923ac2b5e 100644 --- a/flecsi/execution/hpx/task_epilog.h +++ b/flecsi/execution/hpx/task_epilog.h @@ -15,7 +15,9 @@ /*! @file */ +#include #include +#include #include #include #include @@ -26,14 +28,21 @@ @date Initial file creation: May 19, 2017 */ +#include +#include #include #include "mpi.h" -#include + +#include #include #include #include +#include "flecsi/utils/mpi_type_traits.h" +#include +#include + namespace flecsi { namespace execution { @@ -45,14 +54,17 @@ namespace execution { @ingroup execution */ -struct task_epilog_t : public utils::tuple_walker__ { +struct task_epilog_t : public flecsi::utils::tuple_walker_u { + /*! Construct a task_epilog_t instance. */ + task_epilog_t() = default; /*! FIXME: Need a description. + @tparam T The data type referenced by the handle. @tparam EXCLUSIVE_PERMISSIONS The permissions required on the exclusive indices of the index partition. @@ -60,6 +72,7 @@ struct task_epilog_t : public utils::tuple_walker__ { indices of the index partition. @tparam GHOST_PERMISSIONS The permissions required on the ghost indices of the index partition. + */ template { SHARED_PERMISSIONS, GHOST_PERMISSIONS> & a) { auto & h = a.handle; - +#if !defined(FLECSI_USE_AGGCOMM) // Skip Read Only handles - if(EXCLUSIVE_PERMISSIONS == ro && SHARED_PERMISSIONS == ro) + if constexpr((SHARED_PERMISSIONS == ro) || (GHOST_PERMISSIONS == rw) || + (GHOST_PERMISSIONS == wo)) { return; + } + else { + auto & context = context_t::instance(); + const int my_color = static_cast(context.color()); + auto & my_coloring_info = + context.coloring_info(h.index_space).at(my_color); - auto & context = context_t::instance(); - const int my_color = context.color(); - auto & my_coloring_info = context.coloring_info(h.index_space).at(my_color); + auto & field_metadata = context.registered_field_metadata().at(h.fid); + + MPI_Win win = field_metadata.win; - auto & field_metadata = context.registered_field_metadata().at(h.fid); + MPI_Win_post(field_metadata.shared_users_grp, 0, win); + MPI_Win_start(field_metadata.ghost_owners_grp, 0, win); - MPI_Win win = field_metadata.win; + for(auto owner : my_coloring_info.ghost_owners) { + int ghost_owner = static_cast(owner); + MPI_Get(h.ghost_data, 1, field_metadata.origin_types[ghost_owner], + ghost_owner, 0, 1, field_metadata.target_types[ghost_owner], win); + } - MPI_Win_post(field_metadata.shared_users_grp, 0, win); - MPI_Win_start(field_metadata.ghost_owners_grp, 0, win); + MPI_Win_complete(win); + MPI_Win_wait(win); - for(auto ghost_owner : my_coloring_info.ghost_owners) { - MPI_Get(h.ghost_data, 1, field_metadata.origin_types[ghost_owner], - ghost_owner, 0, 1, field_metadata.target_types[ghost_owner], win); - } + } // else +#else + auto & context = context_t::instance(); - MPI_Win_complete(win); - MPI_Win_wait(win); + if constexpr((SHARED_PERMISSIONS == ro) || (GHOST_PERMISSIONS == rw) || + (GHOST_PERMISSIONS == wo)) + *(h.ghost_is_readable) = true; + else if(SHARED_PERMISSIONS == rw || SHARED_PERMISSIONS == wo) + *(h.ghost_is_readable) = false; +#endif } // handle template - void handle(global_accessor__ & a) { + void handle(global_accessor_u & a) { auto & h = a.handle; // Skip Read Only handles @@ -105,170 +133,343 @@ struct task_epilog_t : public utils::tuple_walker__ { return; auto & context = context_t::instance(); - const int my_color = context.color(); - MPI_Bcast(&a.data(), 1, flecsi::coloring::mpi_typetraits_u::type(), 0, - MPI_COMM_WORLD); + const int my_color = static_cast(context.color()); + MPI_Bcast( + &a.data(), static_cast(sizeof(T)), MPI_BYTE, 0, MPI_COMM_WORLD); } // handle template - void handle(sparse_accessor & a) { auto & h = a.handle; - using offset_t = typename mutator_handle__::offset_t; - using entry_value_t = typename mutator_handle__::entry_value_t; - using commit_info_t = typename mutator_handle__::commit_info_t; + using value_t = T; +#if !defined(FLECSI_USE_AGGCOMM) // Skip Read Only handles - if(EXCLUSIVE_PERMISSIONS == ro && SHARED_PERMISSIONS == ro) + if constexpr((SHARED_PERMISSIONS == ro) || (GHOST_PERMISSIONS == rw) || + (GHOST_PERMISSIONS == wo)) { return; - - auto & context = context_t::instance(); - const int my_color = context.color(); - auto & my_coloring_info = context.coloring_info(h.index_space).at(my_color); - auto index_coloring = context.coloring(h.index_space); - - auto & sparse_field_metadata = - context.registered_sparse_field_metadata().at(h.fid); - - entry_value_t * entries = h.entries; - auto offsets = &(h.offsets)[0]; - auto shared_data = entries + h.reserve; - auto ghost_data = shared_data + h.num_shared_ * h.max_entries_per_index; - - // Get entry_values - MPI_Datatype shared_ghost_type; - MPI_Type_contiguous(sizeof(entry_value_t), MPI_BYTE, &shared_ghost_type); - MPI_Type_commit(&shared_ghost_type); - - MPI_Win win; - MPI_Win_create(shared_data, - sizeof(entry_value_t) * h.num_shared_ * h.max_entries_per_index, - sizeof(entry_value_t), MPI_INFO_NULL, MPI_COMM_WORLD, &win); - - MPI_Win_post(sparse_field_metadata.shared_users_grp, 0, win); - MPI_Win_start(sparse_field_metadata.ghost_owners_grp, 0, win); - - int i = 0; - for(auto & ghost : index_coloring.ghost) { - clog_rank(warn, 0) << "ghost id: " << ghost.id << ", rank: " << ghost.rank - << ", offset: " << ghost.offset << std::endl; - MPI_Get(&ghost_data[i * h.max_entries_per_index], h.max_entries_per_index, - shared_ghost_type, ghost.rank, ghost.offset * h.max_entries_per_index, - h.max_entries_per_index, shared_ghost_type, win); - i++; } + else { + auto & context = context_t::instance(); + const int my_color = static_cast(context.color()); + auto & my_coloring_info = + context.coloring_info(h.index_space).at(my_color); + auto index_coloring = context.coloring(h.index_space); + + auto & sparse_field_metadata = + context.registered_sparse_field_metadata().at(h.fid); + + value_t * shared_data = + new value_t[h.num_shared_ * h.max_entries_per_index]; + value_t * ghost_data = + new value_t[h.num_ghost_ * h.max_entries_per_index]; + + // Load data into shared data buffer + for(int i = 0; i < h.num_shared_; ++i) { + int r = static_cast(i + h.num_exclusive_); + const auto & row = h.rows[r]; + size_t count = row.size(); + std::memcpy(&shared_data[i * h.max_entries_per_index], row.begin(), + count * sizeof(value_t)); + } - MPI_Win_complete(win); - MPI_Win_wait(win); + // Get entry_values + MPI_Datatype shared_ghost_type; + MPI_Type_contiguous(sizeof(value_t), MPI_BYTE, &shared_ghost_type); + MPI_Type_commit(&shared_ghost_type); + + MPI_Win win; + MPI_Win_create(shared_data, + sizeof(value_t) * h.num_shared_ * h.max_entries_per_index, + sizeof(value_t), MPI_INFO_NULL, MPI_COMM_WORLD, &win); + + MPI_Win_post(sparse_field_metadata.shared_users_grp, 0, win); + MPI_Win_start(sparse_field_metadata.ghost_owners_grp, 0, win); + + int i = 0; + for(auto & ghost : index_coloring.ghost) { + clog_rank(warn, 0) << "ghost id: " << ghost.id + << ", rank: " << ghost.rank + << ", offset: " << ghost.offset << std::endl; + MPI_Get(&ghost_data[i * h.max_entries_per_index], + static_cast(h.max_entries_per_index), shared_ghost_type, + static_cast(ghost.rank), ghost.offset * h.max_entries_per_index, + static_cast(h.max_entries_per_index), shared_ghost_type, win); + i++; + } - MPI_Win_free(&win); + MPI_Win_complete(win); + MPI_Win_wait(win); - for(int i = 0; i < h.num_ghost_ * h.max_entries_per_index; i++) - clog_rank(warn, 0) << "ghost after: " << ghost_data[i].value << std::endl; + MPI_Win_free(&win); + MPI_Type_free(&shared_ghost_type); - int send_count = 0; - for(auto & shared : index_coloring.shared) { - send_count += shared.shared.size(); - } + for(int i = 0; i < h.num_ghost_ * h.max_entries_per_index; i++) + clog_rank(warn, 0) << "ghost after: " << ghost_data[i] << std::endl; - // Send/Recv counts in entry_values. - std::vector requests(send_count + h.num_ghost_); - std::vector statuses(send_count + h.num_ghost_); + int send_count = 0; + for(auto & shared : index_coloring.shared) { + send_count += static_cast(shared.shared.size()); + } - std::vector send_count_buf; - for(auto & shared : index_coloring.shared) { - for(auto peer : shared.shared) { - send_count_buf.push_back( - offsets[h.num_exclusive_ + shared.offset].count()); + // Send/Recv counts in entry_values. + std::vector requests(send_count + h.num_ghost_); + std::vector statuses(send_count + h.num_ghost_); + + const MPI_Datatype count_mpi_type = utils::mpi_type(); + std::vector send_count_buf; + for(auto & shared : index_coloring.shared) { + for(auto peer : shared.shared) { + send_count_buf.push_back( + h.rows[h.num_exclusive_ + shared.offset].size()); + } + } + + i = 0; + for(auto & shared : index_coloring.shared) { + for(auto peer : shared.shared) { + MPI_Isend(&send_count_buf[i], 1, count_mpi_type, + static_cast(peer), static_cast(shared.id), MPI_COMM_WORLD, + &requests[i]); + i++; + } } - } - i = 0; - for(auto & shared : index_coloring.shared) { - for(auto peer : shared.shared) { - MPI_Isend(&send_count_buf[i], 1, - flecsi::coloring::mpi_typetraits_u::type(), peer, shared.id, - MPI_COMM_WORLD, &requests[i]); + std::vector recv_count_buf(h.num_ghost_); + i = 0; + for(auto & ghost : index_coloring.ghost) { + // MPI_Status status; + MPI_Irecv(&recv_count_buf[i], 1, count_mpi_type, + static_cast(ghost.rank), static_cast(ghost.id), + MPI_COMM_WORLD, &requests[i + send_count]); i++; } - } - std::vector recv_count_buf(h.num_ghost_); - i = 0; - for(auto & ghost : index_coloring.ghost) { - MPI_Status status; - MPI_Irecv(&recv_count_buf[i], 1, - flecsi::coloring::mpi_typetraits_u::type(), ghost.rank, - ghost.id, MPI_COMM_WORLD, &requests[i + send_count]); - i++; - } + MPI_Waitall(static_cast(send_count + h.num_ghost_), requests.data(), + statuses.data()); - MPI_Waitall(send_count + h.num_ghost_, requests.data(), statuses.data()); + for(int i = 0; i < h.num_ghost_; i++) { + clog_rank(warn, 0) << recv_count_buf[i] << std::endl; + } + + // Unload data from ghost data buffer + for(int i = 0; i < static_cast(h.num_ghost_); i++) { + int r = static_cast(h.num_exclusive_ + h.num_shared_ + i); + auto & row = h.rows[r]; + int count = recv_count_buf[i]; + row.resize(count); + std::memcpy(row.begin(), &ghost_data[i * h.max_entries_per_index], + count * sizeof(value_t)); + } - for(int i = 0; i < h.num_ghost_; i++) { - clog_rank(warn, 0) << recv_count_buf[i] << std::endl; - offsets[h.num_exclusive_ + h.num_shared_ + i].set_count( - recv_count_buf[i]); + delete[] shared_data; + delete[] ghost_data; + } // else +#else + if constexpr((SHARED_PERMISSIONS == ro) || (GHOST_PERMISSIONS == rw) || + (GHOST_PERMISSIONS == wo)) { + *(h.ghost_is_readable) = true; } + else { + *(h.ghost_is_readable) = false; + } +#endif + } // handle + + template + void handle(sparse_accessor & a) { + handle(a.ragged); } // handle + template + void handle(ragged_mutator & m) {} // handle + template void handle(sparse_mutator & m) { - auto & h = m.h_; + handle(m.ragged); + } - using offset_t = typename mutator_handle__::offset_t; - using entry_value_t = typename mutator_handle__::entry_value_t; - using commit_info_t = typename mutator_handle__::commit_info_t; + template + void client_handler(data_client_handle_u h) { + + using entity_types_t = typename T::types_t::entity_types; + + if constexpr(I < std::tuple_size::value) { + + // get the entitiy type + using entity_tuple_t = + typename std::tuple_element::type; + using entity_type_t = + typename std::tuple_element<2, entity_tuple_t>::type; + constexpr auto DIM = entity_type_t::dimension; + constexpr auto DOM = entity_type_t::domain; + + // mpi stats + int comm_size, comm_rank; + MPI_Comm_size(MPI_COMM_WORLD, &comm_size); + MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank); + + // loop over entities and exchange the ghost values + auto entity_size = sizeof(entity_type_t); + auto entities = h.template get_entities(); + + // get context information + auto & context = context_t::instance(); + const int my_color = static_cast(context.color()); + + // figure out index space id + constexpr auto index_space = topology::find_index_space_from_dimension_u< + std::tuple_size::value, entity_types_t, DIM, + DOM>::find(); + const auto & index_map = context.index_map(index_space); + + // get ghost/shared info + const auto & my_coloring = context.coloring(index_space); + const auto & my_coloring_info = + context.coloring_info(index_space).at(my_color); + + // entity offsets are relative to the start of shared + auto offset_start = my_coloring_info.exclusive; + entities += offset_start; + + // allocate send and receive buffers + using byte_t = unsigned char; + + // setup send buffers + std::vector sendcounts(comm_size, 0); + for(auto & shared : my_coloring.shared) { + for(auto peer : shared.shared) { + assert(peer != comm_rank); + sendcounts[peer] += entity_size; + } + } - clog_assert(*h.num_exclusive_insertions <= *h.reserve, - "sparse exclusive reserve exceed"); + std::vector senddispls(comm_size + 1); + senddispls[0] = 0; + for(size_t r = 0; r < comm_size; ++r) + senddispls[r + 1] = senddispls[r] + sendcounts[r]; + + std::fill(sendcounts.begin(), sendcounts.end(), 0); + std::vector sendbuf(senddispls[comm_size], 0); + for(auto & shared : my_coloring.shared) { + auto eptr = &entities[shared.offset]; + for(auto peer : shared.shared) { + auto offset = senddispls[peer] + sendcounts[peer]; + std::memcpy(sendbuf.data() + offset, eptr, entity_size); + sendcounts[peer] += entity_size; + } + } - delete h.num_exclusive_insertions; + // setup recv buffers + std::vector recvcounts(comm_size, 0); + for(auto & ghost : my_coloring.ghost) + recvcounts[ghost.rank] += entity_size; - entry_value_t * entries = - reinterpret_cast(&(*h.entries)[0]); + std::vector recvdispls(comm_size + 1); - commit_info_t ci; - ci.offsets = &(*h.offsets)[0]; - ci.entries[0] = entries; - ci.entries[1] = entries + *h.reserve; - ci.entries[2] = ci.entries[1] + h.num_shared() * h.max_entries_per_index(); + recvdispls[0] = 0; + for(size_t r = 0; r < comm_size; ++r) + recvdispls[r + 1] = recvdispls[r] + recvcounts[r]; - h.commit(&ci); + std::vector recvbuf(recvdispls[comm_size]); - } // handle + // exchange data + auto ret = coloring::alltoallv(sendbuf, sendcounts, senddispls, recvbuf, + recvcounts, recvdispls, MPI_COMM_WORLD); + if(ret != MPI_SUCCESS) { + clog_error("Error communicating vertices"); + } - template - void handle(ragged_mutator & m) { - handle(reinterpret_cast &>(m)); + // unpack data + constexpr auto num_domains = T::num_domains; + + size_t i{0}; + std::fill(recvcounts.begin(), recvcounts.end(), 0); + + for(auto & ghost : my_coloring.ghost) { + // get pointer to entity in question + auto offset = recvdispls[ghost.rank] + recvcounts[ghost.rank]; + auto eptr = entities + my_coloring_info.shared + i; + // copy the original ids for now (GROSS) + auto id = eptr->global_id(); + // overrite data + std::memcpy(eptr, recvbuf.data() + offset, entity_size); + // copy back the ids + eptr->set_global_id(id); + // bump counters + recvcounts[ghost.rank] += entity_size; + ++i; + } + + // recursively call this function + client_handler(h); + } // constexpr if + } + + template + typename std::enable_if_t< + std::is_base_of::value> + handle(data_client_handle_u h) { + + // skip read only + if(PERMISSIONS == ro) + return; + + // iterate over types + client_handler<0>(h); } + /*! + Handle individual list items + */ template - void handle(ragged_accessor & a) { - handle(reinterpret_cast &>(a)); - } // handle + std::size_t N, + template + typename Container, + typename = + std::enable_if_t::value>> + void handle(Container & list) { + for(auto & item : list) { + handle(item); + } + } + + /*! + * Handle tuple of items + */ + + template + void handle_tuple_items(std::tuple & items, + std::index_sequence) { + (handle(std::get(items)), ...); + } + + template::value>> + void handle(std::tuple & items) { + handle_tuple_items(items, std::make_index_sequence{}); + } /*! This method is called on any task arguments that are not handles, e.g. scalars or those that did not need any special handling. */ template - static - typename std::enable_if_t::value> - handle(T &) {} // handle + void handle(T &) {} // handle }; // struct task_epilog_t diff --git a/flecsi/execution/hpx/task_prolog.h b/flecsi/execution/hpx/task_prolog.h index 5742a7419..e9045cf7c 100644 --- a/flecsi/execution/hpx/task_prolog.h +++ b/flecsi/execution/hpx/task_prolog.h @@ -1,24 +1,26 @@ /* - @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ - /@@///// /@@ @@////@@ @@////// /@@ - /@@ /@@ @@@@@ @@ // /@@ /@@ - /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ - /@@//// /@@/@@@@@@@/@@ ////////@@/@@ - /@@ /@@/@@//// //@@ @@ /@@/@@ - /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ - // /// ////// ////// //////// // - - Copyright (c) 2016, Los Alamos National Security, LLC - All rights reserved. - */ +@@@@@@@@ @@ @@@@@@ @@@@@@@@ @@ +/@@///// /@@ @@////@@ @@////// /@@ +/@@ /@@ @@@@@ @@ // /@@ /@@ +/@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@ +/@@//// /@@/@@@@@@@/@@ ////////@@/@@ +/@@ /@@/@@//// //@@ @@ /@@/@@ +/@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@ +// /// ////// ////// //////// // + +Copyright (c) 2016, Los Alamos National Security, LLC +All rights reserved. + */ #pragma once /*! @file */ +#include #include #include "mpi.h" -#include +#include +#include #include #include #include @@ -28,6 +30,10 @@ #include #include +#include "flecsi/utils/mpi_type_traits.h" +#include +#include + namespace flecsi { namespace execution { @@ -39,7 +45,7 @@ namespace execution { @ingroup execution */ -struct task_prolog_t : public utils::tuple_walker__ { +struct task_prolog_t : public flecsi::utils::tuple_walker_u { /*! Construct a task_prolog_t instance. @@ -47,39 +53,55 @@ struct task_prolog_t : public utils::tuple_walker__ { task_prolog_t() = default; - /*! - FIXME: Need a description. +#if defined(FLECSI_USE_AGGCOMM) + template + void handle(dense_accessor & a) { - @tparam T The data type referenced by the handle. - @tparam EXCLUSIVE_PERMISSIONS The permissions required on the exclusive - indices of the index partition. - @tparam SHARED_PERMISSIONS The permissions required on the shared - indices of the index partition. - @tparam GHOST_PERMISSIONS The permissions required on the ghost - indices of the index partition. + auto & h = a.handle; + auto & context = context_t::instance(); - @param runtime The Legion task runtime. - */ + auto rank = context_t::instance().color(); + + if(*(h.ghost_is_readable) || (GHOST_PERMISSIONS == na)) + return; + + auto & field_metadata = context.registered_field_metadata().at(h.fid); + + auto & my_coloring_info = + context.coloring_info(h.index_space).at(context.color()); + + auto data = context.registered_field_data().at(h.fid).data(); + auto shared_data = data + my_coloring_info.exclusive * sizeof(T); + auto ghost_data = shared_data + my_coloring_info.shared * sizeof(T); + + field_metadata.shared_data_buffer = shared_data; + field_metadata.ghost_data_buffer = ghost_data; + exchange_queue.emplace(h.index_space, h.fid); + } template - void handle(dense_accessor__ & a) { - // TODO: move field data allocation here? - } // handle + auto & h = a.handle; - template - void handle(global_accessor__ & a) { - if(a.handle.state >= SPECIALIZATION_SPMD_INIT) { - clog_assert(PERMISSIONS == size_t(ro), - "you are not allowed " - "to modify global data in specialization_spmd_init or driver"); - } - } // handle + if(*(h.ghost_is_readable) || (GHOST_PERMISSIONS == na)) + return; + + update_ghost_row_sizes(h); + + sparse_exchange_queue.emplace(h.index_space, h.fid); + } template { EXCLUSIVE_PERMISSIONS, SHARED_PERMISSIONS, GHOST_PERMISSIONS> & a) { -// // TODO: move field data allocation here? -// auto& context = context_t::instance(); -// const int my_color = context.color(); -// auto& my_coloring_info = -// context.coloring_info(h.index_space).at(my_color); -// -// auto& sparse_field_metadata = -// context.registered_sparse_field_metadata().at(h.fid); -// -// for (auto i = my_coloring_info.exclusive; -// i < my_coloring_info.exclusive + my_coloring_info.shared; ++i) { -// h() -// } -#if 0 - MPI_Win win = sparse_field_metadata.win; - - MPI_Win_post(sparse_field_metadata.shared_users_grp, 0, win); - MPI_Win_start(sparse_field_metadata.ghost_owners_grp, 0, win); - - for (auto ghost_owner : my_coloring_info.ghost_owners) { - MPI_Get(h.ghost_entries, 1, - sparse_field_metadata.origin_types[ghost_owner], - ghost_owner, 0, 1, - sparse_field_metadata.target_types[ghost_owner], - win); - } - - MPI_Win_complete(win); - MPI_Win_wait(win); -#endif + handle(a.ragged); } // handle template - void handle(sparse_mutator & m) { - m.h_.init(); + void handle(ragged_mutator & m) { + auto & h = m.handle; + + if(*(h.ghost_is_readable)) + return; + + update_ghost_row_sizes(h); + + sparse_exchange_queue.emplace(h.index_space, h.fid); + *(h.ghost_is_readable) = true; } // handle template - void handle(ragged_mutator & m) { - m.h_.init(); + void handle(sparse_mutator & m) { + handle(m.ragged); + } +#endif + + template + void handle(global_accessor_u & a) { + if(a.handle.state >= SPECIALIZATION_SPMD_INIT) { + clog_assert(PERMISSIONS == size_t(ro), + "you are not allowed " + "to modify global data in specialization_spmd_init or driver"); + } } // handle template typename std::enable_if_t< std::is_base_of::value> - handle(data_client_handle__ & h) { + handle(data_client_handle_u h) { auto & context_ = context_t::instance(); - // h is partially initialized in client.h - auto storage = h.set_storage(new typename T::storage_t); - bool _read{PERMISSIONS == ro || PERMISSIONS == rw}; - int color = context_.color(); + int color = static_cast(context_.color()); + // Finish h initialization started in client.h: for(size_t i{0}; i < h.num_handle_entities; ++i) { data_client_handle_entity_t & ent = h.handle_entities[i]; @@ -172,7 +181,7 @@ struct task_prolog_t : public utils::tuple_walker__ { fieldDataIter = registered_field_data.find(ent.id_fid); if(fieldDataIter == registered_field_data.end()) { - size_t size = ent.size * num_entities; + size_t size = sizeof(utils::id_t) * num_entities; execution::context_t::instance().register_field_data(ent.id_fid, size); } @@ -180,7 +189,7 @@ struct task_prolog_t : public utils::tuple_walker__ { registered_field_data[ent.id_fid].data()); // new allocation every time. - storage->init_entities(ent.domain, ent.dim, ents, ids, ent.size, + h.storage.init_entities(ent.domain, ent.dim, ents, ids, ent.size, num_entities, ent.num_exclusive, ent.num_shared, ent.num_ghost, _read); } // for @@ -214,10 +223,10 @@ struct task_prolog_t : public utils::tuple_walker__ { execution::context_t::instance().register_field_data( adj.index_fid, size); } - adj.indices_buf = - reinterpret_cast(registered_field_data[adj.index_fid].data()); + adj.indices_buf = reinterpret_cast( + registered_field_data[adj.index_fid].data()); - storage->init_connectivity(adj.from_domain, adj.to_domain, adj.from_dim, + h.storage.init_connectivity(adj.from_domain, adj.to_domain, adj.from_dim, adj.to_dim, reinterpret_cast(adj.offsets_buf), adj.num_offsets, reinterpret_cast(adj.indices_buf), adj.num_indices, _read); @@ -238,10 +247,10 @@ struct task_prolog_t : public utils::tuple_walker__ { iss.index_fid, size); } // assign the storage to the buffer - iss.indices_buf = - reinterpret_cast(registered_field_data[iss.index_fid].data()); + iss.indices_buf = reinterpret_cast( + registered_field_data[iss.index_fid].data()); // now initialize the index subspace - storage->init_index_subspace(iss.index_space, iss.index_subspace, + h.storage.init_index_subspace(iss.index_space, iss.index_subspace, iss.domain, iss.dim, reinterpret_cast(iss.indices_buf), num_indices, _read); } @@ -262,18 +271,16 @@ struct task_prolog_t : public utils::tuple_walker__ { template typename std::enable_if_t< std::is_base_of::value> - handle(data_client_handle__ & h) { + handle(data_client_handle_u h) { auto & context_ = context_t::instance(); auto & ism = context_.set_index_space_map(); - // h is partially initialized in client.h - auto storage = h.set_storage(new typename T::storage_t); - bool _read{PERMISSIONS == ro || PERMISSIONS == rw}; int color = context_.color(); + // Finish h initialization started in client.h: for(size_t i{0}; i < h.num_handle_entities; ++i) { data_client_handle_entity_t & ent = h.handle_entities[i]; @@ -306,15 +313,400 @@ struct task_prolog_t : public utils::tuple_walker__ { auto migrate_ents = reinterpret_cast( registered_field_data[ent.fid3].data()); - storage->init_entities(ent.index_space, ent.index_space2, ents, 0, + h.storage.init_entities(ent.index_space, ent.index_space2, ents, 0, active_ents, 0, migrate_ents, 0, ent.size, _read); } } + /*! + Handle individual list items + */ + template + typename Container, + typename = + std::enable_if_t::value>> + void handle(Container & list) { + for(auto & item : list) { + handle(item); + } + } + + /*! + * Handle tuple of items + */ + + template + void handle_tuple_items(std::tuple & items, + std::index_sequence) { + (handle(std::get(items)), ...); + } + + template::value>> + void handle(std::tuple & items) { + handle_tuple_items(items, std::make_index_sequence{}); + } + template - static typename std::enable_if_t< - !std::is_base_of::value> - handle(T &) {} // handle + void handle(T &) {} // handle + +#if defined(FLECSI_USE_AGGCOMM) + void launch_copies() { + auto & context = context_t::instance(); + auto const my_color = context.color(); + auto const num_colors = context.colors(); + + auto & ispace_dmap = context.index_space_data_map(); + + std::vector sharedSize(num_colors, 0); + std::vector ghostSize(num_colors, 0); + + std::vector> modified_fields; + + while(!exchange_queue.empty()) { + auto & fi = exchange_queue.front(); + auto & field_metadata = context.registered_field_metadata().at(fi.second); + modified_fields.emplace_back(fi.first, fi.second); + + for(auto rank = 0; rank < num_colors; ++rank) { + ghostSize[rank] += + static_cast(field_metadata.ghost_field_sizes[rank]); + sharedSize[rank] += + static_cast(field_metadata.shared_field_sizes[rank]); + } + + exchange_queue.pop(); + } + + std::vector allSendBuffer(num_colors); + std::vector allRecvBuffer(num_colors); + + std::vector allSendRequests(num_colors); + std::vector allRecvRequests(num_colors); + + // Post receives + + for(int rank = 0; rank < num_colors; ++rank) { + + const auto & bufSize = ghostSize[rank]; + + if(bufSize == 0) { + allRecvRequests[rank] = MPI_REQUEST_NULL; + continue; + } + + const int resultAlloc = + MPI_Alloc_mem(bufSize, MPI_INFO_NULL, &allRecvBuffer[rank]); + if(resultAlloc != MPI_SUCCESS) { + clog(fatal) << "MPI failed to alloc memory on rank: " << my_color + << " with error code: " << resultAlloc << std::endl; + } + + const int resultRecv = MPI_Irecv(allRecvBuffer[rank], bufSize, MPI_CHAR, + rank, rank, MPI_COMM_WORLD, &allRecvRequests[rank]); + if(resultRecv != MPI_SUCCESS) { + clog(error) << "MPI_Irecv failed on rank " << my_color + << " with error code: " << resultRecv << std::endl; + } + } + + // pack and send data + + for(int rank = 0; rank < num_colors; ++rank) { + + const auto & bufSize = sharedSize[rank]; + + if(bufSize == 0) { + allSendRequests[rank] = MPI_REQUEST_NULL; + continue; + } + + const int resultAlloc = + MPI_Alloc_mem(bufSize, MPI_INFO_NULL, &allSendBuffer[rank]); + if(resultAlloc != MPI_SUCCESS) { + clog(fatal) << "MPI failed to alloc memory on rank: " << my_color + << " with error code: " << resultAlloc << std::endl; + } + + size_t sendBufferOffset = 0; + + for(auto & fi : modified_fields) { + auto & field_metadata = + context.registered_field_metadata().at(fi.second); + + for(auto const & ind : field_metadata.shared_indices[rank]) { + + memcpy(&allSendBuffer[rank][sendBufferOffset], + &field_metadata.shared_data_buffer[ind[0]], ind[1]); + sendBufferOffset += ind[1]; + } + } + + const int resultSend = MPI_Isend(allSendBuffer[rank], + static_cast(bufSize), MPI_CHAR, static_cast(rank), + static_cast(my_color), MPI_COMM_WORLD, &allSendRequests[rank]); + if(resultSend != MPI_SUCCESS) { + clog(error) << "ERROR: MPI_Isend of rank " << my_color + << " for data sent to " << rank + << " failed with error code: " << resultSend << std::endl; + } + } + + // wait for data to arrive + const int result = MPI_Waitall(static_cast(allRecvRequests.size()), + allRecvRequests.data(), MPI_STATUSES_IGNORE); + if(result != MPI_SUCCESS) { + clog(fatal) << "ERROR: MPI_Waitall of rank " << my_color + << " on recv requests failed with error code: " << result + << std::endl; + } + + // unpack data + for(int rank = 0; rank < num_colors; ++rank) { + + const auto & bufSize = ghostSize[rank]; + + if(bufSize == 0) + continue; + + size_t recvBufferOffset = 0; + + for(auto & fi : modified_fields) { + + auto & field_metadata = + context.registered_field_metadata().at(fi.second); + + for(auto const & ind : field_metadata.ghost_indices[rank]) { + + memcpy(&field_metadata.ghost_data_buffer[ind[0]], + &allRecvBuffer[rank][recvBufferOffset], ind[1]); + recvBufferOffset += ind[1]; + } + } + + MPI_Free_mem(allRecvBuffer[rank]); + } + + // ensure all send are completed + MPI_Waitall(static_cast(allSendRequests.size()), + allSendRequests.data(), MPI_STATUSES_IGNORE); + + for(int rank = 0; rank < num_colors; ++rank) + MPI_Free_mem(allSendBuffer[rank]); + } + + void launch_sparse_copies() { + auto & context = context_t::instance(); + auto const my_color = context.color(); + auto const num_colors = context.colors(); + + auto & ispace_dmap = context.index_space_data_map(); + + std::map shared_sizes; + std::map ghost_sizes; + std::vector> modified_fields; + + // compute aggregated communication sizes + while(!sparse_exchange_queue.empty()) { + auto & fi = sparse_exchange_queue.front(); + auto & field_data = context.registered_sparse_field_data().at(fi.second); + auto & field_metadata = + context.registered_sparse_field_metadata().at(fi.second); + modified_fields.emplace_back(fi.first, fi.second); + + for(const auto & el : field_metadata.ghost_indices) { + for(size_t ind : el.second) { + auto count = field_metadata.ghost_row_sizes[ind]; + auto gsize = ghost_sizes.find(el.first); + if(gsize != ghost_sizes.end()) + gsize->second += + static_cast(count * field_data.type_size); + else + ghost_sizes[el.first] = + static_cast(count * field_data.type_size); + } + } + + auto * rows = + reinterpret_cast *>(field_data.rows.data()); + for(const auto & el : field_metadata.shared_indices) { + for(size_t ind : el.second) { + const auto & row = rows[field_data.num_exclusive + ind]; + auto count = row.size(); + auto ssize = shared_sizes.find(el.first); + if(ssize != shared_sizes.end()) + ssize->second += + static_cast(count * field_data.type_size); + else + shared_sizes[el.first] = + static_cast(count * field_data.type_size); + } + } + + sparse_exchange_queue.pop(); + } + + std::map> all_send_buf; + std::map> all_recv_buf; + std::vector all_send_req; + std::vector all_recv_req; + + // post recieves + for(const auto & el : ghost_sizes) { + int rank = el.first; + int bufsize = el.second; + all_recv_buf.emplace(rank, bufsize); + all_recv_req.push_back(MPI_REQUEST_NULL); + int err = MPI_Irecv(all_recv_buf[rank].data(), static_cast(bufsize), + MPI_BYTE, static_cast(rank), static_cast(rank), + MPI_COMM_WORLD, &all_recv_req.back()); + if(err != MPI_SUCCESS) { + clog(error) << "MPI_Irecv failed on rank " << rank + << " with error code: " << err << std::endl; + } + } + + // pack and send data + for(const auto & el : shared_sizes) { + int rank = el.first; + int bufsize = el.second; + all_send_buf.emplace(rank, bufsize); + all_send_req.push_back(MPI_REQUEST_NULL); + + size_t buf_offset = 0; + for(auto & fi : modified_fields) { + auto & field_metadata = + context.registered_sparse_field_metadata().at(fi.second); + auto & field_data = + context.registered_sparse_field_data().at(fi.second); + auto * rows = reinterpret_cast *>( + field_data.rows.data()); + for(size_t i : field_metadata.shared_indices[rank]) { + int r = static_cast(i + field_data.num_exclusive); + const auto & row = rows[r]; + size_t count = row.size(); + std::memcpy(&all_send_buf[rank][buf_offset], row.begin(), + count * field_data.type_size); + buf_offset += count * field_data.type_size; + } + } + + int err = MPI_Isend(all_send_buf[rank].data(), static_cast(bufsize), + MPI_BYTE, static_cast(rank), static_cast(my_color), + MPI_COMM_WORLD, &all_send_req.back()); + if(err != MPI_SUCCESS) { + clog(error) << "MPI_Isend of rank " << my_color + << " with error code: " << err << std::endl; + } + } + + // wait for halo data + { + int err = MPI_Waitall(static_cast(all_recv_req.size()), + all_recv_req.data(), MPI_STATUSES_IGNORE); + if(err != MPI_SUCCESS) { + clog(fatal) << "MPI_Waitall " + << " on recv requests failed with error code: " << err + << std::endl; + } + } + + // unpack data + for(const auto & el : ghost_sizes) { + int rank = el.first; + int bufsize = el.second; + + size_t buf_offset = 0; + for(auto & fi : modified_fields) { + auto & field_metadata = + context.registered_sparse_field_metadata().at(fi.second); + auto & field_data = + context.registered_sparse_field_data().at(fi.second); + auto * rows = reinterpret_cast *>( + field_data.rows.data()); + for(size_t i : field_metadata.ghost_indices[rank]) { + int r = static_cast( + field_data.num_exclusive + field_data.num_shared + i); + auto & row = rows[r]; + int count = field_metadata.ghost_row_sizes[i]; + std::memcpy(row.begin(), &all_recv_buf[rank][buf_offset], + count * field_data.type_size); + buf_offset += count * field_data.type_size; + } + } + } + + // wait for sends + MPI_Waitall(static_cast(all_send_req.size()), all_send_req.data(), + MPI_STATUSES_IGNORE); + } + + template + void update_ghost_row_sizes(HANDLE_TYPE & h) { + auto & context = context_t::instance(); + auto & index_coloring = context.coloring(h.index_space); + auto & field_metadata = + context.registered_sparse_field_metadata().at(h.fid); + + // send shared row counts to populate ghost row count list (TODO: aggregate + // this communication) + std::map> all_send_buf; + std::map> all_recv_buf; + std::vector all_send_req; + std::vector all_recv_req; + const MPI_Datatype count_mpi_type = utils::mpi_type(); + + // post revieves + for(const auto & el : field_metadata.ghost_indices) { + int rank = el.first; + int bufsize = static_cast(el.second.size()); + all_recv_buf.emplace(rank, bufsize); + all_recv_req.push_back(MPI_REQUEST_NULL); + MPI_Irecv(all_recv_buf[rank].data(), bufsize, count_mpi_type, rank, rank, + MPI_COMM_WORLD, &all_recv_req.back()); + } + + // pack and send data + for(const auto & el : field_metadata.shared_indices) { + int rank = el.first; + all_send_req.push_back(MPI_REQUEST_NULL); + for(size_t i : field_metadata.shared_indices[rank]) { + all_send_buf[rank].push_back(h.rows[h.num_exclusive_ + i].size()); + } + int my_color = static_cast(context.color()); + MPI_Isend(all_send_buf[rank].data(), + static_cast(all_send_buf[rank].size()), count_mpi_type, + static_cast(rank), static_cast(my_color), MPI_COMM_WORLD, + &all_send_req.back()); + } + + // wait for row sizes + MPI_Waitall(static_cast(all_recv_req.size()), all_recv_req.data(), + MPI_STATUSES_IGNORE); + + for(const auto & el : field_metadata.ghost_indices) { + int rank = el.first; + int buf_offset = 0; + for(size_t i : field_metadata.ghost_indices[rank]) { + field_metadata.ghost_row_sizes[i] = all_recv_buf[rank][buf_offset]; + int r = static_cast(h.num_exclusive_ + h.num_shared_ + i); + auto & row = h.rows[r]; + row.resize(field_metadata.ghost_row_sizes[i]); + buf_offset++; + } + } + + // wait for sends + MPI_Waitall(static_cast(all_send_req.size()), all_send_req.data(), + MPI_STATUSES_IGNORE); + } + + std::queue> exchange_queue; + std::queue> sparse_exchange_queue; +#endif }; // struct task_prolog_t diff --git a/flecsi/execution/hpx/task_wrapper.h b/flecsi/execution/hpx/task_wrapper.h deleted file mode 100644 index 01f23f261..000000000 --- a/flecsi/execution/hpx/task_wrapper.h +++ /dev/null @@ -1,34 +0,0 @@ -/*~--------------------------------------------------------------------------~* - * Copyright (c) 2015 Los Alamos National Security, LLC - * All rights reserved. - *~--------------------------------------------------------------------------~*/ - -#ifndef flecsi_execution_hpx_task_wrapper_h -#define flecsi_execution_hpx_task_wrapper_h - -clog_register_tag(wrapper); - -namespace flecsi { -namespace execution { - -template -struct functor_task_wrapper_u {}; - -template -struct task_wrapper_u { - //--------------------------------------------------------------------------// - //! The task_args_t type defines a task argument type for task - //! execution through the HPX runtime. - //--------------------------------------------------------------------------// - - // using task_args_t = - // typename utils::base_convert_tuple_type< - // accessor_base_t, data_handle_u, ARG_TUPLE>::type; -}; - -} // namespace execution -} // namespace flecsi -#endif // flecsi_execution_hpx_task_wrapper_h diff --git a/flecsi/execution/test/dense_data.cc b/flecsi/execution/test/dense_data.cc index 57ef6bb8f..dd93ac058 100644 --- a/flecsi/execution/test/dense_data.cc +++ b/flecsi/execution/test/dense_data.cc @@ -149,10 +149,11 @@ driver(int argc, char ** argv) { auto ph = flecsi_get_handle(ch, hydro, pressure, size_t, dense, 0); flecsi_execute_task(init, flecsi::execution, index, ch, ph); - flecsi_execute_task(print, flecsi::execution, index, ch, ph); + auto future = flecsi_execute_task(print, flecsi::execution, index, ch, ph); + future.wait(); // wait before modifying the data flecsi_execute_task(modify, flecsi::execution, index, ch, ph); - auto future = flecsi_execute_task(print, flecsi::execution, index, ch, ph); + future = flecsi_execute_task(print, flecsi::execution, index, ch, ph); future.wait(); // wait before comparing results auto & context = execution::context_t::instance(); diff --git a/flecsi/execution/test/future_handle.cc b/flecsi/execution/test/future_handle.cc index 27c8ecb00..687fe4751 100644 --- a/flecsi/execution/test/future_handle.cc +++ b/flecsi/execution/test/future_handle.cc @@ -61,7 +61,7 @@ flecsi_register_task(index_writer, , loc, index); void index_reader(index_handle_t x) { int y = 1 + flecsi::execution::context_t::instance().color(); - ASSERT_EQ(x, y); + ASSERT_EQ(x.get(), y); } flecsi_register_task(index_reader, , loc, index); diff --git a/flecsi/execution/test/ghost_access_drivers.cc b/flecsi/execution/test/ghost_access_drivers.cc index d47e9c009..ad55fcc4b 100644 --- a/flecsi/execution/test/ghost_access_drivers.cc +++ b/flecsi/execution/test/ghost_access_drivers.cc @@ -93,8 +93,9 @@ driver(int argc, char ** argv) { flecsi_execute_task_simple( set_primary_cells_task, index, handle, test_handle, cycle); - flecsi_execute_task_simple( + auto future = flecsi_execute_task_simple( check_all_cells_task, index, handle, test_handle, cycle); + future.get(); // make sure that next iteration doesn't start prematurely } } // driver diff --git a/flecsi/topology/hpx/set_storage_policy.h b/flecsi/topology/hpx/set_storage_policy.h index 7026d5fd6..bfb3c91f6 100644 --- a/flecsi/topology/hpx/set_storage_policy.h +++ b/flecsi/topology/hpx/set_storage_policy.h @@ -61,16 +61,31 @@ struct hpx_set_topology_storage_policy_u { } void init_entities(size_t index_space, + size_t active_migrate_index_space, set_entity_t * entities, - size_t size, size_t num_entities, + set_entity_t * active_entities, + size_t num_active_entities, + set_entity_t * migrate_entities, + size_t num_migrate_entities, + size_t size, bool read) { + auto itr = index_space_map.find(index_space); clog_assert(itr != index_space_map.end(), "invalid index space"); auto & is = index_spaces[itr->second]; auto s = is.storage(); - s->set_buffer(entities, num_entities, read); + *s = {{entities, num_entities}, read ? num_entities : 0}; + + itr = index_space_map.find(active_migrate_index_space); + clog_assert( + itr != index_space_map.end(), "invalid active migrate index space"); + auto & amis = index_spaces[itr->second]; + auto s2 = amis.storage(); + + // how to handle migration buffer? + s2->set_buffer(active_entities, num_entities, read); if(!read) { return; @@ -82,16 +97,18 @@ struct hpx_set_topology_storage_policy_u { void finalize_storage() { auto & context = execution::context_t::instance(); - auto & im = context.local_index_space_data_map(); - for(auto & itr : im) { - std::size_t index_space = itr.first; + /* + auto& im = context.local_index_space_data_map(); + for(auto& itr : im){ + size_t index_space = itr.first; auto sitr = index_space_map.find(index_space); clog_assert(sitr != index_space_map.end(), "invalid index space"); - auto & is = index_spaces[sitr->second]; - execution::context_t::local_index_space_data_t & isd = itr.second; + auto& is = index_spaces[sitr->second]; + execution::context_t::local_index_space_data_t& isd = itr.second; isd.size = is.size(); } + */ } template @@ -99,15 +116,9 @@ struct hpx_set_topology_storage_policy_u { constexpr std::size_t index_space = find_set_index_space_u::find(); - auto & is = index_spaces[index_space].template cast(); - std::size_t entity = is.size(); - - auto placement_ptr = static_cast(is.storage()->buffer()) + entity; + auto & is = index_spaces[index_space]; + auto placement_ptr = static_cast(is.data.buffer()) + is.ids.size(); auto ent = new(placement_ptr) T(std::forward(args)...); - auto storage = is.storage(); - storage->pushed(); - is.pushed(); - return ent; } }; diff --git a/flecsi/utils/CMakeLists.txt b/flecsi/utils/CMakeLists.txt index 88427f1e8..f6d398324 100644 --- a/flecsi/utils/CMakeLists.txt +++ b/flecsi/utils/CMakeLists.txt @@ -117,13 +117,13 @@ set(utils_SOURCES # Unit tests. #------------------------------------------------------------------------------# -if(NOT FLECSI_RUNTIME_MODEL STREQUAL "hpx") cinch_add_devel_target(clog SOURCES test/clog.cc + LIBRARIES + ${CINCH_RUNTIME_LIBRARIES} POLICY ${UNIT_POLICY} ) -endif() set(factory_blessed_input test/factory.blessed.gnug) @@ -133,11 +133,12 @@ endif() cinch_add_unit(factory SOURCES - demangle.cc test/factory.cc INPUTS test/factory.blessed ${factory_blessed_input} + LIBRARIES + FleCSI ) cinch_add_unit(fixed_vector @@ -190,10 +191,11 @@ cinch_add_unit(static_verify cinch_add_unit(test_utility SOURCES - demangle.cc test/utility.cc INPUTS test/utility.blessed.gnug + LIBRARIES + FleCSI ) set(tuple_type_converter_blessed_input test/tuple_type_converter.blessed.gnug) @@ -204,16 +206,18 @@ endif() cinch_add_unit(tuple_type_converter SOURCES - demangle.cc test/tuple_type_converter.cc INPUTS ${tuple_type_converter_blessed_input} + LIBRARIES + FleCSI ) cinch_add_unit(tuple_wrapper SOURCES - demangle.cc test/tuple_wrapper.cc + LIBRARIES + FleCSI ) set(array_ref_blessed_input test/array_ref.blessed.gnug) @@ -224,10 +228,11 @@ endif() cinch_add_unit(array_ref SOURCES - demangle.cc test/array_ref.cc INPUTS test/array_ref.blessed ${array_ref_blessed_input} + LIBRARIES + FleCSI ) set(common_blessed_input test/common.blessed.gnug) @@ -238,10 +243,11 @@ endif() cinch_add_unit(common SOURCES - demangle.cc test/common.cc INPUTS test/common.blessed.ppc test/common.blessed ${common_blessed_input} + LIBRARIES + FleCSI ) set(id_blessed_input test/id.blessed.gnug) @@ -252,10 +258,11 @@ endif() cinch_add_unit(id SOURCES - demangle.cc test/id.cc INPUTS test/id.blessed ${id_blessed_input} + LIBRARIES + FleCSI ) if(ENABLE_OPENSSL) diff --git a/flecsi/utils/annotation.h b/flecsi/utils/annotation.h index f7b9950b2..122538b8d 100644 --- a/flecsi/utils/annotation.h +++ b/flecsi/utils/annotation.h @@ -102,6 +102,16 @@ class annotation inline static const std::string tag{"finalize-handles"}; static constexpr detail detail_level = detail::high; }; + struct execute_task_collect_dependencies + : execute_task { + inline static const std::string tag{"collect-dependencies"}; + static constexpr detail detail_level = detail::high; + }; + struct execute_task_add_dependencies + : execute_task { + inline static const std::string tag{"add-dependencies"}; + static constexpr detail detail_level = detail::high; + }; /** * Tag beginning of code region with caliper annotation. diff --git a/flecsi/utils/tuple_walker.h b/flecsi/utils/tuple_walker.h index d6d5c905f..307bd0887 100644 --- a/flecsi/utils/tuple_walker.h +++ b/flecsi/utils/tuple_walker.h @@ -39,6 +39,11 @@ struct tuple_walker_u { static_cast(*this).handle(t); } + template + void dispatch(T1 & t1, T2 & t2) { + static_cast(*this).handle(t1, t2); + } + template void dispatch() { static_cast(*this).template handle_type(); @@ -52,6 +57,14 @@ struct tuple_walker_u { } } + template + void walk_impl(TUPLE_TYPE1 & t1, TUPLE_TYPE2 & t2) { + if constexpr(index < std::tuple_size::value) { + dispatch(std::get(t1), std::get(t2)); + walk_impl(t1, t2); + } + } + template void walk_types_impl() { if constexpr(index < std::tuple_size::value) { @@ -77,6 +90,25 @@ struct tuple_walker_u { walk_impl(t); } + //--------------------------------------------------------------------------// + //! Walk the given tuples, applying the handler to each element. + //! + //! @tparam TUPLE_TYPE1 The first tuple type. + //! @tparam TUPLE_TYPE2 The second tuple type. + //! + //! @param t An instance of the tuple. + //! + //! @ingroup utils + //--------------------------------------------------------------------------// + + template + void walk(TUPLE_TYPE1 & t1, TUPLE_TYPE2 & t2) { + static_assert(std::tuple_size::value == + std::tuple_size::value, + "tuple sizes must match"); + walk_impl(t1, t2); + } + //--------------------------------------------------------------------------// //! Walk the given tuple by type, applying the handler to each element. //!