Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
link energy: code simplification
[simgrid.git] / src / surf / plugins / link_energy.cpp
1 /* Copyright (c) 2017. 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/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 link energy plugin, accounting 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="125Mbps" latency="5us" sharing_policy="SHARED" >
27  <prop id="watt_range" 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: sg_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 LinkEnergy {
48 public:
49   static simgrid::xbt::Extension<simgrid::s4u::Link, LinkEnergy> EXTENSION_ID;
50
51   explicit LinkEnergy(simgrid::s4u::Link* ptr);
52   ~LinkEnergy();
53
54   double getALinkTotalPower();
55   void initWattsRangeList();
56   double getTotalEnergy();
57   void update();
58
59 private:
60   double getPower();
61
62   simgrid::s4u::Link* link{};
63
64   bool inited{false};
65   double idle{0.0};
66   double busy{0.0};
67
68   double total_energy{0.0};
69   double last_updated{0.0}; /*< Timestamp of the last energy update event*/
70 };
71
72 simgrid::xbt::Extension<simgrid::s4u::Link, LinkEnergy> LinkEnergy::EXTENSION_ID;
73
74 LinkEnergy::LinkEnergy(simgrid::s4u::Link* ptr) : link(ptr), last_updated(surf_get_clock())
75 {
76 }
77
78 LinkEnergy::~LinkEnergy() = default;
79
80 void LinkEnergy::update()
81 {
82   double power = getPower();
83   double now   = surf_get_clock();
84   total_energy += power * (now - last_updated);
85   last_updated = now;
86 }
87
88 void LinkEnergy::initWattsRangeList()
89 {
90
91   if (inited)
92     return;
93   inited = true;
94
95   const char* all_power_values_str = this->link->getProperty("watt_range");
96
97   if (all_power_values_str == nullptr)
98     return;
99
100   std::vector<std::string> all_power_values;
101   boost::split(all_power_values, all_power_values_str, boost::is_any_of(","));
102
103   for (auto current_power_values_str : all_power_values) {
104     /* retrieve the power values associated */
105     std::vector<std::string> current_power_values;
106     boost::split(current_power_values, current_power_values_str, boost::is_any_of(":"));
107     xbt_assert(current_power_values.size() == 2,
108                "Power properties incorrectly defined - could not retrieve idle and busy power values for link %s",
109                this->link->getCname());
110
111     /* min_power corresponds to the idle power (link load = 0) */
112     /* max_power is the power consumed at 100% link load       */
113     char* idleMsg = bprintf("Invalid idle power value for link%s", this->link->getCname());
114     char* busyMsg = bprintf("Invalid busy power value for %s", this->link->getCname());
115
116     idle = xbt_str_parse_double((current_power_values.at(0)).c_str(), idleMsg);
117     busy = xbt_str_parse_double((current_power_values.at(1)).c_str(), busyMsg);
118
119     xbt_free(idleMsg);
120     xbt_free(busyMsg);
121     update();
122   }
123 }
124
125 double LinkEnergy::getPower()
126 {
127
128   if (!inited)
129     return 0.0;
130
131   double power_slope = busy - idle;
132
133   double normalized_link_usage = link->getUsage() / link->bandwidth();
134   double dynamic_power         = power_slope * normalized_link_usage;
135
136   return idle + dynamic_power;
137 }
138
139 double LinkEnergy::getTotalEnergy()
140 {
141   update();
142   return this->total_energy;
143 }
144 }
145 }
146
147 using simgrid::plugin::LinkEnergy;
148
149 /* **************************** events  callback *************************** */
150 static void onCreation(simgrid::s4u::Link& link)
151 {
152   XBT_DEBUG("onCreation is called for link: %s", link.getCname());
153   link.extension_set(new LinkEnergy(&link));
154 }
155
156 static void onCommunicate(simgrid::surf::NetworkAction* action, simgrid::s4u::Host* src, simgrid::s4u::Host* dst)
157 {
158   XBT_DEBUG("onCommunicate is called");
159   for (simgrid::surf::LinkImpl* link : action->links()) {
160
161     if (link == nullptr)
162       continue;
163
164     XBT_DEBUG("Update link %s", link->getCname());
165     // Get the link_energy extension for the relevant link
166     LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
167     link_energy->initWattsRangeList();
168     link_energy->update();
169   }
170 }
171
172 static void onActionStateChange(simgrid::surf::NetworkAction* action)
173 {
174   XBT_DEBUG("onActionStateChange is called");
175   for (simgrid::surf::LinkImpl* link : action->links()) {
176
177     if (link == nullptr)
178       continue;
179
180     // Get the link_energy extension for the relevant link
181     LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
182     link_energy->update();
183   }
184 }
185
186 static void onLinkStateChange(simgrid::s4u::Link& link)
187 {
188   XBT_DEBUG("onLinkStateChange is called for link: %s", link.getCname());
189
190   LinkEnergy* link_energy = link.extension<LinkEnergy>();
191   link_energy->update();
192 }
193
194 static void onLinkDestruction(simgrid::s4u::Link& link)
195 {
196   XBT_DEBUG("onLinkDestruction is called for link: %s", link.getCname());
197
198   LinkEnergy* link_energy = link.extension<LinkEnergy>();
199   link_energy->update();
200 }
201
202 static void computeAndDisplayTotalEnergy()
203 {
204   std::vector<simgrid::s4u::Link*> link_list;
205   simgrid::s4u::Engine::getInstance()->getLinkList(&link_list);
206   double total_energy = 0.0; // Total dissipated energy (whole platform)
207   for (const auto link : link_list) {
208     LinkEnergy* link_energy = link->extension<LinkEnergy>();
209
210     double a_link_total_energy = link_energy->getTotalEnergy();
211     total_energy += a_link_total_energy;
212     const char* name = link->getCname();
213     if (strcmp(name, "__loopback__"))
214       XBT_INFO("Link '%s' total consumption: %f", name, a_link_total_energy);
215   }
216
217   XBT_INFO("Total energy over all links: %f", total_energy);
218 }
219
220 static void onSimulationEnd()
221 {
222   computeAndDisplayTotalEnergy();
223 }
224 /* **************************** Public interface *************************** */
225 SG_BEGIN_DECL()
226 /** \ingroup SURF_plugin_energy
227  * \brief Enable energy plugin
228  * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before
229  * #MSG_init().
230  */
231 void sg_link_energy_plugin_init()
232 {
233
234   if (LinkEnergy::EXTENSION_ID.valid())
235     return;
236   LinkEnergy::EXTENSION_ID = simgrid::s4u::Link::extension_create<LinkEnergy>();
237
238   simgrid::s4u::Link::onCreation.connect(&onCreation);
239   simgrid::s4u::Link::onStateChange.connect(&onLinkStateChange);
240   simgrid::s4u::Link::onDestruction.connect(&onLinkDestruction);
241   simgrid::s4u::Link::onCommunicationStateChange.connect(&onActionStateChange);
242   simgrid::s4u::Link::onCommunicate.connect(&onCommunicate);
243   simgrid::s4u::onSimulationEnd.connect(&onSimulationEnd);
244 }
245
246 SG_END_DECL()