class ProcessManagerCase(unittest.TestCase):
    def setUp(self):
        self.pm = ProcessManager()
        self.pm.jobs = []  # make sure to work with clean job-queue

    def test_getProcessByName_01(self):
        aprocess = PCB(Process('1'))
        bprocess = PCB(Process('2'))
        print self.pm.jobs

    def test_registerProcess(self):
        # pcb should register itself at creation-time
        aprocess = PCB(Process('X'))
        getit = self.pm.getProcessByName('X')
        self.assertEqual(aprocess, getit)

    def test_registerProcess_02(self):
        # assert raise when you try to register an already known process name
        PCB(Process('F'))
        b = Process('F')
        self.assertRaises(ValueError, PCB, b)

    def test_getActiveProcess_01(self):
        # non-failure test. one running process
        PCB(Process('X'), state=State.L)
        PCB(Process('Y'), state=State.I)

        active_p = self.pm.getActiveProcess()
        self.assertEqual(active_p.state, State.L)

    def test_getActiveProcess_02(self):
        # no running process should raise IndexError
        self.assertRaises(IndexError, self.pm.getActiveProcess)

    def test_getActiveProcess_03(self):
        # two active processes should raise RuntimeError
        PCB(Process("A"), state=State.L)
        PCB(Process("B"), state=State.L)
        self.assertRaises(RuntimeError, self.pm.getActiveProcess)

    def tearDown(self):
        # clear job queue at the end (for security reasons)
        ProcessManager._drop()
Exemple #2
0
class JsonSerializer(object):
    def __init__(self):
        self.se = StrategyEvaluator()
        self.pe = ProcessEvaluator()
        self.pm = ProcessManager()

    def getIDforLane(self, pcb):
        """
        get the lane id for a pcb
        :param pcb: PCB
        :return: int: index of the lane
        """
        process = self.pm.getProcessByName(pcb.process.name)
        return self.pm.jobs.index(process)


    def __generateItems(self):
        items = list()
        for p in self.pm.jobs:
            sections_list = self.pe.getHistorySectionByType(p, Ready)
            sections_list.extend(self.pe.getHistorySectionByType(p, Work))
            sections_list.extend(self.pe.getHistorySectionByType(p, Wait))

            for section in sections_list:

                if isinstance(section, Wait):
                    state = "paused"
                elif isinstance(section, Work):
                    state = "running"
                elif isinstance(section, Ready):
                    state = "ready"

                job_dict = {"lane": self.getIDforLane(p),
                            "id": uuid1().get_urn(),
                            "start": section.starting_at,
                            "end": section.starting_at + section.duration,
                            "state": state,
                            "details": section.__repr__(),
                            }

                items.append(job_dict)
        return items

    def __generateLaunches(self):
        launches = list()
        for p in self.pm.jobs:
            launch_list = self.pe.getHistorySectionByType(p, Launch)
            for launch in launch_list:
                launch_event = {"trigger": self.getIDforLane(p),
                                "target": self.getIDforLane(launch.action),
                                "timestamp": launch.starting_at,
                                }
                launches.append(launch_event)
        return launches

    def __generateStrategyEvaluation(self):
        evaluation = dict()
        evaluation["cpu utilization"] = self.se.getAverageCPUusage()
        evaluation["mean response time"] = self.se.getMeanResponseTime()
        return evaluation

    def __combineResult(self):
        period = self.se.getPeriodDuration()
        launches = self.__generateLaunches()
        items = self.__generateItems()
        lanes = [pe.process.name for pe in self.pm.jobs]

        strategy_eval = self.__generateStrategyEvaluation()

        quantum_data = list()

        data = {'time_begin': 0,
                'time_end': period,
                'lanes': lanes,
                'items': items,
                'quantum_data': quantum_data,
                'launches': launches,
                'strategy evaluation': strategy_eval,
                }

        return data

    def generateJson(self):
        """
        return a json in a defined format
        :return: JSON-string
        """
        data = self.__combineResult()
        return json.dumps(data, indent=4, sort_keys=True)

    def generateData(self):
        """
        return a dictionary of python-object in a defined format
        :return: dict
        """
        data = self.__combineResult()
        return data
