diff --git a/EDFScheduler.cpp b/EDFScheduler.cpp index 183f43c..538dd4c 100755 --- a/EDFScheduler.cpp +++ b/EDFScheduler.cpp @@ -1,6 +1,9 @@ /* * EDFScheduler.cpp * + * Concrete subclass of a Scheduler implementing the + * Earliest Deadline First scheduling algorithm. + * * Created on: Mar 13, 2013 * Author: dam7633 */ @@ -14,6 +17,7 @@ EDFScheduler::~EDFScheduler() { } void EDFScheduler::scheduleTasks() { + // Initialize variables for determining the earliest deadline task. int earliestIdx = -1; long earliestDeadline = LONG_MAX; long currentEarliestDeadline; diff --git a/EDFScheduler.h b/EDFScheduler.h index cd2af19..a21d070 100755 --- a/EDFScheduler.h +++ b/EDFScheduler.h @@ -1,6 +1,9 @@ /* * EDFScheduler.h * + * Concrete subclass of a Scheduler implementing the + * Earliest Deadline First scheduling algorithm. + * * Created on: Mar 13, 2013 * Author: dam7633 */ @@ -9,14 +12,15 @@ #define EDFSCHEDULER_H_ #include "Scheduler.h" -#include "Task.h" -#include class EDFScheduler: public Scheduler { public: EDFScheduler(); virtual ~EDFScheduler(); + /** + * Template method implementing the EDF algorithm. + */ void scheduleTasks(); }; diff --git a/RMAScheduler.cpp b/RMAScheduler.cpp index cca6a17..bcb29c4 100755 --- a/RMAScheduler.cpp +++ b/RMAScheduler.cpp @@ -1,6 +1,9 @@ /* * RMAScheduler.cpp * + * Concrete subclass of a Scheduler implementing the + * Rate-Monotonic scheduling algorithm. + * * Created on: Mar 13, 2013 * Author: dam7633 */ @@ -10,6 +13,14 @@ #include #include "Task.h" +/** + * Comparator function for sorting tasks based on their + * period. + * + * @param t1 - first task + * @param t2 - second task + * @return period of t1 < period of t2 + */ bool comparePeriod(Task *t1, Task *t2) { return t1->getPeriod() < t2->getPeriod(); } @@ -21,16 +32,22 @@ RMAScheduler::~RMAScheduler() { } void RMAScheduler::scheduleTasks() { + // Since RMA is a fixed-priority scheduling algorithm, we + // only need to perform scheduling at the beginning. if (!taskPrioritiesSet) { + // Assert that there are enough priorities for the task set. assert(taskSet.size() < TP_SCHEDULER); + // Sort the tasks by the smallest period. std::sort(taskSet.begin(), taskSet.end(), comparePeriod); + // Assign priorities to tasks in a descending order from TP_SCHEDULER. for (std::size_t i = 0; i < taskSet.size(); i++) { Task *task = taskSet[i]; task->setPriority(TP_SCHEDULER - (i + 1)); } + // Set this flag so that scheduling is only done once. taskPrioritiesSet = true; } } diff --git a/RMAScheduler.h b/RMAScheduler.h index 6e9bed1..6a35d29 100755 --- a/RMAScheduler.h +++ b/RMAScheduler.h @@ -1,6 +1,9 @@ /* * RMAScheduler.h * + * Concrete subclass of a Scheduler implementing the + * Rate-Monotonic scheduling algorithm. + * * Created on: Mar 13, 2013 * Author: dam7633 */ @@ -15,9 +18,24 @@ class RMAScheduler: public Scheduler { RMAScheduler(); virtual ~RMAScheduler(); + /** + * Template method implementing the RMA algorithm. + * + * This scheduler fully utilizes the QNX fixed-priority + * scheduler by assigning descending priorities starting + * from TP_SCHEDULER. + * + * Because of this, RMA can only be run with a task set + * smaller in size than TP_SCHEDULER, and will cause an + * assertion failure otherwise. + */ void scheduleTasks(); private: + /** + * Flag used to only schedule tasks on the first run, + * since RMA is a fixed-priority scheduler. + */ bool taskPrioritiesSet; }; diff --git a/SCTScheduler.cpp b/SCTScheduler.cpp index b4dd3fe..2d90e24 100755 --- a/SCTScheduler.cpp +++ b/SCTScheduler.cpp @@ -1,17 +1,22 @@ /* * SCTScheduler.cpp * + * Concrete subclass of a Scheduler implementing the + * Shortest Completion Time scheduling algorithm. + * * Created on: Mar 13, 2013 * Author: dam7633 */ #include "SCTScheduler.h" +#include "Task.h" SCTScheduler::SCTScheduler() { } SCTScheduler::~SCTScheduler() { } + void SCTScheduler::scheduleTasks() { int shortestIdx = -1; int shortestTimeLeft = INT_MAX; diff --git a/SCTScheduler.h b/SCTScheduler.h index a95e6d3..7c38f58 100755 --- a/SCTScheduler.h +++ b/SCTScheduler.h @@ -1,6 +1,9 @@ /* * SCTScheduler.h * + * Concrete subclass of a Scheduler implementing the + * Shortest Completion Time scheduling algorithm. + * * Created on: Mar 13, 2013 * Author: dam7633 */ @@ -9,13 +12,15 @@ #define SCTSCHEDULER_H_ #include "Scheduler.h" -#include "Task.h" class SCTScheduler: public Scheduler { public: SCTScheduler(); virtual ~SCTScheduler(); + /** + * Template method implementing the SCT algorithm. + */ void scheduleTasks(); }; diff --git a/Scheduler.cpp b/Scheduler.cpp index b581873..2fc4cf8 100755 --- a/Scheduler.cpp +++ b/Scheduler.cpp @@ -1,18 +1,22 @@ /* * Scheduler.cpp * + * Threaded scheduler base class, which is responsible for + * accepting a task set, scheduling it, and running it. + * * Created on: Mar 13, 2013 * Author: dam7633 */ +#include +#include +#include #include "Scheduler.h" #include "Task.h" #include "SchedulingAlgorithms.h" Scheduler::Scheduler() : -Thread("Scheduler"), -tickCounter(0) { - +Thread("Scheduler") { sem_init(&scheduleSem, 0, 0); } @@ -25,25 +29,37 @@ Scheduler::~Scheduler() { sem_destroy(&scheduleSem); } -void Scheduler::createTask(std::string name, int computeTime, int period, -int deadline) { +void Scheduler::createTask(std::string name, int computeTime, int period, int deadline) { taskSet.push_back(new Task(name, computeTime, period, deadline, &scheduleSem)); } void* Scheduler::run() { + // The scheduler must run at its priority - the + // highest in the test fixture. this->setPriority(TP_SCHEDULER); - // calibrate nanospin_ns before the tasks do it. + // Calibrate nanospin_ns before the tasks do it. nanospin_calibrate(0); - //When we first are told to start, start the tasks... + // When we first are told to start, start the tasks... for(std::size_t i; i < taskSet.size(); i++) { + + // Initialize task state so that all are ready to run. taskSet[i]->setState(TP_READY); + + // Create the pthread for the task. taskSet[i]->start(); + + // taskSet[i] will post on scheduleSem. + // This ensures that all task threads are created before + // they are scheduled. sem_wait(&scheduleSem); + + // Lower the priority of the task to not running. taskSet[i]->setPriority(TP_READY); } + // Kick off the deadline timer for each task. for(std::size_t i; i < taskSet.size(); i++) { taskSet[i]->startDeadlineTimer(); } @@ -52,18 +68,22 @@ void* Scheduler::run() { TraceEvent(_NTO_TRACE_INSERTUSRSTREVENT, TRACE_EVENT_SCHEDULING_START, "Scheduling"); #endif + // Perform the first scheduling. scheduleTasks(); #if TRACE_EVENT_LOG_DEBUG TraceEvent(_NTO_TRACE_INSERTUSRSTREVENT, TRACE_EVENT_SCHEDULING_END, "Done Scheduling"); #endif + // Release all of the tasks. for (std::size_t i = 0; i < taskSet.size(); i++) { Task *task = taskSet[i]; task->postSem(); } - //then perform the scheduling + // Continue to perform scheduling when: + // 1. A Task completes its computation. + // 2. A Task's deadline timer puts it into a ready state. while (!killThread) { sem_wait(&scheduleSem); #if TRACE_EVENT_LOG_DEBUG diff --git a/Scheduler.h b/Scheduler.h index 013ab11..f4727d9 100755 --- a/Scheduler.h +++ b/Scheduler.h @@ -1,6 +1,9 @@ /* * Scheduler.h * + * Threaded scheduler base class, which is responsible for + * accepting a task set, scheduling it, and running it. + * * Created on: Mar 13, 2013 * Author: dam7633 */ @@ -11,38 +14,45 @@ #include #include #include -#include "Thread.h" -#include -#include -#include - -// The frequency of the timer tick -#define TIMER_PERIOD_NANO (10000000) -#define TIMER_PERIOD_SEC (0) - -class Task; - -typedef std::vector TaskSet; +#include "Task.h" class Scheduler : public Thread { public: Scheduler(); virtual ~Scheduler(); + + /** + * Pure virtual function requiring subclasses to implement + * how to schedule task sets. + */ virtual void scheduleTasks() = 0; + /** + * Creates a task in the scheduler's task set with the specified attributes. + * + * @param name - user-specified name of the task. + * @param computeTime - user-specified time which the task busy-waits for. + * @param period - user-specified interval of when the task must run. + * @param deadline - user-specified interval of when the task must finish. + */ void createTask(std::string name, int computeTime, int period, int deadline); + /** + * Implementation of the Thread class's run method. + */ void* run(); -// static void tick(union sigval sig); - - std::vector *getTaskSet(); - protected: - TaskSet taskSet; + /** + * Vector of the tasks for which this scheduler must schedule. + */ + std::vector taskSet; - unsigned int tickCounter; private: + /** + * Semaphore for blocking the execution of the scheduler while + * the scheduled task is running. + */ sem_t scheduleSem; }; diff --git a/SchedulingAlgorithms.cc b/SchedulingAlgorithms.cc index 5738ab5..b6bfa41 100755 --- a/SchedulingAlgorithms.cc +++ b/SchedulingAlgorithms.cc @@ -1,3 +1,25 @@ +/* + * SchedulingAlgorithms.cc + * + * Driver for the scheduling algorithms test fixture project. + * + * This driver expects two command line arguments: + * 1. A test file containing the set of tasks on each line + * formatted as: + * + * e.g. T2 3 5 5 + * 2. The scheduling algorithm ID as a number: + * Rate-Monotonic: 1 + * Shortest Completion Time: 2 + * Earliest Deadline First: 3 + * + * Usage: + * ./SchedulingAlgorithms + * + * Created on: Mar 13, 2013 + * Author: dam7633 + */ + #include #include #include @@ -15,12 +37,12 @@ int main(int argc, char *argv[]) { Scheduler* sc; int choice = -1; - //for creating tasks + // Storage for parsing the task set file. string name; int computeTime, deadline, period; if (argc == 3) { - ifstream file; + std::ifstream file; file.open(argv[1], ios::in); //select the scheduling algorithm... @@ -42,9 +64,11 @@ int main(int argc, char *argv[]) { break; } - //create the tasks + // Create tasks from the file until it it has been fully read. while (!(file.eof() || file.fail())) { + // Grab the task as a string in the following order file >> name >> computeTime >> deadline >> period; + if (!(file.eof() || file.fail())) { cout << "Making task: " << name << " " << computeTime << " " << period << " " << deadline << endl; @@ -54,20 +78,17 @@ int main(int argc, char *argv[]) { cout << "Starting..." << endl; - //start the simulation + // Start the simulation sc->start(); -// usleep(100000); + // This will stick because the thread never gets stop()'d + sc->join(); -// sc->stop(); - sc->join(); //this will stick because the thread never gets stop()'d - - //cleanup + // Cleanup delete sc; cout << "Exiting..." << endl; - } else { cerr << "Usage: " << argv[0] << " Filename SchedulerInt" << endl; } diff --git a/SchedulingAlgorithms.h b/SchedulingAlgorithms.h index d7629be..baed11e 100755 --- a/SchedulingAlgorithms.h +++ b/SchedulingAlgorithms.h @@ -1,6 +1,10 @@ /* * SchedulingAlgorithms.h * + * Common header file for the scheduling algorithms + * test fixture project. Includes commonly-used + * definitions and macros. + * * Created on: Mar 18, 2013 * Author: dam7633 */ diff --git a/Task.cpp b/Task.cpp index 99f851f..a5bb3d9 100755 --- a/Task.cpp +++ b/Task.cpp @@ -6,14 +6,20 @@ */ #include "Task.h" +#include +#include +#include #include #include #include -//1ms deadline and period +// 5 milliseconds +// The timeslice value for which the task time values are based. #define TIMER_PERIOD_NANO (5000000) #define TIMER_PERIOD_SEC (0) +// Calibrated number of nanoseconds used for the busy-wait +// using nanospin_ns(). #define BUSY_WAIT_NANO (4440000) Task::Task(std::string n, int c, int p, int d, sem_t* scheduler) : @@ -23,6 +29,7 @@ period(p), deadline(d), state(TP_READY), scheduler(scheduler) { + // Feasibility assertions. assert(computeTime > 0); assert(period > 0); assert(deadline > 0); @@ -30,12 +37,13 @@ scheduler(scheduler) { // produce a thread which calls tick with this as an argument when the timer ticks SIGEV_THREAD_INIT(&deadlineEvent, Task::tick, this, NULL); - /* Establish the measurement period */ + // Establish the measurement period deadlineTimerSpec.it_interval.tv_nsec = (TIMER_PERIOD_NANO * deadline); deadlineTimerSpec.it_interval.tv_sec = TIMER_PERIOD_SEC; deadlineTimerSpec.it_value.tv_nsec = (TIMER_PERIOD_NANO * deadline); deadlineTimerSpec.it_value.tv_sec = TIMER_PERIOD_SEC; + // Cache the logging strings. deadlineTimerString = name + " deadline timer."; deadlineMissedString = name + " missed deadline!"; deadlineTimerMsg = deadlineTimerString.c_str(); @@ -46,6 +54,7 @@ scheduler(scheduler) { } Task::~Task() { + // Clean up the task, timer, and semaphore. pthread_abort(thread); sem_destroy(&doWork); timer_delete(deadlineTimer); @@ -58,6 +67,7 @@ void Task::startDeadlineTimer() { } void* Task::run() { + // Build cached strings for logging. on the stack. std::string runningString(name + " Running"); std::string finishedString(name + " Finished"); const char *runningMsg = runningString.c_str(); @@ -74,7 +84,7 @@ void* Task::run() { TraceEvent(_NTO_TRACE_INSERTUSRSTREVENT, TRACE_EVENT_TASK_START, runningMsg); #endif while(completedTime < computeTime) { - nanospin_ns(BUSY_WAIT_NANO); //spin for a time tick + nanospin_ns(BUSY_WAIT_NANO); // spin for a time tick this->incrementCompletedTime(); state = TP_RUNNING; // Spin-lock to burn CPU } @@ -113,31 +123,19 @@ int Task::getComputeTime() { return computeTime; } -void Task::setComputeTime(int c) { - computeTime = c; -} - long Task::getRemainingDeadline() { timer_gettime(deadlineTimer, &deadlineRemainingSpec); - return (deadlineRemainingSpec.it_value.tv_nsec + 2500000)/50000000; + return (deadlineRemainingSpec.it_value.tv_nsec + (TIMER_PERIOD_NANO/2))/TIMER_PERIOD_NANO; } int Task::getPeriod() { return period; } -void Task::setPeriod(int p) { - period = p; -} - int Task::getDeadline() { return deadline; } -void Task::setDeadline(int d) { - deadline = d; -} - static int missedDeadlines = 0; void Task::tick(union sigval sig) { //get the schedulers semaphore from the timer... diff --git a/Task.h b/Task.h index be2c4a7..f5b14ec 100755 --- a/Task.h +++ b/Task.h @@ -1,6 +1,10 @@ /* * Task.h * + * Threaded object representing a task for the scheduling + * test fixture. Tasks are composed their name, compute time, + * period, and deadline. + * * Created on: Mar 13, 2013 * Author: dam7633 */ @@ -8,30 +12,45 @@ #ifndef TASK_H_ #define TASK_H_ -#include #include #include -#include -#include -#include #include "Thread.h" #include "SchedulingAlgorithms.h" +// The maximum number of misses which a task can endure when +// used with a net deadline met/deadline missed counter. #define MAX_DEADLINE_MISSES (15) +/** + * Enumeration for the set of task priorities and task states. + * Task priorities are specified to be the valid QNX priority + * for which they will run at. + */ enum TaskPriority { TP_FINISHED = 1, TP_READY = 7, TP_RUNNING = 8, TP_SCHEDULER = 9 }; class Task : public Thread { public: + /** + * @param name - user-specified name of the task. + * @param computeTime - user-specified time which the task busy-waits for. + * @param period - user-specified interval of when the task must run. + * @param deadline - user-specified interval of when the task must finish. + * @param scheduler - pointer to the schedler's semaphore. + */ Task(std::string name, int computeTime, int period, int deadline, sem_t* scheduler); virtual ~Task(); + /** + * Kicks off the timer which runs repeatedly at the deadline interval. + */ void startDeadlineTimer(); /** - * @return the return value when the Thread exits. + * Thread's run method which waits for the deadline to pass, + * performs a blocking busy-wait using nanospin, and + * notifies the scheduler that it has completed its work. */ void* run(); @@ -44,27 +63,41 @@ class Task : public Thread { int getComputeTime(); /** - * Sets the compute time of the task; the amount of work to do assuming 0 - * work has been done. + * @return The time remaining before the task's deadline, timesliced + * to the same value for which a single time tick is. */ - void setComputeTime(int computeTime); - long getRemainingDeadline(); /** - * Increments the amount of time completed + * Increments the amount of time completed. */ void incrementCompletedTime(); + /** + * @return the number of time ticks remaining for task computation. + */ int getRemainingComputeTime(); + /** + * @return the period of the task. + */ int getPeriod(); - void setPeriod(int period); + /** + * @return the deadline of the task. + */ int getDeadline(); - void setDeadline(int deadline); + /** + * @return the task's state as a TaskPriority enum value. + */ int getState(); + + /** + * Sets the state as a TaskPriority enum value. + * + * @param newState - the state this task will be in. + */ void setState(int newState); /** @@ -73,31 +106,34 @@ class Task : public Thread { */ void postSem(); - std::string getName(); - +private: /** - * Called by the timer to signify the deadline has passed + * Called by the timer to signify the deadline has passed. + * + * @param sig - contains a pointer to this Task. */ static void tick(union sigval sig); -private: /** - * The time it takes to actually complete the task + * The time it takes to actually complete the task in + * our specified timeslice. */ int computeTime; /** - * The time computed in the current execution cycle of the task. + * The time computed in the current execution cycle of the task + * in our specified timeslice. */ volatile int completedTime; /** - * The period of the task; how frequently it restarts. + * The period of the task; how frequently it restarts in our + * specified timeslice. */ int period; /** - * The deadline the task must finish by. + * The deadline the task must finish by in our specified timeslice. */ int deadline; @@ -112,6 +148,9 @@ class Task : public Thread { */ int state; + /** + * The timer which the task uses to restart its computation. + */ timer_t deadlineTimer; /** @@ -119,10 +158,16 @@ class Task : public Thread { */ sem_t* scheduler; + /** + * Cached values to decrease the latency in scheduling the timer. + */ struct itimerspec deadlineTimerSpec; struct sigevent deadlineEvent; struct itimerspec deadlineRemainingSpec; + /** + * Cached strings to decrease the latency of the trace event logging. + */ std::string deadlineTimerString; std::string deadlineMissedString; const char *deadlineTimerMsg; diff --git a/Thread.cpp b/Thread.cpp index a9d941a..77ad736 100755 --- a/Thread.cpp +++ b/Thread.cpp @@ -1,6 +1,9 @@ /* * Thread.cpp * + * Base object class which provides the basic functionality and + * attributes for a pthread. + * * Created on: Dec 27, 2012 * Author: jeff */ diff --git a/Thread.h b/Thread.h index 2108c6c..d3fa4fc 100755 --- a/Thread.h +++ b/Thread.h @@ -1,6 +1,9 @@ /* * Thread.h * + * Base object class which provides the basic functionality and + * attributes for a pthread. + * * Created on: Dec 27, 2012 * Author: jeff */