#include "global_scheduler.hh" #include "task_scheduler.hh" #include "options.hh" #include "time_io.hh" #include "file_io.hh" #include "ask.hh" #include "llc.hh" #include "be.hh" #include "log.hh" #include #include #include #include #include #include #include #include #include #include #include #include #include bool crash = false; const std::string Global_Scheduler::scheduling_algorithms[] = { "EDF" }; void Global_Scheduler::load(std::string file) { std::ifstream f; get_system_file(f, file); set_global_scheduler_parameters(f); set_global_scheduling_algorithm(f); set_task_schedulers(f); } void Global_Scheduler::get_system_file(std::ifstream& f, std::string file) { if (file != "") { f.open(tasks_path + file, std::ios_base::in); if (!f.good()) { std::cerr << "Can't find file provided with the -s (--system) option: " << tasks_path << file << std::endl; exit(EXIT_FAILURE); } } else { bool first_try = true; do { if (first_try) { first_try = false; } else { std::cout << "No such file. Try again!" << std::endl; } std::cout << std::endl << "In " << tasks_path << ", load what file: "; std::cin >> filename; f.open(tasks_path + filename, std::ios_base::in); } while (!f.good()); } } void Global_Scheduler::set_global_scheduler_parameters(std::ifstream& f) { file_goto_next_colon(f); f >> scheduling_rate; assert(scheduling_rate > ms_t(0)); file_goto_next_colon(f); f >> period; assert(period > ms_t(0)); period_left = period; file_goto_next_colon(f); f >> lifetime; assert(period <= lifetime); } void Global_Scheduler::set_global_scheduling_algorithm(std::ifstream& f) { file_goto_next_colon(f); f >> scheduling_algorithm; bool found_algorithm = false; for (int i = 0, num_scheduling_algorithms = sizeof(scheduling_algorithms)/ sizeof(scheduling_algorithms[0]); i < num_scheduling_algorithms; i++) { if (scheduling_algorithm == scheduling_algorithms[i]) { found_algorithm = true; break; } } if (!found_algorithm) { std::cerr << " Couldn't find global scheduler algorithm: " << scheduling_algorithm << std::endl; exit(EXIT_FAILURE); } } void Global_Scheduler::set_task_schedulers(std::ifstream& f) { number_of_schedulers = 0; std::streampos pos = f.tellg(); file_goto_next_newline(f); while (f.good() and (f.peek() != EOF)) { char current = f.get(); if ((current == '\n') or (current == ' ')) { number_of_schedulers++; } file_goto_next_newline(f); } f.seekg(pos); assert(f.good()); assert(number_of_schedulers > 0); size_t schedulers_size = number_of_schedulers*sizeof(Task_Scheduler *); schedulers = (Task_Scheduler **)malloc(schedulers_size); assert(schedulers); for (int i = 0; i < number_of_schedulers; i++) { schedulers[i] = new Task_Scheduler(f); } check_schedulers(this, schedulers); } void Global_Scheduler::store() { std::cout << "[ to store this SYSTEM, put this in the file " << tasks_path << "SYSTEM ]" << std::endl; std::cout << "Global scheduling rate: " << scheduling_rate << std::endl << "Global period: " << period << std::endl << "Global lifetime: " << lifetime << std::endl << "Global scheduling algorithm: " << scheduling_algorithm << std::endl; for (int i = 0; i < number_of_schedulers; i++) { std::cout << std::endl; schedulers[i]->store(); } std::cout << "[ done ] " << std::endl; } Global_Scheduler::~Global_Scheduler() { for (int i = 0; i < number_of_schedulers; i++) { delete schedulers[i]; } if (schedulers) { free(schedulers); } } void Global_Scheduler::init_from_file(std::string file) { set_tasks_path(); load(file); } void Global_Scheduler::init_from_keyboard() { set_tasks_path(); read_parameters_from_keyboard(); read_tasks_from_keyboard(); } void Global_Scheduler::set_tasks_path() { const int max_path_len = 85; char tasks_abs_path[max_path_len]; readlink("/proc/self/exe", tasks_abs_path, max_path_len); std::string tap_str = tasks_abs_path; tasks_path = tap_str.substr(0, tap_str.find_last_of('/')); tasks_path += "/../sys/"; } void Global_Scheduler::read_parameters_from_keyboard() { std::cout << std::endl; do { do { std::cout << "Global scheduling rate: "; std::cin >> scheduling_rate; } while (!(scheduling_rate > ms_t(0))); do { std::cout << "Global scheduler period: "; std::cin >> period; } while (!(period > ms_t(0))); do { std::cout << "System lifetime: "; std::cin >> lifetime; } while (!(lifetime > ms_t(0))); } while (!(period <= lifetime)); period_left = period; // just set this, there is only one so far anyway scheduling_algorithm = scheduling_algorithms[0]; std::cout << "Global scheduling algorithm: " << scheduling_algorithm << std::endl; } void Global_Scheduler::read_tasks_from_keyboard() { number_of_schedulers = ask_how_many("task schedulers"); size_t schedulers_size = number_of_schedulers*sizeof(Task_Scheduler *); schedulers = (Task_Scheduler **)malloc(schedulers_size); for (int i = 0; i < number_of_schedulers; i++) { schedulers[i] = new Task_Scheduler(); } check_schedulers(this, schedulers); } Global_Scheduler::Global_Scheduler() { period_left = ms_t(0); number_of_schedulers = 0; if (log_tick) { logger.open_log_file(); } } void Global_Scheduler::schedule() { if (scheduling_algorithm == "EDF") { schedule_EDF(); } else { std::cerr << "Unknown algorithm: " << scheduling_algorithm << std::endl; exit(EXIT_FAILURE); } } void Global_Scheduler::schedule_EDF() { int selected_scheduler; tp_t earliest_deadline; tp_t candidate_deadline; bool is_data = false; for (int i = 0; i < number_of_schedulers; i++) { schedulers[i]->schedule(); if (schedulers[i]->is_ready()) { candidate_deadline = schedulers[i]->earliest_deadline(); if (!is_data or (candidate_deadline < earliest_deadline)) { is_data = true; earliest_deadline = candidate_deadline; selected_scheduler = i; } } } if (is_data) { schedulers[selected_scheduler]->run(); } // else if (do_freeze_BE_core) { // if (debug) { std::cout << "No scheduler is ready: unfreeze BE!" << std::endl; } // unfreeze_BE_core(); // } } void Global_Scheduler::resupply() { period_left = period; for (int i = 0; i < number_of_schedulers; i++) { schedulers[i]->resupply(); } } void Global_Scheduler::check_period(ms_t tick_time) { period_left -= tick_time; if (period_left < ms_t(0)) { resupply(); } } void Global_Scheduler::tick(ms_t tick_time, int llc_fd) { long long current_BE_accesses = (poll_llc ? query_BE_monitor(llc_fd) : 0); if (log_tick) { logger.print_time_to_file(); } schedule(); for (int i = 0; i < number_of_schedulers; i++) { schedulers[i]->tick(tick_time, current_BE_accesses, llc_fd); } check_period(tick_time); } void Global_Scheduler::run() { if (do_freeze_BE_core) { init_BE_core(); } int llc_fd = 0; if (poll_llc) { llc_fd = setup_BE_monitor(); } tp_t system_start(std::chrono::system_clock::now()); tp_t system_end(system_start + lifetime); tp_t re_sched_time; int i = 0; do { re_sched_time = system_start + ++i*scheduling_rate; tick(scheduling_rate, llc_fd); std::this_thread::sleep_until(re_sched_time); } while (!crash and std::chrono::system_clock::now() < system_end); pid_t status; if (wait_for_forked_processes) { std::cout << "Waiting for children to terminate..." << std::endl; do { wait(&status); if (status == -1 && errno != ECHILD) { std::cerr << "Error while waiting for children to terminate." << std::endl; exit(EXIT_FAILURE); } re_sched_time = system_start + ++i*scheduling_rate; tick(scheduling_rate, llc_fd); std::this_thread::sleep_until(re_sched_time); } while (status > 0 ); } if (poll_llc) { long long BE_accesses = query_BE_monitor(llc_fd); if (latex) { long long execution_memory_budget = sum_memory_budget()*number_of_periods(); long long errors = BE_accesses - execution_memory_budget; float error_ratio = (errors > 0 ? (float)errors/(float)BE_accesses : 0); std::cout << " " << execution_memory_budget << " & " << BE_accesses << " & " << error_ratio << " \\\\ " << std::endl; } else { std::cout << "Terminated: " << BE_accesses << " BE accesses" << std::endl; } close_BE_monitor(llc_fd); } if (do_freeze_BE_core) { close_BE_core(); } } long long Global_Scheduler::sum_memory_budget() { long long sum_budget = 0; for (int s = 0; s < number_of_schedulers; s++) { sum_budget += schedulers[s]->get_max_BE_accesses(); } return sum_budget; } int Global_Scheduler::number_of_periods() { int int_lifetime = std::chrono::duration_cast(lifetime).count(); int int_period = std::chrono::duration_cast(period).count(); int periods = int_lifetime/int_period; int remainder = int_lifetime%int_period; if (remainder) { periods++; } return periods; } std::ostream& operator<<(std::ostream& os, Global_Scheduler& gs) { os << "*** global (scheduler) scheduler ***" << std::endl << "Rate: " << gs.scheduling_rate << std::endl << "Period: " << gs.period << " (left: " << gs.period_left << ")" << std::endl << "Lifetime: " << gs.lifetime << std::endl << "Schedulers: " << gs.number_of_schedulers << std::endl << std::endl; for (int i = 0; i < gs.number_of_schedulers; i++) { os << gs.schedulers[i]; } return os; } void Global_Scheduler::check_schedulers(Global_Scheduler* gs, Task_Scheduler* ts[]) { ms_t total_budget(0); for (int i = 0; i < gs->number_of_schedulers; i++) { ts[i]->check_tasks(); total_budget += ts[i]->get_budget(); } assert(total_budget <= gs->period); }