Logo AND Algorithmique Numérique Distribuée

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