Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[ENERGY] Instead of using plain integers, use constants
[simgrid.git] / src / surf / plugins / host_energy.cpp
index 9167876..0436ec2 100644 (file)
 #include <utility>
 #include <vector>
 
-/** @addtogroup SURF_plugin_energy
+/** @addtogroup plugin_energy
 
 
 This is the energy plugin, enabling to account not only for computation time,
 but also for the dissipated energy in the simulated platform.
-To activate this plugin, first call MSG_energy_plugin_init() before your #MSG_init(),
+To activate this plugin, first call sg_host_energy_plugin_init() before your #MSG_init(),
 and then use MSG_host_get_consumed_energy() to retrieve the consumption of a given host.
 
 When the host is on, this energy consumption naturally depends on both the
 current CPU load and the host energy profile. According to our measurements,
 the consumption is somehow linear in the amount of cores at full speed,
-with an abnormality when all the cores are idle.
+with an abnormality when all the cores are idle. The full details are in
+<a href="https://hal.inria.fr/hal-01523608">our scientific paper</a> on that topic.
 
 As a result, our energy model takes 4 parameters:
 
@@ -60,10 +61,10 @@ This is enough to compute the consumption as a function of the amount of loaded
 
 ### What if a given core is only at load 50%?
 
-Well, that's impossible in SimGrid because we recompute everything each time
+This is impossible in SimGrid because we recompute everything each time
 that the CPU starts or stops doing something. So if a core is at load 50% over
 a period, it means that it is at load 100% half of the time and at load 0% the
-rest of the time, and the model holds.
+rest of the time, and our model holds.
 
 ### What if the host has only one core?
 
@@ -78,7 +79,7 @@ If you insist on passing 3 parameters in this case, then you must have the same
 </host>
 \endcode
 
-### How does DVFS interact with the energy model?
+### How does DVFS interact with the host energy model?
 
 If your host has several DVFS levels (several pstates), then you should
 give the energetic profile of each pstate level:
@@ -101,6 +102,16 @@ This encodes the following values
 To change the pstate of a given CPU, use the following functions:
 #MSG_host_get_nb_pstates(), simgrid#s4u#Host#setPstate(), #MSG_host_get_power_peak_at().
 
+### How accurate are these models?
+
+This model cannot be more accurate than your instantiation:
+with the default values, your result will not be accurate at all. You can still get
+accurate energy prediction, provided that you carefully instantiate the model.
+The first step is to ensure that your timing prediction match perfectly. But this
+is only the first step of the path, and you really want to read
+<a href="https://hal.inria.fr/hal-01523608">this paper</a> to see all what you need
+to do before you can get accurate energy predictions.
+
  */
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_energy, surf, "Logging specific to the SURF energy plugin");
@@ -141,6 +152,7 @@ private:
    * with the old pstate!)
    */
   int pstate = 0;
+  const int pstate_off = -1;
 
 public:
   double watts_off    = 0.0; /*< Consumption when the machine is turned off (shutdown) */
@@ -155,10 +167,10 @@ void HostEnergy::update()
 {
   double start_time  = this->last_updated;
   double finish_time = surf_get_clock();
-  double cpu_load;
-  double current_speed = host->speed();
+  double current_speed = host->getSpeed();
 
   if (start_time < finish_time) {
+    double cpu_load;
     // We may have start == finish if the past consumption was updated since the simcall was started
     // for example if 2 actors requested to update the same host's consumption in a given scheduling round.
     //
@@ -189,7 +201,7 @@ void HostEnergy::update()
     double previous_energy = this->total_energy;
 
     double instantaneous_consumption;
-    if (this->pstate == -1) // The host was off at the beginning of this time interval
+    if (this->pstate == pstate_off) // The host was off at the beginning of this time interval
       instantaneous_consumption = this->watts_off;
     else
       instantaneous_consumption = this->getCurrentWattsValue(cpu_load);
@@ -203,20 +215,21 @@ void HostEnergy::update()
 
     XBT_DEBUG("[update_energy of %s] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> "
               "%.2f J",
-              host->cname(), start_time, finish_time, host->pimpl_cpu->speed_.peak, previous_energy, energy_this_step);
+              host->getCname(), start_time, finish_time, host->pimpl_cpu->speed_.peak, previous_energy,
+              energy_this_step);
   }
 
   /* Save data for the upcoming time interval: whether it's on/off and the pstate if it's on */
