Assignment P1 - Validating schedules

Due: Monday, January 13, 2020, at the start of class

You may work alone or with a partner, but you must type up the code yourself. You may also discuss the assignment at a high level with other students. You should list any student with whom you discussed the assignment, and the manner of discussion (high-level, partner, etc.) in a readme.txt file that you include with your submission.

You should submit your assignment as a .zip file on Moodle.

Throughout this course, we will build up a scheduling and synchronization software library. This library will make heavy use of JSON structures to respresent task systems and the resulting schedules. The JSON files are parsed into Python objects. For this assignment, you only need to know how the task set and schedule are represented in Python.

Starter Code: .zip

Better starter code, with a few more tests: .zip

Representing a task system

Tasks and jobs are defined in taskset.py. So far, we have only considered aperiodic tasks, so each task has only a single job.

A task set is comprised of multiple tasks. You can iterate through the tasks in a task set, as in the printTasks method of TaskSet:

class TaskSet(object):
    ...

    def printTasks(self):
        print("\nTask Set:")
        for task in self:
            print(task)

You can also retrieve a specific task using its ID via the getTaskById method.

A Task object contains all of the timing parameters we’ve discussed in class: WCET, offset, period, and deadline.

class Task(object):
    def __init__(self, taskDict):
        self.id = int(...)
        self.period = float(...)
        self.wcet = float(...)
        self.relativeDeadline = float(...)
        self.offset = float(...)

        ...

        self.jobs = []

You can iterate through the jobs of a task by calling the getJobs method. You can also request a specific job given the ID using the getJobById method. Again from TaskSet:

    def printJobs(self):
        print("\nJobs:")
        for task in self:
            for job in task.getJobs():
                print(job)

A job object contains the information about the task, as well as the job’s release time and absolute deadline.

class Job(object):
    def __init__(self, task, jobId, releaseTime):
        self.task = task
        self.id = jobId
        self.releaseTime = releaseTime
        self.deadline = releaseTime + task.relativeDeadline

Representing a schedule

In this assignment, you will not have to work through any scheduling decisions. Rather, you will be given the resulting schedule as a list of decisions made at given time instants. Each scheduling decision is represented by a Python ScheduleInterval object, in schedule.py:

class ScheduleInterval(object):
    def __init__(self, intervalDict):
        self.startTime = float(...)
        self.taskId = int(...)
        self.jobId = int(...)
        self.didPreemptPrevious = bool(...)

    def updateIntervalEnd(self, endTime, didJobComplete):
        self.endTime = endTime
        self.jobCompleted = didJobComplete and not self.taskId == 0 # "idle" jobs don't complete

    def isIdle(self):
        return self.taskId == 0

A scheduling decision defines the start of an interval; the end of the interval is defined by the start of the next interval. As a result, a post-processing step after parsing the JSON scheduling decisions calls updateIntervalEnd to set the endTime and jobCompleted fields of each ScheduleInterval instance.

Additionally, each schedule ends with an “idle” interval, in which no job executes. It is also possible that a schedule may have idle intervals between task executions. You can check whether an interval is idle using the isIdle method.

A schedule itself is represented by the Schedule class. The constructor parses the JSON schedule and stores the intervals in the intervals field. You can see it used in the printIntervals method of Schedule:

    def printIntervals(self, displayIdle=True):
        print("\nScheduling intervals:")
        for interval in self.intervals:
            if not interval.isIdle() or displayIdle:
                print(interval)

Getting started

You will not need Pygame for this assignment, but you will in the future. You can run any of taskset.py, schedule.py, or display.py as-is, and it will choose the task set and schedule defined in tasksets/hwp1_test1.json and display some output (text for the first two, and a Pygame window for the third). You can provide a different JSON file by running it at the command line:

    python3 schedule.py tasksets/hwp1_test2.json

Update: the command you run depends on your environment setup. It likely begins with python3, but it is possible to have configured your machine to use python to access Python 3 instead.

Problem 1: Validating WCETs

For this problem, you should fill in the implementation of the areWcetsExceeded method of the Schedule class in schedule.py. This method should check whether the total duration of all intervals for a given job exceed that job’s WCET, as defined by its task. If any WCET is exceeded, the function should return False. Otherwise, it should return True.

    def areWcetsExceeded(self):
        """
        Returns a boolean indicating whether all jobs execute for
        at most their WCET value.
        """
        ### TODO: replace this line with your implementation
        raise(NotImplementedError)

    def checkWcets(self):
        areWcetsExceeded = self.areWcetsExceeded()
        if areWcetsExceeded:
            print("No WCETs are exceeded")
        else:
            print("A job exceeds its WCET :(")

You have two test JSON files for this problem: hwp1_test1.json features a schedule in which WCETs are respected, and hwp1_test2.json contains a schedule in which one of the jobs executes for more than its WCET.

Problem 2: Validating feasibility

In this problem, you will validate that the schedule is feasible – that is, that no deadlines are missed. For this, you will need to implement the doesMeetDeadlines method of the Schedule class. This method should return False if any deadline is missed, and True if no deadlines are missed.

    def doesMeetDeadlines(self):
        """
        Returns a boolean indicating whether all deadlines are met.
        """
        ### TODO: replace this line with your implementation
        raise(NotImplementedError)

    def checkFeasibility(self):
        doesMeetDeadlines = self.doesMeetDeadlines()
        if doesMeetDeadlines:
            print("This schedule is feasible!")
        else:
            print("This schedule is not feasible :(")

Once again, there are two test JSON files for this problem: hwp1_test3.json has a feasible schedule, and the schedule in hwp1_test4.json is infeasible.

A few more test cases

Update: There are a few more tests in the updated .zip file, conveniently corresponding to Problem 2 of W1. Test 5 should pass for both problems. For test 6, the WCET of is decreased, so its WCET is exceeded. For test 7, both the WCET and relative deadline of have been decreased, so it should fail both tests.

What you should submit

You should submit a single .zip file on Moodle. It should contain the following files:

  • readme.txt (collaboration statement listing collaborators and form of collaboration)
  • schedule.py
  • Any new .json files that you chose to create for testing (optional)

An example readme.txt file might be the following:

For this assignment, I collaborated with:
* Colin - partner
* Therese - discussed the difference between relative and absolute deadlines

If you did not collaborate with anyone, you should say so:

For this assignment, I worked alone.