-/* Copyright (c) 2010-2017. The SimGrid Team. All rights reserved. */
+/* Copyright (c) 2010-2018. The SimGrid Team. All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
#include "simgrid/plugins/energy.h"
-#include "simgrid/simix.hpp"
+#include "simgrid/plugins/load.h"
#include "src/plugins/vm/VirtualMachineImpl.hpp"
#include "src/surf/cpu_interface.hpp"
-
#include "simgrid/s4u/Engine.hpp"
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
-#include <string>
-#include <utility>
-#include <vector>
/** @addtogroup plugin_energy
This is enough to compute the consumption 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>Consumption</th><th>Explanation</th></tr>
<tr><td>0</td><td> 100 Watts</td><td>Idle value</td></tr>
<tr><td>1</td><td> 120 Watts</td><td>OneCore value</td></tr>
<tr><td>2</td><td> 147 Watts</td><td>linear extrapolation between OneCore and AllCores</td></tr>
explicit HostEnergy(simgrid::s4u::Host* ptr);
~HostEnergy();
+ double getCurrentWattsValue();
double getCurrentWattsValue(double cpu_load);
double getConsumedEnergy();
double getWattMinAt(int pstate);
{
double start_time = this->last_updated;
double finish_time = surf_get_clock();
- double current_speed = host->getSpeed();
if (start_time < finish_time) {
- double cpu_load;
- // We may have start == finish if the past consumption was updated since the simcall was started
- // for example if 2 actors requested to update the same host's consumption in a given scheduling round.
- //
- // Even in this case, we need to save the pstate for the next call (after this big if),
- // which may have changed since that recent update.
-
- if (current_speed <= 0)
- // Some users declare a pstate of speed 0 flops (e.g., to model boot time).
- // We consider that the machine is then fully loaded. That's arbitrary but it avoids a NaN
- cpu_load = 1;
- else
- cpu_load = host->pimpl_cpu->constraint()->get_usage() / current_speed;
-
- /** Divide by the number of cores here **/
- cpu_load /= host->pimpl_cpu->coreCount();
-
- if (cpu_load > 1) // A machine with a load > 1 consumes as much as a fully loaded machine, not more
- cpu_load = 1;
-
- /* 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.
- */
-
double previous_energy = this->total_energy;
- double instantaneous_consumption;
- if (this->pstate == pstate_off) // The host was off at the beginning of this time interval
- instantaneous_consumption = this->watts_off;
- else
- instantaneous_consumption = this->getCurrentWattsValue(cpu_load);
+ double instantaneous_consumption = this->getCurrentWattsValue();
double energy_this_step = instantaneous_consumption * (finish_time - start_time);
XBT_DEBUG("[update_energy of %s] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> "
"%.2f J",
- host->getCname(), start_time, finish_time, host->pimpl_cpu->speed_.peak, previous_energy,
+ host->get_cname(), start_time, finish_time, host->pimpl_cpu->speed_.peak, previous_energy,
energy_this_step);
}
/* Save data for the upcoming time interval: whether it's on/off and the pstate if it's on */
- this->pstate = host->isOn() ? host->getPstate() : pstate_off;
+ this->pstate = host->is_on() ? host->getPstate() : pstate_off;
}
HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host(ptr), last_updated(surf_get_clock())
{
initWattsRangeList();
- const char* off_power_str = host->getProperty("watt_off");
+ const char* off_power_str = host->get_property("watt_off");
if (off_power_str != nullptr) {
try {
this->watts_off = std::stod(std::string(off_power_str));
} catch (std::invalid_argument& ia) {
- throw std::invalid_argument(std::string("Invalid value for property watt_off of host ") + host->getCname() +
+ throw std::invalid_argument(std::string("Invalid value for property watt_off of host ") + host->get_cname() +
": " + off_power_str);
}
}
double HostEnergy::getWattMinAt(int pstate)
{
- xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->getCname());
+ xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->get_cname());
return power_range_watts_list[pstate].min;
}
double HostEnergy::getWattMaxAt(int pstate)
{
- xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->getCname());
+ xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->get_cname());
return power_range_watts_list[pstate].max;
}
-/** @brief Computes the power consumed by the host according to the current pstate and processor load */
+/** @brief Computes the power consumed by the host according to the current situation
+ *
+ * - If the host is off, that's the watts_off value
+ * - if it's on, take the current pstate and the current processor load into account */
+double HostEnergy::getCurrentWattsValue()
+{
+ if (this->pstate == pstate_off) // The host is off (or was off at the beginning of this time interval)
+ return this->watts_off;
+
+ double current_speed = host->getSpeed();
+
+ double cpu_load;
+ // We may have start == finish if the past consumption was updated since the simcall was started
+ // for example if 2 actors requested to update the same host's consumption in a given scheduling round.
+ //
+ // Even in this case, we need to save the pstate for the next call (after this big if),
+ // which may have changed since that recent update.
+
+ if (current_speed <= 0)
+ // Some users declare a pstate of speed 0 flops (e.g., to model boot time).
+ // We consider that the machine is then fully loaded. That's arbitrary but it avoids a NaN
+ cpu_load = 1;
+ else
+ cpu_load = host->pimpl_cpu->get_constraint()->get_usage() / current_speed;
+
+ /** Divide by the number of cores here **/
+ cpu_load /= host->pimpl_cpu->get_cores_count();
+
+ if (cpu_load > 1) // A machine with a load > 1 consumes as much as a fully loaded machine, not more
+ cpu_load = 1;
+
+ /* 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.
+ */
+ return getCurrentWattsValue(cpu_load);
+}
+
+/** @brief Computes the power that the host would consume at the provided processor load
+ *
+ * Whether the host is ON or OFF is not taken into account.
+ */
double HostEnergy::getCurrentWattsValue(double cpu_load)
{
- xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->getCname());
+ xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->get_cname());
- /*
- * * Return watts_off if pstate == pstate_off
- * * this happens when host is off
- */
+ /* Return watts_off if pstate == pstate_off (ie, if the host is off) */
if (this->pstate == pstate_off) {
return watts_off;
}
double HostEnergy::getConsumedEnergy()
{
if (last_updated < surf_get_clock()) // We need to simcall this as it modifies the environment
- simgrid::simix::kernelImmediate(std::bind(&HostEnergy::update, this));
+ simgrid::simix::simcall(std::bind(&HostEnergy::update, this));
return total_energy;
}
void HostEnergy::initWattsRangeList()
{
- const char* all_power_values_str = host->getProperty("watt_per_state");
+ const char* all_power_values_str = host->get_property("watt_per_state");
if (all_power_values_str == nullptr)
return;
std::vector<std::string> all_power_values;
boost::split(all_power_values, all_power_values_str, boost::is_any_of(","));
- XBT_DEBUG("%s: profile: %s, cores: %d", host->getCname(), all_power_values_str, host->getCoreCount());
+ XBT_DEBUG("%s: profile: %s, cores: %d", host->get_cname(), all_power_values_str, host->getCoreCount());
int i = 0;
for (auto const& current_power_values_str : all_power_values) {
xbt_assert(current_power_values.size() == 2 || current_power_values.size() == 3,
"Power properties incorrectly defined for host %s."
"It should be 'Idle:FullSpeed' power values because you have one core only.",
- host->getCname());
+ host->get_cname());
if (current_power_values.size() == 2) {
// In this case, 1core == AllCores
current_power_values.push_back(current_power_values.at(1));
"The energy profile of mono-cores should be formatted as 'Idle:FullSpeed' only.\n"
"If you go for a 'Idle:OneCore:AllCores' power profile on mono-cores, then OneCore and AllCores "
"must be equal.",
- host->getCname());
+ host->get_cname());
}
} else {
xbt_assert(current_power_values.size() == 3,
"Power properties incorrectly defined for host %s."
"It should be 'Idle:OneCore:AllCores' power values because you have more than one core.",
- host->getCname());
+ host->get_cname());
}
/* min_power corresponds to the idle power (cpu load = 0) */
/* max_power is the power consumed at 100% cpu load */
- char* msg_idle = bprintf("Invalid idle value for pstate %d on host %s: %%s", i, host->getCname());
- char* msg_min = bprintf("Invalid OneCore value for pstate %d on host %s: %%s", i, host->getCname());
- char* msg_max = bprintf("Invalid AllCores value for pstate %d on host %s: %%s", i, host->getCname());
+ char* msg_idle = bprintf("Invalid idle value for pstate %d on host %s: %%s", i, host->get_cname());
+ char* msg_min = bprintf("Invalid OneCore value for pstate %d on host %s: %%s", i, host->get_cname());
+ char* msg_max = bprintf("Invalid AllCores value for pstate %d on host %s: %%s", i, host->get_cname());
PowerRange range(xbt_str_parse_double((current_power_values.at(0)).c_str(), msg_idle),
xbt_str_parse_double((current_power_values.at(1)).c_str(), msg_min),
xbt_str_parse_double((current_power_values.at(2)).c_str(), msg_max));
host.extension_set(new HostEnergy(&host));
}
-static void onActionStateChange(simgrid::surf::CpuAction* action, simgrid::surf::Action::State previous)
+static void onActionStateChange(simgrid::surf::CpuAction* action, simgrid::kernel::resource::Action::State previous)
{
for (simgrid::surf::Cpu* const& cpu : action->cpus()) {
- simgrid::s4u::Host* host = cpu->getHost();
+ simgrid::s4u::Host* host = cpu->get_host();
if (host != nullptr) {
// If it's a VM, take the corresponding PM
if (dynamic_cast<simgrid::s4u::VirtualMachine*>(&host)) // Ignore virtual machines
return;
- XBT_INFO("Energy consumption of host %s: %f Joules", host.getCname(),
+ XBT_INFO("Energy consumption of host %s: %f Joules", host.get_cname(),
host.extension<HostEnergy>()->getConsumedEnergy());
}
static void onSimulationEnd()
{
- sg_host_t* host_list = sg_host_list();
- int host_count = sg_host_count();
+ std::vector<simgrid::s4u::Host*> hosts = simgrid::s4u::Engine::get_instance()->get_all_hosts();
+
double total_energy = 0.0; // Total energy consumption (whole platform)
double used_hosts_energy = 0.0; // Energy consumed by hosts that computed something
- for (int i = 0; i < host_count; i++) {
- if (dynamic_cast<simgrid::s4u::VirtualMachine*>(host_list[i]) == nullptr) { // Ignore virtual machines
+ for (size_t i = 0; i < hosts.size(); i++) {
+ if (dynamic_cast<simgrid::s4u::VirtualMachine*>(hosts[i]) == nullptr) { // Ignore virtual machines
- bool host_was_used = (host_list[i]->extension<HostEnergy>()->last_updated != 0);
- double energy = host_list[i]->extension<HostEnergy>()->getConsumedEnergy();
+ bool host_was_used = (sg_host_get_computed_flops(hosts[i]) != 0);
+ double energy = hosts[i]->extension<HostEnergy>()->getConsumedEnergy();
total_energy += energy;
if (host_was_used)
used_hosts_energy += energy;
}
XBT_INFO("Total energy consumption: %f Joules (used hosts: %f Joules; unused/idle hosts: %f)",
total_energy, used_hosts_energy, total_energy - used_hosts_energy);
- xbt_free(host_list);
}
/* **************************** Public interface *************************** */
-extern "C" {
/** \ingroup plugin_energy
* \brief Enable host energy plugin
if (HostEnergy::EXTENSION_ID.valid())
return;
+ sg_host_load_plugin_init();
+
HostEnergy::EXTENSION_ID = simgrid::s4u::Host::extension_create<HostEnergy>();
- simgrid::s4u::Host::onCreation.connect(&onCreation);
- simgrid::s4u::Host::onStateChange.connect(&onHostChange);
- simgrid::s4u::Host::onSpeedChange.connect(&onHostChange);
- simgrid::s4u::Host::onDestruction.connect(&onHostDestruction);
- simgrid::s4u::onSimulationEnd.connect(&onSimulationEnd);
+ simgrid::s4u::Host::on_creation.connect(&onCreation);
+ simgrid::s4u::Host::on_state_change.connect(&onHostChange);
+ simgrid::s4u::Host::on_speed_change.connect(&onHostChange);
+ simgrid::s4u::Host::on_destruction.connect(&onHostDestruction);
+ simgrid::s4u::on_simulation_end.connect(&onSimulationEnd);
simgrid::surf::CpuAction::onStateChange.connect(&onActionStateChange);
}
*/
void sg_host_energy_update_all()
{
- simgrid::simix::kernelImmediate([]() {
- std::vector<simgrid::s4u::Host*> list;
- simgrid::s4u::Engine::getInstance()->getHostList(&list);
+ simgrid::simix::simcall([]() {
+ std::vector<simgrid::s4u::Host*> list = simgrid::s4u::Engine::get_instance()->get_all_hosts();
for (auto const& host : list)
if (dynamic_cast<simgrid::s4u::VirtualMachine*>(host) == nullptr) // Ignore virtual machines
host->extension<HostEnergy>()->update();
double sg_host_get_consumed_energy(sg_host_t host)
{
xbt_assert(HostEnergy::EXTENSION_ID.valid(),
- "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
+ "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
return host->extension<HostEnergy>()->getConsumedEnergy();
}
double sg_host_get_wattmin_at(sg_host_t host, int pstate)
{
xbt_assert(HostEnergy::EXTENSION_ID.valid(),
- "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
+ "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
return host->extension<HostEnergy>()->getWattMinAt(pstate);
}
/** @ingroup plugin_energy
double sg_host_get_wattmax_at(sg_host_t host, int pstate)
{
xbt_assert(HostEnergy::EXTENSION_ID.valid(),
- "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
+ "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
return host->extension<HostEnergy>()->getWattMaxAt(pstate);
}
double sg_host_get_current_consumption(sg_host_t host)
{
xbt_assert(HostEnergy::EXTENSION_ID.valid(),
- "The Energy plugin is not active. Please call sg_energy_plugin_init() during initialization.");
- double cpu_load = host->pimpl_cpu->constraint()->get_usage() / host->getSpeed();
- return host->extension<HostEnergy>()->getCurrentWattsValue(cpu_load);
-}
+ "The Energy plugin is not active. Please call sg_host_energy_plugin_init() during initialization.");
+ return host->extension<HostEnergy>()->getCurrentWattsValue();
}