Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Update copyright headers.
[simgrid.git] / src / surf / plugins / link_energy.cpp
index f7bc8eb..062502b 100644 (file)
@@ -1,30 +1,28 @@
-/* Copyright (c) 2017. 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/energy.h"
 #include "simgrid/s4u/Engine.hpp"
-#include "simgrid/simix.hpp"
 #include "src/surf/network_interface.hpp"
+#include "surf/surf.hpp"
+
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
-#include <map>
 #include <string>
-#include <utility>
-#include <vector>
 
 /** @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:
 
  \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
@@ -36,7 +34,7 @@
 
  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().
+ 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");
@@ -44,14 +42,6 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(link_energy, surf, "Logging specific to the SURF
 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;
@@ -59,25 +49,26 @@ public:
   explicit LinkEnergy(simgrid::s4u::Link* ptr);
   ~LinkEnergy();
 
-  double getALinkTotalPower();
   void initWattsRangeList();
-  double getTotalEnergy();
+  double getConsumedEnergy();
   void update();
 
 private:
   double getPower();
 
-  simgrid::s4u::Link* link{};
+  simgrid::s4u::Link* link_{};
 
-  std::vector<LinkPowerRange> power_range_watts_list{};
+  bool inited_{false};
+  double idle_{0.0};
+  double busy_{0.0};
 
-  double total_energy{0.0};
-  double last_updated{0.0}; /*< Timestamp of the last energy update event*/
+  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;
 
-LinkEnergy::LinkEnergy(simgrid::s4u::Link* ptr) : link(ptr), last_updated(surf_get_clock())
+LinkEnergy::LinkEnergy(simgrid::s4u::Link* ptr) : link_(ptr), lastUpdated_(surf_get_clock())
 {
 }
 
