Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
54441b8fb44351ba19836072014ac07d8dc2ae57
[simgrid.git] / src / smpi / colls / allgather / allgather-rdb.cpp
1 /* Copyright (c) 2013-2022. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "../colls_private.hpp"
7 #include "smpi_status.hpp"
8
9 namespace simgrid::smpi {
10
11 int
12 allgather__rdb(const void *sbuf, int send_count,
13                MPI_Datatype send_type, void *rbuf,
14                int recv_count, MPI_Datatype recv_type,
15                MPI_Comm comm)
16 {
17   // MPI variables
18   MPI_Status status;
19   MPI_Aint send_chunk, recv_chunk;
20
21   // local int variables
22   unsigned int i, j, k, dst, send_offset, recv_offset, tree_root;
23   int dst_tree_root, rank_tree_root, last_recv_count = 0, num_procs_completed;
24   int offset, tmp_mask;
25   int tag = COLL_TAG_ALLGATHER;
26   unsigned int mask = 1;
27   int success = 0;
28   int curr_count = recv_count;
29
30   // local string variables
31   char *send_ptr = (char *) sbuf;
32   char *recv_ptr = (char *) rbuf;
33
34   // get size of the communicator, followed by rank
35   unsigned int num_procs = comm->size();
36   unsigned int rank = comm->rank();
37
38   // get size of single element's type for send buffer and recv buffer
39   send_chunk = send_type->get_extent();
40   recv_chunk = recv_type->get_extent();
41
42   // multiply size of each element by number of elements to send or recv
43   send_chunk *= send_count;
44   recv_chunk *= recv_count;
45
46   // perform a local copy
47   Request::sendrecv(send_ptr, send_count, send_type, rank, tag,
48                recv_ptr + rank * recv_chunk, recv_count, recv_type, rank, tag,
49                comm, &status);
50
51   i = 0;
52   while (mask < num_procs) {
53     dst = rank ^ mask;
54     dst_tree_root = dst >> i;
55     dst_tree_root <<= i;
56     rank_tree_root = rank >> i;
57     rank_tree_root <<= i;
58     send_offset = rank_tree_root * send_chunk;
59     recv_offset = dst_tree_root * recv_chunk;
60
61     if (dst < num_procs) {
62       Request::sendrecv(recv_ptr + send_offset, curr_count, send_type, dst,
63                    tag, recv_ptr + recv_offset, mask * recv_count,
64                    recv_type, dst, tag, comm, &status);
65       last_recv_count = Status::get_count(&status, recv_type);
66       curr_count += last_recv_count;
67     }
68
69     if (dst_tree_root + mask > num_procs) {
70       num_procs_completed = num_procs - rank_tree_root - mask;
71       /* num_procs_completed is the number of processes in this
72          subtree that have all the data. Send data to others
73          in a tree fashion. First find root of current tree
74          that is being divided into two. k is the number of
75          least-significant bits in this process's rank that
76          must be zeroed out to find the rank of the root */
77
78       j = mask;
79       k = 0;
80       while (j) {
81         j >>= 1;
82         k++;
83       }
84       k--;
85
86       offset = recv_chunk * (rank_tree_root + mask);
87       tmp_mask = mask >> 1;
88
89       while (tmp_mask) {
90         dst = rank ^ tmp_mask;
91
92         tree_root = rank >> k;
93         tree_root <<= k;
94
95         /* send only if this proc has data and destination
96            doesn't have data. at any step, multiple processes
97            can send if they have the data */
98         if ((dst > rank)
99             && (rank < tree_root + num_procs_completed)
100             && (dst >= tree_root + num_procs_completed)) {
101           Request::send(recv_ptr + offset, last_recv_count, recv_type, dst,
102                    tag, comm);
103
104           /* last_recv_cnt was set in the previous
105              receive. that's the amount of data to be
106              sent now. */
107         }
108         /* recv only if this proc. doesn't have data and sender
109            has data */
110         else if ((dst < rank)
111                  && (dst < tree_root + num_procs_completed)
112                  && (rank >= tree_root + num_procs_completed)) {
113           Request::recv(recv_ptr + offset,
114                    recv_count * num_procs_completed,
115                    recv_type, dst, tag, comm, &status);
116           // num_procs_completed is also equal to the no. of processes
117           // whose data we don't have
118           last_recv_count = Status::get_count(&status, recv_type);
119           curr_count += last_recv_count;
120         }
121         tmp_mask >>= 1;
122         k--;
123       }
124     }
125
126     mask <<= 1;
127     i++;
128   }
129
130   return success;
131 }
132
133 } // namespace simgrid::smpi