Commit b2352129 by Michael Schmid

added Faults and minor changes

parent 9aed003b
#!/usr/bin/python3
"""
Example of a script that uses SimSo.
"""
import sys
from simso.core import Model
from simso.configuration import Configuration
def main(argv):
if len(argv) == 2:
# Configuration load from a file.
configuration = Configuration(argv[1])
else:
# Manual configuration:
configuration = Configuration()
configuration.cycles_per_ms = 1
configuration.etm = "pwcet"
configuration.duration = 100 * configuration.cycles_per_ms
# Add tasks:
configuration.add_task(name="T1", identifier=1,
activation_date=0, pwcet=[(2, 0.5), (4, 0.5)], pmit=[(5, 0.2), (6, 0.8)], deadline=5, task_type="Probabilistic", abort_on_miss=True)
configuration.add_task(name="T2", identifier=2,
activation_date=0, pwcet=[(3, 0.5), (4, 0.5)], pmit=[(7, 0.5), (8, 0.5)], deadline=7, task_type="Probabilistic", abort_on_miss=True)
configuration.add_task(name="T3", identifier=3,
activation_date=0, pwcet=[(3, 0.5), (4, 0.5)], pmit=[(8, 0.5), (9, 0.5)], deadline=8, task_type="Probabilistic", abort_on_miss=True)
# Add a processor:
configuration.add_processor(name="CPU 1", identifier=1)
# configuration.add_processor(name="CPU 2", identifier=2)
# Add a scheduler:
# configuration.scheduler_info.filename = "./simso/schedulers/RM.py"
configuration.scheduler_info.clas = "simso.schedulers.RM"
# Check the config before trying to run it.
configuration.check_all()
# Init a model from the configuration.
model = Model(configuration)
# Execute the simulation.
model.run_model()
# Print logs.
for log in model.logs:
print(log)
main(sys.argv)
...@@ -6,6 +6,7 @@ Example of a script that uses SimSo. ...@@ -6,6 +6,7 @@ Example of a script that uses SimSo.
import sys import sys
from simso.core import Model from simso.core import Model
from simso.core.Fault import ProcessorFailure, VoltageDrop, PriorityInversion, TimingError
from simso.configuration import Configuration from simso.configuration import Configuration
...@@ -22,22 +23,24 @@ def main(argv): ...@@ -22,22 +23,24 @@ def main(argv):
configuration.duration = 100 * configuration.cycles_per_ms configuration.duration = 100 * configuration.cycles_per_ms
# Add tasks: # Add tasks:
configuration.add_task(name="T1", identifier=1, period=7, configuration.add_task(name="T1", identifier=1, period=8,
activation_date=0, wcet=3, deadline=7) activation_date=0, wcet=4, deadline=7)
configuration.add_task(name="T2", identifier=2, period=12, configuration.add_task(name="T2", identifier=2, period=12,
activation_date=0, wcet=3, deadline=8) activation_date=0, wcet=3, deadline=8)
configuration.add_task(name="T4", identifier=4, period=15, configuration.add_task(name="T3", identifier=3, period=15,
activation_date=0, wcet=5, deadline=14) activation_date=0, wcet=5, deadline=14)
configuration.add_task(name="T3", identifier=3, period=20, task = configuration.add_task(name="T4", identifier=4, period=20,
activation_date=0, wcet=5, deadline=9) activation_date=0, wcet=6, deadline=12)
# Add a processor: # Add a processor:
configuration.add_processor(name="CPU 1", identifier=1, cs_overhead=1) configuration.add_processor(name="CPU 1", identifier=1)
configuration.add_processor(name="CPU 2", identifier=2, cs_overhead=1) proc = configuration.add_processor(name="CPU 2", identifier=2)
configuration.add_fault(TimingError(task, "period", 8), 0, 21)
# Add a scheduler: # Add a scheduler:
#configuration.scheduler_info.filename = "../simso/schedulers/RM.py" #configuration.scheduler_info.filename = "../simso/schedulers/RM.py"
configuration.scheduler_info.clas = "simso.schedulers.RM" configuration.scheduler_info.clas = "simso.schedulers.EDF"
# Check the config before trying to run it. # Check the config before trying to run it.
configuration.check_all() configuration.check_all()
......
...@@ -35,7 +35,7 @@ def main(argv): ...@@ -35,7 +35,7 @@ def main(argv):
# Add a processor: # Add a processor:
configuration.add_processor(name="CPU 1", identifier=1) configuration.add_processor(name="CPU 1", identifier=1)
configuration.add_processor(name="CPU 2", identifier=2) # configuration.add_processor(name="CPU 2", identifier=2)
# Add a scheduler: # Add a scheduler:
configuration.scheduler_info.filename = "./simso/schedulers/RM.py" configuration.scheduler_info.filename = "./simso/schedulers/RM.py"
......
...@@ -4,10 +4,12 @@ ...@@ -4,10 +4,12 @@
import os import os
import re import re
from xml.dom import minidom from xml.dom import minidom
from functools import reduce
from simso.core.Scheduler import SchedulerInfo from simso.core.Scheduler import SchedulerInfo
from simso.core import Scheduler from simso.core import Scheduler
from simso.core.Task import TaskInfo from simso.core.Task import TaskInfo
from simso.core.Processor import ProcInfo from simso.core.Processor import ProcInfo
from simso.core.Fault import FaultInfo, FaultFunction
from simso.generator.task_generator import gen_probabilistic_arrivals from simso.generator.task_generator import gen_probabilistic_arrivals
from simso.generator.task_generator import cdf from simso.generator.task_generator import cdf
...@@ -22,7 +24,7 @@ if not hasattr(minidom.NamedNodeMap, '__contains__'): ...@@ -22,7 +24,7 @@ if not hasattr(minidom.NamedNodeMap, '__contains__'):
def _gcd(*numbers): def _gcd(*numbers):
"""Return the greatest common divisor of the given integers""" """Return the greatest common divisor of the given integers"""
from fractions import gcd from math import gcd
return reduce(gcd, numbers) return reduce(gcd, numbers)
...@@ -60,6 +62,7 @@ class Configuration(object): ...@@ -60,6 +62,7 @@ class Configuration(object):
self._scheduler_info = parser.scheduler_info self._scheduler_info = parser.scheduler_info
self.penalty_preemption = parser.penalty_preemption self.penalty_preemption = parser.penalty_preemption
self.penalty_migration = parser.penalty_migration self.penalty_migration = parser.penalty_migration
self.fault_info_list = parser.fault_info_list
else: else:
self.etm = "wcet" self.etm = "wcet"
self.duration = 100000000 self.duration = 100000000
...@@ -71,6 +74,7 @@ class Configuration(object): ...@@ -71,6 +74,7 @@ class Configuration(object):
self.task_data_fields = {} self.task_data_fields = {}
self._proc_info_list = [] self._proc_info_list = []
self.proc_data_fields = {} self.proc_data_fields = {}
self.fault_info_list = []
self.memory_access_time = 100 self.memory_access_time = 100
self._scheduler_info = SchedulerInfo() self._scheduler_info = SchedulerInfo()
self.calc_penalty_cache() self.calc_penalty_cache()
...@@ -315,3 +319,10 @@ class Configuration(object): ...@@ -315,3 +319,10 @@ class Configuration(object):
speed) speed)
self.proc_info_list.append(proc) self.proc_info_list.append(proc)
return proc return proc
def add_fault(self, fault_function, start_time, end_time):
"""
Helper method to create a FaultInfo and add it to the list of faults.
"""
fault = FaultInfo(start_time, end_time, fault_function)
self.fault_info_list.append(fault)
...@@ -20,6 +20,7 @@ class Parser(object): ...@@ -20,6 +20,7 @@ class Parser(object):
""" """
Simulation file parser. Simulation file parser.
""" """
def __init__(self, filename): def __init__(self, filename):
self.filename = filename self.filename = filename
self.cur_dir = os.path.split(filename)[0] self.cur_dir = os.path.split(filename)[0]
...@@ -34,6 +35,11 @@ class Parser(object): ...@@ -34,6 +35,11 @@ class Parser(object):
self._parse_processors() self._parse_processors()
self._parse_scheduler() self._parse_scheduler()
self._parse_penalty() self._parse_penalty()
self._parse_faults()
def _parse_faults(self):
# TODO: implement parser for faults
self.fault_info_list = []
def _parse_caches(self): def _parse_caches(self):
self.caches_list = [] self.caches_list = []
...@@ -90,29 +96,31 @@ class Parser(object): ...@@ -90,29 +96,31 @@ class Parser(object):
map(float, attr['list_activation_dates'].value.split(','))) map(float, attr['list_activation_dates'].value.split(',')))
t = TaskInfo( t = TaskInfo(
attr['name'].value, name=attr['name'].value,
int(attr['id'].value), identifier=int(attr['id'].value),
task_type, task_type=task_type,
'abort_on_miss' not in attr abort_on_miss='abort_on_miss' not in attr
or attr['abort_on_miss'].value == 'yes', or attr['abort_on_miss'].value == 'yes',
float(attr['period'].value), period=float(attr['period'].value),
float(attr['activationDate'].value) activation_date=float(attr['activationDate'].value)
if 'activationDate' in attr else 0, if 'activationDate' in attr else 0,
int(attr['instructions'].value), n_instr=int(attr['instructions'].value),
float(attr['mix'].value), mix=float(attr['mix'].value),
(self.cur_dir + '/' + attr['stack'].value, stack_file=(self.cur_dir + '/' + attr['stack'].value,
self.cur_dir) if 'stack' in attr else ("", self.cur_dir), self.cur_dir) if 'stack' in attr else ("", self.cur_dir),
float(attr['WCET'].value), wcet=float(attr['WCET'].value),
float(attr['ACET'].value) if 'ACET' in attr else 0, acet=float(attr['ACET'].value) if 'ACET' in attr else 0,
float(attr['et_stddev'].value) if 'et_stddev' in attr else 0, pwcet=float(attr['PWCET'].value) if 'PWCET' in attr else 0,
float(attr['deadline'].value), et_stddev=float(
float(attr['base_cpi'].value), attr['et_stddev'].value) if 'et_stddev' in attr else 0,
int(attr['followed_by'].value) deadline=float(attr['deadline'].value),
base_cpi=float(attr['base_cpi'].value),
followed_by=int(attr['followed_by'].value)
if 'followed_by' in attr else None, if 'followed_by' in attr else None,
list_activation_dates, list_activation_dates=list_activation_dates,
int(float(attr['preemption_cost'].value)) preemption_cost=int(float(attr['preemption_cost'].value))
if 'preemption_cost' in attr else 0, if 'preemption_cost' in attr else 0,
data) data=data)
self.task_info_list.append(t) self.task_info_list.append(t)
def _parse_processors(self): def _parse_processors(self):
...@@ -244,5 +252,5 @@ class Parser(object): ...@@ -244,5 +252,5 @@ class Parser(object):
clas=clas, overhead=overhead, overhead_activate=overhead_activate, clas=clas, overhead=overhead, overhead_activate=overhead_activate,
overhead_terminate=overhead_terminate, fields=data) overhead_terminate=overhead_terminate, fields=data)
if filename and filename[0] != '/': if filename and filename[0] != '/':
filename = self.cur_dir + '/' + filename filename = self.cur_dir + '/' + filename
self.scheduler_info.filename = filename self.scheduler_info.filename = filename
from simpy import Environment
from typing import Callable
from simso.core.Processor import ProcInfo
class FaultFunction:
"""
The FaultFunction class changes the actual behaviour of the faulty element.
"""
def __init__(self, start_function: Callable, end_function: Callable):
self.start_function = start_function
self.end_function = end_function
class FaultInfo:
"""
The FaultType class is responsible for causing the error.
"""
def __init__(self, start_time: float, end_time: float, fault_function: FaultFunction):
self.start_time = start_time
self.end_time = end_time
self.fault_function = fault_function
class Fault:
"""
The Fault class is the simpy process for triggering a certain error.
"""
def __init__(self, sim, fault_type: FaultInfo):
self._fault_type = fault_type
self._sim = sim
self.process = self._sim.process(self.release())
def release(self):
yield self._sim.timeout(self._fault_type.start_time)
self._fault_type.fault_function.start_function(self._sim)
yield self._sim.timeout(self._fault_type.end_time -
self._fault_type.start_time)
self._fault_type.fault_function.end_function(self._sim)
class ProcessorFailure(FaultFunction):
"""
The ProcessorFailure class simulates a complete stoppage of a processor.
"""
def __init__(self, proc_info: ProcInfo):
super().__init__(self.stop_processor, self.start_processor)
self._proc_info = proc_info
self._processor = None
def stop_processor(self, model):
self._processor = next(
p for p in model.processors if p.identifier == self._proc_info.identifier)
self._processor.fail(self)
def start_processor(self, model):
self._processor.fail()
class VoltageChange(FaultFunction):
def __init__(self, proc_info_list, scaling: float):
super().__init__(self.start_voltage_change, self.end_voltage_change)
self._proc_info_list = proc_info_list
self._processor_list = []
self._scaling = scaling
def start_voltage_change(self, model):
affected_ids = [p.identifier for p in self._proc_info_list]
self._processor_list = [
p for p in model.processors if p.identifier in affected_ids]
for p in self._processor_list:
p.set_speed(self._scaling * p.speed)
def end_voltage_change(self, model):
for p in self._processor_list:
speed = next(
pi for pi in self._proc_info_list if pi.identifier == p.identifier).speed
p.set_speed(speed)
class VoltageDrop(VoltageChange):
"""
The VoltageDrop class simulates the slowdown of one or more processors due to voltage drops.
"""
def __init__(self, proc_info_list, scaling: float):
assert scaling >= 0 and scaling <= 1.0, "Voltage drop reduces the speed of a processor, i.e. scaling has to be >= 0 and <= 1"
super().__init__(proc_info_list, scaling)
# TODO: rethink this class
class PriorityInversion(FaultFunction):
"""
The PriorityInversion class simulates changes in the priority of a job.
"""
def __init__(self, proc_info, until_sched: bool = False):
"""
lambd: Expects task and new value as parameter and returns old value
"""
super().__init__(self.start_priority_inversion, self.end_priority_inversion)
self._proc_info = proc_info
self._until_sched = until_sched
def start_priority_inversion(self, model):
proc = next(p for p in model.processors if p.identifier ==
self._proc_info.identifier)
sched = model.scheduler
running_jobs = [
p.running for p in model.processors if p.running is not None]
job = next(t.job for t in sched.task_list if t.job.is_active()
and t.job not in running_jobs)
if job is not None:
pass
def end_priority_inversion(self, model):
pass
class TimingChange(FaultFunction):
"""
The TimingError class simulates changes in the timing parameters, e.g. deadline, period etc.
"""
def __init__(self, task_info, parameter: str, value: float):
super().__init__(self.start_timing_change, self.end_timing_change)
self._task_info = task_info
self._parameter = parameter
self._value = value
self._old_value = getattr(self._task_info, parameter)
def start_timing_change(self, model):
setattr(self._task_info, self._parameter, self._value)
def end_timing_change(self, model):
setattr(self._task_info, self._parameter, self._old_value)
class TimingError(TimingChange):
"""
The TimingError class simulates changes in the timing parameters, e.g. deadline, period etc.
"""
def __init__(self, task_info, parameter: str, value: float):
super().__init__(task_info, parameter, value)
class Redundancy(TimingChange):
def __init__(self, task_info, value: float):
super().__init__(task_info, "wcet", task_info.wcet + value)
...@@ -94,6 +94,7 @@ class Job: ...@@ -94,6 +94,7 @@ class Job:
self._sim.logger.log(self.name + " Preempted! ret: " + self._sim.logger.log(self.name + " Preempted! ret: " +
str(self.ret), kernel=True) # TODO: what to pass as interrupted? str(self.ret), kernel=True) # TODO: what to pass as interrupted?
# TODO: Jobs that terminate after their deadline are not recorded
def _on_terminated(self): def _on_terminated(self):
self._on_stop_exec() self._on_stop_exec()
self._etm.on_terminated(self) self._etm.on_terminated(self)
...@@ -322,11 +323,3 @@ class Job: ...@@ -322,11 +323,3 @@ class Job:
if ret <= 0: if ret <= 0:
# End of job. # End of job.
self._on_terminated() self._on_terminated()
class SequentialJob(Job):
pass
class ParallelJob(Job):
pass
...@@ -8,6 +8,7 @@ from simso.core.Timer import Timer ...@@ -8,6 +8,7 @@ from simso.core.Timer import Timer
from simso.core.etm import execution_time_models from simso.core.etm import execution_time_models
from simso.core.Logger import Logger from simso.core.Logger import Logger
from simso.core.results import Results from simso.core.results import Results
from simso.core.Fault import Fault
class Model(Environment): class Model(Environment):
...@@ -31,6 +32,7 @@ class Model(Environment): ...@@ -31,6 +32,7 @@ class Model(Environment):
self._logger = Logger(self) self._logger = Logger(self)
task_info_list = configuration.task_info_list task_info_list = configuration.task_info_list
proc_info_list = configuration.proc_info_list proc_info_list = configuration.proc_info_list
fault_info_list = configuration.fault_info_list
self._cycles_per_ms = configuration.cycles_per_ms self._cycles_per_ms = configuration.cycles_per_ms
self.scheduler = configuration.scheduler_info.instantiate(self) self.scheduler = configuration.scheduler_info.instantiate(self)
...@@ -59,6 +61,10 @@ class Model(Environment): ...@@ -59,6 +61,10 @@ class Model(Environment):
proc.caches = proc_info.caches proc.caches = proc_info.caches
self._processors.append(proc) self._processors.append(proc)
self._fault_list = []
for fault_info in fault_info_list:
self._fault_list.append(Fault(self, fault_info))
# XXX: too specific. # XXX: too specific.
self.penalty_preemption = configuration.penalty_preemption self.penalty_preemption = configuration.penalty_preemption
self.penalty_migration = configuration.penalty_migration self.penalty_migration = configuration.penalty_migration
......
...@@ -14,6 +14,7 @@ TERMINATE = 3 ...@@ -14,6 +14,7 @@ TERMINATE = 3
TIMER = 4 TIMER = 4
PREEMPT = 5 PREEMPT = 5
SPEED = 6 SPEED = 6
FAIL = 7
class ProcInfo(object): class ProcInfo(object):
...@@ -75,6 +76,7 @@ class Processor: ...@@ -75,6 +76,7 @@ class Processor:
env=model, name="Monitor Timer" + proc_info.name) env=model, name="Monitor Timer" + proc_info.name)
self._speed = proc_info.speed self._speed = proc_info.speed
self.process = self._model.process(self.run()) self.process = self._model.process(self.run())
self._fault = None
def resched(self): def resched(self):
""" """
...@@ -91,11 +93,14 @@ class Processor: ...@@ -91,11 +93,14 @@ class Processor:
self._running = None self._running = None
def preempt(self, job=None): def preempt(self, job=None):
# self._evts = deque([e for e in self._evts if e[0] != PREEMPT])
self._evts.clear_events(PREEMPT) self._evts.clear_events(PREEMPT)
self._evts.append((PREEMPT,)) self._evts.append((PREEMPT,))
self._running = job self._running = job
def fail(self, fault=None):
self._evts.append((FAIL, fault))
self._fault = fault # TODO: check if I need this
def timer(self, timer): def timer(self, timer):
self._evts.append((TIMER, timer)) self._evts.append((TIMER, timer))
...@@ -202,6 +207,13 @@ class Processor: ...@@ -202,6 +207,13 @@ class Processor:
evt[1].call_handler() evt[1].call_handler()
elif evt[0] == SPEED: elif evt[0] == SPEED:
self._speed = evt[1] self._speed = evt[1]
elif evt[0] == FAIL:
if self._fault is not None:
self.sched.processors.remove(self)
elif not self in self.sched.processors:
self.sched.processors.append(self)
self.resched() # TODO: changed from preempt, check if still works
elif evt[0] == RESCHED: elif evt[0] == RESCHED:
self.monitor.observe(ProcOverheadEvent("Scheduling")) self.monitor.observe(ProcOverheadEvent("Scheduling"))
self.sched.monitor_begin_schedule(self) self.sched.monitor_begin_schedule(self)
......
...@@ -14,12 +14,12 @@ from simso.core.SchedulerEvent import SchedulerBeginScheduleEvent, \ ...@@ -14,12 +14,12 @@ from simso.core.SchedulerEvent import SchedulerBeginScheduleEvent, \
SchedulerEndTerminateEvent SchedulerEndTerminateEvent
class SchedulerInfo(object): class SchedulerInfo(object):
""" """
SchedulerInfo groups the data that characterize a Scheduler (such as the SchedulerInfo groups the data that characterize a Scheduler (such as the
scheduling overhead) and do the dynamic loading of the scheduler. scheduling overhead) and do the dynamic loading of the scheduler.
""" """
def __init__(self, clas='', overhead=0, overhead_activate=0, def __init__(self, clas='', overhead=0, overhead_activate=0,
overhead_terminate=0, fields=None): overhead_terminate=0, fields=None):
""" """
...@@ -142,7 +142,7 @@ class Scheduler(object): ...@@ -142,7 +142,7 @@ class Scheduler(object):
self.sim = sim self.sim = sim
self.processors = [] self.processors = []
self.task_list = [] self.task_list = []
self._lock = Resource(sim) self._lock = Resource(sim)
self.overhead = scheduler_info.overhead self.overhead = scheduler_info.overhead
self.overhead_activate = scheduler_info.overhead_activate self.overhead_activate = scheduler_info.overhead_activate
self.overhead_terminate = scheduler_info.overhead_terminate self.overhead_terminate = scheduler_info.overhead_terminate
...@@ -220,7 +220,7 @@ class Scheduler(object): ...@@ -220,7 +220,7 @@ class Scheduler(object):
""" """
Release the lock. Goes in pair with :meth:`get_lock`. Release the lock. Goes in pair with :meth:`get_lock`.
""" """
self._lock.release(request) self._lock.release(request)
def monitor_begin_schedule(self, cpu): def monitor_begin_schedule(self, cpu):
self.monitor.observe(SchedulerBeginScheduleEvent(cpu)) self.monitor.observe(SchedulerBeginScheduleEvent(cpu))
......
...@@ -16,7 +16,6 @@ class InstanceTimer: ...@@ -16,7 +16,6 @@ class InstanceTimer:
self.cpu = timer.cpu self.cpu = timer.cpu
self.running = False self.running = False
self.overhead = timer.overhead self.overhead = timer.overhead
self.process = self._sim.process(self.run())
def call_handler(self): def call_handler(self):
if self.running: if self.running:
......
...@@ -42,6 +42,7 @@ class WCET(AbstractExecutionTimeModel): ...@@ -42,6 +42,7 @@ class WCET(AbstractExecutionTimeModel):
def get_ret(self, job): def get_ret(self, job):
wcet_cycles = int(job.wcet * self.sim.cycles_per_ms) wcet_cycles = int(job.wcet * self.sim.cycles_per_ms)
# TODO: this leads to rounding errors, use ceil?
return int(wcet_cycles - self.get_executed(job)) return int(wcet_cycles - self.get_executed(job))
def update(self): def update(self):
......
...@@ -8,6 +8,7 @@ class ProcessorR(object): ...@@ -8,6 +8,7 @@ class ProcessorR(object):
Add information about a processor such as the number of CxtSave and Add information about a processor such as the number of CxtSave and
CxtLoad and their total overhead. CxtLoad and their total overhead.
""" """
def __init__(self): def __init__(self):
self.context_save_overhead = 0 self.context_save_overhead = 0
self.context_save_count = 0 self.context_save_count = 0
...@@ -20,6 +21,7 @@ class SchedulerR(object): ...@@ -20,6 +21,7 @@ class SchedulerR(object):
Add information about the scheduler such as the number of scheduling Add information about the scheduler such as the number of scheduling
events and their total overhead. events and their total overhead.
""" """
def __init__(self): def __init__(self):
self.schedule_overhead = 0 self.schedule_overhead = 0
self.activate_overhead = 0 self.activate_overhead = 0
...@@ -36,6 +38,7 @@ class TaskR(object): ...@@ -36,6 +38,7 @@ class TaskR(object):
The attribute jobs contains a list of JobR, sorted by activation date. The attribute jobs contains a list of JobR, sorted by activation date.
""" """
def __init__(self, task, delta_preemption=100): def __init__(self, task, delta_preemption=100):
self.task = task self.task = task
self.delta_preemption = delta_preemption self.delta_preemption = delta_preemption
...@@ -144,6 +147,7 @@ class JobR(object): ...@@ -144,6 +147,7 @@ class JobR(object):
Add a set of metrics to a job. Such metrics include: preemption count, Add a set of metrics to a job. Such metrics include: preemption count,
migration count, response time, etc. migration count, response time, etc.
""" """
def __init__(self, date, job): def __init__(self, date, job):
self.job = job self.job = job
self.preemption_count = 0 self.preemption_count = 0
...@@ -206,6 +210,7 @@ class Results(object): ...@@ -206,6 +210,7 @@ class Results(object):
. .
""" """
def __init__(self, model): def __init__(self, model):
self.model = model self.model = model
self.error = None self.error = None
...@@ -235,7 +240,7 @@ class Results(object): ...@@ -235,7 +240,7 @@ class Results(object):
for task in self.model.task_list: for task in self.model.task_list:
if indices[task] < len(monitors[task]): if indices[task] < len(monitors[task]):
evt = monitors[task][indices[task]] evt = monitors[task][indices[task]]
if m is None or evt[1].id_ < m[0][1].id_: if m is None or evt[1].id_ < m[0][1].id_: # pylint: disable=E1136
m = (evt, task) m = (evt, task)
if m is None: if m is None:
break break
......
...@@ -5,9 +5,11 @@ architectures. ...@@ -5,9 +5,11 @@ architectures.
from simso.core import Scheduler from simso.core import Scheduler
from simso.schedulers import scheduler from simso.schedulers import scheduler
@scheduler("simso.schedulers.EDF") @scheduler("simso.schedulers.EDF")
class EDF(Scheduler): class EDF(Scheduler):
"""Earliest Deadline First""" """Earliest Deadline First"""
def on_activate(self, job): def on_activate(self, job):
job.cpu.resched() job.cpu.resched()
...@@ -22,7 +24,7 @@ class EDF(Scheduler): ...@@ -22,7 +24,7 @@ class EDF(Scheduler):
if ready_jobs: if ready_jobs:
# Select a free processor or, if none, # Select a free processor or, if none,
# the one with the greatest deadline (self in case of equality): # the one with the greatest deadline (self in case of equality):
key = lambda x: ( def key(x): return (
1 if not x.running else 0, 1 if not x.running else 0,
x.running.absolute_deadline if x.running else 0, x.running.absolute_deadline if x.running else 0,
1 if x is cpu else 0 1 if x is cpu else 0
...@@ -34,5 +36,5 @@ class EDF(Scheduler): ...@@ -34,5 +36,5 @@ class EDF(Scheduler):
if (cpu_min.running is None or if (cpu_min.running is None or
cpu_min.running.absolute_deadline > job.absolute_deadline): cpu_min.running.absolute_deadline > job.absolute_deadline):
print(self.sim.now, job.name, cpu_min.name) # print(self.sim.now, job.name, cpu_min.name)
return (job, cpu_min) return (job, cpu_min)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment