#include "simgrid/plugins/energy.h"
#include "simgrid/s4u/Engine.hpp"
-#include "src/kernel/activity/ExecImpl.hpp"
+#include "simgrid/s4u/Exec.hpp"
#include "src/include/surf/surf.hpp"
+#include "src/kernel/activity/ExecImpl.hpp"
#include "src/plugins/vm/VirtualMachineImpl.hpp"
#include "src/surf/cpu_interface.hpp"
SIMGRID_REGISTER_PLUGIN(host_energy, "Cpu energy consumption.", &sg_host_energy_plugin_init)
-/** @addtogroup plugin_energy
+/** @defgroup plugin_host_energy
This is the energy plugin, enabling to account not only for computation time, but also for the dissipated energy in the
simulated platform.
As a result, our energy model takes 4 parameters:
- - @b Idle: instantaneous consumption (in Watt) when your host is up and running, but without anything to do.
- - @b Epsilon: instantaneous consumption (in Watt) when all cores are at 0 or epsilon%, but not in Idle state.
- - @b AllCores: instantaneous consumption (in Watt) when all cores of the host are at 100%.
- - @b Off: instantaneous consumption (in Watt) when the host is turned off.
+ - @b Idle: wattage (i.e., instantaneous consumption in Watt) when your host is up and running, but without anything to
+do.
+ - @b Epsilon: wattage when all cores are at 0 or epsilon%, but not in Idle state.
+ - @b AllCores: wattage when all cores of the host are at 100%.
+ - @b Off: wattage when the host is turned off.
Here is an example of XML declaration:
@code{.xml}
<host id="HostA" speed="100.0Mf" core="4">
- <prop id="watt_per_state" value="100.0:120.0:200.0" />
- <prop id="watt_off" value="10" />
+ <prop id="wattage_per_state" value="100.0:120.0:200.0" />
+ <prop id="wattage_off" value="10" />
</host>
@endcode
-Please note that the 'Epsilon' parameter can be omitted in the XML declaration. In that case, the value of 'Epsilon' will
-be the same as 'Idle'.
-
+If the 'Epsilon' parameter is omitted in the XML declaration, 'Idle' is used instead.
This example gives the following parameters: @b Off is 10 Watts; @b Idle is 100 Watts; @b Epsilon is 120 Watts and @b
AllCores is 200 Watts.
-This is enough to compute the consumption as a function of the amount of loaded cores:
+This is enough to compute the wattage as a function of the amount of loaded cores:
<table>
-<tr><th>@#Cores loaded</th><th>Consumption</th><th>Explanation</th></tr>
+<tr><th>@#Cores loaded</th><th>Wattage</th><th>Explanation</th></tr>
<tr><td>0 (idle)</td><td> 100 Watts</td><td>Idle value</td></tr>
<tr><td>0 (not idle)</td><td> 120 Watts</td><td>Epsilon value</td></tr>
<tr><td>1</td><td> 140 Watts</td><td>linear extrapolation between Epsilon and AllCores</td></tr>
@code{.xml}
<host id="HostC" speed="100.0Mf,50.0Mf,20.0Mf" core="4">
- <prop id="watt_per_state" value="95.0:120.0:200.0, 93.0:115.0:170.0, 90.0:110.0:150.0" />
- <prop id="watt_off" value="10" />
+ <prop id="wattage_per_state" value="95.0:120.0:200.0, 93.0:115.0:170.0, 90.0:110.0:150.0" />
+ <prop id="wattage_off" value="10" />
</host>
@endcode
HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host_(ptr), last_updated_(surf_get_clock())
{
init_watts_range_list();
-
- const char* off_power_str = host_->get_property("watt_off");
+ static bool warned = false;
+
+ const char* off_power_str = host_->get_property("wattage_off");
+ if (off_power_str == nullptr) {
+ off_power_str = host_->get_property("watt_off");
+ if (off_power_str != nullptr && not warned) {
+ warned = true;
+ XBT_WARN("Please use 'wattage_off' instead of 'watt_off' to define the idle wattage of hosts in your XML.");
+ }
+ }
if (off_power_str != nullptr) {
try {
this->watts_off_ = std::stod(std::string(off_power_str));
} catch (const std::invalid_argument&) {
- throw std::invalid_argument(std::string("Invalid value for property watt_off of host ") + host_->get_cname() +
+ throw std::invalid_argument(std::string("Invalid value for property wattage_off of host ") + host_->get_cname() +
": " + off_power_str);
}
}
else {
cpu_load = host_->pimpl_cpu->get_constraint()->get_usage() / current_speed;
- /** Divide by the number of cores here to have a value between 0 and 1 **/
+ /* Divide by the number of cores here to have a value between 0 and 1 */
cpu_load /= host_->pimpl_cpu->get_core_count();
+ xbt_assert(not(cpu_load > 1), "The impossible did happen, as usual.");
- if (cpu_load > 1) // A machine with a load > 1 consumes as much as a fully loaded machine, not more
- cpu_load = 1;
if (cpu_load > 0)
host_was_used_ = true;
}
- /* @mquinson: The problem with this model is that the load is always 0 or 1, never something less.
- * Another possibility could be to model the total energy as
- *
- * X/(X+Y)*W_idle + Y/(X+Y)*W_burn
- *
- * where X is the amount of idling cores, and Y the amount of computing cores.
- *
- * @Mommessc: I do not think the load is always 0 or 1 anymore.
- * Moreover, it is not quite clear how the regular model of power consumption (P = Pstatic + load * Pdynamic)
- * is impacted if we separate the number of idle and working cores.
- */
return get_current_watts_value(cpu_load);
}
void HostEnergy::init_watts_range_list()
{
- const char* all_power_values_str = host_->get_property("watt_per_state");
+ const char* old_prop = host_->get_property("watt_per_state");
+ if (old_prop != nullptr) {
+ std::vector<std::string> all_power_values;
+ boost::split(all_power_values, old_prop, boost::is_any_of(","));
+
+ std::string msg = std::string("DEPRECATION WARNING: Property 'watt_per_state' will not work after v3.28.\n");
+ msg += std::string("The old syntax 'Idle:OneCore:AllCores' must be converted into 'Idle:Epsilon:AllCores' to "
+ "properly model the consumption of non-whole tasks on mono-core hosts. Here are the values to "
+ "use for host '") +
+ host_->get_cname() + "' in your XML file:\n";
+ msg += " <prop id=\"wattage_per_state\" value=\"";
+ for (auto const& current_power_values_str : all_power_values) {
+ std::vector<std::string> current_power_values;
+ boost::split(current_power_values, current_power_values_str, boost::is_any_of(":"));
+ double p_idle = xbt_str_parse_double((current_power_values.at(0)).c_str(),
+ "Invalid obsolete XML file. Fix your watt_per_state property.");
+ double p_one_core;
+ double p_full;
+ double p_epsilon;
+
+ if (current_power_values.size() == 3) {
+ p_idle = xbt_str_parse_double((current_power_values.at(0)).c_str(),
+ "Invalid obsolete XML file. Fix your watt_per_state property.");
+ p_one_core = xbt_str_parse_double((current_power_values.at(1)).c_str(),
+ "Invalid obsolete XML file. Fix your watt_per_state property.");
+ p_full = xbt_str_parse_double((current_power_values.at(2)).c_str(),
+ "Invalid obsolete XML file. Fix your watt_per_state property.");
+ if (host_->get_core_count() == 1) {
+ p_epsilon = p_full;
+ } else {
+ p_epsilon = p_one_core - ((p_full - p_one_core) / (host_->get_core_count() - 1));
+ }
+ } else { // consuption given with idle and full only
+ p_idle = xbt_str_parse_double((current_power_values.at(0)).c_str(),
+ "Invalid obsolete XML file. Fix your watt_per_state property.");
+ p_full = xbt_str_parse_double((current_power_values.at(1)).c_str(),
+ "Invalid obsolete XML file. Fix your watt_per_state property.");
+ if (host_->get_core_count() == 1) {
+ p_epsilon = p_full;
+ } else {
+ p_epsilon = p_idle;
+ }
+ }
+
+ PowerRange range(p_idle, p_epsilon, p_full);
+ power_range_watts_list_.push_back(range);
+
+ msg += std::to_string(p_idle) + ":" + std::to_string(p_epsilon) + ":" + std::to_string(p_full);
+ msg += ",";
+ }
+ msg.pop_back(); // Remove the extraneous ','
+ msg += "\" />";
+ XBT_WARN("%s", msg.c_str());
+ return;
+ }
+ const char* all_power_values_str = host_->get_property("wattage_per_state");
if (all_power_values_str == nullptr)
return;
char* msg_max = bprintf("Invalid AllCores value for pstate %d on host %s: %%s", i, host_->get_cname());
idle_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle);
- if (current_power_values.size() == 2) // Case: Idle:AllCores
- {
- epsilon_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle);
- max_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_max);
- }
- else // Case: Idle:Epsilon:AllCores
- {
- epsilon_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_epsilon);
- max_power = xbt_str_parse_double((current_power_values.at(2)).c_str(), msg_max);
+ if (current_power_values.size() == 2) { // Case: Idle:AllCores
+ epsilon_power = xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle);
+ max_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_max);
+ } else { // Case: Idle:Epsilon:AllCores
+ epsilon_power = xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_epsilon);
+ max_power = xbt_str_parse_double((current_power_values.at(2)).c_str(), msg_max);
}
XBT_DEBUG("Creating PowerRange for host %s. Idle:%f, Epsilon:%f, AllCores:%f.", host_->get_cname(), idle_power, epsilon_power, max_power);
/* **************************** Public interface *************************** */
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief Enable host energy plugin
* @details Enable energy plugin to get joules consumption of each cpu. Call this function before #MSG_init().
*/
// that the next trigger would be the 2nd compute, hence ignoring the idle time
// during the recv call. By updating at the beginning of a compute, we can
// fix that. (If the cpu is not idle, this is not required.)
- simgrid::kernel::activity::ExecImpl::on_creation.connect([](simgrid::kernel::activity::ExecImpl const& activity) {
+ simgrid::s4u::Exec::on_start.connect([](simgrid::s4u::Actor const&, simgrid::s4u::Exec const& activity) {
if (activity.get_host_number() == 1) { // We only run on one host
simgrid::s4u::Host* host = activity.get_host();
simgrid::s4u::VirtualMachine* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host);
});
}
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief updates the consumption of all hosts
*
* After this call, sg_host_get_consumed_energy() will not interrupt your process
});
}
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief Returns the total energy consumed by the host so far (in Joules)
*
* Please note that since the consumption is lazily updated, it may require a simcall to update it.
return host->extension<HostEnergy>()->get_consumed_energy();
}
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief Get the amount of watt dissipated when the host is idling
*/
double sg_host_get_idle_consumption(sg_host_t host)
return host->extension<HostEnergy>()->get_idle_consumption();
}
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief Get the amount of watt dissipated at the given pstate when the host is idling
*/
double sg_host_get_wattmin_at(sg_host_t host, int pstate)
"The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
return host->extension<HostEnergy>()->get_watt_min_at(pstate);
}
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief Returns the amount of watt dissipated at the given pstate when the host burns CPU at 100%
*/
double sg_host_get_wattmax_at(sg_host_t host, int pstate)
"The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
return host->extension<HostEnergy>()->get_watt_max_at(pstate);
}
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief Returns the power slope at the given pstate
*/
double sg_host_get_power_range_slope_at(sg_host_t host, int pstate)
"The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
return host->extension<HostEnergy>()->get_power_range_slope_at(pstate);
}
-/** @ingroup plugin_energy
+/** @ingroup plugin_host_energy
* @brief Returns the current consumption of the host
*/
double sg_host_get_current_consumption(sg_host_t host)