Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
start integrating the link energy model
authorMartin Quinson <martin.quinson@loria.fr>
Tue, 7 Nov 2017 22:06:44 +0000 (23:06 +0100)
committerMartin Quinson <martin.quinson@loria.fr>
Tue, 7 Nov 2017 22:06:44 +0000 (23:06 +0100)
include/simgrid/plugins/link_energy.h [new file with mode: 0644]
src/surf/plugins/link_energy.cpp [new file with mode: 0644]

diff --git a/include/simgrid/plugins/link_energy.h b/include/simgrid/plugins/link_energy.h
new file mode 100644 (file)
index 0000000..02be13b
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (c) 2016. 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. */
+
+#ifndef SIMGRID_PLUGINS_LINK_ENERGY_H_
+#define SIMGRID_PLUGINS_LINK_ENERGY_H_
+
+#include <xbt/base.h>
+#include <simgrid/forward.h>
+
+SG_BEGIN_DECL()
+
+XBT_PUBLIC(double) sg_link_get_consumped_power(sg_link_t link);
+XBT_PUBLIC(double) sg_link_get_usage(sg_link_t link);
+XBT_PUBLIC(void) sg_on_simulation_end();
+XBT_PUBLIC(void) sg_link_energy_plugin_init();
+XBT_PUBLIC(double) sg_link_get_consumed_energy(sg_link_t link);
+
+XBT_PUBLIC(double) ns3__link_get_consumped_power(sg_link_t link);
+XBT_PUBLIC(double) ns3_link_get_usage(sg_link_t link);
+XBT_PUBLIC(void) ns3_on_simulation_end();
+XBT_PUBLIC(double) ns3_link_get_consumed_energy(sg_link_t link);
+XBT_PUBLIC(void) ns3_link_energy_plugin_init();
+
+SG_END_DECL()
+
+#endif
+
diff --git a/src/surf/plugins/link_energy.cpp b/src/surf/plugins/link_energy.cpp
new file mode 100644 (file)
index 0000000..6487ce7
--- /dev/null
@@ -0,0 +1,407 @@
+/* Copyright (c) 2010, 2012-2016. 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/s4u/Engine.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.
+
+ 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" />
+ <prop id="watt_off" value="10" />
+ </link>
+ \endverbatim
+
+ The first property means that when your link is switched on, but without anything to do, it will dissipate 100 Watts.
+ If it's fully loaded, it will dissipate 200 Watts. If its load is at 50%, then it will dissipate 150 Watts.
+ 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().
+ */
+
+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();
+
+       double getAveragePower(sg_link_t link);
+
+
+       double getALinkTotalPower(sg_link_t link);
+       void initWattsRangeList();
+       double getLinkUsage();
+       double getALinkTotalEnergy(sg_link_t link);
+       void update();
+private:
+       double computeALinkPower();
+       void computeALinkTotalEnergy();
+
+
+
+       simgrid::s4u::Link *link { };
+//     simgrid::s4u::Link *up_link { };
+//     simgrid::s4u::Link *down_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 };
+
+};
+
+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() = 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::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(","));
+
+       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());
+
+               /* 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);
+
+
+               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
+
+
+               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();
+
+       }
+
+}
+
+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;
+
+               if (this->last_updated > 0) {
+
+                       double normalized_link_usage = this->current_link_usage
+                                       / this->link->bandwidth();
+                       dynamic_power = power_slope * normalized_link_usage;
+
+               } else {
+
+                       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;
+}
+
+double LinkEnergy::getLinkUsage() {
+       return this->current_link_usage;
+}
+
+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::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;
+
+               // Get the link_energy extension for the relevant link
+               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) {
+       XBT_DEBUG("onLinkDestruction is called for link: %s", link.getCname());
+
+       LinkEnergy *link_energy = link.extension<LinkEnergy>();
+       link_energy->update();
+}
+
+
+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);
+}
+
+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::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);
+
+}
+
+/** @brief Returns the total energy consumed by the link so far (in Joules)
+ *
+ *  See also @ref SURF_plugin_energy.
+ */
+
+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();
+}
+
+SG_END_DECL()