Exemple #3
0
class Scheduler(TimerListener):
    def __init__(self, strategy):
        assert isinstance(strategy, Strategy)
        self.howToSchedule = strategy

        # timer listeners
        self.cpu = CPU()  # that's what we want to manage
        self.processManager = ProcessManager()  # is responsible for managing processes
        self.ea_queues = [EAQueue()] * 1
        self.ready_queue = list()  # hold only processes waiting for the cpu
        self.init_process = None  # you have to initialize the scheduler first

        self._loop_counter = 0  # count how many time the run-method was called

        # every process needs the same quantum at beginning of the run
        try:
            self.quantum = strategy.__getattribute__("quantum")
        except AttributeError:
            self.quantum = 4
        self.processManager.setQuantumForEveryProcess(
            self.quantum)  # TODO:move to run-method / assuming here: processes are created before scheduler instantiates

        try:
            self.timeslice = strategy.__getattribute__("timeslice")  # make timeslice public
        except AttributeError:
            self.timeslice = 10

        SystemTimer().timeunit = self.timeslice
        SystemTimer().register(self)  # register at system clock

    def popFromReadyQueue(self):
        """
        get the next process from the ready queue. The state belongs in state ready. I
        :return: PCB
        """
        try:
            return self.ready_queue.pop(0)
        except IndexError:
            raise IndexError("the schedulers ready queue is empty")

    def addToEAQueue(self, pcb, i=0):
        print "add process to EAQueue%i %s" % (i, pcb)
        self.ea_queues[i].append(pcb)

    def notify(self, timestamp):
        """an event occurred. On every event, we have to decide if we dispatch the running process or not"""
        print "Scheduler notified after a step of", timestamp
        if self.schedule():
            # there is still something to do
            SystemTimer().tick()
        else:
            print "FINISHED"

    def initialize(self, start_pcb_str):
        """
        initialize the scheduler by defining the first process to run.
        :param start_pcb_str: name of the initial process
        """
        self.init_process = self.processManager.getProcessByName(start_pcb_str)

    def run(self):
        """
        start the scheduler
        begin with initialisation of the ready queue
        :return:
        """
        if self.init_process is None:
            raise RuntimeError("No init process found! please initialise first")
        else:
            # on the first run, the initial process is pushed to the ready queue
            self.addToMatchingQueue(self.init_process)  # init fill the ready queue

        self.schedule()
        # init process is now in CPU, time is 0
        SystemTimer().tick()  # do the first tick

    def addToMatchingQueue(self, pcb):
        """
        append pcb to right queue
        there are two types of queue: ready queues and waiting queues (aka. EAQueues)
        :param pcb: pcb to push to queue
        :return:
        :raise IndexError: if pcb's Workplan is empty
        """
        if isinstance(pcb.process.workplan.head(), Wait):
            # waiting section means ea queue:
            self.addToEAQueue(pcb)
        elif isinstance(pcb.process.workplan.head(), Work):
            self.addToReadyQueue(pcb)
        elif isinstance(pcb.process.workplan.head(), Launch):
            # interesting! now we have a launch. We push the Included process to the queue!
            print "trying to launch", pcb.process.workplan.head().action
            self.addToMatchingQueue(pcb.process.workplan.head().action)  # the process to launch is stored in the action
        else:
            # these sections are not made for queues
            pass

    def schedule(self):

        # check the ea queues if there are finished processes. if so, append them to the queues
        finished_waiting_processes = self.__check_ea_queues()
        for p in finished_waiting_processes:
            self.addToMatchingQueue(p)

        # active = self.processManager.getActiveProcess()
        active = self.cpu.running_process

        try:
            next_section = active.process.workplan.head()
        except:
            pass
        else:
            if isinstance(next_section, Wait):
                # process will enter wait section: dispatch
                try:
                    next_from_ready_queue = self.ready_queue.pop()
                except IndexError:
                    # ready queue empyt
                    next_from_ready_queue = None
                waiting_pcb = self.cpu.dispatch(next_from_ready_queue)
                self.addToMatchingQueue(waiting_pcb)
                active = self.cpu.running_process  # notwendig, da dispatch ausgefuehrt wurde
            if isinstance(next_section, Launch):
                # process will launch another process
                self.addToMatchingQueue(active)

        # collect information about resources
        sum_waiting_pcbs = sum(map(lambda x: len(x), self.ea_queues))  # Sum of all PCBs in EAQueues
        readyq_empty = True if len(self.ready_queue) == 0 else False  # ready queue empty?

        if not active and readyq_empty:
            # cpu leer, runq leer
            if sum_waiting_pcbs > 0:
                # but there are still waiting processes
                next_run = True
            else:
                next_run = False  # and no more processes in ea_queue
        elif not active and not readyq_empty:
            # cpu leer, runq voll: dispatchen und nochmal laufen
            ready = self.ready_queue.pop()
            ready.refill_quantum()  # refill quantum for next process in cpu
            self.cpu.dispatch(ready)
            # update system timer
            work_duration = ready.process.workplan.head().duration
            SystemTimer().next_tick_in(work_duration)
            next_run = True
        elif active and readyq_empty:
            # cpu voll, runq leer
            # there is no readyq_empty process...
            # reschedule: process in cpu belongs in cpu
            print 'reschedule process'
            if self.cpu.running_process.quantum == 0:
                # quantum gets refilled, if process is allowed to run again and the quantum was already consumed
                self.cpu.running_process.refill_quantum()
            next_run = True
        elif active and not readyq_empty:
            # cpu voll, runq voll
            next_run = True
            if SystemTimer().next_temp_timeunit != 0:
                # we need this distinction because this happens in 2 steps...
                strategy_result = self.howToSchedule.schedule(self)
                if strategy_result is not active:
                    # neuer process
                    old = self.cpu.dispatch(strategy_result)
                    active = strategy_result  # the new active process is the strategy result
                    self.addToMatchingQueue(old)
        else:
            # unefined state
            raise RuntimeError("undefined scheduling state")

        self._loop_counter += 1  # count the scheduling-steps
        return next_run

    def __check_ea_queues(self):
        """
        check if there are finished processes in the queue
        :return list: list of all ready pcbs
        """
        finished_waiting_processes = []
        for ea_q in self.ea_queues:
            p = ea_q.pickup_ready_processes()
            finished_waiting_processes.extend(p)
        return finished_waiting_processes

    def addToReadyQueue(self, pcb):
        """
        add process to ready queue
        :param pcb: pcb to be added
        """
        pcb.setReady()
        self.__maintain_process_history(pcb)
        print "add process to ready queue:", pcb
        # if rescheduled because of time quantum, add at the end, if it's because of preemption, add to the beginning
        self.howToSchedule.addToReadyQueue(scheduler=self, pcb=pcb)
        return True

    def __maintain_process_history(self, pcb):
        """
        usually, the history is maintained in the doWork()-Method in the Process-Class.
        However the Ready-Section must be maintained here.
        The Ready-Section is not part of the regular workplan.
        """
        # if len(pcb.process.history.plan) == 0:
        #     ready_time = 0
        # else:
        #     ready_time = SystemTimer().next_temp_timeunit
        # @TODO: fix this ugly method...
        ready_time = 0
        new_history_section = Ready(ready_time)
        new_history_section.starting_at = SystemTimer().timecounter
        new_history_section.ending_at = SystemTimer().timecounter + ready_time
        pcb.process.history.insert(new_history_section, i=len(pcb.process.history.plan))