@@ -87,17 +78,18 @@ void LinkEnergy::update()
 {
   double power = getPower();
   double now   = surf_get_clock();
-  total_energy += power * (now - last_updated);
-  last_updated = now;
+  totalEnergy_ += power * (now - lastUpdated_);
+  lastUpdated_ = now;
 }
 
 void LinkEnergy::initWattsRangeList()
 {
 
-  if (!power_range_watts_list.empty())
+  if (inited_)
     return;
+  inited_ = true;
 
-  const char* all_power_values_str = this->link->getProperty("watt_range");
+  const char* all_power_values_str = this->link_->getProperty("watt_range");
 
   if (all_power_values_str == nullptr)
     return;
@@ -109,23 +101,20 @@ void LinkEnergy::initWattsRangeList()
     /* 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());
+    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* idle = bprintf("Invalid idle power value for link%s", this->link->getCname());
-    char* busy = bprintf("Invalid busy power value for %s", this->link->getCname());
-
-    double idleVal = xbt_str_parse_double((current_power_values.at(0)).c_str(), idle);
+    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());
 
-    double busyVal = xbt_str_parse_double((current_power_values.at(1)).c_str(), busy);
+    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);
 
-    this->power_range_watts_list.push_back(LinkPowerRange(idleVal, busyVal));
-
-    xbt_free(idle);
-    xbt_free(busy);
+    xbt_free(idleMsg);
+    xbt_free(busyMsg);
     update();
   }
 }
@@ -133,26 +122,22 @@ void LinkEnergy::initWattsRangeList()
 double LinkEnergy::getPower()
 {
 
-  if (power_range_watts_list.empty())
+  if (!inited_)
     return 0.0;
 
-  auto range = power_range_watts_list[0];
-
-  double busy = range.busy;
-  double idle = range.idle;
-
-  double power_slope = busy - idle;
+  double power_slope = busy_ - idle_;
 
-  double normalized_link_usage = link->getUsage() / link->bandwidth();
+  double normalized_link_usage = link_->getUsage() / link_->bandwidth();
   double dynamic_power         = power_slope * normalized_link_usage;
 
-  return idle + dynamic_power;
+  return idle_ + dynamic_power;
 }
 
-double LinkEnergy::getTotalEnergy()
+double LinkEnergy::getConsumedEnergy()
 {
-  update();
-  return this->total_energy;
+  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_;
 }
 }
 }
@@ -160,82 +145,40 @@ double LinkEnergy::getTotalEnergy()
 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::surf::NetworkAction* action, simgrid::s4u::Host* src, simgrid::s4u::Host* dst)
+static void onCommunicate(simgrid::kernel::resource::NetworkAction* action, simgrid::s4u::Host* src,
+                          simgrid::s4u::Host* dst)
 {
   XBT_DEBUG("onCommunicate is called");
-  for (simgrid::surf::LinkImpl* link : action->links()) {
+  for (simgrid::kernel::resource::LinkImpl* link : action->links()) {
 
     if (link == nullptr)
       continue;
 
-    XBT_DEBUG("Update link %s", link->getCname());
-    // Get the link_energy extension for the relevant link
+    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()) {
-
-    if (link == nullptr)
-      continue;
-
-    // Get the link_energy extension for the relevant link
-    LinkEnergy* link_energy = link->piface_.extension<LinkEnergy>();
-    link_energy->update();
-  }
-}
-
-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();
-}
-
-static void onLinkDestruction(simgrid::s4u::Link& link)
+static void onSimulationEnd()
 {
-  XBT_DEBUG("onLinkDestruction is called for link: %s", link.getCname());
-
-  LinkEnergy* link_energy = link.extension<LinkEnergy>();
-  link_energy->update();
-}
+  std::vector<simgrid::s4u::Link*> links = simgrid::s4u::Engine::getInstance()->getAllLinks();
 
-static void computeAndDisplayTotalEnergy()
-{
-  std::vector<simgrid::s4u::Link*> link_list;
-  simgrid::s4u::Engine::getInstance()->getLinkList(&link_list);
   double total_energy = 0.0; // Total dissipated energy (whole platform)
-  for (const auto link : link_list) {
-    LinkEnergy* link_energy = link->extension<LinkEnergy>();
-
-    double a_link_total_energy = link_energy->getTotalEnergy();
-    total_energy += a_link_total_energy;
-    const char* name = link->getCname();
-    if (strcmp(name, "__loopback__"))
-      XBT_INFO("Link '%s' total consumption: %f", name, a_link_total_energy);
+  for (const auto link : links) {
+    double link_energy = link->extension<LinkEnergy>()->getConsumedEnergy();
+    total_energy += link_energy;
   }
 
   XBT_INFO("Total energy over all links: %f", total_energy);
 }
+/* **************************** Public interface *************************** */
 
-static void onSimulationEnd()
+int sg_link_energy_is_inited()
 {
-  computeAndDisplayTotalEnergy();
+  return LinkEnergy::EXTENSION_ID.valid();
 }
-/* **************************** 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
@@ -248,12 +191,41 @@ void sg_link_energy_plugin_init()
     return;
   LinkEnergy::EXTENSION_ID = simgrid::s4u::Link::extension_create<LinkEnergy>();
 
-  simgrid::s4u::Link::onCreation.connect(&onCreation);
-  simgrid::s4u::Link::onStateChange.connect(&onLinkStateChange);
-  simgrid::s4u::Link::onDestruction.connect(&onLinkDestruction);
-  simgrid::s4u::Link::onCommunicationStateChange.connect(&onActionStateChange);
+  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));
+  });
+
+  simgrid::s4u::Link::onStateChange.connect([](simgrid::s4u::Link& link) {
+    link.extension<LinkEnergy>()->update();
+  });
+
+  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::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::onSimulationEnd.connect(&onSimulationEnd);
 }
 
-SG_END_DECL()
+/** @ingroup plugin_energy
+ *  @brief Returns the total energy consumed by the link so far (in Joules)
+ *
+ *  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_consumed_energy(sg_link_t link)
+{
+  return link->extension<LinkEnergy>()->getConsumedEnergy();
+}