-  this->pstate = host->isOn() ? host->pstate() : -1;
+  this->pstate = host->isOn() ? host->getPstate() : pstate_off;
 }
 
 HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host(ptr), last_updated(surf_get_clock())
 {
   initWattsRangeList();
 
-  const char* off_power_str = host->property("watt_off");
+  const char* off_power_str = host->getProperty("watt_off");
   if (off_power_str != nullptr) {
-    char* msg       = bprintf("Invalid value for property watt_off of host %s: %%s", host->cname());
+    char* msg       = bprintf("Invalid value for property watt_off of host %s: %%s", host->getCname());
     this->watts_off = xbt_str_parse_double(off_power_str, msg);
     xbt_free(msg);
   }
@@ -227,20 +240,20 @@ HostEnergy::~HostEnergy() = default;
 
 double HostEnergy::getWattMinAt(int pstate)
 {
-  xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
+  xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->getCname());
   return power_range_watts_list[pstate].min;
 }
 
 double HostEnergy::getWattMaxAt(int pstate)
 {
-  xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
+  xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->getCname());
   return power_range_watts_list[pstate].max;
 }
 
 /** @brief Computes the power consumed by the host according to the current pstate and processor load */
 double HostEnergy::getCurrentWattsValue(double cpu_load)
 {
-  xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
+  xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->getCname());
 
   /* min_power corresponds to the power consumed when only one core is active */
   /* max_power is the power consumed at 100% cpu load       */
@@ -265,7 +278,7 @@ double HostEnergy::getCurrentWattsValue(double cpu_load)
      * (maxCpuLoad is by definition 1)
      */
     double power_slope;
-    int coreCount         = host->coreCount();
+    int coreCount         = host->getCoreCount();
     double coreReciprocal = static_cast<double>(1) / static_cast<double>(coreCount);
     if (coreCount > 1)
       power_slope = (max_power - min_power) / (1 - coreReciprocal);
@@ -293,24 +306,24 @@ double HostEnergy::getConsumedEnergy()
 
 void HostEnergy::initWattsRangeList()
 {
-  const char* all_power_values_str = host->property("watt_per_state");
+  const char* all_power_values_str = host->getProperty("watt_per_state");
   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(","));
-  XBT_DEBUG("%s: profile: %s, cores: %d", host->cname(), all_power_values_str, host->coreCount());
+  XBT_DEBUG("%s: profile: %s, cores: %d", host->getCname(), all_power_values_str, host->getCoreCount());
 
   int i = 0;
   for (auto current_power_values_str : all_power_values) {
     /* retrieve the power values associated with the current pstate */
     std::vector<std::string> current_power_values;
     boost::split(current_power_values, current_power_values_str, boost::is_any_of(":"));
-    if (host->coreCount() == 1) {
+    if (host->getCoreCount() == 1) {
       xbt_assert(current_power_values.size() == 2 || current_power_values.size() == 3,
                  "Power properties incorrectly defined for host %s."
                  "It should be 'Idle:FullSpeed' power values because you have one core only.",
-                 host->cname());
+                 host->getCname());
       if (current_power_values.size() == 2) {
         // In this case, 1core == AllCores
         current_power_values.push_back(current_power_values.at(1));
@@ -320,20 +333,20 @@ void HostEnergy::initWattsRangeList()
                    "The energy profile of mono-cores should be formated 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->cname());
+                   host->getCname());
       }
     } else {
       xbt_assert(current_power_values.size() == 3,
                  "Power properties incorrectly defined for host %s."
                  "It should be 'Idle:OneCore:AllCores' power values because you have more than one core.",
-                 host->cname());
+                 host->getCname());
     }
 
     /* min_power corresponds to the idle power (cpu load = 0) */
     /* max_power is the power consumed at 100% cpu load       */
