X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/ed4256ba9779381bbc3b3ef3c818e56c8917d5c0..611d822b02f836d7abe031cced6adc4281ef4356:/src/surf/plugins/link_energy.cpp diff --git a/src/surf/plugins/link_energy.cpp b/src/surf/plugins/link_energy.cpp index 6487ce7411..062502b16d 100644 --- a/src/surf/plugins/link_energy.cpp +++ b/src/surf/plugins/link_energy.cpp @@ -1,29 +1,28 @@ -/* Copyright (c) 2010, 2012-2016. The SimGrid Team. All rights reserved. */ +/* Copyright (c) 2017-2018. The SimGrid Team. All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it * under the terms of the license (GNU LGPL) which comes with this package. */ -#include "simgrid/plugins/link_energy.h" -#include "simgrid/simix.hpp" -#include "src/surf/network_interface.hpp" +#include "simgrid/plugins/energy.h" #include "simgrid/s4u/Engine.hpp" +#include "src/surf/network_interface.hpp" +#include "surf/surf.hpp" + #include #include #include -#include -#include -#include /** @addtogroup SURF_plugin_energy - This is the energy plugin, enabling to account for the dissipated energy in the simulated platform. + This is the link energy plugin, accounting for the dissipated energy in the simulated platform. - The energy consumption of a link depends directly on its current traffic load. Specify that consumption in your platform file as follows: + The energy consumption of a link depends directly on its current traffic load. Specify that consumption in your + platform file as follows: \verbatim - - + + \endverbatim @@ -33,375 +32,200 @@ The second property means that when your host is turned off, it will dissipate only 10 Watts (please note that these values are arbitrary). - To simulate the energy-related elements, first call the simgrid#energy#sg_link_energy_plugin_init() before your #MSG_init(), - and then use the following function to retrieve the consumption of a given link: MSG_link_get_consumed_energy(). + To simulate the energy-related elements, first call the simgrid#energy#sg_link_energy_plugin_init() before your + #MSG_init(), + and then use the following function to retrieve the consumption of a given link: sg_link_get_consumed_energy(). */ -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(link_energy, surf, - "Logging specific to the SURF LinkEnergy plugin"); +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(link_energy, surf, "Logging specific to the SURF LinkEnergy plugin"); namespace simgrid { namespace plugin { -class LinkPowerRange { -public: - double idle; - double busy; - - LinkPowerRange(double idle, double busy) : - idle(idle), busy(busy) { - } -}; - class LinkEnergy { public: - static simgrid::xbt::Extension EXTENSION_ID; - - explicit LinkEnergy(simgrid::s4u::Link *ptr); - ~LinkEnergy(); + static simgrid::xbt::Extension EXTENSION_ID; - double getAveragePower(sg_link_t link); + explicit LinkEnergy(simgrid::s4u::Link* ptr); + ~LinkEnergy(); + void initWattsRangeList(); + double getConsumedEnergy(); + void update(); - double getALinkTotalPower(sg_link_t link); - void initWattsRangeList(); - double getLinkUsage(); - double getALinkTotalEnergy(sg_link_t link); - void update(); private: - double computeALinkPower(); - void computeALinkTotalEnergy(); - - + double getPower(); - simgrid::s4u::Link *link { }; -// simgrid::s4u::Link *up_link { }; -// simgrid::s4u::Link *down_link { }; + simgrid::s4u::Link* link_{}; - std::vector power_range_watts_list { }; - - std::map a_link_average_power { }; - - - std::map a_link_total_energy { }; - - double last_updated { 0.0 }; /*< Timestamp of the last energy update event*/ - double current_link_usage { 0.0 }; + bool inited_{false}; + double idle_{0.0}; + double busy_{0.0}; + double totalEnergy_{0.0}; + double lastUpdated_{0.0}; /*< Timestamp of the last energy update event*/ }; simgrid::xbt::Extension LinkEnergy::EXTENSION_ID; -//string replacing function -void replace(std::string& str, const std::string& from, const std::string& to, - size_t start_pos) { - str.replace(start_pos, from.length(), to); -} - -LinkEnergy::LinkEnergy(simgrid::s4u::Link *ptr) : - link(ptr), last_updated(surf_get_clock()) { - - /*std::string lnk_name(this->link->name()); - size_t lnk_down = lnk_name.find("_DOWN"); - size_t lnk_up = lnk_name.find("_UP"); - - if (lnk_down != std::string::npos) { - - this->down_link = this->link->byName(lnk_name.c_str()); - replace(lnk_name, "_DOWN", "_UP", lnk_down); - this->up_link = this->link->byName(lnk_name.c_str()); - - } else if (lnk_up != std::string::npos) { - - this->up_link = this->link->byName(lnk_name.c_str()); - replace(lnk_name, "_UP", "_DOWN", lnk_up); - this->down_link = this->link->byName(lnk_name.c_str()); - - } else { - this->up_link = this->link; - }*/ +LinkEnergy::LinkEnergy(simgrid::s4u::Link* ptr) : link_(ptr), lastUpdated_(surf_get_clock()) +{ } LinkEnergy::~LinkEnergy() = default; -void LinkEnergy::update() { - - this->current_link_usage = this->link->getUsage(); - - computeALinkTotalEnergy(); - - /* - double uplink_usage{0.0}; - double downlink_usage{0.0}; - - std::string lnk_name(this->link->name()); - size_t lnk_down = lnk_name.find("_DOWN"); - size_t lnk_up = lnk_name.find("_UP"); - - if (lnk_down != std::string::npos) { - - downlink_usage = lmm_constraint_get_usage( - this->down_link->pimpl_->constraint()); - - this->up_link->extension()->updateLinkUsage(); - - } else if (lnk_up != std::string::npos) { - - uplink_usage = lmm_constraint_get_usage( - this->up_link->pimpl_->constraint()); - - this->link_usage = downlink_usage + uplink_usage; - - } else { - - this->link_usage = lmm_constraint_get_usage( - this->up_link->pimpl_->constraint()); - - }*/ +void LinkEnergy::update() +{ + double power = getPower(); + double now = surf_get_clock(); + totalEnergy_ += power * (now - lastUpdated_); + lastUpdated_ = now; } -void LinkEnergy::initWattsRangeList() { - - if (!power_range_watts_list.empty()) - return; - - xbt_assert(power_range_watts_list.empty(), - "Power properties incorrectly defined - " - "could not retrieve idle and busy power values for link %s", - this->link->getCname()); - - const char* all_power_values_str = this->link->property("watt_range"); - - if (all_power_values_str == nullptr) - return; - - std::vector all_power_values; - boost::split(all_power_values, all_power_values_str, boost::is_any_of(",")); +void LinkEnergy::initWattsRangeList() +{ - for (auto current_power_values_str : all_power_values) { - /* retrieve the power values associated */ - std::vector current_power_values; - boost::split(current_power_values, current_power_values_str, - boost::is_any_of(":")); - xbt_assert(current_power_values.size() == 2, - "Power properties incorrectly defined - " - "could not retrieve idle and busy power values for link %s", - this->link->getCname()); + if (inited_) + return; + inited_ = true; - /* min_power corresponds to the idle power (link load = 0) */ - /* max_power is the power consumed at 100% link load */ - char* idle = bprintf("Invalid idle power value for link%s", - this->link->getCname()); - char* busy = bprintf("Invalid busy power value for %s", - this->link->getCname()); + const char* all_power_values_str = this->link_->getProperty("watt_range"); - double idleVal = xbt_str_parse_double( - (current_power_values.at(0)).c_str(), idle); + if (all_power_values_str == nullptr) + return; + std::vector all_power_values; + boost::split(all_power_values, all_power_values_str, boost::is_any_of(",")); - idleVal *= 2; // the idle value is multiplied by 2 because SimGrid's 1 link is mapped to 2 NetDevices in ECOFEN - double busyVal = xbt_str_parse_double( - (current_power_values.at(1)).c_str(), busy); - busyVal *= 2; // the busy value is multiplied by 2 because SimGrid's 1 link is mapped to 2 NetDevices in ECOFEN + for (auto current_power_values_str : all_power_values) { + /* retrieve the power values associated */ + std::vector current_power_values; + boost::split(current_power_values, current_power_values_str, boost::is_any_of(":")); + xbt_assert(current_power_values.size() == 2, + "Power properties incorrectly defined - could not retrieve idle and busy power values for link %s", + this->link_->get_cname()); + /* min_power corresponds to the idle power (link load = 0) */ + /* max_power is the power consumed at 100% link load */ + char* idleMsg = bprintf("Invalid idle power value for link%s", this->link_->get_cname()); + char* busyMsg = bprintf("Invalid busy power value for %s", this->link_->get_cname()); - this->power_range_watts_list.push_back( - LinkPowerRange(idleVal, busyVal)); - this->a_link_average_power[this->link->getCname()] = idleVal; - - - xbt_free(idle); - xbt_free(busy); - update(); - - } + idle_ = xbt_str_parse_double((current_power_values.at(0)).c_str(), idleMsg); + busy_ = xbt_str_parse_double((current_power_values.at(1)).c_str(), busyMsg); + xbt_free(idleMsg); + xbt_free(busyMsg); + update(); + } } -double LinkEnergy::computeALinkPower(){ - - if (!strcmp(this->link->getCname(), "__loopback__")) - return 0.0; - - double dynamic_power = 0.0; - - if (power_range_watts_list.empty()) { - return 0.0; - } - - xbt_assert(!power_range_watts_list.empty(), - "No power range properties specified for link %s", - this->link->getCname()); - - auto range = power_range_watts_list[0]; - - double busy = range.busy; - double idle = range.idle; - - double power_slope = busy - idle; +double LinkEnergy::getPower() +{ - if (this->last_updated > 0) { + if (!inited_) + return 0.0; - double normalized_link_usage = this->current_link_usage - / this->link->bandwidth(); - dynamic_power = power_slope * normalized_link_usage; + double power_slope = busy_ - idle_; - } else { + double normalized_link_usage = link_->getUsage() / link_->bandwidth(); + double dynamic_power = power_slope * normalized_link_usage; - dynamic_power = 0.0; - } - double current_power = idle + dynamic_power; - - return current_power; - -} - -void LinkEnergy::computeALinkTotalEnergy() { - - double current_power = computeALinkPower(); - double now = surf_get_clock(); - double a_link_total_energy = current_power * (now - last_updated); - this->a_link_total_energy[this->link->getCname()] += a_link_total_energy; - last_updated = now; + return idle_ + dynamic_power; } -double LinkEnergy::getLinkUsage() { - return this->current_link_usage; +double LinkEnergy::getConsumedEnergy() +{ + if (lastUpdated_ < surf_get_clock()) // We need to simcall this as it modifies the environment + simgrid::simix::kernelImmediate(std::bind(&LinkEnergy::update, this)); + return this->totalEnergy_; } - -double LinkEnergy::getAveragePower(sg_link_t link) { - - return this->a_link_average_power[link->getCname()]; -} - -double LinkEnergy::getALinkTotalEnergy(sg_link_t link) { - return this->a_link_total_energy[link->getCname()]; - -} - } } using simgrid::plugin::LinkEnergy; /* **************************** events callback *************************** */ -static void onCreation(simgrid::s4u::Link& link) { - XBT_DEBUG("onCreation is called for link: %s", link.getCname()); - link.extension_set(new LinkEnergy(&link)); -} +static void onCommunicate(simgrid::kernel::resource::NetworkAction* action, simgrid::s4u::Host* src, + simgrid::s4u::Host* dst) +{ + XBT_DEBUG("onCommunicate is called"); + for (simgrid::kernel::resource::LinkImpl* link : action->links()) { -static void onCommunicate(simgrid::surf::NetworkAction* action, - simgrid::s4u::Host* src, simgrid::s4u::Host* dst) { - XBT_DEBUG("onCommunicate is called"); - for (simgrid::surf::LinkImpl* link : action->links()) { + if (link == nullptr) + continue; - if (link == nullptr) - continue; - - // Get the link_energy extension for the relevant link - LinkEnergy* link_energy = link->piface_.extension(); - link_energy->initWattsRangeList(); - link_energy->update(); - } + XBT_DEBUG("Update link %s", link->get_cname()); + LinkEnergy* link_energy = link->piface_.extension(); + link_energy->initWattsRangeList(); + link_energy->update(); + } } -static void onActionStateChange(simgrid::surf::NetworkAction* action) { - XBT_DEBUG("onActionStateChange is called"); - for (simgrid::surf::LinkImpl* link : action->links()) { +static void onSimulationEnd() +{ + std::vector links = simgrid::s4u::Engine::getInstance()->getAllLinks(); - if (link == nullptr) - continue; + double total_energy = 0.0; // Total dissipated energy (whole platform) + for (const auto link : links) { + double link_energy = link->extension()->getConsumedEnergy(); + total_energy += link_energy; + } - // Get the link_energy extension for the relevant link - LinkEnergy* link_energy = link->piface_.extension(); - link_energy->update(); - } + XBT_INFO("Total energy over all links: %f", total_energy); } +/* **************************** Public interface *************************** */ -static void onLinkStateChange(simgrid::s4u::Link &link) { - XBT_DEBUG("onLinkStateChange is called for link: %s", link.getCname()); - - LinkEnergy *link_energy = link.extension(); - link_energy->update(); +int sg_link_energy_is_inited() +{ + return LinkEnergy::EXTENSION_ID.valid(); } +/** \ingroup SURF_plugin_energy + * \brief Enable energy plugin + * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before + * #MSG_init(). + */ +void sg_link_energy_plugin_init() +{ -static void onLinkDestruction(simgrid::s4u::Link& link) { - XBT_DEBUG("onLinkDestruction is called for link: %s", link.getCname()); + if (LinkEnergy::EXTENSION_ID.valid()) + return; + LinkEnergy::EXTENSION_ID = simgrid::s4u::Link::extension_create(); - LinkEnergy *link_energy = link.extension(); - link_energy->update(); -} + xbt_assert(sg_host_count() == 0, "Please call sg_link_energy_plugin_init() before initializing the platform."); + simgrid::s4u::Link::onCreation.connect([](simgrid::s4u::Link& link) { + link.extension_set(new LinkEnergy(&link)); + }); -static void computAndDisplayTotalEnergy() { - simgrid::s4u::Link* link = nullptr; - sg_link_t* link_list = link->listLink(); - int link_count = link->linkCount(); - double total_power = 0.0; // Total power consumption (whole platform) - double total_energy = 0.0; - double total_time = 0.0; - for (int i = 0; i < link_count; i++) { - if (link_list[i] != nullptr) { - LinkEnergy* link_energy = link_list[i]->extension(); - link_energy->update(); - - double a_link_average_power = link_energy->getAveragePower( - link_list[i]); - total_power += a_link_average_power; - - double a_link_total_energy = link_energy->getALinkTotalEnergy( - link_list[i]); - total_energy += a_link_total_energy; - const char* name = link_list[i]->getCname(); - if (strcmp(name, "__loopback__")) { - XBT_INFO("%s Usage %f Bandwidth %f Power %f Energy %f", name, - link_energy->getLinkUsage(), link_list[i]->bandwidth(), - a_link_average_power, a_link_total_energy); - } - } - } - - XBT_INFO("SgTotalPower %f SgTotalEnergy %f SgTransferTime %f", total_power, - total_energy, surf_get_clock()); - xbt_free(link_list); -} + simgrid::s4u::Link::onStateChange.connect([](simgrid::s4u::Link& link) { + link.extension()->update(); + }); -static void onSimulationEnd() { - computAndDisplayTotalEnergy(); -} -/* **************************** Public interface *************************** */ -SG_BEGIN_DECL() -/** \ingroup SURF_plugin_energy - * \brief Enable energy plugin - * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before #MSG_init(). - */ -void sg_link_energy_plugin_init() { - - if (LinkEnergy::EXTENSION_ID.valid()) - return; - LinkEnergy::EXTENSION_ID = - simgrid::s4u::Link::extension_create(); + simgrid::s4u::Link::onDestruction.connect([](simgrid::s4u::Link& link) { + if (strcmp(link.get_cname(), "__loopback__")) + XBT_INFO("Energy consumption of link '%s': %f Joules", link.get_cname(), + link.extension()->getConsumedEnergy()); + }); - simgrid::s4u::Link::onCreation.connect(&onCreation); - simgrid::s4u::Link::onStateChange.connect(&onLinkStateChange); - simgrid::s4u::Link::onDestruction.connect(&onLinkDestruction); - simgrid::s4u::Link::onCommunicationStateChange.connect( - &onActionStateChange); - simgrid::s4u::Link::onCommunicate.connect(&onCommunicate); - simgrid::s4u::onSimulationEnd.connect(&onSimulationEnd); + simgrid::s4u::Link::onCommunicationStateChange.connect([](simgrid::kernel::resource::NetworkAction* action) { + for (simgrid::kernel::resource::LinkImpl* link : action->links()) { + if (link != nullptr) + link->piface_.extension()->update(); + } + }); + simgrid::s4u::Link::onCommunicate.connect(&onCommunicate); + simgrid::s4u::onSimulationEnd.connect(&onSimulationEnd); } -/** @brief Returns the total energy consumed by the link so far (in Joules) +/** @ingroup plugin_energy + * @brief Returns the total energy consumed by the link so far (in Joules) * - * See also @ref SURF_plugin_energy. + * Please note that since the consumption is lazily updated, it may require a simcall to update it. + * The result is that the actor requesting this value will be interrupted, + * the value will be updated in kernel mode before returning the control to the requesting actor. */ - -double sg_link_get_usage(sg_link_t link) { - xbt_assert(LinkEnergy::EXTENSION_ID.valid(), - "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization."); - LinkEnergy *link_energy = link->extension(); - return link_energy->getLinkUsage(); +double sg_link_get_consumed_energy(sg_link_t link) +{ + return link->extension()->getConsumedEnergy(); } - -SG_END_DECL()