Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Update copyright lines for 2023.
[simgrid.git] / src / smpi / colls / allgather / allgather-rhv.cpp
1 /* Copyright (c) 2013-2023. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "../colls_private.hpp"
8
9 namespace simgrid::smpi {
10
11 // now only work with power of two processes
12
13 int
14 allgather__rhv(const void *sbuf, int send_count,
15                MPI_Datatype send_type, void *rbuf,
16                int recv_count, MPI_Datatype recv_type,
17                MPI_Comm comm)
18 {
19   MPI_Status status;
20   MPI_Aint s_extent, r_extent;
21
22   // local int variables
23   int i, dst, send_base_offset, recv_base_offset, send_chunk, recv_chunk,
24       send_offset, recv_offset;
25   int tag = COLL_TAG_ALLGATHER;
26   unsigned int mask;
27   int curr_count;
28
29   // get size of the communicator, followed by rank
30   unsigned int num_procs = comm->size();
31
32   if((num_procs&(num_procs-1)))
33     throw std::invalid_argument("allgather rhv algorithm can't be used with non power of two number of processes!");
34
35   unsigned int rank = comm->rank();
36
37   // get size of single element's type for send buffer and recv buffer
38   s_extent = send_type->get_extent();
39   r_extent = recv_type->get_extent();
40
41   // multiply size of each element by number of elements to send or recv
42   send_chunk = s_extent * send_count;
43   recv_chunk = r_extent * recv_count;
44
45   if (send_chunk != recv_chunk) {
46     XBT_INFO("MPI_allgather_rhv: send_chunk != recv_chunk, use default MPI_allgather.");
47     allgather__default(sbuf, send_count, send_type, rbuf, recv_count,
48                        recv_type, comm);
49     return MPI_SUCCESS;
50   }
51
52   // compute starting offset location to perform local copy
53   int size = num_procs / 2;
54   int base_offset = 0;
55   mask = 1;
56   while (mask < num_procs) {
57     if (rank & mask) {
58       base_offset += size;
59     }
60     mask <<= 1;
61     size /= 2;
62   }
63
64   //perform a remote copy
65
66   dst = base_offset;
67   Request::sendrecv(sbuf, send_count, send_type, dst, tag,
68                (char *)rbuf + base_offset * recv_chunk, recv_count, recv_type, dst, tag,
69                comm, &status);
70
71
72   mask >>= 1;
73   i = 1;
74   curr_count = recv_count;
75   while (mask >= 1) {
76     // destination pair for both send and recv
77     dst = rank ^ mask;
78
79     // compute offsets
80     send_base_offset = base_offset;
81     if (rank & mask) {
82       recv_base_offset = base_offset - i;
83       base_offset -= i;
84     } else {
85       recv_base_offset = base_offset + i;
86     }
87     send_offset = send_base_offset * recv_chunk;
88     recv_offset = recv_base_offset * recv_chunk;
89
90     Request::sendrecv((char*)rbuf + send_offset, curr_count, recv_type, dst, tag, (char*)rbuf + recv_offset, curr_count,
91                       recv_type, dst, tag, comm, &status);
92
93     curr_count *= 2;
94     i *= 2;
95     mask >>= 1;
96   }
97
98   return MPI_SUCCESS;
99 }
100
101 } // namespace simgrid::smpi