Logo AND Algorithmique Numérique Distribuée

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