Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
8f0937d36c5ead2af85121282959076b7922c213
[simgrid.git] / src / plugins / link_load.cpp
1 /* Copyright (c) 2017-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 #include <simgrid/plugins/load.h>
7 #include <simgrid/s4u/Comm.hpp>
8 #include <simgrid/s4u/Engine.hpp>
9
10 #include "src/kernel/activity/CommImpl.hpp"
11 #include "src/kernel/resource/NetworkModel.hpp"
12 #include "src/simgrid/module.hpp" // SIMGRID_REGISTER_PLUGIN
13
14 #include <limits>
15
16 SIMGRID_REGISTER_PLUGIN(link_load, "Link cumulated load.", &sg_link_load_plugin_init)
17
18 /** @defgroup plugin_link_load Plugin Link Cumulated Load
19
20  This is the link cumulated load plugin.
21  It enables to monitor how links are used over time by cumulating the amount of bytes that go through the link.
22
23  Usage:
24  - Call sg_link_load_plugin_init() between the SimGrid engine initialization and the platform loading.
25  - Track the links you want to monitor with sg_link_load_track() — you can untrack them later with
26  sg_link_load_untrack().
27  - Query the cumulated data about your link via these functions:
28    - sg_link_get_cum_load() to get the total load (in bytes) that went though the link since last reset.
29    - sg_link_get_avg_load() to get the average load (in bytes) that went though the link since last reset.
30    - sg_link_get_min_instantaneous_load() to get the peak minimum load (in bytes per second) observed on the link since
31  last reset.
32    - sg_link_get_max_instantaneous_load() to get the peak maximum load (in bytes per second) observer on the link since
33  last reset.
34  - Reset the counters on any tracked link via sg_link_load_reset().
35 */
36
37 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(link_load, kernel, "Logging specific to the LinkLoad plugin");
38
39 namespace simgrid::plugin {
40
41 class LinkLoad {
42   s4u::Link* link_{};      /*< The link onto which this data is attached*/
43   bool is_tracked_{false}; /*<Whether the link is tracked or not*/
44
45   double cumulated_bytes_{};      /*< Cumulated load since last reset*/
46   double min_bytes_per_second_{}; /*< Minimum instantaneous load observed since last reset*/
47   double max_bytes_per_second_{}; /*< Maximum instantaneous load observed since last reset*/
48   double last_reset_{};           /*< Timestamp of the last reset (init timestamp by default)*/
49   double last_updated_{};         /*< Timestamp of the last energy update event*/
50
51 public:
52   static xbt::Extension<s4u::Link, LinkLoad> EXTENSION_ID;
53
54   explicit LinkLoad(s4u::Link* ptr);
55
56   void track();
57   void untrack();
58   void reset();
59   void update();
60   double get_average_bytes();
61
62   /// Getter methods.
63   bool is_tracked() const { return is_tracked_; }
64   double get_cumulated_bytes();
65   double get_min_bytes_per_second();
66   double get_max_bytes_per_second();
67 };
68
69 xbt::Extension<s4u::Link, LinkLoad> LinkLoad::EXTENSION_ID;
70
71 LinkLoad::LinkLoad(s4u::Link* ptr) : link_(ptr)
72 {
73   XBT_DEBUG("Instantiating a LinkLoad for link '%s'", link_->get_cname());
74 }
75
76 void LinkLoad::track()
77 {
78   xbt_assert(not is_tracked_, "Trying to track load of link '%s' while it is already tracked, aborting.",
79              link_->get_cname());
80   XBT_DEBUG("Tracking load of link '%s'", link_->get_cname());
81
82   is_tracked_ = true;
83   reset();
84 }
85
86 void LinkLoad::untrack()
87 {
88   xbt_assert(is_tracked_, "Trying to untrack load of link '%s' while it is not tracked, aborting.", link_->get_cname());
89   XBT_DEBUG("Untracking load of link '%s'", link_->get_cname());
90
91   is_tracked_ = false;
92 }
93
94 void LinkLoad::reset()
95 {
96   XBT_DEBUG("Resetting load of link '%s'", link_->get_cname());
97
98   cumulated_bytes_      = 0.0;
99   min_bytes_per_second_ = std::numeric_limits<double>::max();
100   max_bytes_per_second_ = std::numeric_limits<double>::lowest();
101   XBT_DEBUG("min_bytes_per_second_ = %g", min_bytes_per_second_);
102   XBT_DEBUG("max_bytes_per_second_ = %g", max_bytes_per_second_);
103   last_reset_   = simgrid::s4u::Engine::get_clock();
104   last_updated_ = last_reset_;
105 }
106
107 void LinkLoad::update()
108 {
109   XBT_DEBUG("Updating load of link '%s'", link_->get_cname());
110   xbt_assert(is_tracked_,
111              "Trying to update load of link '%s' while it is NOT tracked, aborting."
112              " Please track your link with sg_link_load_track before trying to access any of its load metrics.",
113              link_->get_cname());
114
115   double current_instantaneous_bytes_per_second = link_->get_load();
116   double now                                    = simgrid::s4u::Engine::get_clock();
117
118   // Update minimum/maximum observed values if needed
119   min_bytes_per_second_ = std::min(min_bytes_per_second_, current_instantaneous_bytes_per_second);
120   max_bytes_per_second_ = std::max(max_bytes_per_second_, current_instantaneous_bytes_per_second);
121
122   // Update cumulated load
123   double duration_since_last_update = now - last_updated_;
124   double bytes_since_last_update    = duration_since_last_update * current_instantaneous_bytes_per_second;
125   XBT_DEBUG("Cumulated %g bytes since last update (duration of %g seconds)", bytes_since_last_update,
126             duration_since_last_update);
127   xbt_assert(bytes_since_last_update >= 0, "LinkLoad plugin inconsistency: negative amount of bytes is accumulated.");
128
129   cumulated_bytes_ += bytes_since_last_update;
130   last_updated_ = now;
131 }
132
133 double LinkLoad::get_cumulated_bytes()
134 {
135   update();
136   return cumulated_bytes_;
137 }
138 double LinkLoad::get_min_bytes_per_second()
139 {
140   update();
141   return min_bytes_per_second_;
142 }
143 double LinkLoad::get_max_bytes_per_second()
144 {
145   update();
146   return max_bytes_per_second_;
147 }
148
149 double LinkLoad::get_average_bytes()
150 {
151   update();
152
153   double now = simgrid::s4u::Engine::get_clock();
154   if (now > last_reset_)
155     return cumulated_bytes_ / (now - last_reset_);
156   else
157     return 0;
158 }
159
160 } // namespace simgrid::plugin
161
162 using simgrid::plugin::LinkLoad;
163
164 /* **************************** events  callback *************************** */
165 static void on_communication(const simgrid::s4u::Comm& comm)
166 {
167   auto* pimpl = static_cast<simgrid::kernel::activity::CommImpl*>(comm.get_impl());
168   for (auto const* link : pimpl->get_traversed_links()) {
169     if (link != nullptr && link->get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
170       auto* link_load = link->extension<LinkLoad>();
171       XBT_DEBUG("Update %s on Comm Start/End", link->get_cname());
172       if (link_load->is_tracked())
173         link_load->update();
174     }
175   }
176 }
177
178 /* **************************** Public interface *************************** */
179
180 /**
181  * @ingroup plugin_link_load
182  * @brief Initialize the link cumulated load plugin.
183  * @pre The energy plugin should NOT be initialized.
184  */
185 void sg_link_load_plugin_init()
186 {
187   xbt_assert(simgrid::s4u::Engine::get_instance()->get_host_count() == 0 &&
188                  simgrid::s4u::Engine::get_instance()->get_link_count() == 0,
189              "Please call sg_link_load_plugin_init() BEFORE initializing the platform.");
190   xbt_assert(not LinkLoad::EXTENSION_ID.valid(), "Double call to sg_link_load_plugin_init. Aborting.");
191   LinkLoad::EXTENSION_ID = simgrid::s4u::Link::extension_create<LinkLoad>();
192
193   // Attach new LinkLoad links created in the future.
194   simgrid::s4u::Link::on_creation_cb([](simgrid::s4u::Link& link) {
195     if (link.get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
196       XBT_DEBUG("Wired link '%s' created. Attaching a LinkLoad to it.", link.get_cname());
197       link.extension_set(new LinkLoad(&link));
198     } else {
199       XBT_DEBUG("Wireless link '%s' created. NOT attaching any LinkLoad to it.", link.get_cname());
200     }
201   });
202
203   // Call this plugin on some of the links' events.
204   simgrid::s4u::Comm::on_start_cb(&on_communication);
205   simgrid::s4u::Comm::on_completion_cb(&on_communication);
206
207   simgrid::s4u::Link::on_onoff_cb([](simgrid::s4u::Link const& link) {
208     if (link.get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
209       auto link_load = link.extension<LinkLoad>();
210       if (link_load->is_tracked())
211         link_load->update();
212     }
213   });
214   simgrid::s4u::Link::on_communication_state_change_cb([](simgrid::kernel::resource::NetworkAction const& action,
215                                                           simgrid::kernel::resource::Action::State /* previous */) {
216     for (auto const* link : action.get_links()) {
217       if (link != nullptr && link->get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
218         auto link_load = link->get_iface()->extension<LinkLoad>();
219         if (link_load->is_tracked())
220           link_load->update();
221       }
222     }
223   });
224 }
225
226 /**
227  * @ingroup plugin_link_load
228  * @brief Start the tracking of a link.
229  * @details This is required so the link cumulated load can be obtained later on.
230  * @pre The energy plugin should be initialized (cf. sg_link_load_plugin_init()).
231  * @pre The link should be in "untracked" state. In other words, do not call this function twice on the same link
232  * without a sg_link_load_untrack() call between them.
233  *
234  * @param link The link to track.
235  */
236 void sg_link_load_track(const_sg_link_t link)
237 {
238   xbt_assert(LinkLoad::EXTENSION_ID.valid(),
239              "Please call sg_link_load_plugin_init before sg_link_load_track. Aborting.");
240   link->extension<LinkLoad>()->track();
241 }
242
243 /**
244  * @ingroup plugin_link_load
245  * @brief Stop the tracking of a link.
246  * @details Once the tracking is stopped, the cumulated load of the link can no longer be obtained until
247  * sg_link_load_track() is called again on this link.
248  * @pre The energy plugin should be initialized (cf. sg_link_load_plugin_init()).
249  * @pre The link should be in "tracked" state. In other words, do not call this function twice on the same link without
250  * a sg_link_load_track() call between them.
251  *
252  * @param link The link to untrack.
253  */
254 void sg_link_load_untrack(const_sg_link_t link)
255 {
256   xbt_assert(LinkLoad::EXTENSION_ID.valid(),
257              "Please call sg_link_load_plugin_init before sg_link_load_untrack. Aborting.");
258   link->extension<LinkLoad>()->untrack();
259 }
260
261 /**
262  * @ingroup plugin_link_load
263  * @brief Resets the cumulated load counters of a link.
264  * @pre The energy plugin should be initialized (cf. sg_link_load_plugin_init()).
265  * @pre The link should be in "tracked" state (cf. sg_link_load_track()).
266  *
267  * @param link The link whose counters should be reset.
268  */
269 void sg_link_load_reset(const_sg_link_t link)
270 {
271   xbt_assert(LinkLoad::EXTENSION_ID.valid(),
272              "Please call sg_link_load_plugin_init before sg_link_load_reset. Aborting.");
273   link->extension<LinkLoad>()->reset();
274 }
275
276 /**
277  * @ingroup plugin_link_load
278  * @brief Get the cumulated load of a link (since the last call to sg_link_load_reset()).
279  * @pre The energy plugin should be initialized (cf. sg_link_load_plugin_init()).
280  * @pre The link should be in "tracked" state (cf. sg_link_load_track()).
281
282  * @param link The link whose cumulated load is requested.
283  * @return The load (in bytes) that passed through the given link since the last call to sg_link_load_reset.
284  */
285 double sg_link_get_cum_load(const_sg_link_t link)
286 {
287   xbt_assert(LinkLoad::EXTENSION_ID.valid(),
288              "Please call sg_link_load_plugin_init before sg_link_get_cum_load. Aborting.");
289   return link->extension<LinkLoad>()->get_cumulated_bytes();
290 }
291
292 /**
293  * @ingroup plugin_link_load
294  * @brief Get the average load of a link (since the last call to sg_link_load_reset()).
295  * @pre The energy plugin should be initialized (cf. sg_link_load_plugin_init()).
296  * @pre The link should be in "tracked" state (cf. sg_link_load_track()).
297
298  * @param link The link whose average load is requested.
299  * @return The average load (in bytes) that passed through the given link since the last call to sg_link_load_reset.
300  */
301 double sg_link_get_avg_load(const_sg_link_t link)
302 {
303   xbt_assert(LinkLoad::EXTENSION_ID.valid(),
304              "Please call sg_link_load_plugin_init before sg_link_get_avg_load. Aborting.");
305   return link->extension<LinkLoad>()->get_average_bytes();
306 }
307
308 /**
309  * @ingroup plugin_link_load
310  * @brief Get the minimum instantaneous load of a link (since the last call to sg_link_load_reset()).
311  * @pre The energy plugin should be initialized (cf. sg_link_load_plugin_init()).
312  * @pre The link should be in "tracked" state (cf. sg_link_load_track()).
313
314  * @param link The link whose average load is requested.
315  * @return The minimum load instantaneous load (in bytes per second) that passed through the given link since the last
316  call to sg_link_load_reset.
317  */
318 double sg_link_get_min_instantaneous_load(const_sg_link_t link)
319 {
320   xbt_assert(LinkLoad::EXTENSION_ID.valid(),
321              "Please call sg_link_load_plugin_init before sg_link_get_min_load. Aborting.");
322   return link->extension<LinkLoad>()->get_min_bytes_per_second();
323 }
324
325 /**
326  * @ingroup plugin_link_load
327  * @brief Get the maximum instantaneous load of a link (since the last call to sg_link_load_reset()).
328  * @pre The energy plugin should be initialized (cf. sg_link_load_plugin_init()).
329  * @pre The link should be in "tracked" state (cf. sg_link_load_track()).
330
331  * @param link The link whose average load is requested.
332  * @return The maximum load instantaneous load (in bytes per second) that passed through the given link since the last
333  call to sg_link_load_reset.
334  */
335 double sg_link_get_max_instantaneous_load(const_sg_link_t link)
336 {
337   xbt_assert(LinkLoad::EXTENSION_ID.valid(),
338              "Please call sg_link_load_plugin_init before sg_link_get_max_load. Aborting.");
339   return link->extension<LinkLoad>()->get_max_bytes_per_second();
340 }