diff --git a/meson.build b/meson.build index 93730cee67cec56e4348594660a9edd1917f4628..fbdfd5612bca7c73114362510192bbd2fdb9ee9e 100644 --- a/meson.build +++ b/meson.build @@ -66,6 +66,8 @@ src = [ 'src/algo/rejecter.hpp', 'src/algo/sequencer.cpp', 'src/algo/sequencer.hpp', + 'src/algo/sequencer_dvfs.cpp', + 'src/algo/sequencer_dvfs.hpp', 'src/algo/sleeper.cpp', 'src/algo/sleeper.hpp', 'src/algo/submitter.cpp', diff --git a/src/algo/sequencer_dvfs.cpp b/src/algo/sequencer_dvfs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0bb8cae3a21fb441d8139e10f5dfd2171351dca0 --- /dev/null +++ b/src/algo/sequencer_dvfs.cpp @@ -0,0 +1,117 @@ +#include "sequencer_dvfs.hpp" + +#include <loguru.hpp> + +#include "../pempek_assert.hpp" + +SequencerDVFS::SequencerDVFS(Workload *workload, + SchedulingDecision *decision, + Queue *queue, + ResourceSelector *selector, + double rjms_delay, + rapidjson::Document *variant_options) : + ISchedulingAlgorithm(workload, decision, queue, selector, rjms_delay, variant_options) +{ + PPK_ASSERT_ERROR(variant_options->HasMember("monitoring_period"), "invalid options: 'monitoring_period' is missing"); + PPK_ASSERT_ERROR((*variant_options)["monitoring_period"].IsNumber(), "invalid options: 'monitoring_period' is not a number"); + _monitoring_period = (*variant_options)["monitoring_period"].GetDouble(); + PPK_ASSERT_ERROR(_monitoring_period > 0, "invalid options: 'monitoring period' should be strictly positive but got %g", _monitoring_period); + + PPK_ASSERT_ERROR(variant_options->HasMember("pstate_compute_fast"), "invalid options: 'pstate_compute_fast' is missing"); + PPK_ASSERT_ERROR((*variant_options)["pstate_compute_fast"].IsNumber(), "invalid options: 'pstate_compute_fast' is not a number"); + _pstate_compute_fast = (*variant_options)["pstate_compute_fast"].GetInt(); + PPK_ASSERT_ERROR(_pstate_compute_fast >= 0, "invalid options: 'pstate_compute_fast period' should be positive but got %d", _pstate_compute_fast); + + PPK_ASSERT_ERROR(variant_options->HasMember("pstate_compute_slow"), "invalid options: 'pstate_compute_slow' is missing"); + PPK_ASSERT_ERROR((*variant_options)["pstate_compute_slow"].IsNumber(), "invalid options: 'pstate_compute_slow' is not a number"); + _pstate_compute_slow = (*variant_options)["pstate_compute_slow"].GetInt(); + PPK_ASSERT_ERROR(_pstate_compute_slow >= 0, "invalid options: 'pstate_compute_slow period' should be positive but got %d", _pstate_compute_slow); + + PPK_ASSERT_ERROR(_pstate_compute_fast != _pstate_compute_slow, "invalid options: 'pstate_compute_fast' and 'pstate_compute_slow' should be different but both have value %d", _pstate_compute_fast); + + LOG_SCOPE_FUNCTION(INFO); + LOG_F(INFO, "monitoring_period: %g", _monitoring_period); + LOG_F(INFO, "pstate_compute_fast: %d", _pstate_compute_fast); + LOG_F(INFO, "pstate_compute_slow: %d", _pstate_compute_slow); +} + +SequencerDVFS::~SequencerDVFS() +{ + +} + +void SequencerDVFS::on_simulation_start(double date, const rapidjson::Value &batsim_config) +{ + (void) date; + (void) batsim_config; + + _machines.insert(IntervalSet::ClosedInterval(0, _nb_machines - 1)); + PPK_ASSERT_ERROR(_machines.size() == (unsigned int) _nb_machines); + + // Request the initial future call. Future ones will be requested in the on_requested_call function. + _decision->add_call_me_later(date + _monitoring_period, date); +} + +void SequencerDVFS::on_simulation_end(double date) +{ +} + +void SequencerDVFS::on_requested_call(double date) +{ + LOG_SCOPE_FUNCTION(INFO); + LOG_F(INFO, "requested call received!"); + + // Request a future call at current date + period (unless simulation is about to finish) + if (!_no_more_static_job_to_submit_received || _is_job_running) + { + _decision->add_call_me_later(date + _monitoring_period, date); + } + + // Toggle DVFS state of allocated machines if a job is being run + if (_is_job_running) + { + int new_pstate = _currently_fast ? _pstate_compute_slow : _pstate_compute_fast; + _decision->add_set_resource_state(_allocated_machines, new_pstate, date); + } +} + +void SequencerDVFS::make_decisions(double date, + SortableJobOrder::UpdateInformation *update_info, + SortableJobOrder::CompareInformation *compare_info) +{ + // This algorithm executes all the jobs, one after the other. + // At any time, either 0 or 1 job is running on the platform. + // The order of the sequence depends on the queue order. + + // Up to one job finished since last call. + PPK_ASSERT_ERROR(_jobs_ended_recently.size() <= 1); + if (!_jobs_ended_recently.empty()) + { + PPK_ASSERT_ERROR(_is_job_running); + _is_job_running = false; + } + + // Add valid jobs into the queue + for (const std::string & job_id : _jobs_released_recently) + { + const Job * job = (*_workload)[job_id]; + + if (job->nb_requested_resources <= _nb_machines) + _queue->append_job(job, update_info); + else + _decision->add_reject_job(job->id, date); + } + + // Sort queue if needed + _queue->sort_queue(update_info, compare_info); + + // Execute the first job if the machine is empty + const Job * job = _queue->first_job_or_nullptr(); + if (job != nullptr && !_is_job_running) + { + _allocated_machines = _machines.left(job->nb_requested_resources); + _decision->add_execute_job(job->id, _allocated_machines, date); + _is_job_running = true; + _queue->remove_job(job); + } +} diff --git a/src/algo/sequencer_dvfs.hpp b/src/algo/sequencer_dvfs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..018f2495dcaf22e05774341faa49cb999bd9a2b6 --- /dev/null +++ b/src/algo/sequencer_dvfs.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "../isalgorithm.hpp" + +#include "../locality.hpp" +#include <intervalset.hpp> + +class Workload; +class SchedulingDecision; + +class SequencerDVFS : public ISchedulingAlgorithm +{ +public: + SequencerDVFS(Workload * workload, SchedulingDecision * decision, Queue * queue, ResourceSelector * selector, + double rjms_delay, rapidjson::Document * variant_options); + + virtual ~SequencerDVFS(); + + virtual void on_simulation_start(double date, const rapidjson::Value & batsim_config); + + virtual void on_simulation_end(double date); + + virtual void on_requested_call(double date); + + virtual void make_decisions(double date, + SortableJobOrder::UpdateInformation * update_info, + SortableJobOrder::CompareInformation * compare_info); + +private: + IntervalSet _machines; + IntervalSet _allocated_machines; + bool _is_job_running = false; + double _monitoring_period = -1; + + int _pstate_compute_fast = -1; + int _pstate_compute_slow = -1; + bool _currently_fast = true; +}; diff --git a/src/main.cpp b/src/main.cpp index 1827cb7fdfdc3bfaaa901fa73844098baeee76db..56b245fc710e419831778b3c785b870bc589924c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,6 +40,7 @@ #include "algo/rejecter.hpp" #include "algo/sleeper.hpp" #include "algo/sequencer.hpp" +#include "algo/sequencer_dvfs.hpp" #include "algo/submitter.hpp" #include "algo/wt_estimator.hpp" @@ -80,7 +81,7 @@ int main(int argc, char ** argv) "energy_bf_monitoring_inertial", "energy_bf_subpart_sleeper", "energy_watcher", "fcfs", "fcfs_fast", "filler", "killer", "killer2", "random", "rejecter", - "sequencer", "sleeper", "submitter", "waiting_time_estimator"}; + "sequencer", "sequencer_dvfs", "sleeper", "submitter", "waiting_time_estimator"}; const set<string> policies_set = {"basic", "contiguous"}; const set<string> queue_orders_set = {"fcfs", "lcfs", "desc_bounded_slowdown", "desc_slowdown", "asc_size", "desc_size", "asc_walltime", "desc_walltime"}; @@ -298,6 +299,8 @@ int main(int argc, char ** argv) algo = new Rejecter(&w, &decision, queue, selector, rjms_delay, &json_doc_variant_options); else if (scheduling_variant == "sequencer") algo = new Sequencer(&w, &decision, queue, selector, rjms_delay, &json_doc_variant_options); + else if (scheduling_variant == "sequencer_dvfs") + algo = new SequencerDVFS(&w, &decision, queue, selector, rjms_delay, &json_doc_variant_options); else if (scheduling_variant == "sleeper") algo = new Sleeper(&w, &decision, queue, selector, rjms_delay, &json_doc_variant_options); else if (scheduling_variant == "submitter")