Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Make the link_energy plugin actually compile
[simgrid.git] / src / surf / plugins / link_energy.cpp
1 /* Copyright (c) 2010, 2012-2016. 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/link_energy.h"
7 #include "simgrid/s4u/Engine.hpp"
8 #include "simgrid/simix.hpp"
9 #include "src/surf/network_interface.hpp"
10 #include <boost/algorithm/string/classification.hpp>
11 #include <boost/algorithm/string/split.hpp>
12 #include <map>
13 #include <string>
14 #include <utility>
15 #include <vector>
16
17 /** @addtogroup SURF_plugin_energy
18
19
20  This is the energy plugin, enabling to account for the dissipated energy in the simulated platform.
21
22  The energy consumption of a link depends directly on its current traffic load. Specify that consumption in your
23  platform file as follows:
24
25  \verbatim
26  <link id="SWITCH1" bandwidth="125000000" latency="5E-5" sharing_policy="SHARED" >
27  <prop id="watts" value="100.0:200.0" />
28  <prop id="watt_off" value="10" />
29  </link>
30  \endverbatim
31
32  The first property means that when your link is switched on, but without anything to do, it will dissipate 100 Watts.
33  If it's fully loaded, it will dissipate 200 Watts. If its load is at 50%, then it will dissipate 150 Watts.
34  The second property means that when your host is turned off, it will dissipate only 10 Watts (please note that these
35  values are arbitrary).
36
37  To simulate the energy-related elements, first call the simgrid#energy#sg_link_energy_plugin_init() before your
38  #MSG_init(),
39  and then use the following function to retrieve the consumption of a given link: MSG_link_get_consumed_energy().
40  */
41
42 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(link_energy, surf, "Logging specific to the SURF LinkEnergy plugin");
43
44 namespace simgrid {
45 namespace plugin {
46
47 class LinkPowerRange {
48 public:
49   double idle;
50   double busy;
51
52   LinkPowerRange(double idle, double busy) : idle(idle), busy(busy) {}
53 };
54
55 class LinkEnergy {
56 public:
57   static simgrid::xbt::Extension<simgrid::s4u::Link, LinkEnergy> EXTENSION_ID;
58
59   explicit LinkEnergy(simgrid::s4u::Link* ptr);
60   ~LinkEnergy();
61
62   double getALinkTotalPower(sg_link_t link);
63   void initWattsRangeList();
64   double getLinkUsage();
65   double getALinkTotalEnergy(sg_link_t link);
66   void update();
67
68 private:
69   double computeALinkPower();
70   void computeALinkTotalEnergy();
71
72   simgrid::s4u::Link* link{};
73   //    simgrid::s4u::Link *up_link { };
74   //    simgrid::s4u::Link *down_link { };
75
76   std::vector<LinkPowerRange> power_range_watts_list{};
77
78   double a_link_total_energy{0.0};
79
80   double last_updated{0.0}; /*< Timestamp of the last energy update event*/
81   double current_link_usage{0.0};
82 };
83
84 simgrid::xbt::Extension<simgrid::s4u::Link, LinkEnergy> LinkEnergy::EXTENSION_ID;
85
86 LinkEnergy::LinkEnergy(simgrid::s4u::Link* ptr) : link(ptr), last_updated(surf_get_clock())
87 {
88
89   /*std::string lnk_name(this->link->name());
90    size_t lnk_down = lnk_name.find("_DOWN");
91    size_t lnk_up = lnk_name.find("_UP");
92
93    if (lnk_down != std::string::npos) {
94
95    this->down_link = this->link->byName(lnk_name.c_str());
96    replace(lnk_name, "_DOWN", "_UP", lnk_down);
97    this->up_link = this->link->byName(lnk_name.c_str());
98
99    } else if (lnk_up != std::string::npos) {
100
101    this->up_link = this->link->byName(lnk_name.c_str());
102    replace(lnk_name, "_UP", "_DOWN", lnk_up);
103    this->down_link = this->link->byName(lnk_name.c_str());
104
105    } else {
106    this->up_link = this->link;
107    }*/
108 }
109
110 LinkEnergy::~LinkEnergy() = default;
111
112 void LinkEnergy::update()
113 {
114
115   this->current_link_usage = this->link->getUsage();
116
117   computeALinkTotalEnergy();
118
119   /*
120    double uplink_usage{0.0};
121    double downlink_usage{0.0};
122
123    std::string lnk_name(this->link->name());
124    size_t lnk_down = lnk_name.find("_DOWN");
125    size_t lnk_up = lnk_name.find("_UP");
126
127    if (lnk_down != std::string::npos) {
128
129    downlink_usage = lmm_constraint_get_usage(
130    this->down_link->pimpl_->constraint());
131
132    this->up_link->extension<LinkEnergy>()->updateLinkUsage();
133
134    } else if (lnk_up != std::string::npos) {
135
136    uplink_usage = lmm_constraint_get_usage(
137    this->up_link->pimpl_->constraint());
138
139    this->link_usage = downlink_usage + uplink_usage;
140
141    } else {
142
143    this->link_usage = lmm_constraint_get_usage(
144    this->up_link->pimpl_->constraint());
145
146    }*/
147 }
148
149 void LinkEnergy::initWattsRangeList()
150 {
151
152   if (!power_range_watts_list.empty())
153     return;
154
155   xbt_assert(power_range_watts_list.empty(), "Power properties incorrectly defined - "
156                                              "could not retrieve idle and busy power values for link %s",
157              this->link->getCname());
158
159   const char* all_power_values_str = this->link->getProperty("watt_range");
160
161   if (all_power_values_str == nullptr)
162     return;
163
164   std::vector<std::string> all_power_values;
165   boost::split(all_power_values, all_power_values_str, boost::is_any_of(","));
166
167   for (auto current_power_values_str : all_power_values) {
168     /* retrieve the power values associated */
169     std::vector<std::string> current_power_values;
170     boost::split(current_power_values, current_power_values_str, boost::is_any_of(":"));
171     xbt_assert(current_power_values.size() == 2, "Power properties incorrectly defined - "
172                                                  "could not retrieve idle and busy power values for link %s",
173                this->link->getCname());
174
175     /* min_power corresponds to the idle power (link load = 0) */
176     /* max_power is the power consumed at 100% link load       */
177     char* idle = bprintf("Invalid idle power value for link%s", this->link->getCname());
178     char* busy = bprintf("Invalid busy power value for %s", this->link->getCname());
179
180     double idleVal = xbt_str_parse_double((current_power_values.at(0)).c_str(), idle);
181
182     idleVal *= 2; // the idle value is multiplied by 2 because SimGrid's 1 link is mapped to 2 NetDevices in ECOFEN
183     double busyVal = xbt_str_parse_double((current_power_values.at(1)).c_str(), busy);
184     busyVal *= 2; // the busy value is multiplied by 2 because SimGrid's 1 link is mapped to 2 NetDevices in ECOFEN
185
186     this->power_range_watts_list.push_back(LinkPowerRange(idleVal, busyVal));
187
188     xbt_free(idle);
189     xbt_free(busy);
190     update();
191   }
192 }
193
194 double LinkEnergy::computeALinkPower()
195 {
196
197   double dynamic_power = 0.0;
198
199   if (power_range_watts_list.empty()) {
200     return 0.0;
201   }
202
203   auto range = power_range_watts_list[0];
204
205   double busy = range.busy;
206   double idle = range.idle;
207
208   double power_slope = busy - idle;
209
210   if (this->last_updated > 0) {
211
212     double normalized_link_usage = this->current_link_usage / this->link->bandwidth();
213     dynamic_power                = power_slope * normalized_link_usage;
214
215   } else {
216     dynamic_power = 0.0;
217   }
218   double current_power = idle + dynamic_power;
219
220   return current_power;
221 }
222
223 void LinkEnergy::computeALinkTotalEnergy()
224 {
225   double current_power = computeALinkPower();
226   double now           = surf_get_clock();
227   this->a_link_total_energy += current_power * (now - last_updated);
228   last_updated = now;
229 }
230
231 double LinkEnergy::getLinkUsage()
232 {
233   return this->current_link_usage;
234 }
235
236 double LinkEnergy::getALinkTotalEnergy(sg_link_t link)
237 {
238   return this->a_link_total_energy;
239 }
240 }
241 }
242
243 using simgrid::plugin::LinkEnergy;
244
245 /* **************************** events  callback *************************** */
246 static void onCreation(simgrid::s4u::Link& link)
247 {
248   XBT_DEBUG("onCreation is called for link: %s", link.getCname());
249   link.extension_set(new LinkEnergy(&link));
250 }
251
252 static void onCommunicate(simgrid::surf::NetworkAction* action, simgrid::s4u::Host* src, simgrid::s4u::Host* dst)
253 {
254   XBT_DEBUG("onCommunicate is called");
255   for (simgrid::surf::LinkImpl* link : action->links()) {
256
257     if (link == nullptr)
258       continue;
259
260     // Get the link_energy extension for the relevant link
261     LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
262     link_energy->initWattsRangeList();
263     link_energy->update();
264   }
265 }
266
267 static void onActionStateChange(simgrid::surf::NetworkAction* action)
268 {
269   XBT_DEBUG("onActionStateChange is called");
270   for (simgrid::surf::LinkImpl* link : action->links()) {
271
272     if (link == nullptr)
273       continue;
274
275     // Get the link_energy extension for the relevant link
276     LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
277     link_energy->update();
278   }
279 }
280
281 static void onLinkStateChange(simgrid::s4u::Link& link)
282 {
283   XBT_DEBUG("onLinkStateChange is called for link: %s", link.getCname());
284
285   LinkEnergy* link_energy = link.extension<LinkEnergy>();
286   link_energy->update();
287 }
288
289 static void onLinkDestruction(simgrid::s4u::Link& link)
290 {
291   XBT_DEBUG("onLinkDestruction is called for link: %s", link.getCname());
292
293   LinkEnergy* link_energy = link.extension<LinkEnergy>();
294   link_energy->update();
295 }
296
297 static void computeAndDisplayTotalEnergy()
298 {
299   std::vector<simgrid::s4u::Link*> link_list;
300   simgrid::s4u::Engine::getInstance()->getLinkList(&link_list);
301   double total_power  = 0.0; // Total power consumption (whole platform)
302   double total_energy = 0.0;
303   for (const auto link : link_list) {
304     LinkEnergy* link_energy = link->extension<LinkEnergy>();
305     link_energy->update();
306
307     double a_link_total_energy = link_energy->getALinkTotalEnergy(link);
308     total_energy += a_link_total_energy;
309     const char* name = link->getCname();
310     if (strcmp(name, "__loopback__")) {
311       XBT_INFO("%s Usage %f Bandwidth %f Energy %f", name, link_energy->getLinkUsage(), link->bandwidth(),
312                a_link_total_energy);
313     }
314   }
315
316   XBT_INFO("SgTotalPower %f SgTotalEnergy %f SgTransferTime %f", total_power, total_energy, surf_get_clock());
317 }
318
319 static void onSimulationEnd()
320 {
321   computeAndDisplayTotalEnergy();
322 }
323 /* **************************** Public interface *************************** */
324 SG_BEGIN_DECL()
325 /** \ingroup SURF_plugin_energy
326  * \brief Enable energy plugin
327  * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before
328  * #MSG_init().
329  */
330 void sg_link_energy_plugin_init()
331 {
332
333   if (LinkEnergy::EXTENSION_ID.valid())
334     return;
335   LinkEnergy::EXTENSION_ID = simgrid::s4u::Link::extension_create<LinkEnergy>();
336
337   simgrid::s4u::Link::onCreation.connect(&onCreation);
338   simgrid::s4u::Link::onStateChange.connect(&onLinkStateChange);
339   simgrid::s4u::Link::onDestruction.connect(&onLinkDestruction);
340   simgrid::s4u::Link::onCommunicationStateChange.connect(&onActionStateChange);
341   simgrid::s4u::Link::onCommunicate.connect(&onCommunicate);
342   simgrid::s4u::onSimulationEnd.connect(&onSimulationEnd);
343 }
344
345 /** @brief Returns the total energy consumed by the link so far (in Joules)
346  *
347  *  See also @ref SURF_plugin_energy.
348  */
349
350 double sg_link_get_usage(sg_link_t link)
351 {
352   xbt_assert(LinkEnergy::EXTENSION_ID.valid(),
353              "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
354   LinkEnergy* link_energy = link->extension<LinkEnergy>();
355   return link_energy->getLinkUsage();
356 }
357
358 SG_END_DECL()