Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
New example: Torus cluster of multi-cpu hosts(Star Zones)
[simgrid.git] / examples / cpp / torus-multicpu / s4u-torus-multicpu.cpp
1 /* Copyright (c) 2010-2021. 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 /* This example shows how to build a torus cluster with multi-core hosts.
7  *
8  * However, each leaf in the torus is a StarZone, composed of several CPUs
9  *
10  * Each actor runs in a specific CPU. One sender broadcasts a message to all receivers.
11  */
12
13 #include "simgrid/s4u.hpp"
14 namespace sg4 = simgrid::s4u;
15
16 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_torus_multicpu, "Messages specific for this s4u example");
17
18 class Sender {
19   long msg_size = 1e6; /* message size in bytes */
20   std::vector<sg4::Host*> hosts_;
21
22 public:
23   explicit Sender(const std::vector<sg4::Host*> hosts) : hosts_{hosts} {}
24   void operator()() const
25   {
26     /* Vector in which we store all ongoing communications */
27     std::vector<sg4::CommPtr> pending_comms;
28
29     /* Make a vector of the mailboxes to use */
30     std::vector<sg4::Mailbox*> mboxes;
31
32     /* Start dispatching 1 message to all receivers */
33     std::string msg_content =
34         std::string("Hello, I'm alive and running on ") + std::string(sg4::this_actor::get_host()->get_name());
35     for (const auto* host : hosts_) {
36       /* Copy the data we send: the 'msg_content' variable is not a stable storage location.
37        * It will be destroyed when this actor leaves the loop, ie before the receiver gets it */
38       auto* payload = new std::string(msg_content);
39
40       /* Create a communication representing the ongoing communication, and store it in pending_comms */
41       auto mbox = sg4::Mailbox::by_name(host->get_name());
42       mboxes.push_back(mbox);
43       sg4::CommPtr comm = mbox->put_async(payload, msg_size);
44       pending_comms.push_back(comm);
45     }
46
47     XBT_INFO("Done dispatching all messages");
48
49     /* Now that all message exchanges were initiated, wait for their completion in one single call */
50     sg4::Comm::wait_all(&pending_comms);
51
52     XBT_INFO("Goodbye now!");
53   }
54 };
55
56 /* Receiver actor: wait for 1 message on the mailbox identified by the hostname */
57 class Receiver {
58 public:
59   void operator()()
60   {
61     auto mbox     = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
62     auto received = mbox->get_unique<std::string>();
63     XBT_INFO("I got a '%s'.", received->c_str());
64   }
65 };
66
67 /**
68  * @brief Callback to set a Torus leaf/element
69  *
70  * In our example, each leaf if a StarZone, composed of 8 CPUs.
71  * Each CPU is modeled as a host, connected to the outer world through a high-speed PCI link.
72  * Obs.: CPU0 is the gateway for this zone
73  *
74  *    (outer world)
75  *        CPU0 (gateway)
76  *         |
77  *         |
78  *         +
79  *        /|\
80  *       / | \  <-- 100Gbs, 10us link (single link for UP/DOWN communications)
81  *      /  |  \
82  *     /   |   \
83  *  CPU1  ...  CPU8
84  *
85  * @param zone Torus netzone being created (usefull to create the hosts/links inside it)
86  * @param coord Coordinates in the torus (e.g. "0,0,0", "0,1,0")
87  * @param id Internal identifier in the torus (for information)
88  * @return netpoint, gateway: the netpoint to the StarZone and CPU0 as gateway
89  */
90 static std::pair<simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*>
91 create_hostzone(sg4::NetZone* zone, const std::vector<unsigned int>& coord, int id)
92 {
93   constexpr int num_cpus    = 8;     //!< Number of CPUs in the zone
94   constexpr double speed    = 1e9;   //!< Speed of each CPU
95   constexpr double link_bw  = 100e9; //!< Link bw connecting the CPU
96   constexpr double link_lat = 1e-9;  //!< Link latency
97
98   std::string hostname = "host" + std::to_string(id);
99   /* create the StarZone */
100   auto* host_zone = sg4::create_star_zone(hostname);
101   /* setting my Torus parent zone */
102   host_zone->set_parent(zone);
103
104   sg4::Host* gateway = nullptr;
105   /* create CPUs */
106   for (int i = 0; i < num_cpus; i++) {
107     std::string cpu_name = hostname + "-cpu" + std::to_string(i);
108     sg4::Host* host      = host_zone->create_host(cpu_name, speed)->seal();
109     /* the first CPU is the gateway */
110     if (i == 0)
111       gateway = host;
112     /* create link and add route to external world */
113     sg4::Link* link = host_zone->create_link("link-" + cpu_name, link_bw)->set_latency(link_lat)->seal();
114     host_zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {link});
115   }
116   return std::make_pair(host_zone->get_netpoint(), gateway->get_netpoint());
117 }
118
119 /**
120  * @brief Creates a TORUS cluster
121  *
122  * Creates a TORUS clustes with dimensions 2x2x2
123  *
124  * The cluster has 8 elements/leaves in total. Each element is a StarZone containing 8 Hosts.
125  * Each pair in the torus is connected through 2 links:
126  * 1) limiter: a 1Gbs limiter link (set by user through the set_limiter callback)
127  * 2) link: 10Gbs link connecting the components (created automatically)
128  *
129  * (Y-axis=2)
130  * A
131  * |
132  * |   X (Z-axis=2)
133  * |  / 10 Gbs
134  * | +
135  * |/ limiter=1Gps
136  * B----------C (X-axis=2)
137  *
138  * For example, a communication from A to C goes through:
139  * <tt> A->limiter(A)->link(A-B)->limiter(B)->link(B-C)->C </tt>
140  *
141  * More precisely, considering that A and C are StarZones, a
142  * communication from A-CPU-3 to C-CPU-7 goes through:
143  * 1) StarZone A: A-CPU-3 -> link -> A-CPU-0
144  * 2) A-CPU-0->limiter(A)->link(A-B)->limiter(B)->link(B-C)->C-CPU-0
145  * 3) C-CPU-0-> link -> C-CPU-7
146  *
147  * More details in: <a href="https://simgrid.org/doc/latest/Platform_examples.html?highlight=torus#torus-cluster">Torus
148  * Cluster</a>
149  */
150 static void create_torus_cluster()
151 {
152   // Callback to create limiter link (1Gbs) for each host
153   auto create_limiter = [](sg4::NetZone* zone, const std::vector<unsigned int>& coord, int id) -> sg4::Link* {
154     return zone->create_link("limiter-" + std::to_string(id), 1e9)->seal();
155   };
156
157   /* create the torus cluster, 10Gbs link between elements in the cluster */
158   sg4::create_torus_zone("cluster", nullptr, {2, 2, 2}, 10e9, 10e-6, sg4::Link::SharingPolicy::SPLITDUPLEX,
159                          create_hostzone, {}, create_limiter)
160       ->seal();
161 }
162
163 int main(int argc, char* argv[])
164 {
165   sg4::Engine e(&argc, argv);
166
167   /* create platform */
168   create_torus_cluster();
169
170   std::vector<sg4::Host*> host_list = e.get_all_hosts();
171   /* create the sender actor running on first host */
172   sg4::Actor::create("sender", host_list[0], Sender(host_list));
173   /* create receiver in every host */
174   for (auto* host : host_list) {
175     sg4::Actor::create(std::string("receiver-") + std::string(host->get_name()), host, Receiver());
176   }
177
178   /* runs the simulation */
179   e.run();
180
181   return 0;
182 }