Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
a8e93989356cd75e339e710f9fffa9780a92f91b
[simgrid.git] / src / surf / plugins / energy.cpp
1 /* Copyright (c) 2010, 2012-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
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. */
6
7 #include "energy.hpp"
8 #include "../cpu_cas01.hpp"
9
10 /** @addtogroup SURF_plugin_energy
11
12
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.
15
16 The energy consumption of a CPU depends directly of its current load. Specify that consumption in your platform file as follows:
17
18 \verbatim
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" />
22 </host>
23 \endverbatim
24
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).
28
29 If your CPU is using pstates, then you can provide one consumption interval per pstate.
30
31 \verbatim
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" />
35 </host>
36 \endverbatim
37
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.
42
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().
44
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().
47  */
48
49 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_energy, surf,
50                                 "Logging specific to the SURF energy plugin");
51
52 std::map<Cpu*, CpuEnergy*> *surf_energy=NULL;
53
54 static void energyCpuCreatedCallback(Cpu *cpu){
55   (*surf_energy)[cpu] = new CpuEnergy(cpu);
56 }
57
58
59 /* Computes the consumption so far.  Called lazily on need. */
60 static void update_consumption(Cpu *cpu, CpuEnergy *cpu_energy) {
61         double cpu_load = lmm_constraint_get_usage(cpu->getConstraint()) / cpu->m_powerPeak;
62         double start_time = cpu_energy->last_updated;
63         double finish_time = surf_get_clock();
64
65         double previous_energy = cpu_energy->total_energy;
66
67         double instantaneous_consumption;
68         if (cpu->getState() == SURF_RESOURCE_OFF)
69                 instantaneous_consumption = cpu_energy->watts_off;
70         else
71                 instantaneous_consumption = cpu_energy->getCurrentWattsValue(cpu_load);
72
73         double energy_this_step = instantaneous_consumption*(finish_time-start_time);
74
75         cpu_energy->total_energy = previous_energy + energy_this_step;
76         cpu_energy->last_updated = finish_time;
77
78         XBT_DEBUG("[cpu_update_energy] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> %.2f J",
79                   start_time, finish_time, cpu->m_powerPeak, previous_energy, energy_this_step);
80 }
81
82 static void energyCpuDestructedCallback(Cpu *cpu){
83   std::map<Cpu*, CpuEnergy*>::iterator cpu_energy_it = surf_energy->find(cpu);
84   xbt_assert(cpu_energy_it != surf_energy->end(), "The cpu is not in surf_energy.");
85
86   CpuEnergy *cpu_energy = cpu_energy_it->second;
87   update_consumption(cpu, cpu_energy);
88
89   // Do nothing if that's a virtual CPU, only act for physical CPUs
90   if(cpu->getPhysicalCPU() == NULL){
91     XBT_INFO("Total energy of host %s: %f Joules", cpu->getName(), cpu_energy->getConsumedEnergy());
92     delete cpu_energy_it->second;
93     surf_energy->erase(cpu_energy_it);
94   }
95
96 }
97
98 static void energyCpuActionStateChangedCallback(CpuAction *action, e_surf_action_state_t old, e_surf_action_state_t cur){
99   Cpu *cpu  = getActionCpu(action);
100
101   CpuEnergy *cpu_energy = (*surf_energy)[cpu];
102
103   if(cpu_energy->last_updated < surf_get_clock())
104           update_consumption(cpu, cpu_energy);
105 }
106
107 static void energyStateChangedCallback(Cpu *cpu, e_surf_resource_state_t oldState, e_surf_resource_state_t newState){
108   CpuEnergy *cpu_energy = (*surf_energy)[cpu];
109
110   if(cpu_energy->last_updated < surf_get_clock())
111           update_consumption(cpu, cpu_energy);
112 }
113
114 static void sg_energy_plugin_exit()
115 {
116   delete surf_energy;
117   surf_energy = NULL;
118 }
119
120 /** \ingroup SURF_plugin_energy
121  * \brief Enable energy plugin
122  * \details Enable energy plugin to get joules consumption of each cpu. You should call this function before #MSG_init().
123  */
124 void sg_energy_plugin_init() {
125   if (surf_energy == NULL) {
126     surf_energy = new std::map<Cpu*, CpuEnergy*>();
127     surf_callback_connect(cpuCreatedCallbacks, energyCpuCreatedCallback);
128     surf_callback_connect(cpuDestructedCallbacks, energyCpuDestructedCallback);
129     surf_callback_connect(cpuActionStateChangedCallbacks, energyCpuActionStateChangedCallback);
130     surf_callback_connect(surfExitCallbacks, sg_energy_plugin_exit);
131     surf_callback_connect(cpuStateChangedCallbacks, energyStateChangedCallback);
132   }
133 }
134
135 /**
136  *
137  */
138 CpuEnergy::CpuEnergy(Cpu *ptr)
139 {
140   cpu = ptr;
141   total_energy = 0;
142   power_range_watts_list = getWattsRangeList();
143   last_updated = surf_get_clock();
144
145   if (cpu->getProperties() != NULL) {
146         char* off_power_str = (char*)xbt_dict_get_or_null(cpu->getProperties(), "watt_off");
147         if (off_power_str != NULL)
148                 watts_off = atof(off_power_str);
149         else
150                 watts_off = 0;
151   }
152
153 }
154
155 CpuEnergy::~CpuEnergy(){
156   unsigned int iter;
157   xbt_dynar_t power_tuple = NULL;
158   xbt_dynar_foreach(power_range_watts_list, iter, power_tuple)
159     xbt_dynar_free(&power_tuple);
160   xbt_dynar_free(&power_range_watts_list);
161 }
162
163
164 double CpuEnergy::getWattMinAt(int pstate) {
165   xbt_dynar_t power_range_list = power_range_watts_list;
166   xbt_assert(power_range_watts_list, "No power range properties specified for host %s", cpu->getName());
167   xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, static_cast<CpuCas01*>(cpu)->getPState(), xbt_dynar_t);
168   double min_power = xbt_dynar_get_as(current_power_values, 0, double);
169   return min_power;
170 }
171 double CpuEnergy::getWattMaxAt(int pstate) {
172   xbt_dynar_t power_range_list = power_range_watts_list;
173   xbt_assert(power_range_watts_list, "No power range properties specified for host %s", cpu->getName());
174   xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, static_cast<CpuCas01*>(cpu)->getPState(), xbt_dynar_t);
175   double max_power = xbt_dynar_get_as(current_power_values, 1, double);
176   return max_power;
177 }
178
179 /**
180  * Computes the power consumed by the host according to the current pstate and processor load
181  *
182  */
183 double CpuEnergy::getCurrentWattsValue(double cpu_load)
184 {
185         xbt_dynar_t power_range_list = power_range_watts_list;
186         xbt_assert(power_range_watts_list, "No power range properties specified for host %s", cpu->getName());
187
188     /* retrieve the power values associated with the current pstate */
189     xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, static_cast<CpuCas01*>(cpu)->getPState(), xbt_dynar_t);
190
191     /* min_power corresponds to the idle power (cpu load = 0) */
192     /* max_power is the power consumed at 100% cpu load       */
193     double min_power = xbt_dynar_get_as(current_power_values, 0, double);
194     double max_power = xbt_dynar_get_as(current_power_values, 1, double);
195     double power_slope = max_power - min_power;
196
197     double current_power = min_power + cpu_load * power_slope;
198
199         XBT_DEBUG("[get_current_watts] min_power=%f, max_power=%f, slope=%f", min_power, max_power, power_slope);
200     XBT_DEBUG("[get_current_watts] Current power (watts) = %f, load = %f", current_power, cpu_load);
201
202         return current_power;
203 }
204
205 double CpuEnergy::getConsumedEnergy()
206 {
207
208         if(last_updated < surf_get_clock())
209                 update_consumption(cpu, this);
210         return total_energy;
211
212 }
213
214 xbt_dynar_t CpuEnergy::getWattsRangeList()
215 {
216         xbt_dynar_t power_range_list;
217         xbt_dynar_t power_tuple;
218         int i = 0, pstate_nb=0;
219         xbt_dynar_t current_power_values;
220         double min_power, max_power;
221
222         if (cpu->getProperties() == NULL)
223                 return NULL;
224
225         char* all_power_values_str = (char*)xbt_dict_get_or_null(cpu->getProperties(), "watt_per_state");
226
227         if (all_power_values_str == NULL)
228                 return NULL;
229
230
231         power_range_list = xbt_dynar_new(sizeof(xbt_dynar_t), NULL);
232         xbt_dynar_t all_power_values = xbt_str_split(all_power_values_str, ",");
233
234         pstate_nb = xbt_dynar_length(all_power_values);
235         for (i=0; i< pstate_nb; i++)
236         {
237                 /* retrieve the power values associated with the current pstate */
238                 current_power_values = xbt_str_split(xbt_dynar_get_as(all_power_values, i, char*), ":");
239                 xbt_assert(xbt_dynar_length(current_power_values) > 1,
240                                 "Power properties incorrectly defined - could not retrieve min and max power values for host %s",
241                                 cpu->getName());
242
243                 /* min_power corresponds to the idle power (cpu load = 0) */
244                 /* max_power is the power consumed at 100% cpu load       */
245                 min_power = atof(xbt_dynar_get_as(current_power_values, 0, char*));
246                 max_power = atof(xbt_dynar_get_as(current_power_values, 1, char*));
247
248                 power_tuple = xbt_dynar_new(sizeof(double), NULL);
249                 xbt_dynar_push_as(power_tuple, double, min_power);
250                 xbt_dynar_push_as(power_tuple, double, max_power);
251
252                 xbt_dynar_push_as(power_range_list, xbt_dynar_t, power_tuple);
253                 xbt_dynar_free(&current_power_values);
254         }
255         xbt_dynar_free(&all_power_values);
256         return power_range_list;
257 }