Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
cosmetics: cpu_load is not supposed to be >1 anymore
[simgrid.git] / src / plugins / host_energy.cpp
index b3cb2a7379128450778ec42a9278f038dccd5cfa..5b3cfca1f0bca2b7df40d4279cbc60cbd3a9651f 100644 (file)
@@ -5,8 +5,9 @@
 
 #include "simgrid/plugins/energy.h"
 #include "simgrid/s4u/Engine.hpp"
-#include "src/kernel/activity/ExecImpl.hpp"
+#include "simgrid/s4u/Exec.hpp"
 #include "src/include/surf/surf.hpp"
+#include "src/kernel/activity/ExecImpl.hpp"
 #include "src/plugins/vm/VirtualMachineImpl.hpp"
 #include "src/surf/cpu_interface.hpp"
 
@@ -15,7 +16,7 @@
 
 SIMGRID_REGISTER_PLUGIN(host_energy, "Cpu energy consumption.", &sg_host_energy_plugin_init)
 
-/** @addtogroup plugin_energy
+/** @defgroup plugin_host_energy
 
 This is the energy plugin, enabling to account not only for computation time, but also for the dissipated energy in the
 simulated platform.
@@ -29,30 +30,29 @@ abnormality when all the cores are idle. The full details are in
 
 As a result, our energy model takes 4 parameters:
 
-  - @b Idle: instantaneous consumption (in Watt) when your host is up and running, but without anything to do.
-  - @b Epsilon: instantaneous consumption (in Watt) when all cores are at 0 or epsilon%, but not in Idle state.
-  - @b AllCores: instantaneous consumption (in Watt) when all cores of the host are at 100%.
-  - @b Off: instantaneous consumption (in Watt) when the host is turned off.
+  - @b Idle: wattage (i.e., instantaneous consumption in Watt) when your host is up and running, but without anything to
+do.
+  - @b Epsilon: wattage when all cores are at 0 or epsilon%, but not in Idle state.
+  - @b AllCores: wattage when all cores of the host are at 100%.
+  - @b Off: wattage when the host is turned off.
 
 Here is an example of XML declaration:
 
 @code{.xml}
 <host id="HostA" speed="100.0Mf" core="4">
-    <prop id="watt_per_state" value="100.0:120.0:200.0" />
-    <prop id="watt_off" value="10" />
+    <prop id="wattage_per_state" value="100.0:120.0:200.0" />
+    <prop id="wattage_off" value="10" />
 </host>
 @endcode
 
-Please note that the 'Epsilon' parameter can be omitted in the XML declaration. In that case, the value of 'Epsilon' will
-be the same as 'Idle'.
-
+If the 'Epsilon' parameter is omitted in the XML declaration, 'Idle' is used instead.
 
 This example gives the following parameters: @b Off is 10 Watts; @b Idle is 100 Watts; @b Epsilon is 120 Watts and @b
 AllCores is 200 Watts.
-This is enough to compute the consumption as a function of the amount of loaded cores:
+This is enough to compute the wattage as a function of the amount of loaded cores:
 
 <table>
-<tr><th>@#Cores loaded</th><th>Consumption</th><th>Explanation</th></tr>
+<tr><th>@#Cores loaded</th><th>Wattage</th><th>Explanation</th></tr>
 <tr><td>0 (idle)</td><td> 100 Watts</td><td>Idle value</td></tr>
 <tr><td>0 (not idle)</td><td> 120 Watts</td><td>Epsilon value</td></tr>
 <tr><td>1</td><td> 140 Watts</td><td>linear extrapolation between Epsilon and AllCores</td></tr>
@@ -68,8 +68,8 @@ If your host has several DVFS levels (several pstates), then you should give the
 
 @code{.xml}
 <host id="HostC" speed="100.0Mf,50.0Mf,20.0Mf" core="4">
-    <prop id="watt_per_state" value="95.0:120.0:200.0, 93.0:115.0:170.0, 90.0:110.0:150.0" />
-    <prop id="watt_off" value="10" />
+    <prop id="wattage_per_state" value="95.0:120.0:200.0, 93.0:115.0:170.0, 90.0:110.0:150.0" />
+    <prop id="wattage_off" value="10" />
 </host>
 @endcode
 
@@ -187,13 +187,21 @@ void HostEnergy::update()
 HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host_(ptr), last_updated_(surf_get_clock())
 {
   init_watts_range_list();
-
-  const char* off_power_str = host_->get_property("watt_off");
+  static bool warned = false;
+
+  const char* off_power_str = host_->get_property("wattage_off");
+  if (off_power_str == nullptr) {
+    off_power_str = host_->get_property("watt_off");
+    if (off_power_str != nullptr && not warned) {
+      warned = true;
+      XBT_WARN("Please use 'wattage_off' instead of 'watt_off' to define the idle wattage of hosts in your XML.");
+    }
+  }
   if (off_power_str != nullptr) {
     try {
       this->watts_off_ = std::stod(std::string(off_power_str));
     } catch (const std::invalid_argument&) {
-      throw std::invalid_argument(std::string("Invalid value for property watt_off of host ") + host_->get_cname() +
+      throw std::invalid_argument(std::string("Invalid value for property wattage_off of host ") + host_->get_cname() +
                                   ": " + off_power_str);
     }
   }
@@ -251,26 +259,14 @@ double HostEnergy::get_current_watts_value()
   else {
     cpu_load = host_->pimpl_cpu->get_constraint()->get_usage() / current_speed;
 
-    /** Divide by the number of cores here to have a value between 0 and 1 **/
+    /* Divide by the number of cores here to have a value between 0 and 1 */
     cpu_load /= host_->pimpl_cpu->get_core_count();
