Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge pull request #193 from Takishipp/signals
[simgrid.git] / src / smpi / colls / bcast / bcast-SMP-linear.cpp
1 /* Copyright (c) 2013-2017. 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 int bcast_SMP_linear_segment_byte = 8192;
10 namespace simgrid{
11 namespace smpi{
12 int Coll_bcast_SMP_linear::bcast(void *buf, int count,
13                                      MPI_Datatype datatype, int root,
14                                      MPI_Comm comm)
15 {
16   int tag = COLL_TAG_BCAST;
17   MPI_Status status;
18   MPI_Request request;
19   MPI_Request *request_array;
20   MPI_Status *status_array;
21   int rank, size;
22   int i;
23   MPI_Aint extent;
24   extent = datatype->get_extent();
25
26   rank = comm->rank();
27   size = comm->size();
28   if(comm->get_leaders_comm()==MPI_COMM_NULL){
29     comm->init_smp();
30   }
31   int num_core=1;
32   if (comm->is_uniform()){
33     num_core = comm->get_intra_comm()->size();
34   }else{
35     //implementation buggy in this case
36     return Coll_bcast_mpich::bcast( buf , count, datatype,
37               root, comm);
38   }
39
40   int segment = bcast_SMP_linear_segment_byte / extent;
41   segment =  segment == 0 ? 1 :segment;
42   int pipe_length = count / segment;
43   int remainder = count % segment;
44   int increment = segment * extent;
45
46
47   /* leader of each SMP do inter-communication
48      and act as a root for intra-communication */
49   int to_inter = (rank + num_core) % size;
50   int to_intra = (rank + 1) % size;
51   int from_inter = (rank - num_core + size) % size;
52   int from_intra = (rank + size - 1) % size;
53
54   // call native when MPI communication size is too small
55   if (size <= num_core) {
56     XBT_WARN("MPI_bcast_SMP_linear use default MPI_bcast.");
57     Coll_bcast_default::bcast(buf, count, datatype, root, comm);
58     return MPI_SUCCESS;
59   }
60   // if root is not zero send to rank zero first
61   if (root != 0) {
62     if (rank == root)
63       Request::send(buf, count, datatype, 0, tag, comm);
64     else if (rank == 0)
65       Request::recv(buf, count, datatype, root, tag, comm, &status);
66   }
67   // when a message is smaller than a block size => no pipeline
68   if (count <= segment) {
69     // case ROOT
70     if (rank == 0) {
71       Request::send(buf, count, datatype, to_inter, tag, comm);
72       Request::send(buf, count, datatype, to_intra, tag, comm);
73     }
74     // case last ROOT of each SMP
75     else if (rank == (((size - 1) / num_core) * num_core)) {
76       request = Request::irecv(buf, count, datatype, from_inter, tag, comm);
77       Request::wait(&request, &status);
78       Request::send(buf, count, datatype, to_intra, tag, comm);
79     }
80     // case intermediate ROOT of each SMP
81     else if (rank % num_core == 0) {
82       request = Request::irecv(buf, count, datatype, from_inter, tag, comm);
83       Request::wait(&request, &status);
84       Request::send(buf, count, datatype, to_inter, tag, comm);
85       Request::send(buf, count, datatype, to_intra, tag, comm);
86     }
87     // case last non-ROOT of each SMP
88     else if (((rank + 1) % num_core == 0) || (rank == (size - 1))) {
89       request = Request::irecv(buf, count, datatype, from_intra, tag, comm);
90       Request::wait(&request, &status);
91     }
92     // case intermediate non-ROOT of each SMP
93     else {
94       request = Request::irecv(buf, count, datatype, from_intra, tag, comm);
95       Request::wait(&request, &status);
96       Request::send(buf, count, datatype, to_intra, tag, comm);
97     }
98     return MPI_SUCCESS;
99   }
100   // pipeline bcast
101   else {
102     request_array =
103         (MPI_Request *) xbt_malloc((size + pipe_length) * sizeof(MPI_Request));
104     status_array =
105         (MPI_Status *) xbt_malloc((size + pipe_length) * sizeof(MPI_Status));
106
107     // case ROOT of each SMP
108     if (rank % num_core == 0) {
109       // case real root
110       if (rank == 0) {
111         for (i = 0; i < pipe_length; i++) {
112           Request::send((char *) buf + (i * increment), segment, datatype, to_inter,
113                    (tag + i), comm);
114           Request::send((char *) buf + (i * increment), segment, datatype, to_intra,
115                    (tag + i), comm);
116         }
117       }
118       // case last ROOT of each SMP
119       else if (rank == (((size - 1) / num_core) * num_core)) {
120         for (i = 0; i < pipe_length; i++) {
121           request_array[i] = Request::irecv((char *) buf + (i * increment), segment, datatype,
122                     from_inter, (tag + i), comm);
123         }
124         for (i = 0; i < pipe_length; i++) {
125           Request::wait(&request_array[i], &status);
126           Request::send((char *) buf + (i * increment), segment, datatype, to_intra,
127                    (tag + i), comm);
128         }
129       }
130       // case intermediate ROOT of each SMP
131       else {
132         for (i = 0; i < pipe_length; i++) {
133           request_array[i] = Request::irecv((char *) buf + (i * increment), segment, datatype,
134                     from_inter, (tag + i), comm);
135         }
136         for (i = 0; i < pipe_length; i++) {
137           Request::wait(&request_array[i], &status);
138           Request::send((char *) buf + (i * increment), segment, datatype, to_inter,
139                    (tag + i), comm);
140           Request::send((char *) buf + (i * increment), segment, datatype, to_intra,
141                    (tag + i), comm);
142         }
143       }
144     } else {                    // case last non-ROOT of each SMP
145       if (((rank + 1) % num_core == 0) || (rank == (size - 1))) {
146         for (i = 0; i < pipe_length; i++) {
147           request_array[i] = Request::irecv((char *) buf + (i * increment), segment, datatype,
148                     from_intra, (tag + i), comm);
149         }
150         for (i = 0; i < pipe_length; i++) {
151           Request::wait(&request_array[i], &status);
152         }
153       }
154       // case intermediate non-ROOT of each SMP
155       else {
156         for (i = 0; i < pipe_length; i++) {
157           request_array[i] = Request::irecv((char *) buf + (i * increment), segment, datatype,
158                     from_intra, (tag + i), comm);
159         }
160         for (i = 0; i < pipe_length; i++) {
161           Request::wait(&request_array[i], &status);
162           Request::send((char *) buf + (i * increment), segment, datatype, to_intra,
163                    (tag + i), comm);
164         }
165       }
166     }
167     free(request_array);
168     free(status_array);
169   }
170
171   // when count is not divisible by block size, use default BCAST for the remainder
172   if ((remainder != 0) && (count > segment)) {
173     XBT_WARN("MPI_bcast_SMP_linear use default MPI_bcast.");
174     Colls::bcast((char *) buf + (pipe_length * increment), remainder, datatype,
175               root, comm);
176   }
177
178   return MPI_SUCCESS;
179 }
180
181 }
182 }