From 7c40994ab90ecf3eb2e147af8c202e68bdb23415 Mon Sep 17 00:00:00 2001 From: Tim Niklas Uhl Date: Tue, 14 Jan 2025 08:55:38 +0100 Subject: [PATCH] Add an example for the named paramter namespace. --- examples/usage/allgatherv_example.cpp | 124 +++++++++++++++----------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/examples/usage/allgatherv_example.cpp b/examples/usage/allgatherv_example.cpp index bbc642d4..632054d2 100644 --- a/examples/usage/allgatherv_example.cpp +++ b/examples/usage/allgatherv_example.cpp @@ -38,61 +38,81 @@ int main() { // Note, that the size of the input vector is different for each rank. std::vector input(comm.rank(), comm.rank_signed()); - { // Basic use case; gather the inputs across all ranks to all ranks. + { + // we are including the namespace here to reduce verbosity + using namespace kamping; + { // Basic use case; gather the inputs across all ranks to all ranks. + auto const output = comm.allgatherv(send_buf(input)); + print_result_on_root(output, comm); + } + + { // We can also request the number of elements received from each rank. The recv_buf will always be the first + // out parameter. After that, the output parameters are ordered as they appear in the function call. KaMPIng + // calls like allgatherv return a result object which can be decomposed using structured bindings (here) or + // explicit extract_*() calls (see below). + auto [recv_buffer, recv_counts] = comm.allgatherv(send_buf(input), recv_counts_out()); + } + + { // To re-use memory, we can provide an already allocated container to the MPI call. + std::vector output; + // Let KaMPIng resize the recv_buffer to the correct size. Other possibilities are no_resize and grow_only. + comm.allgatherv(send_buf(input), recv_buf(output)); + + // We can also re-use already allocated containers for the other output parameters, e.g. recv_counts. + std::vector output_counts(comm.size()); + std::iota(output_counts.begin(), output_counts.end(), 0); + comm.allgatherv(send_buf(input), recv_buf(output), recv_counts(output_counts)); + + std::vector displacements(comm.size()); + std::exclusive_scan(output_counts.begin(), output_counts.end(), displacements.begin(), 0); + output.clear(); + + // In this example, we combine all of the concepts mentioned above: + // - Use input as the send buffer + // - Receive all elements into recv_buffer, resizing it to fit exactly the number of elements received. + // - Output the number of elements received from each rank into recv_counts. + // - Output the displacement of the first element received from each rank into recv_displs. + comm.allgatherv( + send_buf(input), + recv_buf(output), + recv_counts(output_counts), + recv_displs(displacements) + ); + } + + { // It is also possible to use result.extract_*() calls instead of decomposing the result object using + // structured bindings in order to increase readability. + auto result = comm.allgatherv(send_buf(input), recv_counts_out(), recv_displs_out()); + auto const recv_buffer = result.extract_recv_buffer(); + auto const recv_counts = result.extract_recv_counts(); + auto const recv_displs = result.extract_recv_displs(); + } + + { // C++ views can be used to send parts of the data. + input.resize(comm.rank() + 1, comm.rank_signed()); + + // Note, if you're on C++ >= 20 you can use std::span instead. + comm.allgatherv(send_buf(kamping::Span(input).subspan(0, comm.rank()))); + + // Alternatively + comm.allgatherv(send_buf(input), send_count(comm.rank_signed())); + + // let's restore the input + input.resize(comm.rank()); + } + } + { + // if you don't want to polute your global namespace with all KaMPIng's symbols, you can just use the namespace + // for named parameters + using namespace kamping::params; auto const output = comm.allgatherv(send_buf(input)); print_result_on_root(output, comm); } - - { // We can also request the number of elements received from each rank. The recv_buf will always be the first out - // parameter. After that, the output parameters are ordered as they appear in the function call. - // KaMPIng calls like allgatherv return a result object which can be decomposed using structured - // bindings (here) or explicit extract_*() calls (see below). - auto [recv_buffer, recv_counts] = comm.allgatherv(send_buf(input), recv_counts_out()); - } - - { // To re-use memory, we can provide an already allocated container to the MPI call. - std::vector output; - // Let KaMPIng resize the recv_buffer to the correct size. Other possibilities are no_resize and grow_only. - comm.allgatherv(send_buf(input), recv_buf(output)); - - // We can also re-use already allocated containers for the other output parameters, e.g. recv_counts. - std::vector output_counts(comm.size()); - std::iota(output_counts.begin(), output_counts.end(), 0); - comm.allgatherv(send_buf(input), recv_buf(output), recv_counts(output_counts)); - - std::vector displacements(comm.size()); - std::exclusive_scan(output_counts.begin(), output_counts.end(), displacements.begin(), 0); - output.clear(); - - // In this example, we combine all of the concepts mentioned above: - // - Use input as the send buffer - // - Receive all elements into recv_buffer, resizing it to fit exactly the number of elements received. - // - Output the number of elements received from each rank into recv_counts. - // - Output the displacement of the first element received from each rank into recv_displs. - comm.allgatherv( - send_buf(input), - recv_buf(output), - recv_counts(output_counts), - recv_displs(displacements) - ); - } - - { // It is also possible to use result.extract_*() calls instead of decomposing the result object using structured - // bindings in order to increase readability. - auto result = comm.allgatherv(send_buf(input), recv_counts_out(), recv_displs_out()); - auto const recv_buffer = result.extract_recv_buffer(); - auto const recv_counts = result.extract_recv_counts(); - auto const recv_displs = result.extract_recv_displs(); - } - - { // C++ views can be used to send parts of the data. - input.resize(comm.rank() + 1, comm.rank_signed()); - - // Note, if you're on C++ >= 20 you can use std::span instead. - comm.allgatherv(send_buf(kamping::Span(input).subspan(0, comm.rank()))); - - // Alternatively - comm.allgatherv(send_buf(input), send_count(comm.rank_signed())); + { + // you can also use define a shorthand for the named parameter namespace, to reduce code verbosity + namespace kmp = kamping::params; + auto const output = comm.allgatherv(kmp::send_buf(input)); + print_result_on_root(output, comm); } return 0;