Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
47bfda4f36ae4d57972ed230cf024be6a4103611
[simgrid.git] / src / plugins / host_energy.cpp
1 /* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include <simgrid/Exception.hpp>
7 #include <simgrid/plugins/energy.h>
8 #include <simgrid/s4u/Engine.hpp>
9 #include <simgrid/s4u/Exec.hpp>
10 #include <simgrid/s4u/Host.hpp>
11 #include <simgrid/s4u/VirtualMachine.hpp>
12 #include <simgrid/simix.hpp>
13
14 #include "src/kernel/activity/ActivityImpl.hpp"
15 #include "src/kernel/resource/CpuImpl.hpp"
16 #include "src/simgrid/module.hpp"
17
18 #include <boost/algorithm/string/classification.hpp>
19 #include <boost/algorithm/string/split.hpp>
20
21 SIMGRID_REGISTER_PLUGIN(host_energy, "Cpu energy consumption.", &sg_host_energy_plugin_init)
22
23 /** @defgroup plugin_host_energy plugin_host_energy Plugin Host Energy
24
25   @beginrst
26
27 This is the energy plugin, enabling to account not only for computation time, but also for the dissipated energy in the
28 simulated platform.
29 To activate this plugin, first call :cpp:func:`sg_host_energy_plugin_init()` before your loading your platform, and
30 then use :cpp:func:`sg_host_get_consumed_energy()` to retrieve the consumption of a given host.
31
32 When the host is on, this energy consumption naturally depends on both the current CPU load and the host energy profile.
33 According to our measurements, the consumption is somehow linear in the amount of cores at full speed, with an
34 abnormality when all the cores are idle. The full details are in `our scientific paper
35 <https://hal.inria.fr/hal-01523608>`_ on that topic.
36
37 As a result, our energy model takes 4 parameters:
38
39   - ``Idle`` wattage (i.e., instantaneous consumption in Watt) when your host is up and running, but without anything to
40     do.
41   - ``Epsilon`` wattage when all cores are at 0 or epsilon%, but not in Idle state.
42   - ``AllCores`` wattage when all cores of the host are at 100%.
43   - ``Off`` wattage when the host is turned off.
44
45 Here is an example of XML declaration:
46
47 .. code-block:: xml
48
49    <host id="HostA" speed="100.0Mf" core="4">
50        <prop id="wattage_per_state" value="100.0:120.0:200.0" />
51        <prop id="wattage_off" value="10" />
52    </host>
53
54 If only two values are given, ``Idle`` is used for the missing ``Epsilon`` value.
55
56 This example gives the following parameters: ``Off`` is 10 Watts; ``Idle`` is 100 Watts; ``Epsilon`` is 120 Watts and
57 ``AllCores`` is 200 Watts.
58 This is enough to compute the wattage as a function of the amount of loaded cores:
59
60 .. raw:: html
61
62    <table border="1">
63    <tr><th>#Cores loaded</th><th>Wattage</th><th>Explanation</th></tr>
64    <tr><td>0 (idle)</td><td> 100 Watts&nbsp;</td><td>Idle value</td></tr>
65    <tr><td>1</td><td> 140 Watts</td><td> Linear extrapolation between Epsilon and AllCores</td></tr>
66    <tr><td>2</td><td> 160 Watts</td><td> Linear extrapolation between Epsilon and AllCores</td></tr>
67    <tr><td>3</td><td> 180 Watts</td><td> Linear extrapolation between Epsilon and AllCores</td></tr>
68    <tr><td>4</td><td> 200 Watts</td><td> AllCores value</td></tr>
69    </table>
70
71 Here is how it looks graphically:
72
73 .. image:: img/plugin-energy.svg
74    :scale: 80%
75    :align: center
76
77 As you can see, the ``Epsilon`` parameter allows to freely specify the slope you want, while using the 2 parameters
78 version of the model (with only ``Idle`` and ``AllCores``) requires that the ``Idle`` value is on the extension of the
79 line crossing the consumption you mesure for each core amount. Please note that specifying the consumption for each core
80 amount separately was not a solution because parallel tasks can use an amount of cores that is not an integer. The good
81 news is that it was not necessary, as our experiments (detailed in the paper) show that the proposed linear model is
82 sufficient to capture reality.
83
84 .. raw:: html
85
86    <h4>How does DVFS interact with the host energy model?</h4>
87
88 If your host has several DVFS levels (several pstates), then you should give the energetic profile of each pstate level:
89
90 .. code-block:: xml
91
92    <host id="HostC" speed="100.0Mf,50.0Mf,20.0Mf" core="4">
93        <prop id="wattage_per_state"
94              value="95.0:120.0:200.0, 93.0:115.0:170.0, 90.0:110.0:150.0" />
95        <prop id="wattage_off" value="10" />
96    </host>
97
98 This encodes the following values:
99
100 .. raw:: html
101
102    <table border="1">
103    <tr><th>pstate</th><th>Performance</th><th>Idle</th><th>Epsilon</th><th>AllCores</th></tr>
104    <tr><td>0</td><td>100 Mflop/s</td><td>95 Watts</td><td>120 Watts</td><td>200 Watts</td></tr>
105    <tr><td>1</td><td>50 Mflop/s</td><td>93 Watts</td><td>115 Watts</td><td>170 Watts</td></tr>
106    <tr><td>2</td><td>20 Mflop/s</td><td>90 Watts</td><td>110 Watts</td><td>150 Watts</td></tr>
107    </table>
108
109 To change the pstate of a given CPU, use the following functions:
110 :cpp:func:`sg_host_get_nb_pstates()`, :cpp:func:`simgrid::s4u::Host::set_pstate()`,
111 :cpp:func:`sg_host_get_pstate_speed()`.
112
113 .. raw:: html
114
115    <h4>How accurate are these models?</h4>
116
117 This model cannot be more accurate than your instantiation: with the default values, your result will not be accurate at
118 all. You can still get accurate energy prediction, provided that you carefully instantiate the model.
119 The first step is to ensure that your timing prediction match perfectly. But this is only the first step of the path,
120 and you really want to read `this paper <https://hal.inria.fr/hal-01523608>`_ to see all what you need to do
121 before you can get accurate energy predictions.
122
123   @endrst
124  */
125
126 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(host_energy, kernel, "Logging specific to the host energy plugin");
127
128 // Forwards declaration needed to make this function a friend (because friends have external linkage by default)
129 static void on_simulation_end();
130
131 namespace simgrid::plugin {
132
133 class PowerRange {
134 public:
135   double idle_;
136   double epsilon_;
137   double max_;
138   double slope_;
139
140   PowerRange(double idle, double epsilon, double max) : idle_(idle), epsilon_(epsilon), max_(max), slope_(max-epsilon) {}
141 };
142
143 class HostEnergy {
144   simgrid::s4u::Host* host_ = nullptr;
145   /*< List of (idle_power, epsilon_power, max_power) tuple corresponding to each cpu pstate */
146   std::vector<PowerRange> power_range_watts_list_;
147   bool has_pstate_power_values_ = false; /*< Whether power consumption values were provided for all pstates */
148
149   /* We need to keep track of what pstate has been used, as we will sometimes be notified only *after* a pstate has been
150    * used (but we need to update the energy consumption with the old pstate!)
151    */
152   int pstate_           = 0;
153   const int pstate_off_ = -1;
154   double watts_off_     = 0.0;              /*< Consumption when the machine is turned off (shutdown) */
155   double total_energy_  = 0.0;              /*< Total energy consumed by the host */
156   double last_updated_  = simgrid::s4u::Engine::get_clock(); /*< Timestamp of the last energy update event*/
157
158   /* Only used to split total energy into unused/used hosts.
159    * If you want to get this info for something else, rather use the host_load plugin
160    */
161   bool host_was_used_ = false;
162
163   void init_watts_range_list();
164   friend void ::on_simulation_end(); // For access to host_was_used_
165
166 public:
167   static simgrid::xbt::Extension<simgrid::s4u::Host, HostEnergy> EXTENSION_ID;
168
169   explicit HostEnergy(simgrid::s4u::Host* ptr);
170   ~HostEnergy();
171
172   bool has_pstate_power_values() const;
173
174   double get_current_watts_value();
175   double get_current_watts_value(double cpu_load) const;
176   double get_consumed_energy();
177   double get_watt_idle_at(int pstate) const;
178   double get_watt_min_at(int pstate) const;
179   double get_watt_max_at(int pstate) const;
180   double get_power_range_slope_at(int pstate) const;
181   double get_last_update_time() const { return last_updated_; }
182   void update();
183 };
184
185 simgrid::xbt::Extension<simgrid::s4u::Host, HostEnergy> HostEnergy::EXTENSION_ID;
186
187 /* Returns whether power consumption values were provided for all pstates. */
188 bool HostEnergy::has_pstate_power_values() const {
189   return has_pstate_power_values_;
190 }
191
192 /* Computes the consumption so far. Called lazily on need. */
193 void HostEnergy::update()
194 {
195   double start_time  = last_updated_;
196   double finish_time = simgrid::s4u::Engine::get_clock();
197   //
198   // We may have start == finish if the past consumption was updated since the simcall was started
199   // for example if 2 actors requested to update the same host's consumption in a given scheduling round.
200   //
201   // Even in this case, we need to save the pstate for the next call (after this if),
202   // which may have changed since that recent update.
203   if (start_time < finish_time) {
204     double previous_energy = total_energy_;
205
206     double instantaneous_power_consumption = this->get_current_watts_value();
207
208     double energy_this_step = instantaneous_power_consumption * (finish_time - start_time);
209
210     // TODO Trace: Trace energy_this_step from start_time to finish_time in host->getName()
211
212     total_energy_ = previous_energy + energy_this_step;
213     last_updated_ = finish_time;
214
215     XBT_DEBUG("[update_energy of %s] period=[%.8f-%.8f]; current speed=%.2E flop/s (pstate %i); total consumption "
216               "before: %.8f J -> added now: %.8f J",
217               host_->get_cname(), start_time, finish_time, host_->get_pstate_speed(pstate_), pstate_, previous_energy,
218               energy_this_step);
219   }
220
221   /* Save data for the upcoming time interval: whether it's on/off and the pstate if it's on */
222   pstate_ = host_->is_on() ? host_->get_pstate() : pstate_off_;
223 }
224
225 HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host_(ptr)
226 {
227   init_watts_range_list();
228
229   const char* off_power_str = host_->get_property("wattage_off");
230   if (off_power_str != nullptr) {
231     try {
232       this->watts_off_ = std::stod(off_power_str);
233     } catch (const std::invalid_argument&) {
234       throw std::invalid_argument("Invalid value for property wattage_off of host " + host_->get_name() + ": " +
235                                   off_power_str);
236     }
237   }
238   /* watts_off is 0 by default */
239 }
240
241 HostEnergy::~HostEnergy() = default;
242
243 double HostEnergy::get_watt_idle_at(int pstate) const
244 {
245   if (not has_pstate_power_values_)
246     return 0.0;
247   return power_range_watts_list_[pstate].idle_;
248 }
249
250 double HostEnergy::get_watt_min_at(int pstate) const
251 {
252   if (not has_pstate_power_values_)
253     return 0.0;
254   return power_range_watts_list_[pstate].epsilon_;
255 }
256
257 double HostEnergy::get_watt_max_at(int pstate) const
258 {
259   if (not has_pstate_power_values_)
260     return 0.0;
261   return power_range_watts_list_[pstate].max_;
262 }
263
264 double HostEnergy::get_power_range_slope_at(int pstate) const
265 {
266   if (not has_pstate_power_values_)
267     return 0.0;
268   return power_range_watts_list_[pstate].slope_;
269 }
270
271 /** @brief Computes the power consumed by the host according to the current situation
272  *
273  * - If the host is off, that's the watts_off value
274  * - if it's on, take the current pstate and the current processor load into account */
275 double HostEnergy::get_current_watts_value()
276 {
277   if (this->pstate_ == pstate_off_) // The host is off (or was off at the beginning of this time interval)
278     return this->watts_off_;
279
280   double current_speed = host_->get_pstate_speed(this->pstate_);
281
282   double cpu_load;
283
284   if (current_speed <= 0)
285     // Some users declare a pstate of speed 0 flops (e.g., to model boot time).
286     // We consider that the machine is then fully loaded. That's arbitrary but it avoids a NaN
287     cpu_load = 1;
288   else {
289     cpu_load = host_->get_load() / current_speed;
290
291     /* Divide by the number of cores here to have a value between 0 and 1 */
292     cpu_load /= host_->get_core_count();
293
294     if (cpu_load > 1) // This condition is true for energy_ptask on 32 bits, even if cpu_load is displayed as 1.000000
295       cpu_load = 1;   // That may be an harmless rounding error?
296     if (cpu_load > 0)
297       host_was_used_ = true;
298   }
299
300   return get_current_watts_value(cpu_load);
301 }
302
303 /** @brief Computes the power that the host would consume at the provided processor load
304  *
305  * Whether the host is ON or OFF is not taken into account.
306  */
307 double HostEnergy::get_current_watts_value(double cpu_load) const
308 {
309   if (not has_pstate_power_values_)
310     return 0.0;
311
312   /* Return watts_off if pstate == pstate_off (ie, if the host is off) */
313   if (this->pstate_ == pstate_off_) {
314     return watts_off_;
315   }
316
317   PowerRange power_range = power_range_watts_list_.at(this->pstate_);
318   double current_power;
319
320   if (cpu_load > 0)
321   {
322       /**
323        * Something is going on, the host is not idle.
324        *
325        * The power consumption follows the regular model:
326        * P(cpu_load) = Pstatic + Pdynamic * cpu_load
327        * where Pstatic = power_range.epsilon_ and Pdynamic = power_range.slope_
328        * and the cpu_load is a value between 0 and 1.
329        */
330       current_power = power_range.epsilon_ + cpu_load * power_range.slope_;
331   }
332   else
333   {
334       /* The host is idle, take the dedicated value! */
335       current_power = power_range.idle_;
336   }
337
338   XBT_DEBUG("[get_current_watts] pstate=%i, epsilon_power=%f, max_power=%f, slope=%f", this->pstate_, power_range.epsilon_,
339             power_range.max_, power_range.slope_);
340   XBT_DEBUG("[get_current_watts] Current power (watts) = %f, load = %f", current_power, cpu_load);
341
342   return current_power;
343 }
344
345 double HostEnergy::get_consumed_energy()
346 {
347   if (last_updated_ < simgrid::s4u::Engine::get_clock()) // We need to simcall this as it modifies the environment
348     simgrid::kernel::actor::simcall_answered(std::bind(&HostEnergy::update, this));
349
350   return total_energy_;
351 }
352
353 void HostEnergy::init_watts_range_list()
354 {
355   const char* all_power_values_str = host_->get_property("wattage_per_state");
356   if (all_power_values_str == nullptr) {
357     XBT_WARN("No energetic profiles (wattage_per_state) given for host %s, using 0 W by default. Direct request of power/energy consumption of this host will fail.", host_->get_cname());
358     return;
359   }
360
361   std::vector<std::string> all_power_values;
362   boost::split(all_power_values, all_power_values_str, boost::is_any_of(","));
363   XBT_DEBUG("%s: power properties: %s", host_->get_cname(), all_power_values_str);
364
365   xbt_assert(all_power_values.size() == host_->get_pstate_count(),
366              "Invalid XML file. Found %zu energetic profiles for %lu pstates", all_power_values.size(),
367              host_->get_pstate_count());
368
369   int i = 0;
370   for (auto const& current_power_values_str : all_power_values) {
371     /* retrieve the power values associated with the pstate i */
372     std::vector<std::string> current_power_values;
373     boost::split(current_power_values, current_power_values_str, boost::is_any_of(":"));
374
375     xbt_assert(current_power_values.size() == 2 || current_power_values.size() == 3,
376                "Power properties incorrectly defined for host %s."
377                "It should be 'Idle:AllCores' (or 'Idle:Epsilon:AllCores') power values.",
378                host_->get_cname());
379
380     double idle_power;
381     double epsilon_power;
382     double max_power;
383
384     auto msg_idle    = xbt::string_printf("Invalid Idle value for pstate %d on host %s", i, host_->get_cname());
385     auto msg_epsilon = xbt::string_printf("Invalid Epsilon value for pstate %d on host %s", i, host_->get_cname());
386     auto msg_max     = xbt::string_printf("Invalid AllCores value for pstate %d on host %s", i, host_->get_cname());
387
388     idle_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle.c_str());
389     if (current_power_values.size() == 2) { // Case: Idle:AllCores
390       epsilon_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle.c_str());
391       max_power     = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_max.c_str());
392     } else { // Case: Idle:Epsilon:AllCores
393       epsilon_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_epsilon.c_str());
394       max_power     = xbt_str_parse_double((current_power_values.at(2)).c_str(), msg_max.c_str());
395     }
396
397     XBT_DEBUG("Creating PowerRange for host %s. Idle:%f, Epsilon:%f, AllCores:%f.", host_->get_cname(), idle_power, epsilon_power, max_power);
398
399     PowerRange range(idle_power, epsilon_power, max_power);
400     power_range_watts_list_.push_back(range);
401     ++i;
402   }
403
404   has_pstate_power_values_ = true;
405 }
406 } // namespace simgrid::plugin
407
408 using simgrid::plugin::HostEnergy;
409
410 /* **************************** events  callback *************************** */
411 static void on_creation(simgrid::s4u::Host& host)
412 {
413   if (dynamic_cast<simgrid::s4u::VirtualMachine*>(&host)) // Ignore virtual machines
414     return;
415
416   // TODO Trace: set to zero the energy variable associated to host->get_name()
417
418   host.extension_set(new HostEnergy(&host));
419 }
420
421 static void on_action_state_change(simgrid::kernel::resource::CpuAction const& action,
422                                    simgrid::kernel::resource::Action::State /*previous*/)
423 {
424   for (simgrid::kernel::resource::CpuImpl const* cpu : action.cpus()) {
425     simgrid::s4u::Host* host = cpu->get_iface();
426     if (host != nullptr) {
427       // If it's a VM, take the corresponding PM
428       if (const auto* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host))
429         host = vm->get_pm();
430
431       // Get the host_energy extension for the relevant host
432       auto* host_energy = host->extension<HostEnergy>();
433
434       if (host_energy->get_last_update_time() < simgrid::s4u::Engine::get_clock())
435         host_energy->update();
436     }
437   }
438 }
439
440 /* This callback is fired either when the host changes its state (on/off) ("onStateChange") or its speed
441  * (because the user changed the pstate, or because of external trace events) ("onSpeedChange") */
442 static void on_host_change(simgrid::s4u::Host const& h)
443 {
444   auto* host = &h;
445   if (const auto* vm = dynamic_cast<simgrid::s4u::VirtualMachine const*>(host)) // Take the PM of virtual machines
446     host = vm->get_pm();
447
448   host->extension<HostEnergy>()->update();
449 }
450
451 static void on_host_destruction(simgrid::s4u::Host const& host)
452 {
453   if (dynamic_cast<simgrid::s4u::VirtualMachine const*>(&host)) // Ignore virtual machines
454     return;
455
456   XBT_INFO("Energy consumption of host %s: %f Joules", host.get_cname(),
457            host.extension<HostEnergy>()->get_consumed_energy());
458 }
459
460 static void on_simulation_end()
461 {
462   double total_energy      = 0.0; // Total energy consumption (whole platform)
463   double used_hosts_energy = 0.0; // Energy consumed by hosts that computed something
464   for (simgrid::s4u::Host const* host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
465     if (host && dynamic_cast<const simgrid::s4u::VirtualMachine*>(host) == nullptr) { // Ignore virtual machines
466       double energy = host->extension<HostEnergy>()->get_consumed_energy();
467       total_energy += energy;
468       if (host->extension<HostEnergy>()->host_was_used_)
469         used_hosts_energy += energy;
470     }
471   }
472   XBT_INFO("Total energy consumption: %f Joules (used hosts: %f Joules; unused/idle hosts: %f)", total_energy,
473            used_hosts_energy, total_energy - used_hosts_energy);
474 }
475
476 static void on_activity_suspend_resume(simgrid::s4u::Activity const& activity)
477 {
478   if (auto* action = dynamic_cast<simgrid::kernel::resource::CpuAction*>(activity.get_impl()->model_action_);
479       action != nullptr)
480     on_action_state_change(*action, /*ignored*/ action->get_state());
481 }
482
483 /* **************************** Public interface *************************** */
484
485 /** @ingroup plugin_host_energy
486  * @brief Enable host energy plugin
487  * @details Enable energy plugin to get joules consumption of each cpu. Call this function before loading your platform.
488  */
489 void sg_host_energy_plugin_init()
490 {
491   if (HostEnergy::EXTENSION_ID.valid())
492     return;
493
494   HostEnergy::EXTENSION_ID = simgrid::s4u::Host::extension_create<HostEnergy>();
495
496   simgrid::s4u::Host::on_creation_cb(&on_creation);
497   simgrid::s4u::Host::on_onoff_cb(&on_host_change);
498   simgrid::s4u::Host::on_speed_change_cb(&on_host_change);
499   simgrid::s4u::Host::on_destruction_cb(&on_host_destruction);
500   simgrid::s4u::Host::on_exec_state_change_cb(&on_action_state_change);
501   simgrid::s4u::VirtualMachine::on_suspend_cb(&on_host_change);
502   simgrid::s4u::VirtualMachine::on_resume_cb(&on_host_change);
503   simgrid::s4u::Exec::on_suspend_cb(on_activity_suspend_resume);
504   simgrid::s4u::Exec::on_resume_cb(on_activity_suspend_resume);
505   simgrid::s4u::Engine::on_simulation_end_cb(&on_simulation_end);
506   // We may only have one actor on a node. If that actor executes something like
507   //   compute -> recv -> compute
508   // the recv operation will not trigger a "Host::on_exec_state_change_cb". This means
509   // that the next trigger would be the 2nd compute, hence ignoring the idle time
510   // during the recv call. By updating at the beginning of a compute, we can
511   // fix that. (If the cpu is not idle, this is not required.)
512   simgrid::s4u::Exec::on_start_cb([](simgrid::s4u::Exec const& activity) {
513     if (activity.get_host_number() == 1) { // We only run on one host
514       simgrid::s4u::Host* host = activity.get_host();
515       if (const auto* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host))
516         host = vm->get_pm();
517       host->extension<HostEnergy>()->update();
518     }
519   });
520 }
521
522 /** @ingroup plugin_host_energy
523  *  @brief updates the consumption of all hosts
524  *
525  * After this call, sg_host_get_consumed_energy() will not interrupt your process
526  * (until after the next clock update).
527  */
528 void sg_host_energy_update_all()
529 {
530   simgrid::kernel::actor::simcall_answered([]() {
531     std::vector<simgrid::s4u::Host*> list = simgrid::s4u::Engine::get_instance()->get_all_hosts();
532     for (auto const& host : list)
533       if (dynamic_cast<simgrid::s4u::VirtualMachine*>(host) == nullptr) { // Ignore virtual machines
534         xbt_assert(host != nullptr);
535         host->extension<HostEnergy>()->update();
536       }
537   });
538 }
539
540 static void ensure_plugin_inited()
541 {
542   if (not HostEnergy::EXTENSION_ID.valid())
543     throw simgrid::xbt::InitializationError("The Energy plugin is not active. Please call sg_host_energy_plugin_init() "
544                                             "before calling any function related to that plugin.");
545 }
546
547 /** @ingroup plugin_host_energy
548  *  @brief Returns the total energy consumed by the host so far (in Joules)
549  *
550  *  Please note that since the consumption is lazily updated, it may require a simcall to update it.
551  *  The result is that the actor requesting this value will be interrupted,
552  *  the value will be updated in kernel mode before returning the control to the requesting actor.
553  */
554 double sg_host_get_consumed_energy(const_sg_host_t host)
555 {
556   ensure_plugin_inited();
557   auto host_energy = host->extension<HostEnergy>();
558   xbt_assert(host_energy->has_pstate_power_values(), "No power range properties specified for host %s",
559              host->get_cname());
560   return host_energy->get_consumed_energy();
561 }
562
563 /** @ingroup plugin_host_energy
564  *  @brief Get the amount of watt dissipated when the host is idling
565  */
566 double sg_host_get_idle_consumption(const_sg_host_t host)
567 {
568   ensure_plugin_inited();
569   return host->extension<HostEnergy>()->get_watt_idle_at(0);
570 }
571
572 /** @ingroup plugin_host_energy
573  *  @brief Get the amount of watt dissipated at the given pstate when the host is idling
574  */
575 double sg_host_get_idle_consumption_at(const_sg_host_t host, int pstate)
576 {
577   ensure_plugin_inited();
578   return host->extension<HostEnergy>()->get_watt_idle_at(pstate);
579 }
580
581 /** @ingroup plugin_host_energy
582  *  @brief Get the amount of watt dissipated at the given pstate when the host is at 0 or epsilon% CPU usage.
583  */
584 double sg_host_get_wattmin_at(const_sg_host_t host, int pstate)
585 {
586   ensure_plugin_inited();
587   return host->extension<HostEnergy>()->get_watt_min_at(pstate);
588 }
589 /** @ingroup plugin_host_energy
590  *  @brief  Returns the amount of watt dissipated at the given pstate when the host burns CPU at 100%
591  */
592 double sg_host_get_wattmax_at(const_sg_host_t host, int pstate)
593 {
594   ensure_plugin_inited();
595   return host->extension<HostEnergy>()->get_watt_max_at(pstate);
596 }
597 /** @ingroup plugin_host_energy
598  *  @brief  Returns the power slope at the given pstate
599  */
600 double sg_host_get_power_range_slope_at(const_sg_host_t host, int pstate)
601 {
602   ensure_plugin_inited();
603   return host->extension<HostEnergy>()->get_power_range_slope_at(pstate);
604 }
605 /** @ingroup plugin_host_energy
606  *  @brief Returns the current consumption of the host
607  */
608 double sg_host_get_current_consumption(const_sg_host_t host)
609 {
610   ensure_plugin_inited();
611   auto host_energy = host->extension<HostEnergy>();
612   xbt_assert(host_energy->has_pstate_power_values(), "No power range properties specified for host %s",
613              host->get_cname());
614   return host_energy->get_current_watts_value();
615 }