Logo AND Algorithmique Numérique Distribuée

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