Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid
authorMartin Quinson <martin.quinson@loria.fr>
Tue, 21 Nov 2017 23:15:16 +0000 (00:15 +0100)
committerMartin Quinson <martin.quinson@loria.fr>
Tue, 21 Nov 2017 23:15:16 +0000 (00:15 +0100)
17 files changed:
.gitignore
CMakeLists.txt
doc/doxygen/inside_release.doc
examples/platforms/energy_platform.xml
examples/s4u/CMakeLists.txt
examples/s4u/energy-link/s4u-energy-link.cpp [new file with mode: 0644]
examples/s4u/energy-link/s4u-energy-link.tesh [new file with mode: 0644]
include/simgrid/plugins/energy.h
include/simgrid/s4u/Actor.hpp
include/simgrid/s4u/Engine.hpp
include/simgrid/s4u/Link.hpp
src/s4u/s4u_engine.cpp
src/s4u/s4u_link.cpp
src/surf/network_interface.cpp
src/surf/network_interface.hpp
src/surf/plugins/link_energy.cpp [new file with mode: 0644]
tools/cmake/DefinePackages.cmake

index 7c78757..e0eb0b8 100644 (file)
@@ -209,6 +209,7 @@ examples/s4u/basic/s4u-basic
 examples/s4u/basic/s4u-basic_deployment
 examples/s4u/basic/s4u-basic_function
 examples/s4u/dht-chord/s4u-dht-chord
+examples/s4u/energy-link/s4u-energy-link
 examples/s4u/io/s4u-io
 examples/s4u/mutex/s4u-mutex
 examples/s4u/plugin-hostload/s4u-plugin-hostload
index 7b93105..58b548b 100644 (file)
@@ -40,7 +40,7 @@ if(COMPILER_SUPPORTS_CXX11)
 else() 
   message(FATAL_ERROR 
           "The compiler ${CMAKE_CXX_COMPILER} (v${CMAKE_CXX_COMPILER_VERSION}) has no C++11 support. "
-           "Please use a decent C++ compiler.")
+          "Please install a decent C++ compiler (remove CMakeCache.txt once it's installed).")
 endif()
 
 ### And we need C11 standard, too
index f3be6de..5fbed80 100644 (file)
@@ -94,6 +94,7 @@ the settings icon of the release you want to change.
   - make -C org all sync
   - git commit -a && git push
 - Announce the release
+ - Document the tag on https://github.com/simgrid/simgrid/releases
  - Mail the simgrid-user mailing list
     - the NEWS chunk in the mail;
     - the ChangeLog chunk as attachment
index 03ce9c7..7d9ace5 100644 (file)
       <prop id="watt_per_state" value="100.0:200.0, 93.0:170.0, 90.0:150.0" />
       <prop id="watt_off" value="10" />
     </host>
-
-    <link id="bus" bandwidth="100kBps" latency="0"/>
+    <link id="bus" bandwidth="100kBps" latency="0" sharing_policy="SHARED">
+<!--   REALISTIC VALUES                    <prop id="watt_range" value="10.3581:10.7479" /> -->
+<!--  IREALISTIC VALUES FOR THE TEST -->   <prop id="watt_range" value="1:3" /> 
+    </link>
     <route src="MyHost1" dst="MyHost2">
       <link_ctn id="bus"/>
     </route>
index dac2b6b..5b88ee4 100644 (file)
@@ -2,6 +2,7 @@ foreach (example actions-comm actions-storage
                  actor-create actor-daemon actor-execute actor-kill actor-lifetime actor-migration actor-suspend actor-priority
                  app-masterworker app-pingpong app-token-ring
                 async-wait async-waitany async-waitall
+                energy-link
                 plugin-hostload io mutex)
   add_executable       (s4u-${example}  ${example}/s4u-${example}.cpp)
   target_link_libraries(s4u-${example}  simgrid)
