Logo AND Algorithmique Numérique Distribuée

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