From 08b1ab21deb36efb13da7db686054177546fbde7 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Fri, 4 Mar 2022 18:43:29 -0700 Subject: [PATCH] Provide an overload of broadcast() for MPI types. --- include/deal.II/base/mpi.h | 83 +++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/include/deal.II/base/mpi.h b/include/deal.II/base/mpi.h index 3269e0a306..fd3ca10ca5 100644 --- a/include/deal.II/base/mpi.h +++ b/include/deal.II/base/mpi.h @@ -1178,33 +1178,70 @@ namespace Utilities const unsigned int root_process = 0); /** - * Sends an object @p object_to_send from the process @p root_process + * This function sends an object @p object_to_send from the process @p root_process * to all other processes. * - * A generalization of the classic `MPI_Bcast` function that accepts - * arbitrary data types `T`, as long as Utilities::pack() (which in turn - * uses `boost::serialize`, see in Utilities::pack() for details) accepts - * `T` as an argument. + * This function is a generalization of the classic `MPI_Bcast` function + * that accepts arbitrary data types `T`, as long as Utilities::pack() + * (which in turn uses `boost::serialize`, see in Utilities::pack() for + * details) accepts `T` as an argument. * * @note Be aware that this function is typically a lot more - * expensive than an `MPI_Bcast` if you are using simple types - * directly supported by MPI. This function will use + * expensive than an `MPI_Bcast` because the function will use * boost::serialization to (de)serialize, and execute a second * `MPI_Bcast` to transmit the size before sending the data - * itself. You can also use the other broadcast() function in this - * namespace. + * itself. On the other hand, if you have a single element of + * a data type `T` that is natively supported by MPI, then the + * compiler will choose another broadcast() overload that is efficient. + * If you have an array of such elements, you should use the other + * broadcast() function in this namespace that takes a pointer and a count + * argument. * * @param[in] comm MPI communicator. * @param[in] object_to_send An object to send to all processes. * @param[in] root_process The process that sends the object to all * processes. By default the process with rank 0 is the root process. * + * @tparam T Any type for which the Utilities::pack() and + * Utilities::unpack() functions can be used to convert the object + * into an array of `char`. The compiler will not select this function + * if `T` is a type that is natively supported by MPI and instead + * use a more efficient overload. + * * @return On the root process, return a copy of @p object_to_send. * On every other process, return a copy of the object sent by * the @p root_process. */ template - T + typename std::enable_if == false, T>::type + broadcast(const MPI_Comm & comm, + const T & object_to_send, + const unsigned int root_process = 0); + + /** + * This function sends an object @p object_to_send from the process @p root_process + * to all other processes. + * + * This function is wrapper around the `MPI_Bcast` function selected + * by the compiler whenever `T` is a data type natively supported by + * MPI. + * + * @param[in] comm MPI communicator. + * @param[in] object_to_send An object to send to all processes. + * @param[in] root_process The process that sends the object to all + * processes. By default the process with rank 0 is the root process. + * + * @tparam T Any type. The compiler will only select this function + * if `T` is a type that is natively supported by MPI. It will choose + * the other overloaded version of this function if that is not + * the case. + * + * @return On the root process, return a copy of @p object_to_send. + * On every other process, return a copy of the object sent by + * the @p root_process. + */ + template + typename std::enable_if == true, T>::type broadcast(const MPI_Comm & comm, const T & object_to_send, const unsigned int root_process = 0); @@ -1886,7 +1923,7 @@ namespace Utilities template - T + typename std::enable_if == false, T>::type broadcast(const MPI_Comm & comm, const T & object_to_send, const unsigned int root_process) @@ -1934,6 +1971,30 @@ namespace Utilities } + + template + typename std::enable_if == true, T>::type + broadcast(const MPI_Comm & comm, + const T & object_to_send, + const unsigned int root_process) + { +# ifndef DEAL_II_WITH_MPI + (void)comm; + (void)root_process; + return object_to_send; +# else + + T object = object_to_send; + int ierr = + MPI_Bcast(&object, 1, mpi_type_id_for_type, root_process, comm); + AssertThrowMPI(ierr); + + return object; +# endif + } + + + # ifdef DEAL_II_WITH_MPI template std::pair::real_type> -- 2.39.5