Logo AND Algorithmique Numérique Distribuée

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