@@ -62,6 +63,8 @@ foreach(example actions-comm actions-storage
                 actor-create actor-daemon actor-execute actor-kill actor-lifetime actor-migration actor-suspend
                 app-bittorrent app-masterworker app-pingpong app-token-ring 
                async-wait async-waitall async-waitany actor-priority
-               dht-chord plugin-hostload io mutex)
+               dht-chord 
+               energy-link
+               plugin-hostload io mutex)
   ADD_TESH_FACTORIES(s4u-${example} "thread;ucontext;raw;boost" --setenv bindir=${CMAKE_CURRENT_BINARY_DIR}/${example} --setenv srcdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --cd ${CMAKE_HOME_DIRECTORY}/examples/s4u/${example} s4u-${example}.tesh)
 endforeach()
diff --git a/examples/s4u/energy-link/s4u-energy-link.cpp b/examples/s4u/energy-link/s4u-energy-link.cpp
new file mode 100644 (file)
index 0000000..be53d6c
--- /dev/null
@@ -0,0 +1,143 @@
+/* Copyright (c) 2017. 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 "xbt/log.h"
+#include <simgrid/s4u.hpp>
+
+#include <random>
+
+/* Parameters of the random generation of the flow size */
+static const unsigned long int min_size = 1e6;
+static const unsigned long int max_size = 1e9;
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_app_energyconsumption, "Messages specific for this s4u example");
+
+static void sender(std::vector<std::string> args)
+{
+  xbt_assert(args.size() == 2, "The master function expects 2 arguments.");
+  int flow_amount  = std::stoi(args.at(0));
+  double comm_size = std::stod(args.at(1));
+  XBT_INFO("Send %.0f bytes, in %d flows", comm_size, flow_amount);
+
+  simgrid::s4u::MailboxPtr mailbox = simgrid::s4u::Mailbox::byName(std::string("message"));
+
+  simgrid::s4u::this_actor::sleep_for(10);
+
+  /* - Send the task to the @ref worker */
+  char* payload = bprintf("%f", comm_size);
+
+  if (flow_amount == 1) {
+    mailbox->put(payload, comm_size);
+  } else {
+    // Start all comms in parallel
+    std::vector<simgrid::s4u::CommPtr> comms;
+    for (int i = 0; i < flow_amount; i++)
+      comms.push_back(mailbox->put_async(const_cast<char*>("message"), comm_size));
+
+    // And now, wait for all comms. Manually since wait_all is not part of this_actor yet
+    for (int i = 0; i < flow_amount; i++) {
+      simgrid::s4u::CommPtr comm = comms.at(i);
+      comm->wait();
+    }
+    comms.clear();
+  }
+  XBT_INFO("sender done.");
+}
+
+static void receiver(std::vector<std::string> args)
+{
+  int flow_amount = std::stoi(args.at(0));
+
+  XBT_INFO("Receiving %d flows ...", flow_amount);
+
+  simgrid::s4u::MailboxPtr mailbox = simgrid::s4u::Mailbox::byName(std::string("message"));
+
+  if (flow_amount == 1) {
+    void* res = mailbox->get();
+    xbt_free(res);
+  } else {
+    void* ignored;
+
+    // Start all comms in parallel
+    std::vector<simgrid::s4u::CommPtr> comms;
+    for (int i = 0; i < flow_amount; i++)
+      comms.push_back(mailbox->get_async(&ignored));
+
+    // And now, wait for all comms. Manually since wait_all is not part of this_actor yet
+    for (int i = 0; i < flow_amount; i++)
+      comms.at(i)->wait();
+    comms.clear();
+  }
+  XBT_INFO("receiver done.");
+}
+
+int main(int argc, char* argv[])
+{
+
+  simgrid::s4u::Engine* e = new simgrid::s4u::Engine(&argc, argv);
+
+  /* Check if we got --NS3 on the command line, and activate ecofen if so */
+  bool NS3 = false;
+  for (int i = 0; i < argc; i++) {
+    if (strcmp(argv[i], "--NS3") == 0)
+      NS3 = true;
+    if (NS3) // Found the --NS3 parameter previously; shift the rest of the line
+      argv[i] = argv[i + 1];
+  }
+  if (NS3) {
+    xbt_die("No Ecofen in this build");
+    //    XBT_INFO("Activating the Ecofen energy plugin");
+    //    ns3_link_energy_plugin_init();
+    //    xbt_cfg_set_parse("network/model:NS3");
+    //    argc -= 1; // We removed it from the parameters
+  } else {
+    XBT_INFO("Activating the SimGrid link energy plugin");
+    sg_link_energy_plugin_init();
+  }
+
+  xbt_assert(argc > 1, "\nUsage: %s platform_file [flowCount [datasize]] [--NS3]\n"
+                       "\tExample: %s s4uplatform.xml \n"
+                       "\tIf you add NS3 as last parameter, this will try to activate the ecofen plugin.\n"
+                       "\tWithout it, it will use the SimGrid link energy plugin.\n",
+             argv[0], argv[0]);
+  e->loadPlatform(argv[1]);
+
+  /* prepare to launch the actors */
+  std::vector<std::string> argSender;
+  std::vector<std::string> argReceiver;
+  if (argc > 2) {
+    argSender.push_back(argv[2]); // Take the amount of flows from the command line
+    argReceiver.push_back(argv[2]);
+  } else {
+    argSender.push_back("1"); // Default value
+    argReceiver.push_back("1");
+  }
+  if (argc > 3) {
+    if (strcmp(argv[3], "random") == 0) { // We're asked to get a random size
+      /* Initialize the random number generator */
+      std::random_device rd;
+      std::default_random_engine generator(rd());
+
+      /* Distribution on which to apply the generator */
+      std::uniform_int_distribution<unsigned long int> distribution(min_size, max_size);
+
+      char* size = bprintf("%lu", distribution(generator));
+      argSender.push_back(std::string(size));
+      xbt_free(size);
+    } else {                        // Not "random" ? Then it should be the size to use
+      argSender.push_back(argv[3]); // Take the datasize from the command line
+    }
+  } else { // No parameter at all? Then use the default value
+    argSender.push_back("25000");
+  }
+  simgrid::s4u::Actor::createActor("sender", simgrid::s4u::Host::by_name("MyHost1"), sender, argSender);
+  simgrid::s4u::Actor::createActor("receiver", simgrid::s4u::Host::by_name("MyHost2"), receiver, argReceiver);
+
+  /* And now, launch the simulation */
+  e->run();
+
+  return 0;
+}
diff --git a/examples/s4u/energy-link/s4u-energy-link.tesh b/examples/s4u/energy-link/s4u-energy-link.tesh
new file mode 100644 (file)
index 0000000..2622a4b
--- /dev/null
@@ -0,0 +1,28 @@
+#! ./tesh
+
+p Testing the mechanism for computing link energy consumption (using CM02 as a network model)
+
+$ ${bindir:=.}/s4u-energy-link$EXEEXT ${srcdir:=.}/../platforms/energy_platform.xml  "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=network/model:CM02 --cfg=network/crosstraffic:no
+> [  0.000000] (0:maestro@) Configuration change: Set 'network/model' to 'CM02'
+> [  0.000000] (0:maestro@) Configuration change: Set 'network/crosstraffic' to 'no'
+> [  0.000000] (0:maestro@) Activating the SimGrid link energy plugin
+> [  0.000000] (1:sender@MyHost1) Send 25000 bytes, in 1 flows
+> [  0.000000] (2:receiver@MyHost2) Receiving 1 flows ...
+> [ 10.250000] (2:receiver@MyHost2) receiver done.
+> [ 10.250000] (1:sender@MyHost1) sender done.
+> [ 10.250000] (0:maestro@) Link 'bus' total consumption: 10.750000
+> [ 10.250000] (0:maestro@) Total energy over all links: 10.750000
+
+p And now test with 500000 bytes
+
+$ ${bindir:=.}/s4u-energy-link$EXEEXT ${srcdir:=.}/../platforms/energy_platform.xml 1 50000000 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=network/model:CM02 --cfg=network/crosstraffic:no
+> [  0.000000] (0:maestro@) Configuration change: Set 'network/model' to 'CM02'
+> [  0.000000] (0:maestro@) Configuration change: Set 'network/crosstraffic' to 'no'
+> [  0.000000] (0:maestro@) Activating the SimGrid link energy plugin
+> [  0.000000] (1:sender@MyHost1) Send 50000000 bytes, in 1 flows
+> [  0.000000] (2:receiver@MyHost2) Receiving 1 flows ...
+> [510.000000] (2:receiver@MyHost2) receiver done.
+> [510.000000] (1:sender@MyHost1) sender done.
+> [510.000000] (0:maestro@) Link 'bus' total consumption: 1510.000000
+> [510.000000] (0:maestro@) Total energy over all links: 1510.000000
+
index 2a697ab..a5663c0 100644 (file)
@@ -18,6 +18,9 @@ XBT_PUBLIC(double) sg_host_get_wattmin_at(sg_host_t host, int pstate);
 XBT_PUBLIC(double) sg_host_get_wattmax_at(sg_host_t host, int pstate);
 XBT_PUBLIC(double) sg_host_get_current_consumption(sg_host_t host);
 
