double finish_time = surf_get_clock();
double cpu_load;
double current_speed = host->speed();
- 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 = lmm_constraint_get_usage(host->pimpl_cpu->constraint()) / 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;
+ if (start_time < finish_time) {
+ // 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 = lmm_constraint_get_usage(host->pimpl_cpu->constraint()) / 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 == -1) // 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;
- if (host->isOff())
- instantaneous_consumption = this->watts_off;
- else
- instantaneous_consumption = this->getCurrentWattsValue(cpu_load);
+ double energy_this_step = instantaneous_consumption * (finish_time - start_time);
- double energy_this_step = instantaneous_consumption * (finish_time - start_time);
+ // TODO Trace: Trace energy_this_step from start_time to finish_time in host->name()
- //TODO Trace: Trace energy_this_step from start_time to finish_time in host->name()
+ this->total_energy = previous_energy + energy_this_step;
+ this->last_updated = finish_time;
- this->total_energy = previous_energy + energy_this_step;
- this->last_updated = finish_time;
- this->pstate = host->pstate();
- XBT_DEBUG(
- "[update_energy of %s] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> %.2f J",
- host->cname(), start_time, finish_time, host->pimpl_cpu->speed_.peak, previous_energy, energy_this_step);
+ XBT_DEBUG("[update_energy of %s] period=[%.2f-%.2f]; current power peak=%.0E flop/s; consumption change: %.2f J -> "
+ "%.2f J",
+ host->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->pstate() : -1;
}
HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host(ptr), last_updated(surf_get_clock())
double HostEnergy::getWattMinAt(int pstate)
{
- xbt_assert(!power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
+ xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
return power_range_watts_list[pstate].min;
}
double HostEnergy::getWattMaxAt(int pstate)
{
- xbt_assert(!power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
+ xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
return power_range_watts_list[pstate].max;
}
/** @brief Computes the power consumed by the host according to the current pstate and processor load */
double HostEnergy::getCurrentWattsValue(double cpu_load)
{
- xbt_assert(!power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
+ xbt_assert(not power_range_watts_list.empty(), "No power range properties specified for host %s", host->cname());
/* min_power corresponds to the power consumed when only one core is active */
/* max_power is the power consumed at 100% cpu load */
double power_slope = 0;
if (cpu_load > 0) { /* Something is going on, the machine is not idle */
- double min_power = range.min;
- double max_power = range.max;
+ min_power = range.min;
+ max_power = range.max;
/**
* The min_power states how much we consume when only one single
* i.e., we need min_power + (maxCpuLoad-1/coreCount)*power_slope == max_power
* (maxCpuLoad is by definition 1)
*/
- double power_slope;
int coreCount = host->coreCount();
double coreReciprocal = static_cast<double>(1) / static_cast<double>(coreCount);
- if (coreCount > 1)
+ if (coreCount > 1) {
power_slope = (max_power - min_power) / (1 - coreReciprocal);
- else
- power_slope = 0; // Should be 0, since max_power == min_power (in this case)
+ current_power = min_power + (cpu_load - coreReciprocal) * power_slope;
+ } else {
+ current_power = max_power;
+ }
- current_power = min_power + (cpu_load - coreReciprocal) * power_slope;
} else { /* Our machine is idle, take the dedicated value! */
current_power = range.idle;
}
simgrid::surf::CpuAction::onStateChange.connect(&onActionStateChange);
}
+/** @brief updates the consumption of all hosts
+ *
+ * After this call, sg_host_get_consumed_energy() will not interrupt your process
+ * (until after the next clock update).
+ */
+void sg_host_energy_update_all()
+{
+ simgrid::simix::kernelImmediate([]() {
+ std::vector<simgrid::s4u::Host*> list;
+ simgrid::s4u::Engine::instance()->hostList(&list);
+ for (auto host : list)
+ host->extension<HostEnergy>()->update();
+ });
+}
+
/** @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.
+ * The result is that the actor requesting this value will be interrupted,
+ * the value will be updated in kernel mode before returning the control to the requesting actor.
*
* See also @ref SURF_plugin_energy.
*/