diff --git a/.vscode/launch.json b/.vscode/launch.json index ff5fff91d937e99ff00c5ea1b251d240289baf15..dec5cc032c97c6052a3ec27008e4207fb6a1bc41 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -82,21 +82,41 @@ "console": "externalTerminal" }, { - "name": "RoundRobinSchedulingTicksOnly", + "name": "RoundRobinSchedulingTicksOnlyExample", "type": "cppvsdbg", "request": "launch", - "program": "${workspaceFolder}/build/examples/RoundRobinScheduling/Debug/RoundRobinSchedulingTicksOnly.exe", - "args": ["-o" "c:/tmp" "-t" "2000" "-r" "1" "2"], + "program": "${workspaceFolder}/build/examples/PriorityScheduling/Debug/RoundRobinSchedulingTicksOnly.exe", + "args": ["-o" "${workspaceFolder}/traces" "-t" "2000" "-r" "1" "2"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "console": "integratedTerminal" }, { - "name": "RoundRobinScheduling", + "name": "RoundRobinSchedulingExample", "type": "cppvsdbg", "request": "launch", - "program": "${workspaceFolder}/build/examples/RoundRobinScheduling/Debug/RoundRobinScheduling.exe", - "args": ["-o" "c:/tmp" "-t" "2000" "-r" "1" "2"], + "program": "${workspaceFolder}/build/examples/PriorityScheduling/Debug/RoundRobinScheduling.exe", + "args": ["-o" "${workspaceFolder}/traces" "-t" "2000" "-r" "1" "2"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "console": "integratedTerminal" + }, + { + "name": "PrioritySchedulingExample", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/PriorityScheduling/Debug/PriorityScheduling.exe", + "args": ["-o" "${workspaceFolder}/traces" "-t" "2000" "-r" "1" "2"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "console": "integratedTerminal" + }, + { + "name": "PosixRealtimeSchedulingExample", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/PriorityScheduling/Debug/PosixRealtimeScheduling.exe", + "args": ["-o" "${workspaceFolder}/traces" "-t" "2000" "-r" "1" "2"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "console": "integratedTerminal" diff --git a/app4mc.sim_lib/OsModel/CMakeLists.txt b/app4mc.sim_lib/OsModel/CMakeLists.txt index e300fad267248e156b1a4b7bf197dd4639b5190a..5c2c317d6805777645a8b064c1376a7102a14475 100644 --- a/app4mc.sim_lib/OsModel/CMakeLists.txt +++ b/app4mc.sim_lib/OsModel/CMakeLists.txt @@ -6,4 +6,5 @@ target_sources(app4mc.sim_lib PRIVATE "ExternalSchedulerIF.cpp" "SchedulingParameter.cpp" "PriorityRoundRobinScheduler.cpp" + "PosixRealtimeScheduler.cpp" ) \ No newline at end of file diff --git a/app4mc.sim_lib/OsModel/PosixRealtimeScheduler.cpp b/app4mc.sim_lib/OsModel/PosixRealtimeScheduler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4cbc64a69697cbb92c62100185659bac8b04c84 --- /dev/null +++ b/app4mc.sim_lib/OsModel/PosixRealtimeScheduler.cpp @@ -0,0 +1,110 @@ +/** + ******************************************************************************** + * Copyright (c) 2022 Robert Bosch GmbH + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * - Robert Bosch GmbH - initial contribution + * Author: Behnaz Pourmohseni <behnaz.pourmohseni@de.bosch.com> + ******************************************************************************** + */ + +#include "PosixRealtimeScheduler.h" +#include "Schedulable.h" +#include "Common.h" +#include "PriorityScheduler.h" +#include "PriorityRoundRobinScheduler.h" + +using POLICY = PosixRealtimeScheduler::PosixSchedPolicy; + +std::string PosixRealtimeScheduler::getSchedulingPolicyName(const POLICY &policy) const { + switch(policy){ + case POLICY::SCHED_FIFO: + return "SCHED_FIFO"; + case POLICY::SCHED_RR: + return "SCHED_RR"; + default: + throw std::runtime_error("scheduling policy has no defined name"); + } +} + +POLICY PosixRealtimeScheduler::getSchedulingPolicy(const std::string &policyName) const { + if(getSchedulingPolicyName(POLICY::SCHED_FIFO)== policyName){ + return POLICY::SCHED_FIFO; + } + if(getSchedulingPolicyName(POLICY::SCHED_RR)== policyName){ + return POLICY::SCHED_RR; + } + throw std::runtime_error("unknown scheduling policy name: " + policyName); +} + +POLICY PosixRealtimeScheduler::getSchedulingPolicy(const std::shared_ptr<Schedulable> &task) const { + if(task->getTaskAllocation().isParameterSet("schedulingPolicy")){ + return getSchedulingPolicy(task->getTaskAllocation().getSchedulingParameter<app4mc::ParameterType::String, false>("schedulingPolicy")); + } + return POLICY::SCHED_FIFO; +} + +std::shared_ptr<Schedulable> PosixRealtimeScheduler::chooseTask(const std::shared_ptr<ProcessingUnit> &pu) { + auto chosenTask = schedule[pu]; + if(chosenTask){ + switch(getSchedulingPolicy(chosenTask)){ + case POLICY::SCHED_FIFO: + return PriorityScheduler::chooseTask(pu); + case POLICY::SCHED_RR: + return PriorityRoundRobinScheduler::chooseTask(pu); + default: + throw std::runtime_error("scheduling policy not supported"); + } + } + return chosenTask; +} + +void PosixRealtimeScheduler::taskStart(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { + switch(getSchedulingPolicy(task)){ + case POLICY::SCHED_FIFO: + return PriorityScheduler::taskStart(task,pu); + case POLICY::SCHED_RR: + return PriorityRoundRobinScheduler::taskStart(task,pu); + default: + throw std::runtime_error("scheduling policy not supported"); + } +} + +void PosixRealtimeScheduler::taskPreemt(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { + switch(getSchedulingPolicy(task)){ + case POLICY::SCHED_FIFO: + return PriorityScheduler::taskPreemt(task,pu); + case POLICY::SCHED_RR: + return PriorityRoundRobinScheduler::taskPreemt(task,pu); + default: + throw std::runtime_error("scheduling policy not supported"); + } +} + +void PosixRealtimeScheduler::taskResume(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { + switch(getSchedulingPolicy(task)){ + case POLICY::SCHED_FIFO: + return PriorityScheduler::taskResume(task,pu); + case POLICY::SCHED_RR: + return PriorityRoundRobinScheduler::taskResume(task,pu); + default: + throw std::runtime_error("scheduling policy not supported"); + } +} + +void PosixRealtimeScheduler::taskTerminate(const std::shared_ptr<Schedulable> &task) { + switch(getSchedulingPolicy(task)){ + case POLICY::SCHED_FIFO: + return PriorityScheduler::taskTerminate(task); + case POLICY::SCHED_RR: + return PriorityRoundRobinScheduler::taskTerminate(task); + default: + throw std::runtime_error("scheduling policy not supported"); + } +} \ No newline at end of file diff --git a/app4mc.sim_lib/OsModel/PriorityRoundRobinScheduler.cpp b/app4mc.sim_lib/OsModel/PriorityRoundRobinScheduler.cpp index 15fc9a94a85fe767ed3452e7c1e80337f2d88236..13388718da1ba8d1b13a65e00cd1c0b9afc84b46 100644 --- a/app4mc.sim_lib/OsModel/PriorityRoundRobinScheduler.cpp +++ b/app4mc.sim_lib/OsModel/PriorityRoundRobinScheduler.cpp @@ -14,25 +14,20 @@ ******************************************************************************** */ -#include "Common.h" -#include "HardwareModel.h" #include "PriorityRoundRobinScheduler.h" - +#include <algorithm> +#include "Schedulable.h" +#include "HardwareModel.h" +#include "Event.h" +#include "Tracer.h" sc_core::sc_time PriorityRoundRobinScheduler::getTimeSliceLength(){ return convertTime(getAlgorithmParameter<app4mc::ParameterType::Time, false>("timeSliceLength")); } -void PriorityRoundRobinScheduler::addTaskMapping(std::shared_ptr<Schedulable> task) { - if(!task->getTaskAllocation().isParameterSet("priority")){ - throw std::runtime_error("Task \""+task->getName()+"\" uses PriorityRoundRobin Scheduler but has no Priority set"); - } - Scheduler::addTaskMapping(task); -} - void PriorityRoundRobinScheduler::addResponsibleCore(std::shared_ptr<ProcessingUnit> pu) { if(!vectorContains(coresResponsible,pu)){ - Scheduler::addResponsibleCore(pu); + PriorityScheduler::addResponsibleCore(pu); // timer event auto exprEv = std::make_shared<Event>(getName() + "_TimerTimeoutEvent_" + pu->getName()); Event::cancelEvent(exprEv); @@ -47,8 +42,6 @@ void PriorityRoundRobinScheduler::addResponsibleCore(std::shared_ptr<ProcessingU timerOpts->dont_initialize(); sc_core::sc_spawn( sc_bind(&PriorityRoundRobinScheduler::PuTimerTimeoutService, this, pu), timerName.c_str(), &*timerOpts); timerOptions[pu] = timerOpts; - - schedule[pu].reset(); } } @@ -66,7 +59,6 @@ void PriorityRoundRobinScheduler::PuTimerTimeoutService(const std::shared_ptr<Pr } std::shared_ptr<Schedulable> PriorityRoundRobinScheduler::chooseTask(const std::shared_ptr<ProcessingUnit> &pu) { - auto chosenTask = schedule[pu]; if(runningTasks.count(pu)>0 && runningTasks[pu] == chosenTask){ if(timerExpired[pu]){ @@ -81,24 +73,15 @@ std::shared_ptr<Schedulable> PriorityRoundRobinScheduler::chooseTask(const std:: return chosenTask; } -void PriorityRoundRobinScheduler::taskActivate(const std::shared_ptr<Schedulable> &task, const Stimulus &stimulus) { - printStateUpdateLog(task, "activated"); - Scheduler::taskActivate(task,stimulus); - enqueueTask(task); - interruptPUs(); -} - void PriorityRoundRobinScheduler::taskStart(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { - printStateUpdateLog(task, "start", pu, getTimeSliceLength()); - Scheduler::taskStart(task,pu); + PriorityScheduler::taskStart(task,pu); lastPuAssignTime[task] = sc_core::sc_time_stamp(); usedSlicePortion[task] = sc_core::SC_ZERO_TIME; setTimer(pu, getTimeSliceLength()); } void PriorityRoundRobinScheduler::taskPreemt(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { - printStateUpdateLog(task, "preempt", pu); - Scheduler::taskPreemt(task,pu); + PriorityScheduler::taskPreemt(task,pu); if(timerExpired[pu]){ usedSlicePortion[task] = sc_core::SC_ZERO_TIME; timerExpired[pu] =false; @@ -109,70 +92,29 @@ void PriorityRoundRobinScheduler::taskPreemt(const std::shared_ptr<Schedulable> } void PriorityRoundRobinScheduler::taskResume(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { - printStateUpdateLog(task, "resume", pu, (getTimeSliceLength() - usedSlicePortion[task])); - Scheduler::taskResume(task,pu); + PriorityScheduler::taskResume(task,pu); lastPuAssignTime[task] = sc_core::sc_time_stamp(); setTimer(pu, getTimeSliceLength() - usedSlicePortion[task]); } void PriorityRoundRobinScheduler::taskTerminate(const std::shared_ptr<Schedulable> &task) { - printStateUpdateLog(task, "terminate"); - Scheduler::taskTerminate(task); - dequeueTask(task); + auto it = std::find_if(schedule.begin(), schedule.end(), [&task] (const std::pair<std::shared_ptr<ProcessingUnit>,std::shared_ptr<Schedulable>>& entry) { + return entry.second == task; + }); + auto pu = it->first; + PriorityScheduler::taskTerminate(task); + cancelTimer(pu); usedSlicePortion.erase(task); lastPuAssignTime.erase(task); } -void PriorityRoundRobinScheduler::enqueueTask(const std::shared_ptr<Schedulable> &task){ - vectorRemove(readyQueue, task); - // get an iterator itr to the first location in the readyQueue for which priority(*itr) < priority(task) - auto itr = std::lower_bound(readyQueue.begin(), readyQueue.end(), task, comparePrio); - readyQueue.insert(itr, task); - updateSchedule(); -} - -void PriorityRoundRobinScheduler::dequeueTask(const std::shared_ptr<Schedulable> &task){ - vectorRemove(readyQueue, task); - updateSchedule(); -} - void PriorityRoundRobinScheduler::updateSchedule(){ - //log the state of readyQueue - printReadyQueueLog(); - - int schedSize = std::min(coresResponsible.size(), readyQueue.size()); - std::vector<std::shared_ptr<Schedulable>> schedVect(readyQueue.begin(), readyQueue.begin() + schedSize); - std::vector<std::shared_ptr<ProcessingUnit>> unassignedCores; - - auto schedVectEnd = schedVect.end(); - for(const auto &pu: coresResponsible) { - if(runningTasks.count(pu) && vectorContains(schedVect, runningTasks[pu])){ - // the task currently running on the core is part of the new schedule too - - // Note: explicit schedule assignment is necessary to make sure if multiple scheduleUpdate calls - // take place at the same sim time, schedule changes in one call which become deprecated in the - // next one will be overwritten - schedule[pu] = runningTasks[pu]; - schedVectEnd = std::remove(schedVect.begin(), schedVectEnd, runningTasks[pu]); - } else { - unassignedCores.push_back(pu); - } - } - - // update the schedule of unassigned cores - auto itr = schedVect.begin(); - for(const auto &pu : unassignedCores){ - if(itr != schedVectEnd){ - schedule[pu] = *itr; - itr++; - } else { - schedule[pu].reset(); + PriorityScheduler::updateSchedule(); + for(const auto &pu : coresResponsible){ + if(!schedule[pu]){ cancelTimer(pu); } } - - // log the updated schedule - printScheduleLog(); } void PriorityRoundRobinScheduler::cancelTimer(const std::shared_ptr<ProcessingUnit> &pu){ @@ -181,45 +123,4 @@ void PriorityRoundRobinScheduler::cancelTimer(const std::shared_ptr<ProcessingUn void PriorityRoundRobinScheduler::setTimer(const std::shared_ptr<ProcessingUnit> &pu, const sc_core::sc_time time){ Event::notifyEvent(timerTimeoutEvents[pu], time); -} - -bool PriorityRoundRobinScheduler::comparePrio(const std::shared_ptr<Schedulable> &a, const std::shared_ptr<Schedulable> &b){ - return a->getTaskAllocation().getSchedulingParameter<app4mc::ParameterType::Integer, false>(std::string("priority")) - >= b->getTaskAllocation().getSchedulingParameter<app4mc::ParameterType::Integer, false>("priority"); -} - -void PriorityRoundRobinScheduler::printLog(const std::string& msg){ - VLOG_TIME(2) << "[PriorityRoundRobinScheduler] | " << msg; -} - -void PriorityRoundRobinScheduler::printScheduleLog(){ - std::stringstream buff; - buff << "schedule updated: "; - for(const auto &pu : coresResponsible){ - buff << pu->getName() << ":" << ((schedule[pu]) ? (schedule[pu])->getName() : "()") << ", "; - } - buff << "\b\b"; - printLog(buff.str()); -} - -void PriorityRoundRobinScheduler::printReadyQueueLog() const { - std::stringstream buff; - buff << "readyQueue updated: ["; - for(const auto &t: readyQueue){ - buff << t->getName() << ", "; - } - buff << (readyQueue.empty()? " ]" : "\b\b]"); - printLog(buff.str()); -} - -void PriorityRoundRobinScheduler::printStateUpdateLog(const std::shared_ptr<Schedulable> &task, const std::string &_state, const std::shared_ptr<ProcessingUnit> &pu, const sc_core::sc_time &time) const { - std::stringstream buff; - buff << _state << " " << task->getName(); - if(pu != NULL) { - buff << " on " << pu->getName(); - if(time.value()){ - buff << " -- (timeout in " << time << ")"; - } - } - printLog(buff.str()); } \ No newline at end of file diff --git a/app4mc.sim_lib/OsModel/PriorityScheduler.cpp b/app4mc.sim_lib/OsModel/PriorityScheduler.cpp index f7c3e401a82dd91bf118225e08e6c6191ea92b77..216277df018f3687028f02f4b3650e720e86976e 100644 --- a/app4mc.sim_lib/OsModel/PriorityScheduler.cpp +++ b/app4mc.sim_lib/OsModel/PriorityScheduler.cpp @@ -1,6 +1,6 @@ /** ******************************************************************************** - * Copyright (c) 2020 University of Rostock and others + * Copyright (c) 2022 University of Rostock and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,78 +10,153 @@ * * Contributors: * - Benjamin Beichler <Benjamin.Beichler@uni-rostock.de> - initial contribution + * - Robert Bosch GmbH ******************************************************************************** */ -#include "Common.h" +#include <memory> +#include <algorithm> #include "PriorityScheduler.h" -std::shared_ptr<Schedulable> PriorityScheduler::chooseTask(const std::shared_ptr<ProcessingUnit> &requestingPu){ - - std::shared_ptr<Schedulable> chosenTask; - if(runningTasks.count(requestingPu) > 0){ - chosenTask = runningTasks[requestingPu]; - }; - //find the task with the highest priority and compare to current running task - - - //DO NOT CHANGE SEQUENCE: readyTasks -> activeTasks - //if a task has been chosen from the ready list, it may only be replaced by higher prio from active list - //if both are equal prio, tasks from ready list must be chosen - if(readyTasks.size() > 0){ - auto maxReady = std::max_element(readyTasks.begin(),readyTasks.end(),&comparePrio); - if(!chosenTask || comparePrio(chosenTask, *maxReady)) - chosenTask = *maxReady; +#include "Schedulable.h" +#include "HardwareModel.h" +#include "Stimuli.h" +#include "Common.h" + +void PriorityScheduler::addTaskMapping(std::shared_ptr<Schedulable> task) { + if(!task->getTaskAllocation().isParameterSet("priority")){ + throw std::runtime_error("Task \""+task->getName()+"\" uses Priority Scheduler but has no Priority set"); } - if(activeTasks.size() > 0){ - auto maxActive = std::max_element(activeTasks.begin(), activeTasks.end(),&comparePrio); - if(!chosenTask || comparePrio(chosenTask, *maxActive)) - chosenTask = *maxActive; + Scheduler::addTaskMapping(task); +} + +void PriorityScheduler::addResponsibleCore(std::shared_ptr<ProcessingUnit> pu) { + if(!vectorContains(coresResponsible,pu)){ + Scheduler::addResponsibleCore(pu); + schedule[pu].reset(); } +} +std::shared_ptr<Schedulable> PriorityScheduler::chooseTask(const std::shared_ptr<ProcessingUnit> &pu) { + auto chosenTask = schedule[pu]; + if(runningTasks.count(pu)>0 && runningTasks[pu] == chosenTask){ + printStateUpdateLog(chosenTask, "continue", pu); + } + return chosenTask; +} - //log decision - VLOG_TIME(2) << this->printChooseTask(requestingPu, chosenTask); +void PriorityScheduler::taskActivate(const std::shared_ptr<Schedulable> &task, const Stimulus &stimulus) { + printStateUpdateLog(task, "activated"); + Scheduler::taskActivate(task,stimulus); + enqueueTask(task); + interruptPUs(); +} - return chosenTask; +void PriorityScheduler::taskStart(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { + printStateUpdateLog(task, "start", pu); + Scheduler::taskStart(task,pu); } -std::string PriorityScheduler::printChooseTask( - const std::shared_ptr<ProcessingUnit> &requestingPu, - const std::shared_ptr<Schedulable> &nextChosenTask) - { - std::string buf = "\n"; - buf.append("PriorityScheduler::chooseTask() for : " + requestingPu->getName() + "\n"); - buf.append("running Task: "); - std::shared_ptr<Schedulable> chosenTask; - if(runningTasks.count(requestingPu) > 0){ - chosenTask = runningTasks[requestingPu]; - } - if (chosenTask != nullptr){ - buf.append(std::dynamic_pointer_cast<HasName>(chosenTask)->getName()); +void PriorityScheduler::taskPreemt(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { + printStateUpdateLog(task, "preempt", pu); + Scheduler::taskPreemt(task,pu); +} + +void PriorityScheduler::taskResume(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) { + printStateUpdateLog(task, "resume", pu); + Scheduler::taskResume(task,pu); +} + +void PriorityScheduler::taskTerminate(const std::shared_ptr<Schedulable> &task) { + printStateUpdateLog(task, "terminate"); + Scheduler::taskTerminate(task); + dequeueTask(task); +} + +void PriorityScheduler::enqueueTask(const std::shared_ptr<Schedulable> &task){ + vectorRemove(readyQueue, task); + // get an iterator itr to the first location in the readyQueue for which priority(*itr) < priority(task) + auto itr = std::lower_bound(readyQueue.begin(), readyQueue.end(), task, comparePrio); + readyQueue.insert(itr, task); + updateSchedule(); +} + +void PriorityScheduler::dequeueTask(const std::shared_ptr<Schedulable> &task){ + vectorRemove(readyQueue, task); + updateSchedule(); +} + +void PriorityScheduler::updateSchedule(){ + //log the state of readyQueue + printReadyQueueLog(); + + int schedSize = std::min(coresResponsible.size(), readyQueue.size()); + std::vector<std::shared_ptr<Schedulable>> schedVect(readyQueue.begin(), readyQueue.begin() + schedSize); + std::vector<std::shared_ptr<ProcessingUnit>> unassignedCores; + + auto schedVectEnd = schedVect.end(); + for(const auto &pu: coresResponsible) { + if(runningTasks.count(pu) && vectorContains(schedVect, runningTasks[pu])){ + // the task currently running on the core is part of the new schedule too + + // Note: explicit schedule assignment is necessary to make sure if multiple scheduleUpdate calls + // take place at the same sim time, schedule changes in one call which become deprecated in the + // next one will be overwritten + schedule[pu] = runningTasks[pu]; + schedVectEnd = std::remove(schedVect.begin(), schedVectEnd, runningTasks[pu]); + } else { + unassignedCores.push_back(pu); + } } - - std::string readyTasksString = "\nReady Tasks"; - for (auto task : readyTasks){ - readyTasksString.append(std::dynamic_pointer_cast<HasName>(task)->getName()); - readyTasksString.append (", "); + // update the schedule of unassigned cores + auto itr = schedVect.begin(); + for(const auto &pu : unassignedCores){ + if(itr != schedVectEnd){ + schedule[pu] = *itr; + itr++; + } else { + schedule[pu].reset(); + } } - buf.append(readyTasksString); - std::string activeTasksString = "\nActive Tasks"; - for (auto task : activeTasks){ - activeTasksString.append(std::dynamic_pointer_cast<HasName>(task)->getName()); - activeTasksString.append (", "); + // log the updated schedule + printScheduleLog(); +} - } - buf.append(activeTasksString); +bool PriorityScheduler::comparePrio(const std::shared_ptr<Schedulable> &a, const std::shared_ptr<Schedulable> &b){ + return a->getTaskAllocation().getSchedulingParameter<app4mc::ParameterType::Integer, false>(std::string("priority")) + >= b->getTaskAllocation().getSchedulingParameter<app4mc::ParameterType::Integer, false>("priority"); +} - buf.append("\n---> now running "); - if (nextChosenTask != nullptr) - buf.append(std::dynamic_pointer_cast<HasName>(nextChosenTask)->getName()); - else - buf.append("nothing to run"); +void PriorityScheduler::printLog(const std::string& msg) const { + VLOG_TIME(2) << "[" + this->getName() + "] | " << msg; +} - return buf; +void PriorityScheduler::printScheduleLog(){ + std::stringstream buff; + buff << "schedule updated: "; + for(const auto &pu : coresResponsible){ + buff << pu->getName() << ":" << ((schedule[pu]) ? (schedule[pu])->getName() : "()") << ", "; + } + buff << "\b\b"; + printLog(buff.str()); } +void PriorityScheduler::printReadyQueueLog() const { + std::stringstream buff; + buff << "readyQueue updated: ["; + for(const auto &t: readyQueue){ + buff << t->getName() << ", "; + } + buff << (readyQueue.empty()? " ]" : "\b\b]"); + printLog(buff.str()); +} + +void PriorityScheduler::printStateUpdateLog(const std::shared_ptr<Schedulable> &task, const std::string &_state, const std::shared_ptr<ProcessingUnit> &pu) const { + std::stringstream buff; + buff << _state << " " << task->getName(); + if(pu != NULL) { + buff << " on " << pu->getName(); + } + printLog(buff.str()); +} \ No newline at end of file diff --git a/app4mc.sim_lib/include/APP4MCsim.h b/app4mc.sim_lib/include/APP4MCsim.h index f8a71cd6fe37d21d752685e23a9162d409552307..5ec30cfaa917eee2699528a896cdb1720cfabf31 100644 --- a/app4mc.sim_lib/include/APP4MCsim.h +++ b/app4mc.sim_lib/include/APP4MCsim.h @@ -14,6 +14,7 @@ #include "RandomScheduler.h" #include "OsModel/BudgetScheduler.h" #include "OsModel/PriorityRoundRobinScheduler.h" +#include "OsModel/PosixRealtimeScheduler.h" #include "OsModel/Semaphore.h" #include "OsModel/SchedulingParameter.h" //stimuli model diff --git a/app4mc.sim_lib/include/OSModel.h b/app4mc.sim_lib/include/OSModel.h index f22d8d017fc2380c410a6c9ffba554176ef2f39d..9e491c1c28ab0a3bb06e1626d2aa10858553fda8 100644 --- a/app4mc.sim_lib/include/OSModel.h +++ b/app4mc.sim_lib/include/OSModel.h @@ -70,7 +70,7 @@ protected: // this map uses pu as key, therefore need linear search for (auto &i : runningTasks) { - auto &[pu, putask] = i; + auto [pu, putask] = i; if (putask == task) { runningTasks.erase(pu); return pu; diff --git a/app4mc.sim_lib/include/OsModel/PosixRealtimeScheduler.h b/app4mc.sim_lib/include/OsModel/PosixRealtimeScheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..a346a834314ea17a9343c013ec07002e6ca654f5 --- /dev/null +++ b/app4mc.sim_lib/include/OsModel/PosixRealtimeScheduler.h @@ -0,0 +1,49 @@ +/** + ******************************************************************************** + * Copyright (c) 2022 Robert Bosch GmbH + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * - Robert Bosch GmbH - initial contribution + * Author: Behnaz Pourmohseni <behnaz.pourmohseni@de.bosch.com> + ******************************************************************************** + */ + +#pragma once +#include <systemc> +#include <memory> +#include <algorithm> +#include "Common.h" +#include "PriorityRoundRobinScheduler.h" + +class Schedulable; +class ProcessingUnit; +class Event; + +class PosixRealtimeScheduler: public PriorityRoundRobinScheduler { + +public: + + PosixRealtimeScheduler(std::string name): PriorityRoundRobinScheduler(std::move(name)) { } + + std::shared_ptr<Schedulable> chooseTask(const std::shared_ptr<ProcessingUnit> &pu) override; + + void taskStart(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; + void taskPreemt(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; + void taskResume(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; + void taskTerminate(const std::shared_ptr<Schedulable> &task) override; + + enum class PosixSchedPolicy {SCHED_FIFO, SCHED_RR}; + std::string getSchedulingPolicyName(const PosixSchedPolicy &policy) const; + PosixSchedPolicy getSchedulingPolicy(const std::string &policyName) const; + +protected: + + PosixSchedPolicy getSchedulingPolicy(const std::shared_ptr<Schedulable> &task) const; + typedef std::map<std::shared_ptr<Schedulable>,PosixSchedPolicy> schedulingPolicy; +}; \ No newline at end of file diff --git a/app4mc.sim_lib/include/OsModel/PriorityRoundRobinScheduler.h b/app4mc.sim_lib/include/OsModel/PriorityRoundRobinScheduler.h index f6dc316ddafd41dc09065b2a39f054fd4c888aec..b61487a7a42857c6eec6f2b822fade2788250693 100644 --- a/app4mc.sim_lib/include/OsModel/PriorityRoundRobinScheduler.h +++ b/app4mc.sim_lib/include/OsModel/PriorityRoundRobinScheduler.h @@ -18,15 +18,16 @@ #include <systemc> #include <memory> #include <algorithm> -#include "OSModel.h" -#include "SoftwareModel.h" +#include "Common.h" +#include "PriorityScheduler.h" -class PriorityRoundRobinScheduler: public Scheduler { +class Schedulable; +class ProcessingUnit; +class Event; -protected: +class PriorityRoundRobinScheduler: public PriorityScheduler { - std::vector<std::shared_ptr<Schedulable>> readyQueue; - std::map<std::shared_ptr<ProcessingUnit>,std::shared_ptr<Schedulable>> schedule; +protected: std::map<std::shared_ptr<Schedulable>,sc_core::sc_time> lastPuAssignTime; // start, resume, or continue to execute std::map<std::shared_ptr<Schedulable>,sc_core::sc_time> usedSlicePortion; @@ -36,34 +37,21 @@ protected: std::map<std::shared_ptr<ProcessingUnit>,bool> timerExpired; std::map<std::shared_ptr<ProcessingUnit>,std::shared_ptr<sc_core::sc_spawn_options>> timerOptions; - - void enqueueTask(const std::shared_ptr<Schedulable> &task); - void dequeueTask(const std::shared_ptr<Schedulable> &task); - void updateSchedule(); - - static bool comparePrio(const std::shared_ptr<Schedulable> &a, const std::shared_ptr<Schedulable> &b); - void PuTimerTimeoutService(const std::shared_ptr<ProcessingUnit> &pu); void cancelTimer(const std::shared_ptr<ProcessingUnit> &pu); void setTimer(const std::shared_ptr<ProcessingUnit> &pu, const sc_core::sc_time time); - - static void printLog(const std::string& msg); - void printScheduleLog(); - void printReadyQueueLog() const; - void printStateUpdateLog(const std::shared_ptr<Schedulable> &task, const std::string &_state, const std::shared_ptr<ProcessingUnit> &pu=NULL, const sc_core::sc_time &time=sc_core::sc_time()) const; + + void updateSchedule() override; + + sc_core::sc_time getTimeSliceLength(); public: - PriorityRoundRobinScheduler(std::string name): Scheduler(std::move(name)) { } - - sc_core::sc_time getTimeSliceLength(); + PriorityRoundRobinScheduler(std::string name): PriorityScheduler(std::move(name)) { } - void addTaskMapping(std::shared_ptr<Schedulable> task) override; + std::shared_ptr<Schedulable> chooseTask(const std::shared_ptr<ProcessingUnit> &pu) override; void addResponsibleCore(std::shared_ptr<ProcessingUnit> pu) override; - std::shared_ptr<Schedulable> chooseTask(const std::shared_ptr<ProcessingUnit> &pu) override; - - void taskActivate(const std::shared_ptr<Schedulable> &task, const Stimulus &stimulus) override; void taskStart(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; void taskPreemt(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; void taskResume(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; diff --git a/app4mc.sim_lib/include/OsModel/PriorityScheduler.h b/app4mc.sim_lib/include/OsModel/PriorityScheduler.h index 91d20a43cd4f6579a84cf0e32866ea6eb56a095a..e22f0b918c0829444f04441659035bc9c25f7069 100644 --- a/app4mc.sim_lib/include/OsModel/PriorityScheduler.h +++ b/app4mc.sim_lib/include/OsModel/PriorityScheduler.h @@ -1,6 +1,6 @@ /** ******************************************************************************** - * Copyright (c) 2020 University of Rostock and others + * Copyright (c) 2022 University of Rostock and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,47 +10,47 @@ * * Contributors: * - Benjamin Beichler <Benjamin.Beichler@uni-rostock.de> - initial contribution + * - Robert Bosch GmbH ******************************************************************************** */ #pragma once -#include <systemc> #include <memory> -#include <algorithm> -#include "OSModel.h" -#include "Task.h" -#include "HardwareModel.h" -#include "SchedulingParameter.h" - - /** - * Sets for every state of a Task * - * See task model definition - * https://www.eclipse.org/app4mc/help/latest/index.html#section3.7 - */ - -class PriorityScheduler : public Scheduler{ -public: - //returns true: if priority of a < priority of b - static bool comparePrio(const std::shared_ptr<Schedulable> &a, const std::shared_ptr<Schedulable> &b){ - return a->getTaskAllocation().getSchedulingParameter<app4mc::ParameterType::Integer, false>(std::string("priority")) - < b->getTaskAllocation().getSchedulingParameter<app4mc::ParameterType::Integer, false>("priority"); - }; - - std::shared_ptr<Schedulable> chooseTask(const std::shared_ptr<ProcessingUnit> &requestingPu) override; - - void taskActivate(const std::shared_ptr<Schedulable> &task, const Stimulus &stimulus) override { - Scheduler::taskActivate(task,stimulus); - interruptPUs(); - }; +#include "OSModel.h" // provides the declaration of the Scheduler class + +class Schedulable; +class ProcessingUnit; +class Stimulus; + +class PriorityScheduler: public Scheduler { + +protected: + + std::vector<std::shared_ptr<Schedulable>> readyQueue; + std::map<std::shared_ptr<ProcessingUnit>,std::shared_ptr<Schedulable>> schedule; + + virtual void enqueueTask(const std::shared_ptr<Schedulable> &task); + virtual void dequeueTask(const std::shared_ptr<Schedulable> &task); + virtual void updateSchedule(); + + static bool comparePrio(const std::shared_ptr<Schedulable> &a, const std::shared_ptr<Schedulable> &b); + + void printScheduleLog(); + void printReadyQueueLog() const; + void printStateUpdateLog(const std::shared_ptr<Schedulable> &task, const std::string &_state, const std::shared_ptr<ProcessingUnit> &pu=NULL) const; + virtual void printLog(const std::string& msg) const; + +public: + + PriorityScheduler(std::string name): Scheduler(std::move(name)) { } + + void addTaskMapping(std::shared_ptr<Schedulable> task) override; + void addResponsibleCore(std::shared_ptr<ProcessingUnit> pu) override; + std::shared_ptr<Schedulable> chooseTask(const std::shared_ptr<ProcessingUnit> &pu) override; - PriorityScheduler(std::string name) : Scheduler(std::move(name)){}; - void addTaskMapping(std::shared_ptr<Schedulable> task) override { - if(!task->getTaskAllocation().isParameterSet("priority")){ - auto namePtr = std::dynamic_pointer_cast<HasName>(task); - throw std::runtime_error("Task \""+namePtr->getName()+"\" uses Priority Scheduler but has no Priority set"); - } - Scheduler::addTaskMapping(task); - }; -private: - std::string printChooseTask(const std::shared_ptr<ProcessingUnit> &, const std::shared_ptr<Schedulable> &); + void taskActivate(const std::shared_ptr<Schedulable> &task, const Stimulus &stimulus) override; + void taskStart(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; + void taskPreemt(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; + void taskResume(const std::shared_ptr<Schedulable> &task, const std::shared_ptr<ProcessingUnit> &pu) override; + void taskTerminate(const std::shared_ptr<Schedulable> &task) override; }; \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2240cac7de32433a6088acce6345a68efc24218e..07d912745d31a9f3f2f53344c00ab6944e327e70 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -26,4 +26,4 @@ add_subdirectory("Semaphore") add_subdirectory("Parameter") add_subdirectory("ExternalScheduler") add_subdirectory("ExternalEvents") -add_subdirectory("RoundRobinScheduling") +add_subdirectory("PriorityScheduling") diff --git a/examples/PriorityScheduling/CMakeLists.txt b/examples/PriorityScheduling/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7f3672f0bcf22ce536d6f4f150679fb460ce4a3 --- /dev/null +++ b/examples/PriorityScheduling/CMakeLists.txt @@ -0,0 +1,24 @@ +add_executable (PriorityScheduling "PriorityScheduling.cpp") +target_link_libraries(PriorityScheduling app4mc.sim_lib) +target_precompile_headers(PriorityScheduling REUSE_FROM app4mc.sim_lib) +add_test(NAME PriorityScheduling COMMAND PriorityScheduling ${ADDITIONAL_TEST_ARGS}) + +add_executable (RoundRobinScheduling "RoundRobinScheduling.cpp") +target_link_libraries(RoundRobinScheduling app4mc.sim_lib) +target_precompile_headers(RoundRobinScheduling REUSE_FROM app4mc.sim_lib) +add_test(NAME Run_RoundRobinScheduling COMMAND RoundRobinScheduling ${ADDITIONAL_TEST_ARGS}) + +add_executable (RoundRobinSchedulingTicksOnly "RoundRobinSchedulingTicksOnly.cpp") +target_link_libraries(RoundRobinSchedulingTicksOnly app4mc.sim_lib) +target_precompile_headers(RoundRobinSchedulingTicksOnly REUSE_FROM app4mc.sim_lib) +add_test(NAME RoundRobinSchedulingTicksOnly COMMAND RoundRobinSchedulingTicksOnly ${ADDITIONAL_TEST_ARGS}) + +add_executable (PosixRealtimeScheduling "PosixRealtimeScheduling.cpp") +target_link_libraries(PosixRealtimeScheduling app4mc.sim_lib) +target_precompile_headers(PosixRealtimeScheduling REUSE_FROM app4mc.sim_lib) +add_test(NAME PosixRealtimeScheduling COMMAND PosixRealtimeScheduling ${ADDITIONAL_TEST_ARGS}) + +install( + TARGETS PriorityScheduling RoundRobinScheduling RoundRobinSchedulingTicksOnly PosixRealtimeScheduling + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/examples/PriorityScheduling +) \ No newline at end of file diff --git a/examples/PriorityScheduling/PosixRealtimeScheduling.cpp b/examples/PriorityScheduling/PosixRealtimeScheduling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfbf53027e64ae5b3da8b67f8a22bfcfb6fa6986 --- /dev/null +++ b/examples/PriorityScheduling/PosixRealtimeScheduling.cpp @@ -0,0 +1,201 @@ + /** + ******************************************************************************** + * Copyright (c) 2022 Robert Bosch GmbH + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * - Robert Bosch GmbH - initial contribution + * Author: Behnaz Pourmohseni <behnaz.pourmohseni@de.bosch.com> + ******************************************************************************** + */ + +#include <systemc> +#include <memory> +#include "APP4MCsim.h" +#include "BTFTracer.h" +#include "Common.h" + +INITIALIZE_EASYLOGGINGPP + +int sc_main(int argc, char *argv[]) { + sc_core::sc_set_time_resolution(1.0, sc_core::SC_NS); + SimParam args; + SimParamParser::parse(argc, argv, args); + START_EASYLOGGINGPP(argc, argv); + + /* Hardware */ + sc_core::sc_time ECU_Freq_Domain_CycleTime(10, sc_core::SC_NS); + ProcessingUnitDefinition pudef("CoreDef"); + HwStructure ECU("ECU"); + + auto mainMem = ECU.createModule<Memory>("Memory", 1 * 1024 * 1024 * 1024); + mainMem->clock_period = ECU_Freq_Domain_CycleTime; + + auto core1 = ECU.createModule<ProcessingUnit>("Core1", pudef); + core1->clock_period = ECU_Freq_Domain_CycleTime; + + HwAccessElement mainMemC1Access; + mainMemC1Access.dest = mainMem; + mainMemC1Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC1Access.setReadLatency(DiscreteValueConstant(0)); + core1->addHWAccessElement(mainMemC1Access); + + auto core2 = ECU.createModule<ProcessingUnit>("Core2", pudef); + core2->clock_period = ECU_Freq_Domain_CycleTime; + + HwAccessElement mainMemC2Access; + mainMemC2Access.dest = mainMem; + mainMemC2Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC2Access.setReadLatency(DiscreteValueConstant(0)); + core2->addHWAccessElement(mainMemC2Access); + + /* Stimuli */ + auto stimuli0 = std::make_shared<FixedPeriodicStimulus>("Stim0", 100_ms); + auto stimuli1 = std::make_shared<FixedPeriodicStimulus>("Stim1", 100_ms, 2_ms); + auto stimuli2 = std::make_shared<FixedPeriodicStimulus>("Stim2", 100_ms, 5_ms); + auto stimuli3 = std::make_shared<FixedPeriodicStimulus>("Stim3", 100_ms, 12_ms); + auto stimuli4 = std::make_shared<FixedPeriodicStimulus>("Stim4", 100_ms, 78_ms); + auto stimuli5 = std::make_shared<FixedPeriodicStimulus>("Stim5", 100_ms, 79_ms); + + + /* Software */ + auto label0 = std::make_shared<DataLabel>("label0", 30); + auto label1 = std::make_shared<DataLabel>("label1", 60); + auto label2 = std::make_shared<DataLabel>("label2", 80); + auto label3 = std::make_shared<DataLabel>("label3", 100); + auto label4 = std::make_shared<DataLabel>("label4", 180); + + + auto task1 = Task::createTask("Task1"); + task1->addStimulus(stimuli0); + task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(380000)}); + task1->addActivityGraphItem<LabelAccess>({label1, 1, tlm::TLM_READ_COMMAND}); + task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(380000)}); + task1->addActivityGraphItem<LabelAccess>({label3, 1, tlm::TLM_READ_COMMAND}); + task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(1400000)}); + + auto task2 = Task::createTask("Task2"); + task2->addStimulus(stimuli0); + task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(180000)}); + task2->addActivityGraphItem<LabelAccess>({label2, 1, tlm::TLM_READ_COMMAND}); + task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(50000)}); + task2->addActivityGraphItem<LabelAccess>({label1, 1, tlm::TLM_READ_COMMAND}); + task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(2400000)}); + + auto task3 = Task::createTask("Task3"); + task3->addStimulus(stimuli1); + task3->addActivityGraphItem<Ticks>({DiscreteValueConstant(4200000)}); + + auto task4 = Task::createTask("Task4"); + task4->addStimulus(stimuli3); + task4->addActivityGraphItem<Ticks>({DiscreteValueConstant(370000)}); + task4->addActivityGraphItem<LabelAccess>({label1, 1, tlm::TLM_READ_COMMAND}); + task4->addActivityGraphItem<Ticks>({DiscreteValueConstant(1800000)}); + + auto task5 = Task::createTask("Task5"); + task5->addStimulus(stimuli2); + task5->addActivityGraphItem<Ticks>({DiscreteValueConstant(1100000)}); + task5->addActivityGraphItem<LabelAccess>({label4, 1, tlm::TLM_READ_COMMAND}); + task5->addActivityGraphItem<Ticks>({DiscreteValueConstant(1500000)}); + + auto task6 = Task::createTask("Task6"); + task6->addStimulus(stimuli3); + task6->addActivityGraphItem<Ticks>({DiscreteValueConstant(2300000)}); + + auto task7 = Task::createTask("Task7"); + task7->addStimulus(stimuli4); + task7->addActivityGraphItem<Ticks>({DiscreteValueConstant(900000)}); + + auto task8 = Task::createTask("Task8"); + task8->addStimulus(stimuli5); + task8->addActivityGraphItem<Ticks>({DiscreteValueConstant(900000)}); + + TaskAllocation ta_task1; + ta_task1.setSchedulingParameter("priority", 0); + ta_task1.setSchedulingParameter("schedulingPolicy", "SCHED_FIFO"); // optional + task1->setTaskAllocation(ta_task1); + + TaskAllocation ta_task2; + ta_task2.setSchedulingParameter("priority", 0); + ta_task2.setSchedulingParameter("schedulingPolicy", "SCHED_RR"); + task2->setTaskAllocation(ta_task2); + + TaskAllocation ta_task3; + ta_task3.setSchedulingParameter("priority", 1); + ta_task3.setSchedulingParameter("schedulingPolicy", "SCHED_RR"); + task3->setTaskAllocation(ta_task3); + + TaskAllocation ta_task4; + ta_task4.setSchedulingParameter("priority", 0); + ta_task4.setSchedulingParameter("schedulingPolicy", "SCHED_RR"); + task4->setTaskAllocation(ta_task4); + + TaskAllocation ta_task5; + ta_task5.setSchedulingParameter("priority", 1); + task5->setTaskAllocation(ta_task5); + + TaskAllocation ta_task6; + ta_task6.setSchedulingParameter("priority", 2); + task6->setTaskAllocation(ta_task6); + + TaskAllocation ta_task7; + ta_task7.setSchedulingParameter("priority", 1); + task7->setTaskAllocation(ta_task7); + + TaskAllocation ta_task8; + ta_task8.setSchedulingParameter("priority", 1); + task8->setTaskAllocation(ta_task8); + + + /* OS and mapping */ + auto posixSched = std::make_shared<PosixRealtimeScheduler>("posixSched"); + posixSched->setAlgorithmSchedulingParameter("timeSliceLength", 4_ms); + posixSched->setExecutionCore(core1); + posixSched->addResponsibleCore(core1); + posixSched->addResponsibleCore(core2); + posixSched->addTaskMapping(task1); + posixSched->addTaskMapping(task2); + posixSched->addTaskMapping(task3); + posixSched->addTaskMapping(task4); + posixSched->addTaskMapping(task5); + posixSched->addTaskMapping(task6); + posixSched->addTaskMapping(task7); + posixSched->addTaskMapping(task8); + + + MappingModel::addMemoryMapping(label0, mainMem); + MappingModel::addMemoryMapping(label1, mainMem); + MappingModel::addMemoryMapping(label2, mainMem); + MappingModel::addMemoryMapping(label3, mainMem); + MappingModel::addMemoryMapping(label4, mainMem); + + VLOG(0) << "simulation model created"; + + /* tracing */ + auto vcdPath = TraceManager::createTraceFilePath("trace").string(); + sc_core::sc_trace_file *tf = sc_core::sc_create_vcd_trace_file(vcdPath.c_str()); + sc_trace(tf, &*core1, "Core1"); + sc_trace(tf, &*core2, "Core2"); + sc_trace(tf, &*mainMem, "Memory"); + + try { + VLOG(0) << "starting simulation"; + sc_core::sc_start(2000, sc_core::SC_MS); + } catch (sc_core::sc_report &e) { + const char *file = e.get_file_name(); + const int line = e.get_line_number(); + const char *msg = e.get_msg(); + VLOG(0) << msg << "\nin file: " << file << "\nline: " << line; + return -1; + } + + sc_core::sc_close_vcd_trace_file(tf); + + VLOG(0) << "simulation done"; + return 0; +} \ No newline at end of file diff --git a/examples/PriorityScheduling/PriorityScheduling.cpp b/examples/PriorityScheduling/PriorityScheduling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..29542dfb434e1104929fda0033afa6bffd5603fa --- /dev/null +++ b/examples/PriorityScheduling/PriorityScheduling.cpp @@ -0,0 +1,195 @@ +/** + ******************************************************************************** + * Copyright (c) 2022 Robert Bosch GmbH + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * - Robert Bosch GmbH - initial contribution + * Author: Behnaz Pourmohseni <behnaz.pourmohseni@de.bosch.com> + ******************************************************************************** + */ + +#include <systemc> +#include <memory> +#include "APP4MCsim.h" +#include "BTFTracer.h" +#include "Common.h" + +INITIALIZE_EASYLOGGINGPP + +int sc_main(int argc, char *argv[]) { + sc_core::sc_set_time_resolution(1.0, sc_core::SC_NS); + SimParam args; + SimParamParser::parse(argc, argv, args); + START_EASYLOGGINGPP(argc, argv); + + /* Hardware */ + sc_core::sc_time ECU_Freq_Domain_CycleTime(10, sc_core::SC_NS); + ProcessingUnitDefinition pudef("CoreDef"); + HwStructure ECU("ECU"); + + auto mainMem = ECU.createModule<Memory>("Memory", 1 * 1024 * 1024 * 1024); + mainMem->clock_period = ECU_Freq_Domain_CycleTime; + + auto core1 = ECU.createModule<ProcessingUnit>("Core1", pudef); + core1->clock_period = ECU_Freq_Domain_CycleTime; + + HwAccessElement mainMemC1Access; + mainMemC1Access.dest = mainMem; + mainMemC1Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC1Access.setReadLatency(DiscreteValueConstant(0)); + core1->addHWAccessElement(mainMemC1Access); + + auto core2 = ECU.createModule<ProcessingUnit>("Core2", pudef); + core2->clock_period = ECU_Freq_Domain_CycleTime; + + HwAccessElement mainMemC2Access; + mainMemC2Access.dest = mainMem; + mainMemC2Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC2Access.setReadLatency(DiscreteValueConstant(0)); + core2->addHWAccessElement(mainMemC2Access); + + /* Stimuli */ + auto stimuli0 = std::make_shared<FixedPeriodicStimulus>("Stim0", 100_ms); + auto stimuli1 = std::make_shared<FixedPeriodicStimulus>("Stim1", 100_ms, 2_ms); + auto stimuli2 = std::make_shared<FixedPeriodicStimulus>("Stim2", 100_ms, 5_ms); + auto stimuli3 = std::make_shared<FixedPeriodicStimulus>("Stim3", 100_ms, 12_ms); + auto stimuli4 = std::make_shared<FixedPeriodicStimulus>("Stim4", 100_ms, 78_ms); + auto stimuli5 = std::make_shared<FixedPeriodicStimulus>("Stim5", 100_ms, 79_ms); + + + /* Software */ + auto label0 = std::make_shared<DataLabel>("label0", 30); + auto label1 = std::make_shared<DataLabel>("label1", 60); + auto label2 = std::make_shared<DataLabel>("label2", 80); + auto label3 = std::make_shared<DataLabel>("label3", 100); + auto label4 = std::make_shared<DataLabel>("label4", 180); + + + auto task1 = Task::createTask("Task1"); + task1->addStimulus(stimuli0); + task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(380000)}); + task1->addActivityGraphItem<LabelAccess>({label1, 1, tlm::TLM_READ_COMMAND}); + task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(380000)}); + task1->addActivityGraphItem<LabelAccess>({label3, 1, tlm::TLM_READ_COMMAND}); + task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(1400000)}); + + auto task2 = Task::createTask("Task2"); + task2->addStimulus(stimuli0); + task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(180000)}); + task2->addActivityGraphItem<LabelAccess>({label2, 1, tlm::TLM_READ_COMMAND}); + task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(50000)}); + task2->addActivityGraphItem<LabelAccess>({label1, 1, tlm::TLM_READ_COMMAND}); + task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(2400000)}); + + auto task3 = Task::createTask("Task3"); + task3->addStimulus(stimuli1); + task3->addActivityGraphItem<Ticks>({DiscreteValueConstant(4200000)}); + + auto task4 = Task::createTask("Task4"); + task4->addStimulus(stimuli3); + task4->addActivityGraphItem<Ticks>({DiscreteValueConstant(370000)}); + task4->addActivityGraphItem<LabelAccess>({label1, 1, tlm::TLM_READ_COMMAND}); + task4->addActivityGraphItem<Ticks>({DiscreteValueConstant(1800000)}); + + auto task5 = Task::createTask("Task5"); + task5->addStimulus(stimuli2); + task5->addActivityGraphItem<Ticks>({DiscreteValueConstant(1100000)}); + task5->addActivityGraphItem<LabelAccess>({label4, 1, tlm::TLM_READ_COMMAND}); + task5->addActivityGraphItem<Ticks>({DiscreteValueConstant(1500000)}); + + auto task6 = Task::createTask("Task6"); + task6->addStimulus(stimuli3); + task6->addActivityGraphItem<Ticks>({DiscreteValueConstant(2300000)}); + + auto task7 = Task::createTask("Task7"); + task7->addStimulus(stimuli4); + task7->addActivityGraphItem<Ticks>({DiscreteValueConstant(900000)}); + + auto task8 = Task::createTask("Task8"); + task8->addStimulus(stimuli5); + task8->addActivityGraphItem<Ticks>({DiscreteValueConstant(900000)}); + + TaskAllocation ta_task1; + ta_task1.setSchedulingParameter("priority", 0); + task1->setTaskAllocation(ta_task1); + + TaskAllocation ta_task2; + ta_task2.setSchedulingParameter("priority", 0); + task2->setTaskAllocation(ta_task2); + + TaskAllocation ta_task3; + ta_task3.setSchedulingParameter("priority", 1); + task3->setTaskAllocation(ta_task3); + + TaskAllocation ta_task4; + ta_task4.setSchedulingParameter("priority", 0); + task4->setTaskAllocation(ta_task4); + + TaskAllocation ta_task5; + ta_task5.setSchedulingParameter("priority", 1); + task5->setTaskAllocation(ta_task5); + + TaskAllocation ta_task6; + ta_task6.setSchedulingParameter("priority", 2); + task6->setTaskAllocation(ta_task6); + + TaskAllocation ta_task7; + ta_task7.setSchedulingParameter("priority", 1); + task7->setTaskAllocation(ta_task7); + + TaskAllocation ta_task8; + ta_task8.setSchedulingParameter("priority", 1); + task8->setTaskAllocation(ta_task8); + + + /* OS and mapping */ + auto fifoScheduler = std::make_shared<PriorityScheduler>("fifoSched"); + fifoScheduler->setExecutionCore(core1); + fifoScheduler->addResponsibleCore(core1); + fifoScheduler->addResponsibleCore(core2); + fifoScheduler->addTaskMapping(task1); + fifoScheduler->addTaskMapping(task2); + fifoScheduler->addTaskMapping(task3); + fifoScheduler->addTaskMapping(task4); + fifoScheduler->addTaskMapping(task5); + fifoScheduler->addTaskMapping(task6); + fifoScheduler->addTaskMapping(task7); + fifoScheduler->addTaskMapping(task8); + + MappingModel::addMemoryMapping(label0, mainMem); + MappingModel::addMemoryMapping(label1, mainMem); + MappingModel::addMemoryMapping(label2, mainMem); + MappingModel::addMemoryMapping(label3, mainMem); + MappingModel::addMemoryMapping(label4, mainMem); + + VLOG(0) << "simulation model created"; + + /* tracing */ + auto vcdPath = TraceManager::createTraceFilePath("trace").string(); + sc_core::sc_trace_file *tf = sc_core::sc_create_vcd_trace_file(vcdPath.c_str()); + sc_trace(tf, &*core1, "Core1"); + sc_trace(tf, &*core2, "Core2"); + sc_trace(tf, &*mainMem, "Memory"); + + try { + VLOG(0) << "starting simulation"; + sc_core::sc_start(2000, sc_core::SC_MS); + } catch (sc_core::sc_report &e) { + const char *file = e.get_file_name(); + const int line = e.get_line_number(); + const char *msg = e.get_msg(); + VLOG(0) << msg << "\nin file: " << file << "\nline: " << line; + return -1; + } + + sc_core::sc_close_vcd_trace_file(tf); + + VLOG(0) << "simulation done"; + return 0; +} \ No newline at end of file diff --git a/examples/RoundRobinScheduling/RoundRobinScheduling.cpp b/examples/PriorityScheduling/RoundRobinScheduling.cpp similarity index 95% rename from examples/RoundRobinScheduling/RoundRobinScheduling.cpp rename to examples/PriorityScheduling/RoundRobinScheduling.cpp index c593f61d8558cd33ad9db839a73e97f9da0e0e77..a45ef4cc845b73f0b3641232264527ca138b01ab 100644 --- a/examples/RoundRobinScheduling/RoundRobinScheduling.cpp +++ b/examples/PriorityScheduling/RoundRobinScheduling.cpp @@ -42,6 +42,7 @@ int sc_main(int argc, char *argv[]) { HwAccessElement mainMemC1Access; mainMemC1Access.dest = mainMem; mainMemC1Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC1Access.setReadLatency(DiscreteValueConstant(0)); core1->addHWAccessElement(mainMemC1Access); auto core2 = ECU.createModule<ProcessingUnit>("Core2", pudef); @@ -50,6 +51,7 @@ int sc_main(int argc, char *argv[]) { HwAccessElement mainMemC2Access; mainMemC2Access.dest = mainMem; mainMemC2Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC2Access.setReadLatency(DiscreteValueConstant(0)); core2->addHWAccessElement(mainMemC2Access); /* Stimuli */ @@ -76,9 +78,6 @@ int sc_main(int argc, char *argv[]) { task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(380000)}); task1->addActivityGraphItem<LabelAccess>({label3, 1, tlm::TLM_READ_COMMAND}); task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(1400000)}); - //task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(1000000)}); - //task1->addActivityGraphItem<LabelAccess>({label1, 50000, tlm::TLM_READ_COMMAND}); - //task1->addActivityGraphItem<Ticks>({DiscreteValueConstant(400000)}); auto task2 = Task::createTask("Task2"); task2->addStimulus(stimuli0); @@ -86,7 +85,6 @@ int sc_main(int argc, char *argv[]) { task2->addActivityGraphItem<LabelAccess>({label2, 1, tlm::TLM_READ_COMMAND}); task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(50000)}); task2->addActivityGraphItem<LabelAccess>({label1, 1, tlm::TLM_READ_COMMAND}); - //task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(1700000)}); task2->addActivityGraphItem<Ticks>({DiscreteValueConstant(2400000)}); auto task3 = Task::createTask("Task3"); diff --git a/examples/RoundRobinScheduling/RoundRobinSchedulingTicksOnly.cpp b/examples/PriorityScheduling/RoundRobinSchedulingTicksOnly.cpp similarity index 97% rename from examples/RoundRobinScheduling/RoundRobinSchedulingTicksOnly.cpp rename to examples/PriorityScheduling/RoundRobinSchedulingTicksOnly.cpp index 78c09e89dad6fbe414f9802801814c9d6884a359..e4542fd6ddfc903e6fea3a1d24403489b189cb17 100644 --- a/examples/RoundRobinScheduling/RoundRobinSchedulingTicksOnly.cpp +++ b/examples/PriorityScheduling/RoundRobinSchedulingTicksOnly.cpp @@ -42,6 +42,7 @@ int sc_main(int argc, char *argv[]) { HwAccessElement mainMemC1Access; mainMemC1Access.dest = mainMem; mainMemC1Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC1Access.setReadLatency(DiscreteValueConstant(0)); core1->addHWAccessElement(mainMemC1Access); auto core2 = ECU.createModule<ProcessingUnit>("Core2", pudef); @@ -50,6 +51,7 @@ int sc_main(int argc, char *argv[]) { HwAccessElement mainMemC2Access; mainMemC2Access.dest = mainMem; mainMemC2Access.setDataRate({100, DataRateUnit::kbitPerSecond}); + mainMemC2Access.setReadLatency(DiscreteValueConstant(0)); core2->addHWAccessElement(mainMemC2Access); /* Stimuli */ diff --git a/examples/RoundRobinScheduling/CMakeLists.txt b/examples/RoundRobinScheduling/CMakeLists.txt deleted file mode 100644 index eac2da7d9780a2de2264d99c2064cb90220c02e0..0000000000000000000000000000000000000000 --- a/examples/RoundRobinScheduling/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_executable (RoundRobinScheduling "RoundRobinScheduling.cpp") -target_link_libraries(RoundRobinScheduling app4mc.sim_lib) -target_precompile_headers(RoundRobinScheduling REUSE_FROM app4mc.sim_lib) -add_test(NAME Run_RoundRobinScheduling COMMAND RoundRobinScheduling ${ADDITIONAL_TEST_ARGS}) - -add_executable (RoundRobinSchedulingTicksOnly "RoundRobinSchedulingTicksOnly.cpp") -target_link_libraries(RoundRobinSchedulingTicksOnly app4mc.sim_lib) -target_precompile_headers(RoundRobinSchedulingTicksOnly REUSE_FROM app4mc.sim_lib) -add_test(NAME RoundRobinSchedulingTicksOnly COMMAND RoundRobinSchedulingTicksOnly ${ADDITIONAL_TEST_ARGS}) - -install( - TARGETS RoundRobinScheduling RoundRobinSchedulingTicksOnly - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/examples/RoundRobinScheduling -) \ No newline at end of file