+    xbt_assert(not(cpu_load > 1), "The impossible did happen, as usual.");
 
-    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;
   }
 
-  /* @mquinson: 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
-   *
-   *   X/(X+Y)*W_idle + Y/(X+Y)*W_burn
-   *
-   * where X is the amount of idling cores, and Y the amount of computing cores.
-   *
-   * @Mommessc: I do not think the load is always 0 or 1 anymore.
-   * Moreover, it is not quite clear how the regular model of power consumption (P = Pstatic + load * Pdynamic)
-   * is impacted if we separate the number of idle and working cores.
-   */
   return get_current_watts_value(cpu_load);
 }
 
@@ -326,7 +322,62 @@ double HostEnergy::get_consumed_energy()
 
 void HostEnergy::init_watts_range_list()
 {
-  const char* all_power_values_str = host_->get_property("watt_per_state");
+  const char* old_prop = host_->get_property("watt_per_state");
+  if (old_prop != nullptr) {
+    std::vector<std::string> all_power_values;
+    boost::split(all_power_values, old_prop, boost::is_any_of(","));
+
+    std::string msg = std::string("DEPRECATION WARNING: Property 'watt_per_state' will not work after v3.28.\n");
+    msg += std::string("The old syntax 'Idle:OneCore:AllCores' must be converted into 'Idle:Epsilon:AllCores' to "
+                       "properly model the consumption of non-whole tasks on mono-core hosts. Here are the values to "
+                       "use for host '") +
+           host_->get_cname() + "' in your XML file:\n";
+    msg += "     <prop id=\"wattage_per_state\" value=\"";
+    for (auto const& current_power_values_str : all_power_values) {
+      std::vector<std::string> current_power_values;
+      boost::split(current_power_values, current_power_values_str, boost::is_any_of(":"));
+      double p_idle = xbt_str_parse_double((current_power_values.at(0)).c_str(),
+                                           "Invalid obsolete XML file. Fix your watt_per_state property.");
+      double p_one_core;
+      double p_full;
+      double p_epsilon;
+
+      if (current_power_values.size() == 3) {
+        p_idle     = xbt_str_parse_double((current_power_values.at(0)).c_str(),
+                                      "Invalid obsolete XML file. Fix your watt_per_state property.");
+        p_one_core = xbt_str_parse_double((current_power_values.at(1)).c_str(),
+                                          "Invalid obsolete XML file. Fix your watt_per_state property.");
+        p_full     = xbt_str_parse_double((current_power_values.at(2)).c_str(),
+                                      "Invalid obsolete XML file. Fix your watt_per_state property.");
+        if (host_->get_core_count() == 1) {
+          p_epsilon = p_full;
+        } else {
+          p_epsilon = p_one_core - ((p_full - p_one_core) / (host_->get_core_count() - 1));
+        }
+      } else { // consuption given with idle and full only
+        p_idle = xbt_str_parse_double((current_power_values.at(0)).c_str(),
+                                      "Invalid obsolete XML file. Fix your watt_per_state property.");
+        p_full = xbt_str_parse_double((current_power_values.at(1)).c_str(),
+                                      "Invalid obsolete XML file. Fix your watt_per_state property.");
+        if (host_->get_core_count() == 1) {
+          p_epsilon = p_full;
+        } else {
+          p_epsilon = p_idle;
+        }
+      }
+
+      PowerRange range(p_idle, p_epsilon, p_full);
+      power_range_watts_list_.push_back(range);
+
+      msg += std::to_string(p_idle) + ":" + std::to_string(p_epsilon) + ":" + std::to_string(p_full);
+      msg += ",";
+    }
+    msg.pop_back(); // Remove the extraneous ','
+    msg += "\" />";
+    XBT_WARN("%s", msg.c_str());
+    return;
+  }
+  const char* all_power_values_str = host_->get_property("wattage_per_state");
   if (all_power_values_str == nullptr)
     return;
 
@@ -354,15 +405,12 @@ void HostEnergy::init_watts_range_list()
     char* msg_max     = bprintf("Invalid AllCores value for pstate %d on host %s: %%s", i, host_->get_cname());
 
     idle_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle);
