Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Jenkins::Flag2: use ninja if avail; verbose builds
[simgrid.git] / examples / cpp / clusters-multicpu / s4u-clusters-multicpu.cpp
index 7633262..b2ca2e7 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2021. The SimGrid Team. All rights reserved.          */
+/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
 
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
@@ -20,34 +20,33 @@ class Sender {
   std::vector<sg4::Host*> hosts_;
 
 public:
-  explicit Sender(const std::vector<sg4::Host*> hosts) : hosts_{hosts} {}
+  explicit Sender(const std::vector<sg4::Host*>& hosts) : hosts_{hosts} {}
   void operator()() const
   {
     /* Vector in which we store all ongoing communications */
-    std::vector<sg4::CommPtr> pending_comms;
+    sg4::ActivitySet pending_comms;
 
     /* Make a vector of the mailboxes to use */
     std::vector<sg4::Mailbox*> mboxes;
 
     /* Start dispatching 1 message to all receivers */
-    std::string msg_content =
-        std::string("Hello, I'm alive and running on ") + std::string(sg4::this_actor::get_host()->get_name());
+    std::string msg_content = "Hello, I'm alive and running on " + sg4::this_actor::get_host()->get_name();
     for (const auto* host : hosts_) {
       /* Copy the data we send: the 'msg_content' variable is not a stable storage location.
        * It will be destroyed when this actor leaves the loop, ie before the receiver gets it */
       auto* payload = new std::string(msg_content);
 
       /* Create a communication representing the ongoing communication, and store it in pending_comms */
-      auto mbox = sg4::Mailbox::by_name(host->get_name());
+      auto* mbox = sg4::Mailbox::by_name(host->get_name());
       mboxes.push_back(mbox);
       sg4::CommPtr comm = mbox->put_async(payload, msg_size);
-      pending_comms.push_back(comm);
+      pending_comms.push(comm);
     }
 
     XBT_INFO("Done dispatching all messages");
 
     /* Now that all message exchanges were initiated, wait for their completion in one single call */
-    sg4::Comm::wait_all(&pending_comms);
+    pending_comms.wait_all();
 
     XBT_INFO("Goodbye now!");
   }
@@ -58,7 +57,7 @@ class Receiver {
 public:
   void operator()() const
   {
-    auto mbox     = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
+    auto* mbox    = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
     auto received = mbox->get_unique<std::string>();
     XBT_INFO("I got a '%s'.", received->c_str());
   }
@@ -84,12 +83,11 @@ public:
  *   CPU1   ...   CPU8
  *
  * @param zone Cluster netzone being created (usefull to create the hosts/links inside it)
- * @param coord Coordinates in the torus (e.g. "0,0,0", "0,1,0")
+ * @param coord Coordinates in the cluster
  * @param id Internal identifier in the torus (for information)
  * @return netpoint, gateway: the netpoint to the StarZone and CPU0 as gateway
  */
-static std::pair<simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*>
-create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned int>& /*coord*/, int id)
+static sg4::NetZone* create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned long>& /*coord*/, unsigned long id)
 {
   constexpr int num_cpus    = 8;     //!< Number of CPUs in the zone
   constexpr double speed    = 1e9;   //!< Speed of each CPU
@@ -102,34 +100,41 @@ create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned int>& /*coo
   /* setting my Torus parent zone */
   host_zone->set_parent(zone);
 
-  const sg4::Host* gateway = nullptr;
   /* create CPUs */
   for (int i = 0; i < num_cpus; i++) {
     std::string cpu_name  = hostname + "-cpu" + std::to_string(i);
-    const sg4::Host* host = host_zone->create_host(cpu_name, speed)->seal();
+    const sg4::Host* host = host_zone->create_host(cpu_name, speed);
     /* the first CPU is the gateway */
     if (i == 0)
-      gateway = host;
-    /* create 2 links for a full-duplex communication */
-    sg4::Link* link_up   = host_zone->create_link("link-up-" + cpu_name, link_bw)->set_latency(link_lat)->seal();
-    sg4::Link* link_down = host_zone->create_link("link-down-" + cpu_name, link_bw)->set_latency(link_lat)->seal();
-    /* link UP, connection from CPU to outer world */
-    host_zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {link_up}, false);
-    /* link DOWN, connection from outer to CPU */
-    host_zone->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, {link_down}, false);
+      host_zone->set_gateway(host->get_netpoint());
+    /* create split-duplex link */
+    auto* link = host_zone->create_split_duplex_link("link-" + cpu_name, link_bw)->set_latency(link_lat);
+    /* connecting CPU to outer world */
+    host_zone->add_route(host, nullptr, {{link, sg4::LinkInRoute::Direction::UP}}, true);
   }
