Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
7cb94371cca72adf9473cae5533debc7ac010083
[simgrid.git] / examples / cpp / network-factors / s4u-network-factors.cpp
1 /* Copyright (c) 2010-2023. 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 set custom communication factors
7  *
8  * It uses the netzone interface to register 2 callbacks that are called for every communications.
9  *
10  * These factors are used to change the communication time depending on the message size
11  * and destination.
12  *
13  * This example uses factors obtained by some experiments on dahu cluster in Grid'5000.
14  * You should change the values according to the calibration of your enviroment.
15  */
16
17 #include <map>
18 #include <simgrid/s4u.hpp>
19 namespace sg4 = simgrid::s4u;
20
21 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_network_factors, "Messages specific for this s4u example");
22
23 /* Factors used in this platform, for remote and local communications
24  * Obtained from dahu cluster. Obs.: just an example, change the values according
25  * to the calibration on your environment */
26 static const std::map<double, double> REMOTE_BW_FACTOR = {
27     {0, 1.0000000000000002},         {8000, 1.0000000000000002},     {15798, 0.07435006650635523},
28     {64000, 0.3163352696348148},     {6000000, 0.13003278960133288}, {42672591, 0.10354740223279707},
29     {160097505, 0.40258935729656503}};
30 static const std::map<double, double> LOCAL_BW_FACTOR = {{0, 0.17591906192813994},
31                                                          {16000, 0.12119203247138953},
32                                                          {6000000, 0.07551057012803415},
33                                                          {36900419, 0.04281516758309203},
34                                                          {160097505, 0.17440518795992602}};
35
36 static const std::map<double, double> REMOTE_LAT_FACTOR = {{0, 0.0},
37                                                            {8000, 1731.7102918851567},
38                                                            {15798, 1441.073993161278},
39                                                            {64000, 1761.4784830658123},
40                                                            {6000000, 0.0},
41                                                            {42672591, 0.0},
42                                                            {160097505, 970913.4558162984}};
43 static const std::map<double, double> LOCAL_LAT_FACTOR  = {
44     {0, 0.0}, {16000, 650.2212383180362}, {6000000, 0.0}, {36900419, 0.0}, {160097505, 1017885.3518765072}};
45
46 /* bandwidth and latency used on the platform */
47 constexpr static double BW_REMOTE = 12.5e9;
48 constexpr static double BW_LOCAL  = 25e9;
49 constexpr static double LATENCY   = .1e-6;
50
51 /*************************************************************************************************/
52 /** @brief Create a simple platform based on Dahu cluster */
53 static void load_platform()
54 {
55   /**
56    * Inspired on dahu cluster on Grenoble
57    *     ________________
58    *     |               |
59    *     |     dahu      |
60    *     |_______________|
61    *     / /   | |    \ \
62    *    / /    | |     \ \     <-- 12.5GBps links
63    *   / /     | |      \ \
64    * host1     ...      hostN
65    */
66
67   auto* root         = sg4::create_star_zone("dahu");
68   std::string prefix = "dahu-";
69   std::string suffix = ".grid5000.fr";
70
71   for (int id = 0; id < 32; id++) {
72     std::string hostname = prefix + std::to_string(id) + suffix;
73     /* create host */
74     const sg4::Host* host = root->create_host(hostname, 1)->set_core_count(32)->seal();
75     /* create UP/DOWN link */
76     const sg4::Link* l = root->create_split_duplex_link(hostname, BW_REMOTE)->set_latency(LATENCY)->seal();
77
78     /* add link UP/DOWN for communications from the host */
79     root->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
80
81     sg4::Link* loopback = root->create_link(hostname + "_loopback", BW_LOCAL)->set_latency(LATENCY)->seal();
82     root->add_route(host, host, {loopback});
83   }
84
85   root->seal();
86 }
87
88 /*************************************************************************************************/
89 /** @brief Auxiliary method to get factor for a message size */
90 static double get_factor_from_map(const std::map<double, double>& factors, double size)
91 {
92   double factor = 1.0;
93   for (auto const& [factor_size, factor_value] : factors) {
94     if (size < factor_size) {
95       break;
96     } else {
97       factor = factor_value;
98     }
99   }
100   return factor;
101 }
102
103 /**
104  * @brief Callback to set latency factor for a communication
105  *
106  * Set different factors for local (loopback) and remote communications.
107  * Function signature is defined by API
108  *
109  * @param size Message size
110  * @param src Host origin
111  * @param dst Host destination
112  */
113 static double latency_factor_cb(double size, const sg4::Host* src, const sg4::Host* dst,
114                                 const std::vector<sg4::Link*>& /*links*/,
115                                 const std::unordered_set<sg4::NetZone*>& /*netzones*/)
116 {
117   if (src->get_name() == dst->get_name()) {
118     /* local communication factors */
119     return get_factor_from_map(LOCAL_LAT_FACTOR, size);
120   } else {
121     return get_factor_from_map(REMOTE_LAT_FACTOR, size);
122   }
123 }
124
125 /**
126  * @brief Callback to set bandwidth factor for a communication
127  *
128  * Set different factors for local (loopback) and remote communications.
129  * Function signature is defined by API
130  *
131  * @param size Message size
132  * @param src Host origin
133  * @param dst Host destination
134  */
135 static double bandwidth_factor_cb(double size, const sg4::Host* src, const sg4::Host* dst,
136                                   const std::vector<sg4::Link*>& /*links*/,
137                                   const std::unordered_set<sg4::NetZone*>& /*netzones*/)
138 {
139   if (src->get_name() == dst->get_name()) {
140     /* local communication factors */
141     return get_factor_from_map(LOCAL_BW_FACTOR, size);
142   } else {
143     return get_factor_from_map(REMOTE_BW_FACTOR, size);
144   }
145 }
146
147 /*************************************************************************************************/
148 class Sender {
149   std::vector<sg4::Host*> hosts_;
150   double crosstraffic_ = 1.0;
151
152 public:
153   explicit Sender(const std::vector<sg4::Host*>& hosts, bool crosstraffic) : hosts_{hosts}
154   {
155     if (crosstraffic)
156       crosstraffic_ = 1.05; // add crosstraffic load if it is enabled
157   }
158   void operator()() const
159   {
160     const std::vector<double> msg_sizes = {64e3, 64e6, 64e9}; // 64KB, 64MB, 64GB
161
162     for (double size : msg_sizes) {
163       for (const auto* host : hosts_) {
164         std::string msg;
165         /* calculating the estimated communication time depending of message size and destination */
166         if (host->get_name() == sg4::this_actor::get_host()->get_name()) {
167           double lat_factor = get_factor_from_map(LOCAL_LAT_FACTOR, size);
168           double bw_factor  = get_factor_from_map(LOCAL_BW_FACTOR, size);
169           /* Account for crosstraffic on local communications
170            * local communications use only a single link and crosstraffic impact on resource sharing
171            * on remote communications, we don't see this effect since we have split-duplex links */
172           double est_time =
173               sg4::Engine::get_clock() + size / (BW_LOCAL * bw_factor / crosstraffic_) + LATENCY * lat_factor;
174
175           msg = "Local communication: size=" + std::to_string(size) + ". Use bw_factor=" + std::to_string(bw_factor) +
176                 " lat_factor=" + std::to_string(lat_factor) + ". Estimated finished time=" + std::to_string(est_time);
177         } else {
178           double lat_factor = get_factor_from_map(REMOTE_LAT_FACTOR, size);
179           double bw_factor  = get_factor_from_map(REMOTE_BW_FACTOR, size);
180           double est_time   = sg4::Engine::get_clock() + (size / (BW_REMOTE * bw_factor)) + LATENCY * lat_factor * 2;
181           msg = "Remote communication: size=" + std::to_string(size) + ". Use bw_factor=" + std::to_string(bw_factor) +
182                 " lat_factor=" + std::to_string(lat_factor) + ". Estimated finished time=" + std::to_string(est_time);
183         }
184
185         /* Create a communication representing the ongoing communication */
186         auto* mbox    = sg4::Mailbox::by_name(host->get_name());
187         auto* payload = new std::string(msg);
188         mbox->put(payload, static_cast<uint64_t>(size));
189       }
190     }
191
192     XBT_INFO("Done dispatching all messages");
193     /* sending message to stop receivers */
194     for (const auto* host : hosts_) {
195       auto* mbox = sg4::Mailbox::by_name(host->get_name());
196       mbox->put(new std::string("finalize"), 0);
197     }
198   }
199 };
200
201 /* Receiver actor: wait for messages on the mailbox identified by the hostname */
202 class Receiver {
203 public:
204   void operator()() const
205   {
206     auto* mbox = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
207     // Receiving the message was all we were supposed to do
208     for (bool cont = true; cont;) {
209       auto received = mbox->get_unique<std::string>();
210       XBT_INFO("I got a '%s'.", received->c_str());
211       cont = (*received != "finalize"); // If it's a finalize message, we're done
212     }
213   }
214 };
215
216 /*************************************************************************************************/
217 int main(int argc, char* argv[])
218 {
219   bool crosstraffic = true;
220   sg4::Engine e(&argc, argv);
221   /* setting network model to default one */
222   sg4::Engine::set_config("network/model:CM02");
223
224   /* test with crosstraffic disabled */
225   if (argc == 2 && std::string(argv[1]) == "disable_crosstraffic") {
226     sg4::Engine::set_config("network/crosstraffic:0");
227     crosstraffic = false;
228   }
229
230   /* create platform */
231   load_platform();
232   /* setting network factors callbacks */
233   e.get_netzone_root()->set_latency_factor_cb(latency_factor_cb);
234   e.get_netzone_root()->set_bandwidth_factor_cb(bandwidth_factor_cb);
235
236   sg4::Host* host        = e.host_by_name("dahu-1.grid5000.fr");
237   sg4::Host* host_remote = e.host_by_name("dahu-10.grid5000.fr");
238   sg4::Actor::create("receiver-local", host, Receiver());
239   sg4::Actor::create("receiver-remote", host_remote, Receiver());
240   sg4::Actor::create("sender" + host->get_name(), host, Sender({host, host_remote}, crosstraffic));
241
242   /* runs the simulation */
243   e.run();
244
245   return 0;
246 }