Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
snake_casing the dirty page tracking plugin
[simgrid.git] / src / surf / plugins / link_energy.cpp
index 6487ce7..0640a88 100644 (file)
@@ -1,29 +1,27 @@
-/* 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 <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
-#include <string>
-#include <utility>
-#include <vector>
-#include <map>
 
 /** @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
- <link id="SWITCH1" bandwidth="125000000" latency="5E-5" sharing_policy="SHARED" >
- <prop id="watts" value="100.0:200.0" />
+ <link id="SWITCH1" bandwidth="125Mbps" latency="5us" sharing_policy="SHARED" >
+ <prop id="watt_range" value="100.0:200.0" />
  <prop id="watt_off" value="10" />
  </link>
  \endverbatim
  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<simgrid::s4u::Link, LinkEnergy> EXTENSION_ID;
-
-       explicit LinkEnergy(simgrid::s4u::Link *ptr);
-       ~LinkEnergy();
+  static simgrid::xbt::Extension<simgrid::s4u::Link, LinkEnergy> 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<LinkPowerRange> power_range_watts_list { };
-
-       std::map<const char*, double> a_link_average_power { };
-
-
-       std::map<const char*, double> 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<simgrid::s4u::Link, LinkEnergy> 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<LinkEnergy>()->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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<LinkEnergy>();
-               link_energy->initWattsRangeList();
-               link_energy->update();
-       }
+    XBT_DEBUG("Update link %s", link->get_cname());
+    LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
+    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<simgrid::s4u::Link*> links = simgrid::s4u::Engine::get_instance()->get_all_links();
 
-               if (link == nullptr)
-                       continue;
+  double total_energy = 0.0; // Total dissipated energy (whole platform)
+  for (const auto link : links) {
+    double link_energy = link->extension<LinkEnergy>()->getConsumedEnergy();
+    total_energy += link_energy;
+  }
 
-               // Get the link_energy extension for the relevant link
-               LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
-               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<LinkEnergy>();
-       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>();
 
-       LinkEnergy *link_energy = link.extension<LinkEnergy>();
-       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<LinkEnergy>();
-                       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<LinkEnergy>()->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<LinkEnergy>();
+  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<LinkEnergy>()->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<LinkEnergy>()->update();
+    }
+  });
 
+  simgrid::s4u::Link::onCommunicate.connect(&onCommunicate);
+  simgrid::s4u::on_simulation_end.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<LinkEnergy>();
-       return link_energy->getLinkUsage();
+double sg_link_get_consumed_energy(sg_link_t link)
+{
+  return link->extension<LinkEnergy>()->getConsumedEnergy();
 }
-
-SG_END_DECL()