-  return std::make_pair(host_zone->get_netpoint(), gateway->get_netpoint());
+  /* seal newly created netzone */
+  host_zone->seal();
+  return host_zone;
 }
 
 /*************************************************************************************************/
 /**
  * @brief Callback to create limiter link (1Gbs) for each netpoint
+ *
+ * The coord parameter depends on the cluster being created:
+ * - Torus: Direct translation of the Torus' dimensions, e.g. (0, 0, 0) for a 3-D Torus
+ * - Fat-Tree: A pair (level in the tree, id), e.g. (0, 0) for first leaf in the tree and (1,0) for the first switch at
+ * level 1.
+ * - Dragonfly: a tuple (group, chassis, blades/routers, nodes), e.g. (0, 0, 0, 0) for first node in the cluster. To
+ * identify the router inside a (group, chassis, blade), we use MAX_UINT in the last parameter (e.g. 0, 0, 0,
+ * 4294967295).
+ *
  * @param zone Torus netzone being created (usefull to create the hosts/links inside it)
- * @param coord Coordinates in the torus (e.g. "0,0,0", "0,1,0")
+ * @param coord Coordinates in the cluster
  * @param id Internal identifier in the torus (for information)
  * @return Limiter link
  */
-static sg4::Link* create_limiter(sg4::NetZone* zone, const std::vector<unsigned int>& /*coord*/, int id)
+static sg4::Link* create_limiter(sg4::NetZone* zone, const std::vector<unsigned long>& /*coord*/, unsigned long id)
 {
   return zone->create_link("limiter-" + std::to_string(id), 1e9)->seal();
 }
@@ -154,16 +159,16 @@ static sg4::Link* create_limiter(sg4::NetZone* zone, const std::vector<unsigned
  * B-----+----C (X-axis=2)
  *
  * For example, a communication from A to C goes through:
- * <tt> A->limiter(A)->link(A-B)->limiter(B)->link(B-C)->C </tt>
+ * <tt> A->limiter(A)->link(A-B)->limiter(B)->link(B-C)->limiter(C)->C </tt>
  *
  * More precisely, considering that A and C are StarZones, a
  * communication from A-CPU-3 to C-CPU-7 goes through:
  * 1) StarZone A: A-CPU-3 -> link-up-A-CPU-3 -> A-CPU-0
- * 2) A-CPU-0->limiter(A)->link(A-B)->limiter(B)->link(B-C)->C-CPU-0
+ * 2) A-CPU-0->limiter(A)->link(A-B)->limiter(B)->link(B-C)->limiter(C)->C-CPU-0
  * 3) StarZone C: C-CPU-0-> link-down-C-CPU-7 -> C-CPU-7
  *
  * Note that we don't have limiter links inside the StarZones(A, B, C),
- * but we have limiters in the Torus that are added to the links in the path (as we can see in "2)"")
+ * but we have limiters in the Torus that are added to the links in the path (as we can see in "2)")
  *
  * More details in: <a href="https://simgrid.org/doc/latest/Platform_examples.html?highlight=torus#torus-cluster">Torus
  * Cluster</a>
@@ -171,8 +176,8 @@ static sg4::Link* create_limiter(sg4::NetZone* zone, const std::vector<unsigned
 static void create_torus_cluster()
 {
   /* create the torus cluster, 10Gbs link between elements in the cluster */
-  sg4::create_torus_zone("cluster", nullptr, {2, 2, 2}, 10e9, 10e-6, sg4::Link::SharingPolicy::SPLITDUPLEX,
-                         create_hostzone, {}, create_limiter)
+  sg4::create_torus_zone("cluster", nullptr, {2, 2, 2}, {create_hostzone, {}, create_limiter}, 10e9, 10e-6,
+                         sg4::Link::SharingPolicy::SPLITDUPLEX)
       ->seal();
 }
 
@@ -182,25 +187,30 @@ static void create_torus_cluster()
  *
  * Creates a Fat-Tree cluster with 2 levels and 6 nodes
  * The following parameters are used to create this cluster:
- * - Levels: 2 - two-level cluster
- * - Down links: 2, 3 - L1 routers is connected to 2 elements, L2 routers to 3 elements
- * - Up links: 1, 2 - Each node (A-F) is connected to 1 L2 router, L2 routers are connected to 2 L1
+ * - Levels: 2 - two-level of switches in the cluster
+ * - Down links: 2, 3 - L2 routers is connected to 2 elements, L1 routers to 3 elements
+ * - Up links: 1, 2 - Each node (A-F) is connected to 1 L1 router, L1 routers are connected to 2 L2
  * - Link count: 1, 1 - Use 1 link in each level
  *
  * The first parameter describes how many levels we have.
  * The following ones describe the connection between the elements and must have exactly n_levels components.
  *
  *
- *                         S3     S4                <-- Level 1 routers
- *                        /   \  /  \
- *                       /     /\    \
- *   link: 10GBps -->   |    /    \   |
- *   (full-duplex)      |  /        \ |
- *                      S1           S2             <-- Level 2 routers
- *  link:10GBps  -->  / | \         / | \
+ *                         S3     S4                <-- Level 2 routers
+ *    link:limiter -      /   \  /  \
+ *                       +     ++    +
+ *    link: 10GBps -->  |     /  \    |
+ *     (full-duplex)    |    /    \   |
+ *                      +   +      +  +
+ *                      |  /        \ |
+ *                      S1           S2             <-- Level 1 routers
+ *   link:limiter ->    |             |
+ *                      +             +
+ *  link:10GBps  -->   /|\           /|\
+ *                    / | \         / | \
  *                   +  +  +       +  +  +
  *  link:limiter -> /   |   \     /   |   \
- *                 A    B    C   D    E    F        <-- Nodes
+ *                 A    B    C   D    E    F        <-- level 0 Nodes
  *
  * Each element (A to F) is a StarZone containing 8 Hosts.
  * The connection uses 2 links:
@@ -208,24 +218,22 @@ static void create_torus_cluster()
  * 2) link: 10Gbs link connecting the components (created automatically)
  *
  * For example, a communication from A to C goes through:
- * <tt> A->limiter(A)->link(A-S1)->link(S1-C)->->limiter(C)->C</tt>
+ * <tt> A->limiter(A)->link(A-S1)->limiter(S1)->link(S1-C)->->limiter(C)->C</tt>
  *
  * More precisely, considering that A and C are StarZones, a
  * communication from A-CPU-3 to C-CPU-7 goes through:
  * 1) StarZone A: A-CPU-3 -> link-up-A-CPU-3 -> A-CPU-0
