1 /* Copyright (c) 2017. The SimGrid Team. All rights reserved. */
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. */
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>
17 /** @addtogroup SURF_plugin_energy
20 This is the energy plugin, enabling to account for the dissipated energy in the simulated platform.
22 The energy consumption of a link depends directly on its current traffic load. Specify that consumption in your
23 platform file as follows:
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" />
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).
37 To simulate the energy-related elements, first call the simgrid#energy#sg_link_energy_plugin_init() before your
39 and then use the following function to retrieve the consumption of a given link: MSG_link_get_consumed_energy().
42 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(link_energy, surf, "Logging specific to the SURF LinkEnergy plugin");
47 class LinkPowerRange {
52 LinkPowerRange(double idle, double busy) : idle(idle), busy(busy) {}
57 static simgrid::xbt::Extension<simgrid::s4u::Link, LinkEnergy> EXTENSION_ID;
59 explicit LinkEnergy(simgrid::s4u::Link* ptr);
62 double getALinkTotalPower();
63 void initWattsRangeList();
64 double getTotalEnergy();
70 simgrid::s4u::Link* link{};
72 std::vector<LinkPowerRange> power_range_watts_list{};
74 double total_energy{0.0};
75 double last_updated{0.0}; /*< Timestamp of the last energy update event*/
78 simgrid::xbt::Extension<simgrid::s4u::Link, LinkEnergy> LinkEnergy::EXTENSION_ID;
80 LinkEnergy::LinkEnergy(simgrid::s4u::Link* ptr) : link(ptr), last_updated(surf_get_clock())
84 LinkEnergy::~LinkEnergy() = default;
86 void LinkEnergy::update()
88 double power = getPower();
89 double now = surf_get_clock();
90 total_energy += power * (now - last_updated);
94 void LinkEnergy::initWattsRangeList()
97 if (!power_range_watts_list.empty())
100 const char* all_power_values_str = this->link->getProperty("watt_range");
102 if (all_power_values_str == nullptr)
105 std::vector<std::string> all_power_values;
106 boost::split(all_power_values, all_power_values_str, boost::is_any_of(","));
108 for (auto current_power_values_str : all_power_values) {
109 /* retrieve the power values associated */
110 std::vector<std::string> current_power_values;
111 boost::split(current_power_values, current_power_values_str, boost::is_any_of(":"));
112 xbt_assert(current_power_values.size() == 2, "Power properties incorrectly defined - "
113 "could not retrieve idle and busy power values for link %s",
114 this->link->getCname());
116 /* min_power corresponds to the idle power (link load = 0) */
117 /* max_power is the power consumed at 100% link load */
118 char* idle = bprintf("Invalid idle power value for link%s", this->link->getCname());
119 char* busy = bprintf("Invalid busy power value for %s", this->link->getCname());
121 double idleVal = xbt_str_parse_double((current_power_values.at(0)).c_str(), idle);
123 double busyVal = xbt_str_parse_double((current_power_values.at(1)).c_str(), busy);
125 this->power_range_watts_list.push_back(LinkPowerRange(idleVal, busyVal));
133 double LinkEnergy::getPower()
136 if (power_range_watts_list.empty())
139 auto range = power_range_watts_list[0];
141 double busy = range.busy;
142 double idle = range.idle;
144 double power_slope = busy - idle;
146 double normalized_link_usage = link->getUsage() / link->bandwidth();
147 double dynamic_power = power_slope * normalized_link_usage;
149 return idle + dynamic_power;
152 double LinkEnergy::getTotalEnergy()
155 return this->total_energy;
160 using simgrid::plugin::LinkEnergy;
162 /* **************************** events callback *************************** */
163 static void onCreation(simgrid::s4u::Link& link)
165 XBT_DEBUG("onCreation is called for link: %s", link.getCname());
166 link.extension_set(new LinkEnergy(&link));
169 static void onCommunicate(simgrid::surf::NetworkAction* action, simgrid::s4u::Host* src, simgrid::s4u::Host* dst)
171 XBT_DEBUG("onCommunicate is called");
172 for (simgrid::surf::LinkImpl* link : action->links()) {
177 XBT_DEBUG("Update link %s", link->getCname());
178 // Get the link_energy extension for the relevant link
179 LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
180 link_energy->initWattsRangeList();
181 link_energy->update();
185 static void onActionStateChange(simgrid::surf::NetworkAction* action)
187 XBT_DEBUG("onActionStateChange is called");
188 for (simgrid::surf::LinkImpl* link : action->links()) {
193 // Get the link_energy extension for the relevant link
194 LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
195 link_energy->update();
199 static void onLinkStateChange(simgrid::s4u::Link& link)
201 XBT_DEBUG("onLinkStateChange is called for link: %s", link.getCname());
203 LinkEnergy* link_energy = link.extension<LinkEnergy>();
204 link_energy->update();
207 static void onLinkDestruction(simgrid::s4u::Link& link)
209 XBT_DEBUG("onLinkDestruction is called for link: %s", link.getCname());
211 LinkEnergy* link_energy = link.extension<LinkEnergy>();
212 link_energy->update();
215 static void computeAndDisplayTotalEnergy()
217 std::vector<simgrid::s4u::Link*> link_list;
218 simgrid::s4u::Engine::getInstance()->getLinkList(&link_list);
219 double total_energy = 0.0; // Total dissipated energy (whole platform)
220 for (const auto link : link_list) {
221 LinkEnergy* link_energy = link->extension<LinkEnergy>();
223 double a_link_total_energy = link_energy->getTotalEnergy();
224 total_energy += a_link_total_energy;
225 const char* name = link->getCname();
226 if (strcmp(name, "__loopback__"))
227 XBT_INFO("Link '%s' total consumption: %f", name, a_link_total_energy);
230 XBT_INFO("Total energy over all links: %f", total_energy);
233 static void onSimulationEnd()
235 computeAndDisplayTotalEnergy();
237 /* **************************** Public interface *************************** */
239 /** \ingroup SURF_plugin_energy
240 * \brief Enable energy plugin
241 * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before
244 void sg_link_energy_plugin_init()
247 if (LinkEnergy::EXTENSION_ID.valid())
249 LinkEnergy::EXTENSION_ID = simgrid::s4u::Link::extension_create<LinkEnergy>();
251 simgrid::s4u::Link::onCreation.connect(&onCreation);
252 simgrid::s4u::Link::onStateChange.connect(&onLinkStateChange);
253 simgrid::s4u::Link::onDestruction.connect(&onLinkDestruction);
254 simgrid::s4u::Link::onCommunicationStateChange.connect(&onActionStateChange);
255 simgrid::s4u::Link::onCommunicate.connect(&onCommunicate);
256 simgrid::s4u::onSimulationEnd.connect(&onSimulationEnd);