-    char* msg_idle = bprintf("Invalid idle value for pstate %d on host %s: %%s", i, host->cname());
-    char* msg_min  = bprintf("Invalid OneCore value for pstate %d on host %s: %%s", i, host->cname());
-    char* msg_max  = bprintf("Invalid AllCores value for pstate %d on host %s: %%s", i, host->cname());
+    char* msg_idle = bprintf("Invalid idle value for pstate %d on host %s: %%s", i, host->getCname());
+    char* msg_min  = bprintf("Invalid OneCore value for pstate %d on host %s: %%s", i, host->getCname());
+    char* msg_max  = bprintf("Invalid AllCores value for pstate %d on host %s: %%s", i, host->getCname());
     PowerRange range(xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle),
                      xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_min),
                      xbt_str_parse_double((current_power_values.at(2)).c_str(), msg_max));
@@ -399,7 +412,7 @@ static void onHostDestruction(simgrid::s4u::Host& host)
 
   HostEnergy* host_energy = host.extension<HostEnergy>();
   host_energy->update();
-  XBT_INFO("Energy consumption of host %s: %f Joules", host.cname(), host_energy->getConsumedEnergy());
+  XBT_INFO("Energy consumption of host %s: %f Joules", host.getCname(), host_energy->getConsumedEnergy());
 }
 
 static void onSimulationEnd()
@@ -426,7 +439,7 @@ static void onSimulationEnd()
 /* **************************** Public interface *************************** */
 SG_BEGIN_DECL()
 
-/** \ingroup SURF_plugin_energy
+/** \ingroup plugin_energy
  * \brief Enable host energy plugin
  * \details Enable energy plugin to get joules consumption of each cpu. Call this function before #MSG_init().
  */
@@ -445,7 +458,8 @@ void sg_host_energy_plugin_init()
   simgrid::surf::CpuAction::onStateChange.connect(&onActionStateChange);
 }
 
-/** @brief updates the consumption of all hosts
+/** @ingroup plugin_energy
+ *  @brief updates the consumption of all hosts
  *
  * After this call, sg_host_get_consumed_energy() will not interrupt your process
  * (until after the next clock update).
@@ -454,19 +468,19 @@ void sg_host_energy_update_all()
 {
   simgrid::simix::kernelImmediate([]() {
     std::vector<simgrid::s4u::Host*> list;
-    simgrid::s4u::Engine::instance()->hostList(&list);
+    simgrid::s4u::Engine::getInstance()->getHostList(&list);
     for (auto host : list)
-      host->extension<HostEnergy>()->update();
+      if (dynamic_cast<simgrid::s4u::VirtualMachine*>(host) == nullptr) // Ignore virtual machines
+        host->extension<HostEnergy>()->update();
   });
 }
 
-/** @brief Returns the total energy consumed by the host so far (in Joules)
+/** @ingroup plugin_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.
  *  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.
- *
- *  See also @ref SURF_plugin_energy.
  */
 double sg_host_get_consumed_energy(sg_host_t host)
 {
@@ -475,14 +489,18 @@ double sg_host_get_consumed_energy(sg_host_t host)
   return host->extension<HostEnergy>()->getConsumedEnergy();
 }
 
-/** @brief Get the amount of watt dissipated at the given pstate when the host is idling */
+/** @ingroup plugin_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)
 {
   xbt_assert(HostEnergy::EXTENSION_ID.valid(),
              "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
   return host->extension<HostEnergy>()->getWattMinAt(pstate);
 }
-/** @brief  Returns the amount of watt dissipated at the given pstate when the host burns CPU at 100% */
+/** @ingroup plugin_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)
 {
   xbt_assert(HostEnergy::EXTENSION_ID.valid(),
@@ -490,12 +508,14 @@ double sg_host_get_wattmax_at(sg_host_t host, int pstate)
   return host->extension<HostEnergy>()->getWattMaxAt(pstate);
 }
 
-/** @brief Returns the current consumption of the host */
+/** @ingroup plugin_energy
+ *  @brief Returns the current consumption of the host
+ */
 double sg_host_get_current_consumption(sg_host_t host)
 {
   xbt_assert(HostEnergy::EXTENSION_ID.valid(),
              "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
-  double cpu_load = lmm_constraint_get_usage(host->pimpl_cpu->constraint()) / host->speed();
+  double cpu_load = lmm_constraint_get_usage(host->pimpl_cpu->constraint()) / host->getSpeed();
   return host->extension<HostEnergy>()->getCurrentWattsValue(cpu_load);
 }