Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Objectify MSG task send
[simgrid.git] / src / plugins / host_energy.cpp
index 7441736..f10c827 100644 (file)
@@ -1,11 +1,11 @@
-/* Copyright (c) 2010-2018. The SimGrid Team. All rights reserved.          */
+/* Copyright (c) 2010-2019. 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/plugins/load.h"
 #include "simgrid/s4u/Engine.hpp"
+#include "src/kernel/activity/ExecImpl.hpp"
 #include "src/include/surf/surf.hpp"
 #include "src/plugins/vm/VirtualMachineImpl.hpp"
 #include "src/surf/cpu_interface.hpp"
@@ -108,6 +108,9 @@ before you can get accurate energy predictions.
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_energy, surf, "Logging specific to the SURF energy plugin");
 
+// Forwards declaration needed to make this function a friend (because friends have external linkage by default)
+static void on_simulation_end();
+
 namespace simgrid {
 namespace plugin {
 
@@ -121,6 +124,7 @@ public:
 };
 
 class HostEnergy {
+  friend void ::on_simulation_end(); // For access to host_was_used_
 public:
   static simgrid::xbt::Extension<simgrid::s4u::Host, HostEnergy> EXTENSION_ID;
 
@@ -130,6 +134,7 @@ public:
   double get_current_watts_value();
   double get_current_watts_value(double cpu_load);
   double get_consumed_energy();
+  double get_idle_consumption();
   double get_watt_min_at(int pstate);
   double get_watt_max_at(int pstate);
   void update();
@@ -146,6 +151,10 @@ private:
   int pstate_           = 0;
   const int pstate_off_ = -1;
 
+  /* Only used to split total energy into unused/used hosts.
+   * If you want to get this info for something else, rather use the host_load plugin
+   */
+  bool host_was_used_  = false;
 public:
   double watts_off_    = 0.0; /*< Consumption when the machine is turned off (shutdown) */
   double total_energy_ = 0.0; /*< Total energy consumed by the host */
