1 /* Copyright (c) 2010, 2012-2015. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
7 #include <simgrid/plugins/energy.h>
8 #include <simgrid/simix.hpp>
9 #include <src/surf/plugins/energy.hpp>
10 #include <src/surf/cpu_interface.hpp>
11 #include <src/surf/virtual_machine.hpp>
13 /** @addtogroup SURF_plugin_energy
16 This is the energy plugin, enabling to account not only for computation time,
17 but also for the dissipated energy in the simulated platform.
19 The energy consumption of a CPU depends directly of its current load. Specify that consumption in your platform file as follows:
22 <host id="HostA" power="100.0Mf" >
23 <prop id="watt_per_state" value="100.0:200.0" />
24 <prop id="watt_off" value="10" />
28 The first property means that when your host is up and running, but without anything to do, it will dissipate 100 Watts.
29 If it's fully loaded, it will dissipate 200 Watts. If its load is at 50%, then it will dissipate 150 Watts.
30 The second property means that when your host is turned off, it will dissipate only 10 Watts (please note that these values are arbitrary).
32 If your CPU is using pstates, then you can provide one consumption interval per pstate.
35 <host id="HostB" power="100.0Mf,50.0Mf,20.0Mf" pstate="0" >
36 <prop id="watt_per_state" value="95.0:200.0, 93.0:170.0, 90.0:150.0" />
37 <prop id="watt_off" value="10" />
41 That host has 3 levels of performance with the following performance: 100 Mflop/s, 50 Mflop/s or 20 Mflop/s.
42 It starts at pstate 0 (ie, at 100 Mflop/s). In this case, you have to specify one interval per pstate in the watt_per_state property.
43 In this example, the idle consumption is 95 Watts, 93 Watts and 90 Watts in each pstate while the CPU burn consumption are at 200 Watts,
44 170 Watts and 150 Watts respectively.
46 To change the pstate of a given CPU, use the following functions: #MSG_host_get_nb_pstates(), #MSG_host_set_pstate(), #MSG_host_get_power_peak_at().
48 To simulate the energy-related elements, first call the #sg_energy_plugin_init() before your #MSG_init(),
49 and then use the following function to retrieve the consumption of a given host: #MSG_host_get_consumed_energy().
52 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_energy, surf,
53 "Logging specific to the SURF energy plugin");
55 std::map<simgrid::surf::Host*, simgrid::energy::HostEnergy*> *simgrid::energy::surf_energy = NULL;
57 using simgrid::energy::HostEnergy;
59 /* Computes the consumption so far. Called lazily on need. */
60 static void update_consumption(simgrid::surf::Host *host, HostEnergy *host_energy) {
61 double start_time = host_energy->last_updated;
62 double finish_time = surf_get_clock();
64 if (host->p_cpu->m_speedPeak == 0)
65 // Some users declare a pstate of speed 0 flops (eg to model boot time).
66 // We consider that the machine is then fully loaded. That's arbitrary but it avoids a NaN
69 cpu_load = lmm_constraint_get_usage(host->p_cpu->getConstraint()) / host->p_cpu->m_speedPeak;
71 if (cpu_load > 1) // A machine with a load > 1 consumes as much as a fully loaded machine, not mores
74 double previous_energy = host_energy->total_energy;
76 double instantaneous_consumption;
78 instantaneous_consumption = host_energy->watts_off;
80 instantaneous_consumption = host_energy->getCurrentWattsValue(cpu_load);
82 double energy_this_step = instantaneous_consumption*(finish_time-start_time);
84 host_energy->total_energy = previous_energy + energy_this_step;
85 host_energy->last_updated = finish_time;
87 XBT_DEBUG("[update_energy of %s] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> %.2f J",
88 host->getName(), start_time, finish_time, host->p_cpu->m_speedPeak, previous_energy, energy_this_step);
97 HostEnergy::HostEnergy(simgrid::surf::Host *ptr)
101 power_range_watts_list = getWattsRangeList();
102 last_updated = surf_get_clock();
104 if (host->getProperties() != NULL) {
105 char* off_power_str = (char*)xbt_dict_get_or_null(host->getProperties(), "watt_off");
106 if (off_power_str != NULL)
107 watts_off = atof(off_power_str);
114 HostEnergy::~HostEnergy(){
116 xbt_dynar_t power_tuple = NULL;
117 xbt_dynar_foreach(power_range_watts_list, iter, power_tuple)
118 xbt_dynar_free(&power_tuple);
119 xbt_dynar_free(&power_range_watts_list);
123 double HostEnergy::getWattMinAt(int pstate) {
124 xbt_dynar_t power_range_list = power_range_watts_list;
125 xbt_assert(power_range_watts_list, "No power range properties specified for host %s", host->getName());
126 xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, host->p_cpu->getPState(), xbt_dynar_t);
127 double min_power = xbt_dynar_get_as(current_power_values, 0, double);
130 double HostEnergy::getWattMaxAt(int pstate) {
131 xbt_dynar_t power_range_list = power_range_watts_list;
132 xbt_assert(power_range_watts_list, "No power range properties specified for host %s", host->getName());
133 xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, host->p_cpu->getPState(), xbt_dynar_t);
134 double max_power = xbt_dynar_get_as(current_power_values, 1, double);
138 /** @brief Computes the power consumed by the host according to the current pstate and processor load */
139 double HostEnergy::getCurrentWattsValue(double cpu_load)
141 xbt_dynar_t power_range_list = power_range_watts_list;
142 xbt_assert(power_range_watts_list, "No power range properties specified for host %s", host->getName());
144 int pstate = host->p_cpu->getPState();
145 xbt_assert(pstate < (int)xbt_dynar_length(power_range_list),
146 "pstate %d >= power range amound %d",pstate,(int)xbt_dynar_length(power_range_list));
147 /* retrieve the power values associated with the current pstate */
148 xbt_dynar_t current_power_values = xbt_dynar_get_as( power_range_list, pstate, xbt_dynar_t);
150 /* min_power corresponds to the idle power (cpu load = 0) */
151 /* max_power is the power consumed at 100% cpu load */
152 double min_power = xbt_dynar_get_as(current_power_values, 0, double);
153 double max_power = xbt_dynar_get_as(current_power_values, 1, double);
154 double power_slope = max_power - min_power;
156 double current_power = min_power + cpu_load * power_slope;
158 XBT_DEBUG("[get_current_watts] min_power=%f, max_power=%f, slope=%f", min_power, max_power, power_slope);
159 XBT_DEBUG("[get_current_watts] Current power (watts) = %f, load = %f", current_power, cpu_load);
161 return current_power;
164 double HostEnergy::getConsumedEnergy()
166 if(last_updated < surf_get_clock())
167 update_consumption(host, this);
171 xbt_dynar_t HostEnergy::getWattsRangeList()
173 xbt_dynar_t power_range_list;
174 xbt_dynar_t power_tuple;
175 int i = 0, pstate_nb=0;
176 xbt_dynar_t current_power_values;
177 double min_power, max_power;
179 if (host->getProperties() == NULL)
182 char* all_power_values_str = (char*)xbt_dict_get_or_null(host->getProperties(), "watt_per_state");
184 if (all_power_values_str == NULL)
188 power_range_list = xbt_dynar_new(sizeof(xbt_dynar_t), NULL);
189 xbt_dynar_t all_power_values = xbt_str_split(all_power_values_str, ",");
191 pstate_nb = xbt_dynar_length(all_power_values);
192 for (i=0; i< pstate_nb; i++)
194 /* retrieve the power values associated with the current pstate */
195 current_power_values = xbt_str_split(xbt_dynar_get_as(all_power_values, i, char*), ":");
196 xbt_assert(xbt_dynar_length(current_power_values) > 1,
197 "Power properties incorrectly defined - could not retrieve min and max power values for host %s",
200 /* min_power corresponds to the idle power (cpu load = 0) */
201 /* max_power is the power consumed at 100% cpu load */
202 min_power = atof(xbt_dynar_get_as(current_power_values, 0, char*));
203 max_power = atof(xbt_dynar_get_as(current_power_values, 1, char*));
205 power_tuple = xbt_dynar_new(sizeof(double), NULL);
206 xbt_dynar_push_as(power_tuple, double, min_power);
207 xbt_dynar_push_as(power_tuple, double, max_power);
209 xbt_dynar_push_as(power_range_list, xbt_dynar_t, power_tuple);
210 xbt_dynar_free(¤t_power_values);
212 xbt_dynar_free(&all_power_values);
213 return power_range_list;
217 double surf_host_get_wattmin_at(sg_host_t host, int pstate){
218 xbt_assert(surf_energy!=NULL, "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
219 std::map<simgrid::surf::Host*, HostEnergy*>::iterator hostIt = surf_energy->find(host->extension<simgrid::surf::Host>());
220 return hostIt->second->getWattMinAt(pstate);
222 double surf_host_get_wattmax_at(sg_host_t host, int pstate){
223 xbt_assert(surf_energy!=NULL, "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
224 std::map<simgrid::surf::Host*, HostEnergy*>::iterator hostIt = surf_energy->find(host->extension<simgrid::surf::Host>());
225 return hostIt->second->getWattMaxAt(pstate);
228 double surf_host_get_consumed_energy(sg_host_t host){
229 xbt_assert(surf_energy!=NULL, "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
230 std::map<simgrid::surf::Host*, HostEnergy*>::iterator hostIt = surf_energy->find(host->extension<simgrid::surf::Host>());
231 return hostIt->second->getConsumedEnergy();
237 /* **************************** Public interface *************************** */
239 /** \ingroup SURF_plugin_energy
240 * \brief Enable energy plugin
241 * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before #MSG_init().
243 void sg_energy_plugin_init() {
244 if (simgrid::energy::surf_energy == NULL) {
246 simgrid::energy::surf_energy = new std::map<simgrid::surf::Host*, simgrid::energy::HostEnergy*>();
248 /* The following attaches an anonymous function to the Host::onCreation signal */
249 /* Search for "C++ lambda" for more information on the syntax used here */
250 simgrid::surf::Host::onCreation.connect([](simgrid::surf::Host *host) {
251 if (dynamic_cast<simgrid::surf::VirtualMachine*>(host)) // Ignore virtual machines
254 (*simgrid::energy::surf_energy)[host] = new HostEnergy(host);
257 simgrid::surf::Host::onDestruction.connect([](simgrid::surf::Host *host) {
258 if (dynamic_cast<simgrid::surf::VirtualMachine*>(host)) // Ignore virtual machines
261 std::map<simgrid::surf::Host*, HostEnergy*>::iterator host_energy_it = simgrid::energy::surf_energy->find(host);
262 xbt_assert(host_energy_it != simgrid::energy::surf_energy->end(), "The host is not in surf_energy.");
264 HostEnergy *host_energy = host_energy_it->second;
265 update_consumption(host, host_energy);
267 XBT_INFO("Total energy of host %s: %f Joules", host->getName(), host_energy->getConsumedEnergy());
268 host_energy_it->second->unref();
269 simgrid::energy::surf_energy->erase(host_energy_it);
272 simgrid::surf::CpuAction::onStateChange.connect([](simgrid::surf::CpuAction *action,
273 e_surf_action_state_t old,
274 e_surf_action_state_t cur) {
275 const char *name = getActionCpu(action)->getName();
276 simgrid::surf::Host *host = sg_host_by_name(name)->extension<simgrid::surf::Host>();
277 simgrid::surf::VirtualMachine *vm = dynamic_cast<simgrid::surf::VirtualMachine*>(host);
278 if (vm) // If it's a VM, take the corresponding PM
279 host = vm->getPm()->extension<simgrid::surf::Host>();
281 HostEnergy *host_energy = (*simgrid::energy::surf_energy)[host];
283 if(host_energy->last_updated < surf_get_clock())
284 update_consumption(host, host_energy);
288 simgrid::surf::Host::onStateChange.connect([] (simgrid::surf::Host *host) {
289 if (dynamic_cast<simgrid::surf::VirtualMachine*>(host)) // Ignore virtual machines
292 HostEnergy *host_energy = (*simgrid::energy::surf_energy)[host];
294 if(host_energy->last_updated < surf_get_clock())
295 update_consumption(host, host_energy);
298 simgrid::surf::surfExitCallbacks.connect([]() {
299 delete simgrid::energy::surf_energy;
300 simgrid::energy::surf_energy = NULL;
305 /** @brief Returns the total energy consumed by the host so far (in Joules)
307 * See also @ref SURF_plugin_energy.
309 double sg_host_get_consumed_energy(sg_host_t host) {
310 return simgrid::energy::surf_host_get_consumed_energy(host);
313 /** @brief Get the amount of watt dissipated at the given pstate when the host is idling */
314 double sg_host_get_wattmin_at(sg_host_t host, int pstate) {
315 return simgrid::simix::kernel(std::bind(
316 simgrid::energy::surf_host_get_wattmin_at, host, pstate
319 /** @brief Returns the amount of watt dissipated at the given pstate when the host burns CPU at 100% */
320 double sg_host_get_wattmax_at(sg_host_t host, int pstate) {
321 return simgrid::simix::kernel(std::bind(
322 simgrid::energy::surf_host_get_wattmax_at, host, pstate