Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot//simgrid/simgrid
[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, but also for the dissipated energy in the simulated platform.
14  */
15
16 XBT_LOG_EXTERNAL_CATEGORY(surf_kernel);
17 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_energy, surf,
18                                 "Logging specific to the SURF energy plugin");
19
20 std::map<CpuPtr, CpuEnergyPtr> *surf_energy=NULL;
21
22 static void energyCpuCreatedCallback(CpuPtr cpu){
23   (*surf_energy)[cpu] = new CpuEnergy(cpu);
24 }
25
26 static void update_consumption_running(CpuPtr cpu, CpuEnergyPtr cpu_energy) {
27         double cpu_load = lmm_constraint_get_usage(cpu->getConstraint()) / cpu->m_powerPeak;
28         double start_time = cpu_energy->last_updated;
29         double finish_time = surf_get_clock();
30
31         double previous_energy = cpu_energy->total_energy;
32         double energy_this_step = cpu_energy->getCurrentWattsValue(cpu_load)*(finish_time-start_time);
33
34         cpu_energy->total_energy = previous_energy + energy_this_step;
35         cpu_energy->last_updated = finish_time;
36
37         XBT_DEBUG("[cpu_update_energy] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> %.2f J",
38                   start_time, finish_time, cpu->m_powerPeak, previous_energy, energy_this_step);
39 }
40 static void update_consumption_off(CpuPtr cpu, CpuEnergyPtr cpu_energy) {
41         double start_time = cpu_energy->last_updated;
42         double finish_time = surf_get_clock();
43
44         double previous_energy = cpu_energy->total_energy;
45         double energy_this_step = cpu_energy->watts_off*(finish_time-start_time);
46
47         cpu_energy->total_energy = previous_energy + energy_this_step;
48         cpu_energy->last_updated = finish_time;
49
50         XBT_DEBUG("[cpu_update_energy] off period=[%.2f-%.2f]; consumption change: %.2f J -> %.2f J",
51                   start_time, finish_time, previous_energy, energy_this_step);
52 }
53
54 static void energyCpuDestructedCallback(CpuPtr cpu){
55   std::map<CpuPtr, CpuEnergyPtr>::iterator cpu_energy_it = surf_energy->find(cpu);
56   xbt_assert(cpu_energy_it != surf_energy->end(), "The cpu is not in surf_energy.");
57
58   CpuEnergyPtr cpu_energy = cpu_energy_it->second;
59   if (cpu->getState() == SURF_RESOURCE_OFF)
60           update_consumption_off(cpu, cpu_energy);
61   else
62           update_consumption_running(cpu, cpu_energy);
63
64   XBT_INFO("Total energy of host %s: %f Joules", cpu->getName(), cpu_energy->getConsumedEnergy());
65   delete cpu_energy_it->second;
66   surf_energy->erase(cpu_energy_it);
67 }
68
69 static void energyCpuActionStateChangedCallback(CpuActionPtr action, e_surf_action_state_t old, e_surf_action_state_t cur){
70   CpuPtr cpu  = getActionCpu(action);
71   CpuEnergyPtr cpu_energy = (*surf_energy)[cpu];
72
73   if(cpu_energy->last_updated < surf_get_clock()) {
74           update_consumption_running(cpu, cpu_energy);
75   }
76 }
77
78 static void energyStateChangedCallback(CpuPtr cpu, e_surf_resource_state_t oldState, e_surf_resource_state_t newState){
79   CpuEnergyPtr cpu_energy = (*surf_energy)[cpu];
80
81   if(cpu_energy->last_updated < surf_get_clock()) {
82           if (oldState == SURF_RESOURCE_OFF)
83                   update_consumption_off(cpu, cpu_energy);
84           else
85                   update_consumption_running(cpu, cpu_energy);
86   }
87 }
88
89 static void sg_energy_plugin_exit()
90 {
91   delete surf_energy;
92   surf_energy = NULL;
93 }
94
95 /** \ingroup SURF_plugin_energy
96  * \brief Enable energy plugin
97  * \details Enable energy plugin to get joules consumption of each cpu.
98  */
99 void sg_energy_plugin_init() {
100   if (surf_energy == NULL) {
101     surf_energy = new std::map<CpuPtr, CpuEnergyPtr>();
102     surf_callback_connect(cpuCreatedCallbacks, energyCpuCreatedCallback);
103     surf_callback_connect(cpuDestructedCallbacks, energyCpuDestructedCallback);
104     surf_callback_connect(cpuActionStateChangedCallbacks, energyCpuActionStateChangedCallback);
105     surf_callback_connect(surfExitCallbacks, sg_energy_plugin_exit);
106     surf_callback_connect(cpuStateChangedCallbacks, energyStateChangedCallback);
107   }
108 }
109
110 /**
111  *
112  */
113 CpuEnergy::CpuEnergy(CpuPtr ptr)
114  : cpu(ptr)
115 {
116   total_energy = 0;
117   power_range_watts_list = getWattsRangeList();
118   last_updated = surf_get_clock();
119
120   if (cpu->getProperties() != NULL) {
121         char* off_power_str = (char*)xbt_dict_get_or_null(cpu->getProperties(), "watt_off");
122         if (off_power_str != NULL)
123                 watts_off = atof(off_power_str);
124         else
125                 watts_off = 0;
126   }
127
128 }
129
130 CpuEnergy::~CpuEnergy(){
131   unsigned int iter;
132   xbt_dynar_t power_tuple = NULL;
133   xbt_dynar_foreach(power_range_watts_list, iter, power_tuple)
134     xbt_dynar_free(&power_tuple);
135   xbt_dynar_free(&power_range_watts_list);
136 }
137
138 /**
139  * Computes the power consumed by the host according to the current pstate and processor load
140  *
141  */
142 double CpuEnergy::getCurrentWattsValue(double cpu_load)
143 {
144         xbt_dynar_t power_range_list = power_range_watts_list;
145
146         if (power_range_list == NULL)
147         {
148                 XBT_DEBUG("No power range properties specified for host %s", cpu->getName());
149                 return 0;
150         }
151         /*xbt_assert(xbt_dynar_length(power_range_list) == xbt_dynar_length(cpu->p_powerPeakList),
152                                                 "The number of power ranges in the properties does not match the number of pstates for host %s",
153                                                 cpu->getName());*/
154
155     /* retrieve the power values associated with the current pstate */
156     xbt_dynar_t current_power_values = xbt_dynar_get_as(power_range_list, static_cast<CpuCas01Ptr>(cpu)->getPState(), xbt_dynar_t);
157
158     /* min_power corresponds to the idle power (cpu load = 0) */
159     /* max_power is the power consumed at 100% cpu load       */
160     double min_power = xbt_dynar_get_as(current_power_values, 0, double);
161     double max_power = xbt_dynar_get_as(current_power_values, 1, double);
162     double power_slope = max_power - min_power;
163
164     double current_power = min_power + cpu_load * power_slope;
165
166         XBT_DEBUG("[get_current_watts] min_power=%f, max_power=%f, slope=%f", min_power, max_power, power_slope);
167     XBT_DEBUG("[get_current_watts] Current power (watts) = %f, load = %f", current_power, cpu_load);
168
169         return current_power;
170 }
171
172 double CpuEnergy::getConsumedEnergy()
173 {
174         if(last_updated < surf_get_clock()) {
175                 if (cpu->getState() == SURF_RESOURCE_OFF)
176                         update_consumption_off(cpu, this);
177                 else
178                         update_consumption_running(cpu, this);
179         }
180   return total_energy;
181 }
182
183 xbt_dynar_t CpuEnergy::getWattsRangeList()
184 {
185         xbt_dynar_t power_range_list;
186         xbt_dynar_t power_tuple;
187         int i = 0, pstate_nb=0;
188         xbt_dynar_t current_power_values;
189         double min_power, max_power;
190
191         if (cpu->getProperties() == NULL)
192                 return NULL;
193
194         char* all_power_values_str = (char*)xbt_dict_get_or_null(cpu->getProperties(), "watt_per_state");
195
196         if (all_power_values_str == NULL)
197                 return NULL;
198
199
200         power_range_list = xbt_dynar_new(sizeof(xbt_dynar_t), NULL);
201         xbt_dynar_t all_power_values = xbt_str_split(all_power_values_str, ",");
202
203         pstate_nb = xbt_dynar_length(all_power_values);
204         for (i=0; i< pstate_nb; i++)
205         {
206                 /* retrieve the power values associated with the current pstate */
207                 current_power_values = xbt_str_split(xbt_dynar_get_as(all_power_values, i, char*), ":");
208                 xbt_assert(xbt_dynar_length(current_power_values) > 1,
209                                 "Power properties incorrectly defined - could not retrieve min and max power values for host %s",
210                                 cpu->getName());
211
212                 /* min_power corresponds to the idle power (cpu load = 0) */
213                 /* max_power is the power consumed at 100% cpu load       */
214                 min_power = atof(xbt_dynar_get_as(current_power_values, 0, char*));
215                 max_power = atof(xbt_dynar_get_as(current_power_values, 1, char*));
216
217                 power_tuple = xbt_dynar_new(sizeof(double), NULL);
218                 xbt_dynar_push_as(power_tuple, double, min_power);
219                 xbt_dynar_push_as(power_tuple, double, max_power);
220
221                 xbt_dynar_push_as(power_range_list, xbt_dynar_t, power_tuple);
222                 xbt_dynar_free(&current_power_values);
223         }
224         xbt_dynar_free(&all_power_values);
225         return power_range_list;
226 }