Commit c72e411d by Michael Schmid

Minor changes and bugfixes, import amalthea model

parent 51cc596f
# -*- coding: utf-8 -*-
import sys
import os
sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..')))
import simso # nopep8
#!/usr/bin/python3
"""
Example of a script that uses SimSo.
"""
import sys
import random
from numpy import arange
from context import simso
from simso.core import Model
from simso.configuration import Configuration
from simso.generator.task_generator import gen_periods_uniform, UUniFastDiscard, gen_tasksets, gen_faults, gen_arrivals
import pickle
def main(argv):
# Manual configuration:
schedulers = ["./simso/schedulers/RM.py", "./simso/schedulers/EDF.py","./simso/schedulers/P_RM.py","./simso/schedulers/P_EDF.py"]
# schedulers = []
configuration = Configuration()
configuration.cycles_per_ms = 1000
configuration.etm = "wcet"
configuration.duration = 1000 * configuration.cycles_per_ms
num_processors = 8
# Add a processor:
for np in range(0, num_processors):
configuration.add_processor(name=f"CPU {np}" , identifier=np)
nsets = 20
for u in arange(1,num_processors +0.1, 0.5):
print(f"Utilization = {u}")
utilizations = UUniFastDiscard(20, u, nsets)
periods = gen_periods_uniform(20, nsets, 2, 100)
tasksets = gen_tasksets(utilizations, periods)
missed_deadlines = {}
for sched in schedulers:
missed_deadlines[sched] = 0
for n in range(nsets):
configuration._task_info_list = []
for t in tasksets[n]:
identifier = tasksets[n].index(t)
configuration.add_task(name="t" + str(identifier), identifier=identifier,period=t[1],wcet=t[0],deadline=t[1])
faults = gen_faults(n_faults=5,task_info_list=configuration._task_info_list,processor_info_list=configuration._proc_info_list, sim_duration=configuration.duration_ms)
for f in faults:
configuration.add_fault(fault_type=f['fault_type'], start_time=f['start_time'], end_time=f['end_time'],
fault_target=f['fault_target'], parameter=f.get('parameter'), value=f.get('value'))
for sched in schedulers:
configuration.scheduler_info.filename = sched
# Check the config before trying to run it.
configuration.check_all()
# Init a model from the configuration.
model = Model(configuration)
# Execute the simulation.
try:
model.run_model()
except RuntimeError as e:
if e.args[0] != "Bin packing failed!":
raise e
missed_deadlines[sched] += 1
except AssertionError:
missed_deadlines[sched] += 1
except ValueError:
with open('failed_configuration.pkl', 'wb') as out:
pickle.dump(configuration, out, pickle.HIGHEST_PROTOCOL)
if model.results is not None and model.results.total_exceeded_count > 0:
missed_deadlines[sched] += 1
for sched in schedulers:
print(f"{sched}: {missed_deadlines[sched]}")
# # # Print logs.
# # for log in model.logs:
# # print(log)
main(sys.argv)
\ No newline at end of file
......@@ -5,42 +5,23 @@ Example of a script that uses SimSo.
"""
import sys
from context import simso
from simso.core import Model
from simso.core.Fault import ProcessorFailure, VoltageDrop, PriorityInversion, TimingError
from simso.configuration import Configuration
from simso.configuration.parser import AmaltheaModelParser
import pickle
def main(argv):
if len(argv) == 2:
# Configuration load from a file.
configuration = Configuration(argv[1])
else:
# Manual configuration:
configuration = Configuration()
# Manual configuration:
configuration = Configuration("./misc/mobstr.amxmi")
configuration.cycles_per_ms = 1
configuration.cycles_per_ms = 1000
configuration.duration = 100 * configuration.cycles_per_ms
configuration.duration = 100 * configuration.cycles_per_ms
# Add tasks:
configuration.add_task(name="T1", identifier=1, period=8,
activation_date=0, wcet=4, deadline=7)
configuration.add_task(name="T2", identifier=2, period=12,
activation_date=0, wcet=3, deadline=8)
configuration.add_task(name="T3", identifier=3, period=15,
activation_date=0, wcet=5, deadline=14)
task = configuration.add_task(name="T4", identifier=4, period=20,
activation_date=0, wcet=6, deadline=12)
# Add a processor:
configuration.add_processor(name="CPU 1", identifier=1)
proc = configuration.add_processor(name="CPU 2", identifier=2)
configuration.add_fault(TimingError(task, "period", 8), 0, 21)
# Add a scheduler:
#configuration.scheduler_info.filename = "../simso/schedulers/RM.py"
configuration.scheduler_info.clas = "simso.schedulers.EDF"
configuration.scheduler_info.clas = "simso.schedulers.RM"
# Check the config before trying to run it.
configuration.check_all()
......@@ -57,3 +38,9 @@ def main(argv):
main(sys.argv)
# configuration = None
# with open('failed_configuration.pkl','rb') as input:
# configuration = pickle.load(input)
......@@ -5,6 +5,7 @@ Example of a script that uses SimSo.
"""
import sys
from context import simso
from simso.core import Model
from simso.configuration import Configuration
......@@ -17,7 +18,7 @@ def main(argv):
# Manual configuration:
configuration = Configuration()
configuration.cycles_per_ms = 1
configuration.cycles_per_ms = 1000000
configuration.etm = "pwcet"
......@@ -38,8 +39,7 @@ def main(argv):
# 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"
configuration.scheduler_info.filename = "./simso/schedulers/RM.py"
# Check the config before trying to run it.
configuration.check_all()
......
#!/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"
# 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)
......@@ -17,7 +17,7 @@ setup(
'Topic :: Scientific/Engineering',
'Development Status :: 5 - Production/Stable'
],
python_requires='>=3.6',
python_requires='>=3.10',
packages=find_packages(),
install_requires=[
'SimPy>=4.0.1',
......
......@@ -14,7 +14,7 @@ from simso.generator.task_generator import gen_probabilistic_arrivals
from simso.generator.task_generator import cdf
from .GenerateConfiguration import generate
from .parser import Parser
from .parser import Parser, AmaltheaModelParser
# Hack for Python2
......@@ -48,7 +48,24 @@ class Configuration(object):
Args:
- `filename` A file can be used to initialize the configuration.
"""
if filename:
if filename and any(x in filename for x in [".amxmi", ".amxml"]):
parser = AmaltheaModelParser(filename)
self.etm = "wcet"
self.duration = 100
self.cycles_per_ms = 1
self._caches_list = []
self.memory_access_time = 0
self._task_info_list = parser.task_info_list
self.task_data_fields = []
self._proc_info_list = parser.proc_info_list
self.proc_data_fields = []
self._scheduler_info = parser.scheduler_info
self.penalty_preemption = 0
self.penalty_migration = 0
self.fault_info_list = []
self.fault_data_fields=[]
self.mapping_dict = parser.task_mappings
elif filename:
parser = Parser(filename)
self.etm = parser.etm
self.duration = parser.duration
......@@ -64,6 +81,7 @@ class Configuration(object):
self.penalty_migration = parser.penalty_migration
self.fault_info_list = parser.fault_info_list
self.fault_data_fields = parser.fault_data_fields
self.mapping_dict = parser.mapping_dict # TODO:
else:
self.etm = "wcet"
self.duration = 100000000
......@@ -79,6 +97,7 @@ class Configuration(object):
self.fault_data_fields = {}
self.memory_access_time = 100
self._scheduler_info = SchedulerInfo()
self.mapping_dict = None
self.calc_penalty_cache()
self._set_filename(filename)
......@@ -288,7 +307,7 @@ class Configuration(object):
def add_task(self, name, identifier, task_type="Periodic",
abort_on_miss=True, period=10, activation_date=0,
n_instr=0, mix=0.5, stack_file="", wcet=1, acet=1, pwcet=(1, 1.0), pmit=(0, 1.0),
n_instr=0, mix=0.5, stack_file="", wcet=1, acet=1, pwcet=[(1, 1.0)], pmit=[(10, 1.0)],
et_stddev=0, deadline=10, base_cpi=1.0, followed_by=None,
list_activation_dates=[], preemption_cost=0, data=None):
"""
......@@ -299,7 +318,7 @@ class Configuration(object):
if task_type == "Probabilistic":
list_activation_dates = gen_probabilistic_arrivals(
pmit, activation_date, self.duration, False)
pmit, activation_date, self.duration_ms, False)
pwcet = cdf(pwcet)
task = TaskInfo(name, identifier, task_type, abort_on_miss, period,
......@@ -322,11 +341,17 @@ class Configuration(object):
self.proc_info_list.append(proc)
return proc
def add_fault(self, fault_type: str, start_time, end_time, target, value=None, parameter=None):
def add_fault(self, fault_type: str, start_time, end_time, fault_target, value=None, parameter=None):
"""
Helper method to create a FaultInfo and add it to the list of faults.
"""
fault_info = FaultInfo(fault_type, start_time,
end_time, target, value, parameter)
end_time, fault_target, value, parameter)
self.fault_info_list.append(fault_info)
return fault_info
def add_mappings(self, mapping_dict):
"""
Add mappings in the form of Dict[task_info, List[processor_info]]
"""
self.mapping_dict= mapping_dict
\ No newline at end of file
# coding=utf-8
from xml.etree import ElementTree
from xml.dom.minidom import parse
import os.path
from simso.core.Task import TaskInfo, task_types
......@@ -40,6 +41,7 @@ class Parser(object):
def _parse_faults(self):
# TODO: implement parser for faults
self.fault_info_list = []
self.fault_data_fields = {}
def _parse_caches(self):
self.caches_list = []
......@@ -254,3 +256,171 @@ class Parser(object):
if filename and filename[0] != '/':
filename = self.cur_dir + '/' + filename
self.scheduler_info.filename = filename
class AmaltheaModelParser:
def __init__(self, filename):
self.filename = filename
self.cur_dir = os.path.split(filename)[0]
if not self.cur_dir:
self.cur_dir = '.'
tree = ElementTree.parse(filename)
self.root = tree.getroot()
self._parse_processors()
self._parse_scheduler()
# Tasks have to be parsed after processors due to allocation strategies
self._parse_tasks()
def _parse_tasks(self):
self.task_info_list = []
self.task_mappings = {}
identifier = 0
for tag in self.root.findall('swModel/tasks'):
name = tag.attrib['name']
process = f"{tag.attrib['name']}?type=Task"
activations = []
stimuli = self.root.find(f"stimuliModel/stimuli/[@name='{tag.attrib['stimuli'].split('?')[0]}']")
if stimuli.attrib['{http://www.w3.org/2001/XMLSchema-instance}type'] == 'am:PeriodicStimulus':
task_type = "Periodic"
period = stimuli.find(f"[@name='{tag.attrib['stimuli'].split('?')[0]}']/recurrence")
if period is not None:
unit = period.attrib['unit']
period = int(period.attrib['value'])
if unit == 's':
period *= 1000
elif unit == 'us':
period /=1000
elif unit == 'ns':
period /= 1000000
elif unit == 'ps':
period /= 1000000000
elif stimuli.attrib['{http://www.w3.org/2001/XMLSchema-instance}type'] == 'am:ArrivalCurveStimulus':
task_type = 'Sporadic'
activations= stimuli.find(f"[@name='{tag.attrib['stimuli'].split('?')[0]}']/entries")
# TODO: find example
else:
continue
deadline = self.root.find(f"constraintsModel/requirements/[@process='{process}']/limit/limitValue")
if deadline is not None:
deadline = int(deadline.attrib['value'])
else:
deadline = period
priority = self.root.find(f"mappingModel/taskAllocation/[@task='{process}']/schedulingParameters")
if priority is not None:
priority = int(priority.attrib['priority'])
affinities = next(iter(self.root.findall(f"mappingModel/taskAllocation/[@task='{process}']"))).attrib['affinity']
affinities = affinities.split(' ')
affinity_list = []
for i in affinities:
proc = next((p for p in self.proc_info_list if i.split('?')[0] in p.name), None)
affinity_list.append(proc)
wcet = 0
acet = 0
for r in tag.findall(f"./activityGraph/items/items/[@{{http://www.w3.org/2001/XMLSchema-instance}}type='am:RunnableCall']"):
frequency_domain_list = set([p.name.split('_')[1] for p in affinity_list])
processor = affinity_list[0]
if len(frequency_domain_list) > 1:
processor = min(affinity_list, key=lambda x: x.speed)
pname = processor.name.split('_')[1]+ '?type=ProcessingUnitDefinition'
runnable= r.attrib['runnable'].split('?')[0]
runnable = self.root.find(f"swModel/runnables/[@name='{runnable}']/activityGraph/items/[@{{http://www.w3.org/2001/XMLSchema-instance}}type='am:Ticks']/extended/[@key='{pname}']/value")
if runnable is not None:
if runnable.attrib['{http://www.w3.org/2001/XMLSchema-instance}type']== 'am:DiscreteValueConstant':
wcet += float(runnable.attrib['value'])
acet += float(runnable.attrib['value'])
elif runnable.attrib['{http://www.w3.org/2001/XMLSchema-instance}type']== 'am:DiscreteValueStatistics':
wcet += float(runnable.attrib['upperBound'])
acet += float(runnable.attrib['average'])
# wcet[ms] = Ticks (=wcet before) / frequency[Hz] * 1000 [s -> ms]
wcet = wcet/processor.data['speed'] * 1000
acet = acet/processor.data['speed'] * 1000
task = TaskInfo(name=name,
identifier=identifier,
task_type=task_type,
abort_on_miss=True,
period=period,
activation_date=0,
n_instr = 0,
mix =0,
stack_file=("", self.cur_dir),
wcet = wcet,
acet= acet,
pwcet=None,
et_stddev = 0,
deadline=deadline,
base_cpi=0,
followed_by=None,
list_activation_dates=activations,
preemption_cost=0,
data = {'priority': priority})
identifier += 1
self.task_info_list.append(task)
self.task_mappings[task] = affinity_list
def _parse_scheduler(self):
scheduler = self.root.find("osModel/operatingSystems/taskSchedulers/schedulingAlgorithm")
clas = "simso.schedulers.RM"
if scheduler is not None:
scheduler = scheduler.attrib['{http://www.w3.org/2001/XMLSchema-instance}type']
match scheduler:
case "am:FixedPriorityPreemptive":
clas = "simso.schedulers.C_FP"
case "am:EarliestDeadlineFirst":
clas = "simso.schedulers.EDF"
case "am:PfairPD2":
clas = "simso.schedulers.PD2"
case "am:EarlyReleaseFairPD2":
clas = "simso.schedulers.ER_PD2"
case _:
pass
self.scheduler_info = SchedulerInfo(
clas=clas, overhead=0, overhead_activate=0,
overhead_terminate=0, fields=None)
def _parse_processors(self):
self.proc_info_list = []
num_proc = 0
for tag in self.root.findall("hwModel/definitions/[@puType='CPU']"):
for core in self.root.findall(f"hwModel/structures/structures/modules/[@definition='{tag.attrib['name']}?type=ProcessingUnitDefinition']"):
f_domain = self.root.find(f"hwModel/domains/[@name='{core.attrib['frequencyDomain'].split('?')[0]}']/defaultValue")
unit = f_domain.attrib['unit']
speed = float(f_domain.attrib['value'])
if unit == 'GHz':
speed *= 1000000000
elif unit == 'MHz':
speed *= 1000000
elif unit == 'KHz':
speed *= 1000
proc = ProcInfo(name= core.attrib['name']+ "_" + tag.attrib['name'],
identifier=num_proc,
speed=speed, data={'speed':speed})
self.proc_info_list.append(proc)
num_proc+=1
# adjust speed to range in 0 - 1
max_speed = max(p.speed for p in self.proc_info_list)
for p in self.proc_info_list:
p.speed = p.speed / max_speed
\ No newline at end of file
......@@ -3,6 +3,7 @@ from typing import Callable
from simso.core.Processor import ProcInfo
from simso.core.Monitor import Monitor
from simso.core.FaultEvent import ProcessorFailureEvent, VoltageChangeEvent, TimingChangeEvent
from simso.core.JobEvent import JobEvent
class FaultFunction:
......@@ -50,11 +51,11 @@ class Fault:
@property
def duration_ms(self):
return self._fault_info.start_time - self._fault_info.end_time
return self._fault_info.end_time - self._fault_info.start_time
@property
def duration_cycles(self):
return (self._fault_info.start_time - self._fault_info.end_time) * self._sim.cycles_per_ms
return self.duration_ms * self._sim.cycles_per_ms
def release(self):
yield self._sim.timeout(self._fault_info.start_time * self._sim.cycles_per_ms)
......@@ -62,7 +63,7 @@ class Fault:
self._start_function(self._sim)
yield self._sim.timeout((self._fault_info.end_time -
self._fault_info.start_time) * self._sim.y)
self._fault_info.start_time) * self._sim.cycles_per_ms)
self._end_function(self._sim)
......@@ -195,9 +196,8 @@ fault_types = {
"ProcessorFailure": ProcessorFailure
}
fault_types_names = ["TimingError", "TimingChange", "Redundancy",
"VoltageChange", "VoltageDrop", "ProcessorFailure"]
fault_types_names = ["TimingError", "VoltageDrop", "ProcessorFailure"]
# "TimingChange", "Redundancy", "VoltageChange",
def FaultFactory(sim, fault_info):
"""
......
......@@ -296,7 +296,12 @@ class Job:
def activate_job(self):
self._start_date = self._sim.now
# Notify the OS.
self._task.cpu.activate(self)
if self._task.cpu.has_failure():
proc = next(p for p in self._sim.processors if not p.has_failure())
proc.activate(self)
proc.resched()
else:
self._task.cpu.activate(self)
# While the job's execution is not finished.
while self._end_date is None:
......
......@@ -61,6 +61,7 @@ class Model(Environment):
proc.caches = proc_info.caches
self._processors.append(proc)
self._fault_list = []
for fault_info in fault_info_list:
self._fault_list.append(FaultFactory(self, fault_info))
......@@ -78,6 +79,7 @@ class Model(Environment):
self._callback = callback
self.scheduler.task_list = self._task_list
self.scheduler.processors = self._processors
self.scheduler.configuration = configuration
self.results = None
def now_ms(self):
......
......@@ -98,8 +98,17 @@ class Processor:
self._running = job
def fail(self, fault=None):
self._evts.append((FAIL, fault))
self._fault = fault # TODO: check if I need this
self._fault = fault
if self._fault is not None:
self.sched.processors.remove(self)
self._evts.append((FAIL, fault))
elif not self in self.sched.processors:
self.sched.processors.append(self)
# self.resched() # TODO: changed from preempt, check if still works
def has_failure(self):
return self._fault is not None
def timer(self, timer):
self._evts.append((TIMER, timer))
......@@ -208,14 +217,8 @@ class Processor:
elif evt[0] == SPEED:
self._speed = evt[1]
elif evt[0] == FAIL:
if self._fault is not None:
self.sched.processors.remove(self)
self.monitor.observe(ProcFailedEvent(self._fault))
# self._model.timeout()
elif not self in self.sched.processors:
self.sched.processors.append(self)
self.resched() # TODO: changed from preempt, check if still works
self.monitor.observe(ProcFailedEvent(self._fault))
yield self._model.timeout(self._fault.duration_cycles)
elif evt[0] == RESCHED:
self.monitor.observe(ProcOverheadEvent("Scheduling"))
self.sched.monitor_begin_schedule(self)
......
# coding=utf-8
import simpy
from simpy import Process
from collections import deque
# from SimPy.Simulation import Process, Monitor, hold, passivate
from simso.core.Job import Job
......@@ -66,7 +64,7 @@ class TaskInfo(object):
self.list_activation_dates = list_activation_dates
self.data = data
self.preemption_cost = preemption_cost
self._pwcet = pwcet
self.pwcet = pwcet
@property
def csdp(self):
......@@ -263,15 +261,18 @@ class GenericTask:
self.followed_by.create_job(job)
if len(self._activations_fifo) > 0:
self._activations_fifo.popleft()
# self._activations_fifo.popleft()
self._activations_fifo.remove(job)
if len(self._activations_fifo) > 0:
self.job = self._activations_fifo[0]
self.job.process = self._sim.process(self.job.activate_job())
def _job_killer(self, job):
if job.end_date is None and job.computation_time < job.wcet:
if job.end_date is None and job.actual_computation_time < job.wcet:
if self._task_info.abort_on_miss:
# self.cancel(job) TODO: How to cancel Job?
# if job.process and job.process.is_alive:
# job.process.interrupt(self)
job.abort()
def create_job(self, pred=None):
......@@ -354,10 +355,9 @@ class ProbabilisticTask(GenericTask):
Probabilistic Task process. Inherits from :class:`GenericTask`. The jobs are
created using a list of probabilistic activation times.
"""
fields = ['list_activation_dates', 'deadline', 'pwcet', 'pmit']
fields = ['period', 'activation_date', 'deadline', 'wcet']
def execute(self):
self._init()
for ndate in self.list_activation_dates:
yield self._sim.timeout(int(ndate * self._sim.cycles_per_ms)
......@@ -370,7 +370,7 @@ class ProbabilisticTask(GenericTask):
@property
def pwcet(self):
return self._task_info._pwcet
return self._task_info.pwcet
task_types = {
......
......@@ -22,7 +22,7 @@ class PWCET(AbstractExecutionTimeModel):
def on_activate(self, job):
self.executed[job] = 0
job.wcet = next(x[0] for x in job.task.pwcet if random.uniform(
0, 1) <= x[1]) * self.sim.cycles_per_ms
0, 1) <= x[1]) # * self.sim.cycles_per_ms
def on_execute(self, job):
self.on_execute_date[job] = self.sim.now
......
from simso.core.etm.AbstractExecutionTimeModel \
import AbstractExecutionTimeModel
from math import ceil
class WCET(AbstractExecutionTimeModel):
def __init__(self, sim, _):
......@@ -42,8 +43,7 @@ class WCET(AbstractExecutionTimeModel):
def get_ret(self, job):
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 ceil(wcet_cycles - self.get_executed(job))
def update(self):
for job in list(self.on_execute_date.keys()):
......
......@@ -6,6 +6,8 @@ import numpy as np
import random
import math
from functools import reduce
from simso.core.Fault import TimingError, ProcessorFailure, VoltageDrop
from simso.core.Task import task_types
def UUniFastDiscard(n, u, nsets):
......@@ -341,3 +343,50 @@ def gen_tasksets(utilizations, periods):
return [[(trunc(ui * pi, 6), trunc(pi, 6)) for ui, pi in zip(us, ps)]
for us, ps in zip(utilizations, periods)]
def gen_faultset(arrivals, durations, fault_types):
faults = []
for a in arrivals:
f = random.choice(fault_types)
d = random.choice(durations)
faults.append((f, a, a + d))
return faults
def gen_faults(n_faults, task_info_list, processor_info_list, sim_duration):
arrivals = []
for i in range(n_faults):
arrivals.append(random.uniform(0, sim_duration))
durations = gen_periods_uniform(len(arrivals), 1, 2, 5)[0]
fault_set = []
for i in range(len(arrivals)):
a = arrivals[i]
d = durations[i]
f = random.choice(["TimingError", "VoltageDrop"]) #"ProcessorFailure",
if f == 'ProcessorFailure':
p = random.choice(processor_info_list)
fault_set.append({'fault_type': f, 'start_time':a, 'end_time':a+d, 'fault_target': p})
elif f == 'TimingError':
t = random.choice(task_info_list)
p = random.choice(task_types[t.task_type].fields)
v = getattr(t, p)
# TODO: gaussian distribution parameter with v
ve = random.uniform(v-0.15*v, v+0.15*v)
fault_set.append({'fault_type': f, 'start_time':a, 'end_time':a+d, 'fault_target': t, 'parameter':p, 'value':v})
elif f == 'VoltageDrop':
p = random.choice(processor_info_list)
v = random.uniform(0.5, 0.9)
fault_set.append({'fault_type': f, 'start_time':a, 'end_time':a+d, 'fault_target': p, 'value':v})
return fault_set
\ No newline at end of file
from simso.core import Scheduler
from simso.schedulers import scheduler
@scheduler("simso.schedulers.C_FP", required_task_fields = [
{'name': 'priority', 'type' : 'int', 'default' : '0' }
]
)
class C_FP(Scheduler):
""" Clustered Fixed-Priority """
def init(self):
self.ready_list = []
self.mappings_dict = {}
for k,v in self.configuration.mapping_dict.items():
task = next(t for t in self.task_list if t._task_info == k)
cpu_list = [p for p in self.processors if p.identifier in [pi.identifier for pi in v]]
self.mappings_dict[task] = cpu_list
task.cpu = self.mappings_dict[task][0]
def on_activate(self, job):
self.ready_list.append(job)
job.cpu.resched()
def on_terminated(self, job):
if job in self.ready_list:
self.ready_list.remove(job)
else:
job.cpu.resched()
def schedule(self, cpu):
if self.ready_list:
# Get the job with the highest priority.
job = max(self.ready_list, key=lambda x: x.data['priority'])
# Get a free processor or a processor running a low priority job.
key = lambda x: (
1 if x.running else 0,
x.running.data['priority'] if x.running else 0,
0 if x is cpu else 1
)
cpu_min = min(self.mappings_dict[job.task], key=key)
if (cpu_min.running is None or
cpu_min.running.data['priority'] < job.data['priority']):
self.ready_list.remove(job)
if cpu_min.running:
self.ready_list.append(cpu_min.running)
return (job, cpu_min)
return None
\ No newline at end of file
from simso.core import Scheduler
from simso.schedulers import scheduler
@scheduler("simso.schedulers.C_RM"
)
class C_RM(Scheduler):
""" Clustered Rate-Monotonic """
def init(self):
self.ready_list = []
self.mappings_dict = {}
for k,v in self.configuration.mapping_dict.items():
task = next(t for t in self.task_list if t._task_info == k)
cpu_list = [p for p in self.processors if p.identifier in [pi.identifier for pi in v]]
self.mappings_dict[task] = cpu_list
def on_activate(self, job):
self.ready_list.append(job)
job.cpu.resched()
def on_terminated(self, job):
if job in self.ready_list:
self.ready_list.remove(job)
else:
job.cpu.resched()
def schedule(self, cpu):
decision = None
if self.ready_list:
# Job with highest priority.
job = min(self.ready_list, key=lambda x: x.period)
# Get a free processor or a processor running a low priority job.
key = lambda x: (
0 if x.running is None else 1,
-x.running.period if x.running else 0,
0 if x is cpu else 1
)
cpu_min = min(self.mappings_dict[job.task], key=key)
if (cpu_min.running is None or
cpu_min.running.period > job.period):
self.ready_list.remove(job)
if cpu_min.running:
self.ready_list.append(cpu_min.running)
decision = (job, cpu_min)
return decision
\ No newline at end of file
......@@ -3,6 +3,7 @@ Partitionned EDF without the helping class.
Use EDF_mono.
"""
from simpy import Resource
from simso.core import Scheduler
from simso.core.Scheduler import SchedulerInfo
from simso.schedulers.EDF_mono import EDF_mono
......@@ -16,6 +17,9 @@ class P_EDF2(Scheduler):
# Mapping task to scheduler.
self.map_task_sched = {}
self._lock = Resource(self.sim)
self.request = None
cpus = []
for cpu in self.processors:
# Append the processor to a list with an initial utilization of 0.
......@@ -36,7 +40,8 @@ class P_EDF2(Scheduler):
while cpus[j][1] + float(task.wcet) / task.period > 1.0:
j += 1
if j >= len(self.processors):
print("oops bin packing failed.")
# print("oops bin packing failed.")
raise RuntimeError("Bin packing failed!")
return
# Get the scheduler for this processor.
......@@ -55,7 +60,9 @@ class P_EDF2(Scheduler):
def get_lock(self):
# No lock mechanism is needed.
return True
self._lock.release(self.request)
self.request = self._lock.request()
return self.request
def schedule(self, cpu):
return self.map_cpu_sched[cpu.identifier].schedule(cpu)
......
from simpy import Resource
from simso.core import Scheduler
......@@ -17,7 +18,7 @@ def best_fit(scheduler, task_list=None):
while cpus[j][1] * task.period + float(task.wcet) > task.period:
j += 1
if j >= len(scheduler.processors):
print("oops bin packing failed.")
# print("oops bin packing failed.")
return False
# Affect it to the task.
......@@ -48,7 +49,7 @@ def worst_fit(scheduler, task_list=None):
while cpus[j][1] * task.period + float(task.wcet) > task.period:
j += 1
if j >= len(scheduler.processors):
print("oops bin packing failed.")
# print("oops bin packing failed.")
return False
# Affect it to the task.
......@@ -80,7 +81,7 @@ def next_fit(scheduler, task_list=None):
j = (j + 1) % len(scheduler.processors)
k += 1
if k >= len(scheduler.processors):
print("oops bin packing failed.")
# print("oops bin packing failed.")
return False
# Affect it to the task.
......@@ -109,7 +110,7 @@ def first_fit(scheduler, task_list=None):
while cpus[j][1] * task.period + float(task.wcet) > task.period:
j += 1
if j >= len(scheduler.processors):
print("oops bin packing failed.")
# print("oops bin packing failed.")
return False
# Affect it to the task.
......@@ -177,6 +178,8 @@ class PartitionedScheduler(Scheduler):
"PartitionedScheduler requires a monoprocessor scheduler to " \
"instantiate."
self._lock = Resource(self.sim)
self.request = None
# Mapping processor to scheduler.
self.map_cpu_sched = {}
# Mapping task to scheduler.
......@@ -211,7 +214,9 @@ class PartitionedScheduler(Scheduler):
def get_lock(self):
# No lock mechanism is needed.
return True
self._lock.release(self.request)
self.request = self._lock.request()
return self.request
def schedule(self, cpu):
return self.map_cpu_sched[cpu.identifier].schedule(cpu)
......
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