-    if (current_power_values.size() == 2) // Case: Idle:AllCores
-    {
-        epsilon_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle);
-        max_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_max);
-    }
-    else // Case: Idle:Epsilon:AllCores
-    {
-        epsilon_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_epsilon);
-        max_power = xbt_str_parse_double((current_power_values.at(2)).c_str(), msg_max);
+    if (current_power_values.size() == 2) { // Case: Idle:AllCores
+      epsilon_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle);
+      max_power     = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_max);
+    } else { // Case: Idle:Epsilon:AllCores
+      epsilon_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_epsilon);
+      max_power     = xbt_str_parse_double((current_power_values.at(2)).c_str(), msg_max);
     }
 
     XBT_DEBUG("Creating PowerRange for host %s. Idle:%f, Epsilon:%f, AllCores:%f.", host_->get_cname(), idle_power, epsilon_power, max_power);
@@ -454,7 +502,7 @@ static void on_simulation_end()
 
 /* **************************** Public interface *************************** */
 
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  * @brief Enable host energy plugin
  * @details Enable energy plugin to get joules consumption of each cpu. Call this function before #MSG_init().
  */
@@ -477,7 +525,7 @@ void sg_host_energy_plugin_init()
   // 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::ExecImpl const& activity) {
+  simgrid::s4u::Exec::on_start.connect([](simgrid::s4u::Actor const&, simgrid::s4u::Exec const& activity) {
     if (activity.get_host_number() == 1) { // We only run on one host
       simgrid::s4u::Host* host         = activity.get_host();
       simgrid::s4u::VirtualMachine* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host);
@@ -489,7 +537,7 @@ void sg_host_energy_plugin_init()
   });
 }
 
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  *  @brief updates the consumption of all hosts
  *
  * After this call, sg_host_get_consumed_energy() will not interrupt your process
@@ -507,7 +555,7 @@ void sg_host_energy_update_all()
   });
 }
 
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  *  @brief Returns the total energy consumed by the host so far (in Joules)
  *
  *  Please note that since the consumption is lazily updated, it may require a simcall to update it.
@@ -521,7 +569,7 @@ double sg_host_get_consumed_energy(sg_host_t host)
   return host->extension<HostEnergy>()->get_consumed_energy();
 }
 
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  *  @brief Get the amount of watt dissipated when the host is idling
  */
 double sg_host_get_idle_consumption(sg_host_t host)
@@ -531,7 +579,7 @@ double sg_host_get_idle_consumption(sg_host_t host)
   return host->extension<HostEnergy>()->get_idle_consumption();
 }
 
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  *  @brief Get the amount of watt dissipated at the given pstate when the host is idling
  */
 double sg_host_get_wattmin_at(sg_host_t host, int pstate)
@@ -540,7 +588,7 @@ double sg_host_get_wattmin_at(sg_host_t host, int pstate)
              "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
   return host->extension<HostEnergy>()->get_watt_min_at(pstate);
 }
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  *  @brief  Returns the amount of watt dissipated at the given pstate when the host burns CPU at 100%
  */
 double sg_host_get_wattmax_at(sg_host_t host, int pstate)
@@ -549,7 +597,7 @@ double sg_host_get_wattmax_at(sg_host_t host, int pstate)
              "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
   return host->extension<HostEnergy>()->get_watt_max_at(pstate);
 }
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  *  @brief  Returns the power slope at the given pstate
  */
 double sg_host_get_power_range_slope_at(sg_host_t host, int pstate)
@@ -558,7 +606,7 @@ double sg_host_get_power_range_slope_at(sg_host_t host, int pstate)
              "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
   return host->extension<HostEnergy>()->get_power_range_slope_at(pstate);
 }
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
  *  @brief Returns the current consumption of the host
  */
 double sg_host_get_current_consumption(sg_host_t host)