+XBT_PUBLIC(void) sg_link_energy_plugin_init();
+XBT_PUBLIC(double) sg_link_get_consumed_energy(sg_link_t link);
+
 #define MSG_host_energy_plugin_init() sg_host_energy_plugin_init()
 #define MSG_host_get_consumed_energy(host) sg_host_get_consumed_energy(host)
 #define MSG_host_get_wattmin_at(host,pstate) sg_host_get_wattmin_at(host,pstate)
index 17df501..e9cdd87 100644 (file)
@@ -109,17 +109,17 @@ namespace s4u {
  * <!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid/simgrid.dtd">
  * <platform version="4">
  *
- *   <!-- Start a process called 'master' on the host called 'Tremblay' -->
- *   <process host="Tremblay" function="master">
+ *   <!-- Start an actor called 'master' on the host called 'Tremblay' -->
+ *   <actor host="Tremblay" function="master">
  *      <!-- Here come the parameter that you want to feed to this instance of master -->
  *      <argument value="20"/>        <!-- argv[1] -->
  *      <argument value="50000000"/>  <!-- argv[2] -->
  *      <argument value="1000000"/>   <!-- argv[3] -->
  *      <argument value="5"/>         <!-- argv[4] -->
- *   </process>
+ *   </actor>
  *
- *   <!-- Start a process called 'worker' on the host called 'Jupiter' -->
- *   <process host="Jupiter" function="worker"/> <!-- Don't provide any parameter ->>
+ *   <!-- Start an actor called 'worker' on the host called 'Jupiter' -->
+ *   <actor host="Jupiter" function="worker"/> <!-- Don't provide any parameter ->>
  *
  * </platform>
  * @endcode
@@ -176,7 +176,7 @@ public:
   /** Create an actor using code
    *
    *  Using this constructor, move-only type can be used. The consequence is
-   *  that we cannot copy the value and restart the process in its initial
+   *  that we cannot copy the value and restart the actor in its initial
    *  state. In order to use auto-restart, an explicit `function` must be passed
    *  instead.
    */
@@ -194,7 +194,7 @@ public:
   static ActorPtr createActor(const char* name, s4u::Host* host, const char* function, std::vector<std::string> args);
 
   // ***** Methods *****
-  /** This actor will be automatically terminated when the last non-daemon process finishes **/
+  /** This actor will be automatically terminated when the last non-daemon actor finishes **/
   void daemonize();
 
   /** Retrieves the name of that actor as a C++ string */
@@ -215,17 +215,17 @@ public:
   /** Suspend an actor by suspending the task on which it was waiting for the completion. */
   void suspend();
 
-  /** Resume a suspended process by resuming the task on which it was waiting for the completion. */
+  /** Resume a suspended actor by resuming the task on which it was waiting for the completion. */
   void resume();
 
-  /** Returns true if the process is suspended. */
+  /** Returns true if the actor is suspended. */
   int isSuspended();
 
   /** If set to true, the actor will automatically restart when its host reboots */
   void setAutoRestart(bool autorestart);
 
   /** Add a function to the list of "on_exit" functions for the current actor. The on_exit functions are the functions
-   * executed when your actor is killed. You should use them to free the data used by your process.
+   * executed when your actor is killed. You should use them to free the data used by your actor.
    */
   void onExit(int_f_pvoid_pvoid_t fun, void* data);
 
@@ -341,7 +341,7 @@ XBT_PUBLIC(std::string) getName();
 /** @brief Returns the name of the current actor as a C string. */
 XBT_PUBLIC(const char*) getCname();
 
-/** @brief Returns the name of the host on which the process is running. */
+/** @brief Returns the name of the host on which the actor is running. */
 XBT_PUBLIC(Host*) getHost();
 
 /** @brief Suspend the actor. */
index e705bab..805a309 100644 (file)
@@ -58,6 +58,8 @@ public:
 
   size_t getHostCount();
   void getHostList(std::vector<Host*> * whereTo);
+  size_t getLinkCount();
+  void getLinkList(std::vector<Link*> * list);
 
   /** @brief Run the simulation */
   void run();
index 2255bc1..f554dfe 100644 (file)
@@ -7,11 +7,11 @@
 #define S4U_LINK_HPP_
 
 #include <simgrid/link.h>
-#include <xbt/base.h>
-#include <xbt/signal.hpp>
-
 #include <string>
 #include <unordered_map>
+#include <xbt/Extendable.hpp>
+#include <xbt/base.h>
+#include <xbt/signal.hpp>
 
 /***********
  * Classes *
@@ -23,7 +23,7 @@ class NetworkAction;
 };
 namespace s4u {
 /** @brief A Link represents the network facilities between [hosts](\ref simgrid::s4u::Host) */
-XBT_PUBLIC_CLASS Link
+XBT_PUBLIC_CLASS Link : public simgrid::xbt::Extendable<Link>
 {
   friend simgrid::surf::LinkImpl;
 
@@ -52,6 +52,9 @@ public:
    */
   int sharingPolicy();
 
+  /** @brief Returns the current load (in flops per second) */
+  double getUsage();
+
   /** @brief Check if the Link is used */
   bool isUsed();
 
@@ -68,6 +71,9 @@ public:
   void setLatencyTrace(tmgr_trace_t trace); /*< setup the trace file with latency events (peak latency changes due to
                                                external load). Trace must contain absolute values */
 
+  const char* getProperty(const char* key);
+  void setProperty(std::string key, std::string value);
+
   /* The signals */
   /** @brief Callback signal fired when a new Link is created */
   static simgrid::xbt::signal<void(s4u::Link&)> onCreation;
index c16b189..886cc33 100644 (file)
@@ -93,6 +93,16 @@ void Engine::getHostList(std::vector<Host*>* list)
   for (auto const& kv : host_list)
     list->push_back(kv.second);
 }
+/** @brief Returns the amount of links in the platform */
+size_t Engine::getLinkCount()
+{
+  return simgrid::surf::LinkImpl::linksCount();
+}
+/** @brief Fills the passed list with all hosts found in the platform */
+void Engine::getLinkList(std::vector<Link*>* list)
+{
+  simgrid::surf::LinkImpl::linksList(list);
+}
 
 void Engine::run() {
   if (MC_is_active()) {
index c640077..7a38166 100644 (file)
@@ -114,6 +114,11 @@ int Link::sharingPolicy()
   return this->pimpl_->sharingPolicy();
 }
 
+double Link::getUsage()
+{
+  return lmm_constraint_get_usage(this->pimpl_->constraint());
+}
+
 void Link::turnOn()
 {
   simgrid::simix::kernelImmediate([this]() {
@@ -157,6 +162,15 @@ void Link::setLatencyTrace(tmgr_trace_t trace)
   });
 }
 
+const char* Link::getProperty(const char* key)
+{
+  return this->pimpl_->getProperty(key);
+}
+void Link::setProperty(std::string key, std::string value)
+{
+  simgrid::simix::kernelImmediate([this, key, value] { this->pimpl_->setProperty(key, value); });
+}
+
 /*************
  * Callbacks *
  *************/
index fdb7f86..54c4bb8 100644 (file)
@@ -30,6 +30,13 @@ namespace simgrid {
   {
     return links->size();
   }
+  void LinkImpl::linksList(std::vector<s4u::Link*>* linkList)
+  {
+    for (auto const& kv : *links) {
+      linkList->push_back(&kv.second->piface_);
+    }
+  }
+
   /** @brief Returns a list of all existing links */
   LinkImpl** LinkImpl::linksList()
   {
index 14a1518..476775c 100644 (file)
@@ -174,6 +174,7 @@ public:
   static LinkImpl* byName(std::string name);
   static int linksCount();
   static LinkImpl** linksList();
+  static void linksList(std::vector<s4u::Link*>* linkList);
   static void linksExit();
 };
 
diff --git a/src/surf/plugins/link_energy.cpp b/src/surf/plugins/link_energy.cpp
new file mode 100644 (file)
index 0000000..f7bc8eb
--- /dev/null
@@ -0,0 +1,259 @@
+/* Copyright (c) 2017. 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 <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.
+
+ 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 getALinkTotalPower();
+  void initWattsRangeList();
+  double getTotalEnergy();
+  void update();
+
+private:
+  double getPower();
+
+  simgrid::s4u::Link* link{};
+
+  std::vector<LinkPowerRange> power_range_watts_list{};
+
+  double total_energy{0.0};
+  double last_updated{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() = default;
+
+void LinkEnergy::update()
+{
+  double power = getPower();
+  double now   = surf_get_clock();
+  total_energy += power * (now - last_updated);
+  last_updated = now;
+}
+
+void LinkEnergy::initWattsRangeList()
+{
+
+  if (!power_range_watts_list.empty())
+    return;
+
+  const char* all_power_values_str = this->link->getProperty("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);
+
+    double busyVal = xbt_str_parse_double((current_power_values.at(1)).c_str(), busy);
+
+    this->power_range_watts_list.push_back(LinkPowerRange(idleVal, busyVal));
+
+    xbt_free(idle);
+    xbt_free(busy);
+    update();
+  }
+}
+
+double LinkEnergy::getPower()
+{
+
+  if (power_range_watts_list.empty())
+    return 0.0;
+
+  auto range = power_range_watts_list[0];
+
+  double busy = range.busy;
+  double idle = range.idle;
+
+  double power_slope = busy - idle;
+
+  double normalized_link_usage = link->getUsage() / link->bandwidth();
+  double dynamic_power         = power_slope * normalized_link_usage;
+
+  return idle + dynamic_power;
+}
+
+double LinkEnergy::getTotalEnergy()
+{
+  update();
+  return this->total_energy;
+}
+}
+}
+
+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;
+
+    XBT_DEBUG("Update link %s", link->getCname());
+    // 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 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);
+  }
+
+  XBT_INFO("Total energy over all links: %f", total_energy);
+}
+
+static void onSimulationEnd()
+{
+  computeAndDisplayTotalEnergy();
+}
+/* **************************** 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);
+}
+
+SG_END_DECL()
index a4e4ce8..cff4bca 100644 (file)
@@ -344,6 +344,7 @@ set(SURF_SRC
   src/surf/network_constant.cpp
   src/surf/network_interface.cpp
   src/surf/plugins/host_energy.cpp
+  src/surf/plugins/link_energy.cpp
   src/surf/plugins/host_load.cpp
   src/surf/PropertyHolder.cpp
   src/surf/sg_platf.cpp