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. */
8 #include "../cpu_cas01.hpp"
10 /** @addtogroup SURF_plugin_energy
13 This is the energy plugin, enabling to account not only for computation time,
14 but also for the dissipated energy in the simulated platform.
16 The energy consumption of a CPU depends directly of its current load. Specify that consumption in your platform file as follows:
19 <host id="HostA" power="100.0Mf" >
20 <prop id="watt_per_state" value="100.0:200.0" />
21 <prop id="watt_off" value="10" />
25 The first property means that when your host is up and running, but without anything to do, it will dissipate 100 Watts.
26 If it's fully loaded, it will dissipate 200 Watts. If its load is at 50%, then it will dissipate 150 Watts.
27 The second property means that when your host is turned off, it will dissipate only 10 Watts (please note that these values are arbitrary).
29 If your CPU is using pstates, then you can provide one consumption interval per pstate.
32 <host id="HostB" power="100.0Mf,50.0Mf,20.0Mf" pstate="0" >
33 <prop id="watt_per_state" value="95.0:200.0, 93.0:170.0, 90.0:150.0" />
34 <prop id="watt_off" value="10" />
38 That host has 3 levels of performance with the following performance: 100 Mflop/s, 50 Mflop/s or 20 Mflop/s.
39 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.
40 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,
41 170 Watts and 150 Watts respectively.
43 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().
45 To simulate the energy-related elements, first call the #sg_energy_plugin_init() before your #MSG_init(),
46 and then use the following function to retrieve the consumption of a given host: #MSG_host_get_consumed_energy().
49 XBT_LOG_EXTERNAL_CATEGORY(surf_kernel);
50 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_energy, surf,
51 "Logging specific to the SURF energy plugin");
53 std::map<Cpu*, CpuEnergy*> *surf_energy=NULL;
55 static void energyCpuCreatedCallback(Cpu *cpu){
56 (*surf_energy)[cpu] = new CpuEnergy(cpu);
59 static void update_consumption_running(Cpu *cpu, CpuEnergy *cpu_energy) {
60 double cpu_load = lmm_constraint_get_usage(cpu->getConstraint()) / cpu->m_powerPeak;
61 double start_time = cpu_energy->last_updated;
62 double finish_time = surf_get_clock();
64 double previous_energy = cpu_energy->total_energy;
65 double energy_this_step = cpu_energy->getCurrentWattsValue(cpu_load)*(finish_time-start_time);
67 cpu_energy->total_energy = previous_energy + energy_this_step;
68 cpu_energy->last_updated = finish_time;
70 XBT_DEBUG("[cpu_update_energy] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> %.2f J",
71 start_time, finish_time, cpu->m_powerPeak, previous_energy, energy_this_step);
73 static void update_consumption_off(Cpu *cpu, CpuEnergy *cpu_energy) {
74 double start_time = cpu_energy->last_updated;
75 double finish_time = surf_get_clock();
77 double previous_energy = cpu_energy->total_energy;
78 double energy_this_step = cpu_energy->watts_off*(finish_time-start_time);
80 cpu_energy->total_energy = previous_energy + energy_this_step;
81 cpu_energy->last_updated = finish_time;
83 XBT_DEBUG("[cpu_update_energy] off period=[%.2f-%.2f]; consumption change: %.2f J -> %.2f J",
84 start_time, finish_time, previous_energy, energy_this_step);
87 static void energyCpuDestructedCallback(Cpu *cpu){
88 std::map<Cpu*, CpuEnergy*>::iterator cpu_energy_it = surf_energy->find(cpu);
89 xbt_assert(cpu_energy_it != surf_energy->end(), "The cpu is not in surf_energy.");
91 CpuEnergy *cpu_energy = cpu_energy_it->second;
92 if (cpu->getState() == SURF_RESOURCE_OFF)
93 update_consumption_off(cpu, cpu_energy);
95 update_consumption_running(cpu, cpu_energy);
97 // Adrien - October 2015, Changes related to VM energy extensions
98 // Only report/delete and erase if the cpu_energy is related to a physical one
99 if(cpu->isVirtual() == NULL){
100 XBT_INFO("Total energy of host %s: %f Joules", cpu->getName(), cpu_energy->getConsumedEnergy());
101 delete cpu_energy_it->second;
102 surf_energy->erase(cpu_energy_it);
107 static void energyCpuActionStateChangedCallback(CpuAction *action, e_surf_action_state_t old, e_surf_action_state_t cur){
108 Cpu *cpu = getActionCpu(action);
110 CpuEnergy *cpu_energy = (*surf_energy)[cpu];
112 if(cpu_energy->last_updated < surf_get_clock()) {
113 update_consumption_running(cpu, cpu_energy);
117 static void energyStateChangedCallback(Cpu *cpu, e_surf_resource_state_t oldState, e_surf_resource_state_t newState){
118 CpuEnergy *cpu_energy = (*surf_energy)[cpu];
120 if(cpu_energy->last_updated < surf_get_clock()) {
121 if (oldState == SURF_RESOURCE_OFF)
122 update_consumption_off(cpu, cpu_energy);
124 update_consumption_running(cpu, cpu_energy);
128 static void sg_energy_plugin_exit()
134 /** \ingroup SURF_plugin_energy
135 * \brief Enable energy plugin
136 * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before #MSG_init().
138 void sg_energy_plugin_init() {
139 if (surf_energy == NULL) {
140 surf_energy = new std::map<Cpu*, CpuEnergy*>();
141 surf_callback_connect(cpuCreatedCallbacks, energyCpuCreatedCallback);
142 surf_callback_connect(cpuDestructedCallbacks, energyCpuDestructedCallback);
143 surf_callback_connect(cpuActionStateChangedCallbacks, energyCpuActionStateChangedCallback);
144 surf_callback_connect(surfExitCallbacks, sg_energy_plugin_exit);
145 surf_callback_connect(cpuStateChangedCallbacks, energyStateChangedCallback);
152 CpuEnergy::CpuEnergy(Cpu *ptr)
156 power_range_watts_list = getWattsRangeList();
157 last_updated = surf_get_clock();
159 if (cpu->getProperties() != NULL) {
160 char* off_power_str = (char*)xbt_dict_get_or_null(cpu->getProperties(), "watt_off");
161 if (off_power_str != NULL)
162 watts_off = atof(off_power_str);
169 CpuEnergy::~CpuEnergy(){
171 xbt_dynar_t power_tuple = NULL;
172 xbt_dynar_foreach(power_range_watts_list, iter, power_tuple)
173 xbt_dynar_free(&power_tuple);
174 xbt_dynar_free(&power_range_watts_list);
178 double CpuEnergy::getWattMinAt(int pstate) {
179 xbt_dynar_t power_range_list = power_range_watts_list;
180 xbt_assert(power_range_watts_list, "No power range properties specified for host %s", cpu->getName());
181 xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, static_cast<CpuCas01*>(cpu)->getPState(), xbt_dynar_t);
182 double min_power = xbt_dynar_get_as(current_power_values, 0, double);
185 double CpuEnergy::getWattMaxAt(int pstate) {
186 xbt_dynar_t power_range_list = power_range_watts_list;
187 xbt_assert(power_range_watts_list, "No power range properties specified for host %s", cpu->getName());
188 xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, static_cast<CpuCas01*>(cpu)->getPState(), xbt_dynar_t);
189 double max_power = xbt_dynar_get_as(current_power_values, 1, double);
194 * Computes the power consumed by the host according to the current pstate and processor load
197 double CpuEnergy::getCurrentWattsValue(double cpu_load)
199 xbt_dynar_t power_range_list = power_range_watts_list;
200 xbt_assert(power_range_watts_list, "No power range properties specified for host %s", cpu->getName());
202 /* retrieve the power values associated with the current pstate */
203 xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, static_cast<CpuCas01*>(cpu)->getPState(), xbt_dynar_t);
205 /* min_power corresponds to the idle power (cpu load = 0) */
206 /* max_power is the power consumed at 100% cpu load */
207 double min_power = xbt_dynar_get_as(current_power_values, 0, double);
208 double max_power = xbt_dynar_get_as(current_power_values, 1, double);
209 double power_slope = max_power - min_power;
211 double current_power = min_power + cpu_load * power_slope;
213 XBT_DEBUG("[get_current_watts] min_power=%f, max_power=%f, slope=%f", min_power, max_power, power_slope);
214 XBT_DEBUG("[get_current_watts] Current power (watts) = %f, load = %f", current_power, cpu_load);
216 return current_power;
219 double CpuEnergy::getConsumedEnergy()
222 if(last_updated < surf_get_clock()) {
223 if (cpu->getState() == SURF_RESOURCE_OFF)
224 update_consumption_off(cpu, this);
226 update_consumption_running(cpu, this);
231 xbt_dynar_t CpuEnergy::getWattsRangeList()
233 xbt_dynar_t power_range_list;
234 xbt_dynar_t power_tuple;
235 int i = 0, pstate_nb=0;
236 xbt_dynar_t current_power_values;
237 double min_power, max_power;
239 if (cpu->getProperties() == NULL)
242 char* all_power_values_str = (char*)xbt_dict_get_or_null(cpu->getProperties(), "watt_per_state");
244 if (all_power_values_str == NULL)
248 power_range_list = xbt_dynar_new(sizeof(xbt_dynar_t), NULL);
249 xbt_dynar_t all_power_values = xbt_str_split(all_power_values_str, ",");
251 pstate_nb = xbt_dynar_length(all_power_values);
252 for (i=0; i< pstate_nb; i++)
254 /* retrieve the power values associated with the current pstate */
255 current_power_values = xbt_str_split(xbt_dynar_get_as(all_power_values, i, char*), ":");
256 xbt_assert(xbt_dynar_length(current_power_values) > 1,
257 "Power properties incorrectly defined - could not retrieve min and max power values for host %s",
260 /* min_power corresponds to the idle power (cpu load = 0) */
261 /* max_power is the power consumed at 100% cpu load */
262 min_power = atof(xbt_dynar_get_as(current_power_values, 0, char*));
263 max_power = atof(xbt_dynar_get_as(current_power_values, 1, char*));
265 power_tuple = xbt_dynar_new(sizeof(double), NULL);
266 xbt_dynar_push_as(power_tuple, double, min_power);
267 xbt_dynar_push_as(power_tuple, double, max_power);
269 xbt_dynar_push_as(power_range_list, xbt_dynar_t, power_tuple);
270 xbt_dynar_free(¤t_power_values);
272 xbt_dynar_free(&all_power_values);
273 return power_range_list;