Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
try to get rid of some errors seen by scan-build
[simgrid.git] / src / kernel / routing / DragonflyZone.cpp
1 /* Copyright (c) 2014-2017. 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 "src/kernel/routing/DragonflyZone.hpp"
7 #include "src/kernel/routing/NetPoint.hpp"
8 #include "src/surf/network_interface.hpp"
9
10 #include <boost/algorithm/string/classification.hpp>
11 #include <boost/algorithm/string/split.hpp>
12 #include <string>
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_route_cluster_dragonfly, surf_route_cluster, "Dragonfly Routing part of surf");
15
16 namespace simgrid {
17 namespace kernel {
18 namespace routing {
19
20 DragonflyZone::DragonflyZone(NetZone* father, std::string name) : ClusterZone(father, name)
21 {
22 }
23
24 DragonflyZone::~DragonflyZone()
25 {
26   if (this->routers_ != nullptr) {
27     for (unsigned int i = 0; i < this->numGroups_ * this->numChassisPerGroup_ * this->numBladesPerChassis_; i++)
28       delete (routers_[i]);
29     xbt_free(routers_);
30   }
31 }
32
33 void DragonflyZone::rankId_to_coords(int rankId, unsigned int (*coords)[4])
34 {
35   // coords : group, chassis, blade, node
36   (*coords)[0]         = rankId / (numChassisPerGroup_ * numBladesPerChassis_ * numNodesPerBlade_);
37   rankId               = rankId % (numChassisPerGroup_ * numBladesPerChassis_ * numNodesPerBlade_);
38   (*coords)[1]         = rankId / (numBladesPerChassis_ * numNodesPerBlade_);
39   rankId               = rankId % (numBladesPerChassis_ * numNodesPerBlade_);
40   (*coords)[2]         = rankId / numNodesPerBlade_;
41   (*coords)[3]         = rankId % numNodesPerBlade_;
42 }
43
44 void DragonflyZone::parse_specific_arguments(ClusterCreationArgs* cluster)
45 {
46   std::vector<std::string> parameters;
47   std::vector<std::string> tmp;
48   boost::split(parameters, cluster->topo_parameters, boost::is_any_of(";"));
49
50   // TODO : we have to check for zeros and negative numbers, or it might crash
51   if (parameters.size() != 4) {
52     surf_parse_error(
53         "Dragonfly are defined by the number of groups, chassis per groups, blades per chassis, nodes per blade");
54   }
55
56   // Blue network : number of groups, number of links between each group
57   boost::split(tmp, parameters[0], boost::is_any_of(","));
58   if (tmp.size() != 2) {
59     surf_parse_error("Dragonfly topologies are defined by 3 levels with 2 elements each, and one with one element");
60   }
61
62   try {
63     this->numGroups_ = std::stoi(tmp[0]);
64   } catch (std::invalid_argument& ia) {
65     throw std::invalid_argument(std::string("Invalid number of groups:") + tmp[0]);
66   }
67
68   try {
69     this->numLinksBlue_ = std::stoi(tmp[1]);
70   } catch (std::invalid_argument& ia) {
71     throw std::invalid_argument(std::string("Invalid number of links for the blue level:") + tmp[1]);
72   }
73   // Black network : number of chassis/group, number of links between each router on the black network
74   boost::split(tmp, parameters[1], boost::is_any_of(","));
75   if (tmp.size() != 2) {
76     surf_parse_error("Dragonfly topologies are defined by 3 levels with 2 elements each, and one with one element");
77   }
78
79   try {
80     this->numChassisPerGroup_ = std::stoi(tmp[0]);
81   } catch (std::invalid_argument& ia) {
82     throw std::invalid_argument(std::string("Invalid number of groups:") + tmp[0]);
83   }
84
85   try {
86     this->numLinksBlack_ = std::stoi(tmp[1]);
87   } catch (std::invalid_argument& ia) {
88     throw std::invalid_argument(std::string("Invalid number of links for the black level:") + tmp[1]);
89   }
90
91   // Green network : number of blades/chassis, number of links between each router on the green network
92   boost::split(tmp, parameters[2], boost::is_any_of(","));
93   if (tmp.size() != 2) {
94     surf_parse_error("Dragonfly topologies are defined by 3 levels with 2 elements each, and one with one element");
95   }
96
97   try {
98     this->numBladesPerChassis_ = std::stoi(tmp[0]);
99   } catch (std::invalid_argument& ia) {
100     throw std::invalid_argument(std::string("Invalid number of groups:") + tmp[0]);
101   }
102
103   try {
104     this->numLinksGreen_ = std::stoi(tmp[1]);
105   } catch (std::invalid_argument& ia) {
106     throw std::invalid_argument(std::string("Invalid number of links for the green level:") + tmp[1]);
107   }
108
109   // The last part of topo_parameters should be the number of nodes per blade
110   try {
111     this->numNodesPerBlade_ = std::stoi(parameters[3]);
112   } catch (std::invalid_argument& ia) {
113     throw std::invalid_argument(std::string("Last parameter is not the amount of nodes per blade:") + parameters[3]);
114   }
115
116   this->cluster_ = cluster;
117 }
118
119 /*
120 * Generate the cluster once every node is created
121 */
122 void DragonflyZone::seal()
123 {
124   if (this->numNodesPerBlade_ == 0) {
125     return;
126   }
127
128   this->generateRouters();
129   this->generateLinks();
130 }
131
132 DragonflyRouter::DragonflyRouter(int group, int chassis, int blade) : group_(group), chassis_(chassis), blade_(blade)
133 {
134 }
135
136 DragonflyRouter::~DragonflyRouter()
137 {
138   if (this->myNodes_ != nullptr)
139     xbt_free(myNodes_);
140   if (this->greenLinks_ != nullptr)
141     xbt_free(greenLinks_);
142   if (this->blackLinks_ != nullptr)
143     xbt_free(blackLinks_);
144   if (this->blueLinks_ != nullptr)
145     xbt_free(blueLinks_);
146 }
147
148 void DragonflyZone::generateRouters()
149 {
150   this->routers_ = static_cast<DragonflyRouter**>(xbt_malloc0(this->numGroups_ * this->numChassisPerGroup_ *
151                                                               this->numBladesPerChassis_ * sizeof(DragonflyRouter*)));
152
153   for (unsigned int i = 0; i < this->numGroups_; i++) {
154     for (unsigned int j = 0; j < this->numChassisPerGroup_; j++) {
155       for (unsigned int k = 0; k < this->numBladesPerChassis_; k++) {
156         DragonflyRouter* router = new DragonflyRouter(i, j, k);
157         this->routers_[i * this->numChassisPerGroup_ * this->numBladesPerChassis_ + j * this->numBladesPerChassis_ +
158                        k] = router;
159       }
160     }
161   }
162 }
163
164 void DragonflyZone::createLink(std::string id, int numlinks, surf::LinkImpl** linkup, surf::LinkImpl** linkdown)
165 {
166   *linkup   = nullptr;
167   *linkdown = nullptr;
168   LinkCreationArgs linkTemplate;
169   linkTemplate.bandwidth = this->cluster_->bw * numlinks;
170   linkTemplate.latency   = this->cluster_->lat;
171   linkTemplate.policy    = this->cluster_->sharing_policy; // sthg to do with that ?
172   linkTemplate.id        = id;
173   sg_platf_new_link(&linkTemplate);
174   XBT_DEBUG("Generating link %s", id.c_str());
175   surf::LinkImpl* link;
176   std::string tmpID;
177   if (this->cluster_->sharing_policy == SURF_LINK_FULLDUPLEX) {
178     tmpID     = linkTemplate.id + "_UP";
179     link      = surf::LinkImpl::byName(tmpID);
180     *linkup   = link; // check link?
181     tmpID     = linkTemplate.id + "_DOWN";
182     link      = surf::LinkImpl::byName(tmpID);
183     *linkdown = link; // check link ?
184   } else {
185     link      = surf::LinkImpl::byName(linkTemplate.id);
186     *linkup   = link;
187     *linkdown = link;
188   }
189 }
190
191 void DragonflyZone::generateLinks()
192 {
193   static int uniqueId = 0;
194   surf::LinkImpl* linkup;
195   surf::LinkImpl* linkdown;
196
197   unsigned int numRouters = this->numGroups_ * this->numChassisPerGroup_ * this->numBladesPerChassis_;
198
199   if (this->cluster_->sharing_policy == SURF_LINK_FULLDUPLEX)
200     numLinksperLink_ = 2;
201
202   // Links from routers to their local nodes.
203   for (unsigned int i = 0; i < numRouters; i++) {
204     // allocate structures
205     this->routers_[i]->myNodes_ = static_cast<surf::LinkImpl**>(
206         xbt_malloc0(numLinksperLink_ * this->numNodesPerBlade_ * sizeof(surf::LinkImpl*)));
207     this->routers_[i]->greenLinks_ =
208         static_cast<surf::LinkImpl**>(xbt_malloc0(this->numBladesPerChassis_ * sizeof(surf::LinkImpl*)));
209     this->routers_[i]->blackLinks_ =
210         static_cast<surf::LinkImpl**>(xbt_malloc0(this->numChassisPerGroup_ * sizeof(surf::LinkImpl*)));
211
212     for (unsigned int j = 0; j < numLinksperLink_ * this->numNodesPerBlade_; j += numLinksperLink_) {
213       std::string id = "local_link_from_router_"+ std::to_string(i) + "_to_node_" +
214           std::to_string(j / numLinksperLink_) + "_" + std::to_string(uniqueId);
215       this->createLink(id, 1, &linkup, &linkdown);
216
217       if (this->cluster_->sharing_policy == SURF_LINK_FULLDUPLEX) {
218         this->routers_[i]->myNodes_[j]     = linkup;
219         this->routers_[i]->myNodes_[j + 1] = linkdown;
220       } else {
221         this->routers_[i]->myNodes_[j] = linkup;
222       }
223       uniqueId++;
224     }
225   }
226
227   // Green links from routers to same chassis routers - alltoall
228   for (unsigned int i = 0; i < this->numGroups_ * this->numChassisPerGroup_; i++) {
229     for (unsigned int j = 0; j < this->numBladesPerChassis_; j++) {
230       for (unsigned int k = j + 1; k < this->numBladesPerChassis_; k++) {
231         std::string id = "green_link_in_chassis_" + std::to_string(i % numChassisPerGroup_) +"_between_routers_" +
232             std::to_string(j) + "_and_" + std::to_string(k) + "_" + std::to_string(uniqueId);
233         this->createLink(id, this->numLinksGreen_, &linkup, &linkdown);
234
235         this->routers_[i * numBladesPerChassis_ + j]->greenLinks_[k] = linkup;
236         this->routers_[i * numBladesPerChassis_ + k]->greenLinks_[j] = linkdown;
237         uniqueId++;
238       }
239     }
240   }
241
242   // Black links from routers to same group routers - alltoall
243   for (unsigned int i = 0; i < this->numGroups_; i++) {
244     for (unsigned int j = 0; j < this->numChassisPerGroup_; j++) {
245       for (unsigned int k = j + 1; k < this->numChassisPerGroup_; k++) {
246         for (unsigned int l = 0; l < this->numBladesPerChassis_; l++) {
247           std::string id = "black_link_in_group_" + std::to_string(i) + "_between_chassis_" + std::to_string(j) +
248               "_and_" + std::to_string(k) +"_blade_" + std::to_string(l) + "_" + std::to_string(uniqueId);
249           this->createLink(id, this->numLinksBlack_, &linkup, &linkdown);
250
251           this->routers_[i * numBladesPerChassis_ * numChassisPerGroup_ + j * numBladesPerChassis_ + l]
252               ->blackLinks_[k] = linkup;
253           this->routers_[i * numBladesPerChassis_ * numChassisPerGroup_ + k * numBladesPerChassis_ + l]
254               ->blackLinks_[j] = linkdown;
255           uniqueId++;
256         }
257       }
258     }
259   }
260
261   // Blue links between groups - Not all routers involved, only one per group is linked to others. Let's say router n of
262   // each group is linked to group n.
263   // FIXME: in reality blue links may be attached to several different routers
264   for (unsigned int i = 0; i < this->numGroups_; i++) {
265     for (unsigned int j = i + 1; j < this->numGroups_; j++) {
266       unsigned int routernumi                = i * numBladesPerChassis_ * numChassisPerGroup_ + j;
267       unsigned int routernumj                = j * numBladesPerChassis_ * numChassisPerGroup_ + i;
268       this->routers_[routernumi]->blueLinks_ = static_cast<surf::LinkImpl**>(xbt_malloc0(sizeof(surf::LinkImpl*)));
269       this->routers_[routernumj]->blueLinks_ = static_cast<surf::LinkImpl**>(xbt_malloc0(sizeof(surf::LinkImpl*)));
270       std::string id = "blue_link_between_group_"+ std::to_string(i) +"_and_" + std::to_string(j) +"_routers_" +
271           std::to_string(routernumi) + "_and_" + std::to_string(routernumj) + "_" + std::to_string(uniqueId);
272       this->createLink(id, this->numLinksBlue_, &linkup, &linkdown);
273
274       this->routers_[routernumi]->blueLinks_[0] = linkup;
275       this->routers_[routernumj]->blueLinks_[0] = linkdown;
276       uniqueId++;
277     }
278   }
279 }
280
281 void DragonflyZone::getLocalRoute(NetPoint* src, NetPoint* dst, sg_platf_route_cbarg_t route, double* latency)
282 {
283   // Minimal routing version.
284   // TODO : non-minimal random one, and adaptive ?
285
286   if (dst->isRouter() || src->isRouter())
287     return;
288
289   XBT_VERB("dragonfly getLocalRout from '%s'[%u] to '%s'[%u]", src->name().c_str(), src->id(), dst->name().c_str(),
290            dst->id());
291
292   if ((src->id() == dst->id()) && hasLoopback_) {
293     std::pair<surf::LinkImpl*, surf::LinkImpl*> info = privateLinks_.at(src->id() * linkCountPerNode_);
294
295     route->link_list->push_back(info.first);
296     if (latency)
297       *latency += info.first->latency();
298     return;
299   }
300
301   unsigned int myCoords[4];
302   rankId_to_coords(src->id(), &myCoords);
303   unsigned int targetCoords[4];
304   rankId_to_coords(dst->id(), &targetCoords);
305   XBT_DEBUG("src : %u group, %u chassis, %u blade, %u node", myCoords[0], myCoords[1], myCoords[2], myCoords[3]);
306   XBT_DEBUG("dst : %u group, %u chassis, %u blade, %u node", targetCoords[0], targetCoords[1], targetCoords[2],
307             targetCoords[3]);
308
309   DragonflyRouter* myRouter = routers_[myCoords[0] * (numChassisPerGroup_ * numBladesPerChassis_) +
310                                        myCoords[1] * numBladesPerChassis_ + myCoords[2]];
311   DragonflyRouter* targetRouter = routers_[targetCoords[0] * (numChassisPerGroup_ * numBladesPerChassis_) +
312                                            targetCoords[1] * numBladesPerChassis_ + targetCoords[2]];
313   DragonflyRouter* currentRouter = myRouter;
314
315   // node->router local link
316   route->link_list->push_back(myRouter->myNodes_[myCoords[3] * numLinksperLink_]);
317   if (latency)
318     *latency += myRouter->myNodes_[myCoords[3] * numLinksperLink_]->latency();
319
320   if (hasLimiter_) { // limiter for sender
321     std::pair<surf::LinkImpl*, surf::LinkImpl*> info = privateLinks_.at(src->id() * linkCountPerNode_ + hasLoopback_);
322     route->link_list->push_back(info.first);
323   }
324
325   if (targetRouter != myRouter) {
326
327     // are we on a different group ?
328     if (targetRouter->group_ != currentRouter->group_) {
329       // go to the router of our group connected to this one.
330       if (currentRouter->blade_ != targetCoords[0]) {
331         // go to the nth router in our chassis
332         route->link_list->push_back(currentRouter->greenLinks_[targetCoords[0]]);
333         if (latency)
334           *latency += currentRouter->greenLinks_[targetCoords[0]]->latency();
335         currentRouter = routers_[myCoords[0] * (numChassisPerGroup_ * numBladesPerChassis_) +
336                                  myCoords[1] * numBladesPerChassis_ + targetCoords[0]];
337       }
338
339       if (currentRouter->chassis_ != 0) {
340         // go to the first chassis of our group
341         route->link_list->push_back(currentRouter->blackLinks_[0]);
342         if (latency)
343           *latency += currentRouter->blackLinks_[0]->latency();
344         currentRouter = routers_[myCoords[0] * (numChassisPerGroup_ * numBladesPerChassis_) + targetCoords[0]];
345       }
346
347       // go to destination group - the only optical hop
348       route->link_list->push_back(currentRouter->blueLinks_[0]);
349       if (latency)
350         *latency += currentRouter->blueLinks_[0]->latency();
351       currentRouter = routers_[targetCoords[0] * (numChassisPerGroup_ * numBladesPerChassis_) + myCoords[0]];
352     }
353
354     // same group, but same blade ?
355     if (targetRouter->blade_ != currentRouter->blade_) {
356       route->link_list->push_back(currentRouter->greenLinks_[targetCoords[2]]);
357       if (latency)
358         *latency += currentRouter->greenLinks_[targetCoords[2]]->latency();
359       currentRouter = routers_[targetCoords[0] * (numChassisPerGroup_ * numBladesPerChassis_) + targetCoords[2]];
360     }
361
362     // same blade, but same chassis ?
363     if (targetRouter->chassis_ != currentRouter->chassis_) {
364       route->link_list->push_back(currentRouter->blackLinks_[targetCoords[1]]);
365       if (latency)
366         *latency += currentRouter->blackLinks_[targetCoords[1]]->latency();
367     }
368   }
369
370   if (hasLimiter_) { // limiter for receiver
371     std::pair<surf::LinkImpl*, surf::LinkImpl*> info = privateLinks_.at(dst->id() * linkCountPerNode_ + hasLoopback_);
372     route->link_list->push_back(info.first);
373   }
374
375   // router->node local link
376   route->link_list->push_back(targetRouter->myNodes_[targetCoords[3] * numLinksperLink_ + numLinksperLink_ - 1]);
377   if (latency)
378     *latency += targetRouter->myNodes_[targetCoords[3] * numLinksperLink_ + numLinksperLink_ - 1]->latency();
379 }
380 }
381 }
382 } // namespace