Logo AND Algorithmique Numérique Distribuée

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