- * 2) A-CPU-0->limiter(A)->link(A-S1)->link(S1-C)->limiter(C)->C-CPU-0
+ * 2) A-CPU-0->limiter(A)->link(A-S1)->limiter(S1)->link(S1-C)->limiter(C)->C-CPU-0
  * 3) StarZone C: C-CPU-0-> link-down-C-CPU-7 -> C-CPU-7
  *
- * Note that limiters are only valid for leaves, not routers.
- *
  * More details in: <a href="https://simgrid.org/doc/latest/Platform_examples.html#fat-tree-cluster">Fat-Tree
  * Cluster</a>
  */
 static void create_fatTree_cluster()
 {
   /* create the fat tree cluster, 10Gbs link between elements in the cluster */
-  sg4::create_fatTree_zone("cluster", nullptr, {2, {2, 3}, {1, 2}, {1, 1}}, 10e9, 10e-6,
-                           sg4::Link::SharingPolicy::SPLITDUPLEX, create_hostzone, {}, create_limiter)
+  sg4::create_fatTree_zone("cluster", nullptr, {2, {2, 3}, {1, 2}, {1, 1}}, {create_hostzone, {}, create_limiter}, 10e9,
+                           10e-6, sg4::Link::SharingPolicy::SPLITDUPLEX)
       ->seal();
 }
 
@@ -257,14 +265,12 @@ static void create_fatTree_cluster()
  *  Group 1
  *
  * Each element (A, B, C, etc) is a StarZone containing 8 Hosts.
- * The connection between nodes and routers (e.g. A->R1) uses 2 links:
+ * The connection between elements (e.g. A->R1) uses 2 links:
  * 1) limiter: a 1Gbs limiter link (set by user through the set_limiter callback)
  * 2) link: 10Gbs link connecting the components (created automatically)
  *
  * For example, a communication from A to C goes through:
- * <tt> A->limiter(A)->link(A-R1)->link(R1-R2)->limiter(C)->C</tt>
- *
- * Note that limiters are only valid for leaves, not routers.
+ * <tt> A->limiter(A)->link(A-R1)->limiter(R1)->link(R1-R2)->limiter(R2)->link(R2-C)limiter(C)->C</tt>
  *
  * More details in: <a href="https://simgrid.org/doc/latest/Platform_examples.html#dragonfly-cluster">Dragonfly
  * Cluster</a>
@@ -272,8 +278,8 @@ static void create_fatTree_cluster()
 static void create_dragonfly_cluster()
 {
   /* create the dragonfly cluster, 10Gbs link between elements in the cluster */
-  sg4::create_dragonfly_zone("cluster", nullptr, {{2, 2}, {2, 1}, {2, 2}, 2}, 10e9, 10e-6,
-                             sg4::Link::SharingPolicy::SPLITDUPLEX, create_hostzone, {}, create_limiter)
+  sg4::create_dragonfly_zone("cluster", nullptr, {{2, 2}, {2, 1}, {2, 2}, 2}, {create_hostzone, {}, create_limiter},
+                             10e9, 10e-6, sg4::Link::SharingPolicy::SPLITDUPLEX)
       ->seal();
 }
 
@@ -282,10 +288,9 @@ static void create_dragonfly_cluster()
 int main(int argc, char* argv[])
 {
   sg4::Engine e(&argc, argv);
-  std::string platform = argv[1];
 
   /* create platform */
-  if (platform == "torus")
+  if (std::string platform(argv[1]); platform == "torus")
     create_torus_cluster();
   else if (platform == "fatTree")
     create_fatTree_cluster();
@@ -297,7 +302,7 @@ int main(int argc, char* argv[])
   sg4::Actor::create("sender", host_list[0], Sender(host_list));
   /* create receiver in every host */
   for (auto* host : host_list) {
-    sg4::Actor::create(std::string("receiver-") + std::string(host->get_name()), host, Receiver());
+    sg4::Actor::create("receiver-" + host->get_name(), host, Receiver());
   }
 
   /* runs the simulation */