Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
oops
[simgrid.git] / src / smpi / colls / allgather-rhv.c
1 /* Copyright (c) 2013-2014. 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.h"
8
9 // now only work with power of two processes
10
11 int
12 smpi_coll_tuned_allgather_rhv(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_Status status;
18   MPI_Aint s_extent, r_extent;
19
20   // local int variables
21   int i, dst, send_base_offset, recv_base_offset, send_chunk, recv_chunk,
22       send_offset, recv_offset;
23   int rank, num_procs;
24   int tag = COLL_TAG_ALLGATHER;
25   int mask;
26   int curr_count;
27
28   // get size of the communicator, followed by rank 
29   num_procs = smpi_comm_size(comm);
30
31   if((num_procs&(num_procs-1)))
32     THROWF(arg_error,0, "allgather rhv algorithm can't be used with non power of two number of processes ! ");
33
34   rank = smpi_comm_rank(comm);
35
36   // get size of single element's type for send buffer and recv buffer
37   s_extent = smpi_datatype_get_extent(send_type);
38   r_extent = smpi_datatype_get_extent(recv_type);
39
40   // multiply size of each element by number of elements to send or recv
41   send_chunk = s_extent * send_count;
42   recv_chunk = r_extent * recv_count;
43
44   if (send_chunk != recv_chunk) {
45     XBT_WARN("MPI_allgather_rhv use default MPI_allgather.");  
46     smpi_mpi_allgather(sbuf, send_count, send_type, rbuf, recv_count,
47                               recv_type, comm);
48     return MPI_SUCCESS;        
49   }
50
51   // compute starting offset location to perform local copy
52   int size = num_procs / 2;
53   int base_offset = 0;
54   mask = 1;
55   while (mask < num_procs) {
56     if (rank & mask) {
57       base_offset += size;
58     }
59     mask <<= 1;
60     size /= 2;
61   }
62
63   //  printf("node %d base_offset %d\n",rank,base_offset);
64
65   //perform a remote copy
66
67   dst = base_offset;
68   smpi_mpi_sendrecv(sbuf, send_count, send_type, dst, tag,
69                (char *)rbuf + base_offset * recv_chunk, recv_count, recv_type, dst, tag,
70                comm, &status);
71
72
73   mask >>= 1;
74   i = 1;
75   int phase = 0;
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     //  printf("node %d send to %d in phase %d s_offset = %d r_offset = %d count = %d\n",rank,dst,phase, send_base_offset, recv_base_offset, curr_count);
93
94     smpi_mpi_sendrecv((char *)rbuf + send_offset, curr_count, recv_type, dst, tag,
95                  (char *)rbuf + recv_offset, curr_count, recv_type, dst, tag,
96                  comm, &status);
97
98
99     curr_count *= 2;
100     i *= 2;
101     mask >>= 1;
102     phase++;
103   }
104
105   return MPI_SUCCESS;
106 }