From 6ae3a54bea292b301c18b08ff44c55ad6b6bd09d Mon Sep 17 00:00:00 2001 From: Matej Kafka Date: Tue, 27 Apr 2021 00:05:44 +0200 Subject: [PATCH] #50 Process initialization is now parallel Also adds some `info` level prints to make demos a bit more friendly to new users closes #50 --- src/demos_scheduler.hpp | 2 +- src/partition_manager.hpp | 85 +++++++++++++--------------------- test/0100-api.t | 2 +- test_config/api_init_test.yaml | 15 ++++++ 4 files changed, 50 insertions(+), 54 deletions(-) create mode 100644 test_config/api_init_test.yaml diff --git a/src/demos_scheduler.hpp b/src/demos_scheduler.hpp index cc52535a7..bcee4da96 100644 --- a/src/demos_scheduler.hpp +++ b/src/demos_scheduler.hpp @@ -70,7 +70,7 @@ class DemosScheduler void start_scheduler() { - logger->debug("Starting scheduler"); + logger->info("Starting scheduler"); memory_tracker::enable(); mf.start(std::chrono::steady_clock::now()); } diff --git a/src/partition_manager.hpp b/src/partition_manager.hpp index 5aff1521c..8c416cc6c 100644 --- a/src/partition_manager.hpp +++ b/src/partition_manager.hpp @@ -10,11 +10,10 @@ class PartitionManager { private: Partitions partitions; - Partitions::iterator init_iter = partitions.begin(); - Process *initialized_proc = nullptr; std::function completion_cb = [] {}; // initialized in `run_process_init` std::function init_cb = nullptr; + int remaining_process_inits = 0; public: explicit PartitionManager(Partitions &&partitions) @@ -54,12 +53,33 @@ class PartitionManager } // overwrite process exit callback set in constructor - // we need this to be able to detect that a process exited during initialization - // and we should move on to the next one, otherwise a deadlock would occur + // we need this to be able to detect that a process exited during initialization, + // otherwise a deadlock would occur, waiting for the completion of an exited process // this will be reset to the original callback after initialization is finished set_exit_cb(&PartitionManager::process_init_exit_cb); - init_next_process(); + // count and start all processes that needs initialization in parallel + for (auto &part : partitions) { + for (auto &proc : part.processes) { + if (!proc.needs_initialization()) continue; + logger->trace("Initializing process '{}'", proc.get_pid()); + remaining_process_inits++; + // resume the process; it should stop on its own after initialization is completed + // then, it will call proc_init_completion_cb as callback; if it exits instead + // (probably due to an error), `process_init_exit_cb` will be called + proc.resume(); + } + } + + if (remaining_process_inits == 0) { + logger->info("No processes need initialization"); + // no process needs initialization, we're done + finish_process_init(); + } else { + logger->info("Initializing {} {}", + remaining_process_inits, + remaining_process_inits == 1 ? "process" : "processes"); + } } /** Spawns suspended processes from all partitions. */ @@ -113,45 +133,6 @@ class PartitionManager completion_cb(); } - Process *find_next_uninitialized_process() - { - Process *proc; - for (; init_iter != partitions.end(); init_iter++) { - proc = init_iter->seek_pending_process(); - if (proc) return proc; - } - return nullptr; - } - - void init_next_process() - { - initialized_proc = find_next_uninitialized_process(); - if (initialized_proc) { - init_process(initialized_proc); - } else { - finish_process_init(); - } - } - - /** - * Initializes a single process. - * Completion is handled by `process_init_completion_cb()`. - */ - void init_process(Process *p) - { - if (!p->needs_initialization()) { - p->mark_completed(); - init_next_process(); - return; - } - - logger->trace("Initializing process '{}'", p->get_pid()); - // resume the process; it should stop on its own after initialization is completed - // then, it will call init_next_process as callback; if it exits instead (probably - // due to an error), `process_init_exit_cb` will be called - p->resume(); - } - void finish_process_init() { // reset process exit cb to the original one @@ -165,20 +146,20 @@ class PartitionManager } /** Called as a completion callback from process. */ - void process_init_completion_cb(Process &) + void process_init_completion_cb(Process &proc) { - initialized_proc->suspend(); - initialized_proc->mark_completed(); - init_next_process(); + proc.suspend(); + remaining_process_inits--; + if (remaining_process_inits == 0) { + finish_process_init(); + } } /** Called when a process exits during initialization. */ void process_init_exit_cb(Process &proc, bool partition_empty) { - // if this is false, it means some other process exited, - // this may happen for example on receiving SIGINT - if (!initialized_proc->is_running()) { - // end initialization of this process and move on to the next one + if (proc.needs_initialization()) { + // consider this process initialized process_init_completion_cb(proc); } // call original callback diff --git a/test/0100-api.t b/test/0100-api.t index 619b982c3..b306d8ccd 100755 --- a/test/0100-api.t +++ b/test/0100-api.t @@ -55,7 +55,7 @@ partitions: ') is "$out" \ "init start -init done init start init done +init done " \ No newline at end of file diff --git a/test_config/api_init_test.yaml b/test_config/api_init_test.yaml new file mode 100644 index 000000000..63c620eae --- /dev/null +++ b/test_config/api_init_test.yaml @@ -0,0 +1,15 @@ +windows: + - length: 200 + slices: + - cpu: 0 + sc_partition: SC1 + +partitions: + - name: SC1 + processes: + - cmd: ../build/src/tests/api-init-test + budget: 100 + init: yes + - cmd: ../build/src/tests/api-init-test + budget: 100 + init: yes \ No newline at end of file