diff --git a/src/algo/energy_shutdown_overclock.cpp b/src/algo/energy_shutdown_overclock.cpp index eb87f9c5458a4bbc9c61828167fde98c8bd2e2f2..c72a70f4c6da06550e1369869267bb838e5eec4c 100644 --- a/src/algo/energy_shutdown_overclock.cpp +++ b/src/algo/energy_shutdown_overclock.cpp @@ -60,6 +60,26 @@ void EnergyShutdownOverclock::make_decisions(double date, // Hacks: // - uses priority job's completion time to store its expected starting time + // Handle newly switched machines. + for (auto & [new_pstate, machines]: _machines_whose_pstate_changed_recently) + { + if (new_pstate == _energy_model.compute_pstate) + { + IntervalSet newly_idle_machines = machines & _booting_machines; + _booting_machines -= newly_idle_machines; + _available_machines += newly_idle_machines; + _nb_available_machines += newly_idle_machines.size(); + } + else if (new_pstate == _energy_model.sleep_pstate) + { + IntervalSet newly_unbounded_off_machines = machines & _unbounded_off_machines_ongoing; + _unbounded_off_machines_ongoing -= newly_unbounded_off_machines; + _unbounded_off_machines += newly_unbounded_off_machines; + + // TODO: bounded off machines + } + } + bool job_ended = false; // Handle newly finished jobs @@ -235,6 +255,36 @@ void EnergyShutdownOverclock::make_decisions(double date, } } } + + IntervalSet machines_still_idle = _available_machines; + + // Some idle machines can be turned off if it enables overclocking more processing machines (without delaying the priority job's estimated start time). + + // Just to make sure that the shutdown/restart system works, let us (temporarily) shutdown idle machines when queue is empty. + if (_priority_job == nullptr && _pending_jobs.empty() && machines_still_idle.size() > 0) + { + _decision->add_set_resource_state(machines_still_idle, _energy_model.sleep_pstate, date); + _unbounded_off_machines_ongoing.insert(machines_still_idle); + _available_machines -= machines_still_idle; + _nb_available_machines -= machines_still_idle.size(); + } + + // Wake unbounded off machines if they can be useful to run queued jobs. + int sum_requested_res_in_queue = 0; + if (_priority_job != nullptr) + sum_requested_res_in_queue += _priority_job->nb_requested_resources; + for (auto job_it = _pending_jobs.begin(); job_it != _pending_jobs.end(); ++job_it) + { + sum_requested_res_in_queue += (*job_it)->nb_requested_resources; + } + int nb_res_to_wakeup = min((int)_unbounded_off_machines.size(), sum_requested_res_in_queue - (int)_booting_machines.size()); + if (nb_res_to_wakeup > 0) + { + IntervalSet machines_to_wakeup = _unbounded_off_machines.left(nb_res_to_wakeup); + _decision->add_set_resource_state(machines_to_wakeup, _energy_model.compute_pstate, date); + _unbounded_off_machines -= machines_to_wakeup; + _booting_machines += machines_to_wakeup; + } } double EnergyShutdownOverclock::compute_priority_job_expected_earliest_starting_time() @@ -252,8 +302,7 @@ double EnergyShutdownOverclock::compute_priority_job_expected_earliest_starting_ } } - PPK_ASSERT_ERROR(false, "The job will never be executable."); - return 0; + return 1e16; } std::list<EnergyShutdownOverclock::FinishedHorizonPoint>::iterator EnergyShutdownOverclock::insert_horizon_point(const EnergyShutdownOverclock::FinishedHorizonPoint &point) diff --git a/src/algo/energy_shutdown_overclock.hpp b/src/algo/energy_shutdown_overclock.hpp index 5bbd94d24ce718f5e09f8fb06d8b2a369cab8d26..8bfde733899ca2d4ad2763e0bbc59ecb924b5afa 100644 --- a/src/algo/energy_shutdown_overclock.hpp +++ b/src/algo/energy_shutdown_overclock.hpp @@ -66,6 +66,10 @@ private: IntervalSet _available_machines; //! Machines currently available int _nb_available_machines = -1; + IntervalSet _booting_machines; //! Machines currently being switched on. + IntervalSet _unbounded_off_machines; //! Machines currently off. These machines have no planified waking up date. + IntervalSet _unbounded_off_machines_ongoing; //! These are machines currently being switched off (see previous variable for details). + EnergyModel _energy_model; // Pending jobs (queue; without the priority job)