@@ -204,6 +213,14 @@ HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host_(ptr), last_updated_(surf
 
 HostEnergy::~HostEnergy() = default;
 
+double HostEnergy::get_idle_consumption()
+{
+  xbt_assert(not power_range_watts_list_.empty(), "No power range properties specified for host %s",
+             host_->get_cname());
+
+  return power_range_watts_list_[0].idle_;
+}
+
 double HostEnergy::get_watt_min_at(int pstate)
 {
   xbt_assert(not power_range_watts_list_.empty(), "No power range properties specified for host %s",
@@ -243,6 +260,8 @@ double HostEnergy::get_current_watts_value()
 
   if (cpu_load > 1) // A machine with a load > 1 consumes as much as a fully loaded machine, not more
     cpu_load = 1;
+  if (cpu_load > 0)
+    host_was_used_ = true;
 
   /* The problem with this model is that the load is always 0 or 1, never something less.
    * Another possibility could be to model the total energy as
@@ -271,10 +290,10 @@ double HostEnergy::get_current_watts_value(double cpu_load)
   /* min_power corresponds to the power consumed when only one core is active */
   /* max_power is the power consumed at 100% cpu load       */
   auto range           = power_range_watts_list_.at(this->pstate_);
-  double current_power = 0;
-  double min_power     = 0;
-  double max_power     = 0;
-  double power_slope   = 0;
+  double current_power;
+  double min_power;
+  double max_power;
+  double power_slope;
 
   if (cpu_load > 0) { /* Something is going on, the machine is not idle */
     min_power = range.min_;
@@ -290,7 +309,6 @@ double HostEnergy::get_current_watts_value(double cpu_load)
      * i.e., we need min_power + (maxCpuLoad-1/coreCount)*power_slope == max_power
      * (maxCpuLoad is by definition 1)
      */
-    double power_slope;
     int coreCount         = host_->get_core_count();
     double coreReciprocal = static_cast<double>(1) / static_cast<double>(coreCount);
     if (coreCount > 1)
@@ -300,6 +318,9 @@ double HostEnergy::get_current_watts_value(double cpu_load)
 
     current_power = min_power + (cpu_load - coreReciprocal) * power_slope;
   } else { /* Our machine is idle, take the dedicated value! */
+    min_power     = 0;
+    max_power     = 0;
+    power_slope   = 0;
     current_power = range.idle_;
   }
 
@@ -341,12 +362,15 @@ void HostEnergy::init_watts_range_list()
         // In this case, 1core == AllCores
         current_power_values.push_back(current_power_values.at(1));
       } else { // size == 3
-        xbt_assert((current_power_values.at(1)) == (current_power_values.at(2)),
-                   "Power properties incorrectly defined for host %s.\n"
-                   "The energy profile of mono-cores should be formatted as 'Idle:FullSpeed' only.\n"
-                   "If you go for a 'Idle:OneCore:AllCores' power profile on mono-cores, then OneCore and AllCores "
-                   "must be equal.",
-                   host_->get_cname());
+        current_power_values[1] = current_power_values.at(2);
+        current_power_values[2] = current_power_values.at(2);
+        static bool displayed_warning = false;
+        if (not displayed_warning) { // Otherwise we get in the worst case no_pstate*no_hosts warnings
+          XBT_WARN("Host %s is a single-core machine and part of the power profile is '%s'"
+                   ", which is in the 'Idle:OneCore:AllCores' format."
+                   " Here, only the value for 'AllCores' is used.", host_->get_cname(), current_power_values_str.c_str());
+          displayed_warning = true;
+        }
       }
     } else {
       xbt_assert(current_power_values.size() == 3,
@@ -437,10 +461,9 @@ static void on_simulation_end()
   for (size_t i = 0; i < hosts.size(); i++) {
     if (dynamic_cast<simgrid::s4u::VirtualMachine*>(hosts[i]) == nullptr) { // Ignore virtual machines
 
-      bool host_was_used = (sg_host_get_computed_flops(hosts[i]) != 0);
       double energy      = hosts[i]->extension<HostEnergy>()->get_consumed_energy();
       total_energy += energy;
-      if (host_was_used)
+      if (hosts[i]->extension<HostEnergy>()->host_was_used_)
         used_hosts_energy += energy;
     }
   }
@@ -459,8 +482,6 @@ void sg_host_energy_plugin_init()
   if (HostEnergy::EXTENSION_ID.valid())
     return;
 
-  sg_host_load_plugin_init();
-
   HostEnergy::EXTENSION_ID = simgrid::s4u::Host::extension_create<HostEnergy>();
 
   simgrid::s4u::Host::on_creation.connect(&on_creation);
@@ -469,6 +490,22 @@ void sg_host_energy_plugin_init()
   simgrid::s4u::Host::on_destruction.connect(&on_host_destruction);
   simgrid::s4u::on_simulation_end.connect(&on_simulation_end);
   simgrid::surf::CpuAction::on_state_change.connect(&on_action_state_change);
+  // We may only have one actor on a node. If that actor executes something like
+  //   compute -> recv -> compute
+  // the recv operation will not trigger a "CpuAction::on_state_change". This means
+  // that the next trigger would be the 2nd compute, hence ignoring the idle time
+  // during the recv call. By updating at the beginning of a compute, we can
+  // fix that. (If the cpu is not idle, this is not required.)
+  simgrid::kernel::activity::ExecImpl::on_creation.connect([](simgrid::kernel::activity::ExecImplPtr activity){
+    if (activity->host_ != nullptr) { // We only run on one host
+      simgrid::s4u::Host* host = activity->host_;
+      simgrid::s4u::VirtualMachine* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host);
+      if (vm != nullptr)
+        host = vm->get_pm();
+
+      host->extension<HostEnergy>()->update();
+    }
+  });
 }
 
 /** @ingroup plugin_energy
@@ -501,6 +538,16 @@ double sg_host_get_consumed_energy(sg_host_t host)
   return host->extension<HostEnergy>()->get_consumed_energy();
 }
 
+/** @ingroup plugin_energy
+ *  @brief Get the amount of watt dissipated when the host is idling
+ */
+double sg_host_get_idle_consumption(sg_host_t host)
+{
+  xbt_assert(HostEnergy::EXTENSION_ID.valid(),
+             "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
+  return host->extension<HostEnergy>()->get_idle_consumption();
+}
+
 /** @ingroup plugin_energy
  *  @brief Get the amount of watt dissipated at the given pstate when the host is idling
  */