Logo AND Algorithmique Numérique Distribuée

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