Commit 51cc596f by Michael Schmid

Much work on faults and fault events

parent b2352129
...@@ -9,7 +9,7 @@ from simso.core.Scheduler import SchedulerInfo ...@@ -9,7 +9,7 @@ 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.core.Fault import FaultInfo, FaultFactory
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
...@@ -63,6 +63,7 @@ class Configuration(object): ...@@ -63,6 +63,7 @@ class Configuration(object):
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 self.fault_info_list = parser.fault_info_list
self.fault_data_fields = parser.fault_data_fields
else: else:
self.etm = "wcet" self.etm = "wcet"
self.duration = 100000000 self.duration = 100000000
...@@ -75,6 +76,7 @@ class Configuration(object): ...@@ -75,6 +76,7 @@ class Configuration(object):
self._proc_info_list = [] self._proc_info_list = []
self.proc_data_fields = {} self.proc_data_fields = {}
self.fault_info_list = [] self.fault_info_list = []
self.fault_data_fields = {}
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()
...@@ -193,20 +195,20 @@ class Configuration(object): ...@@ -193,20 +195,20 @@ class Configuration(object):
"Activation date must be positive." "Activation date must be positive."
# Period >= 0: # Period >= 0:
assert task.period >= 0, "Tasks' periods must be positives." assert task.period > 0, "Tasks' periods must be positives."
# Deadline >= 0: # Deadline >= 0:
assert task.deadline >= 0, "Tasks' deadlines must be positives." assert task.deadline > 0, "Tasks' deadlines must be positives."
# N_instr >= 0: # N_instr >= 0:
assert task.n_instr >= 0, \ assert task.n_instr >= 0, \
"A number of instructions must be positive." "A number of instructions must be positive."
# WCET >= 0: # WCET >= 0:
assert task.wcet >= 0, "WCET must be positive." assert task.wcet > 0, "WCET must be positive."
# ACET >= 0: # ACET >= 0:
assert task.acet >= 0, "ACET must be positive." assert task.acet > 0, "ACET must be positive."
# ET-STDDEV >= 0: # ET-STDDEV >= 0:
assert task.et_stddev >= 0, \ assert task.et_stddev >= 0, \
...@@ -286,7 +288,7 @@ class Configuration(object): ...@@ -286,7 +288,7 @@ class Configuration(object):
def add_task(self, name, identifier, task_type="Periodic", def add_task(self, name, identifier, task_type="Periodic",
abort_on_miss=True, period=10, activation_date=0, abort_on_miss=True, period=10, activation_date=0,
n_instr=0, mix=0.5, stack_file="", wcet=0, acet=0, pwcet=(0, 1.0), pmit=(0, 1.0), n_instr=0, mix=0.5, stack_file="", wcet=1, acet=1, pwcet=(1, 1.0), pmit=(0, 1.0),
et_stddev=0, deadline=10, base_cpi=1.0, followed_by=None, et_stddev=0, deadline=10, base_cpi=1.0, followed_by=None,
list_activation_dates=[], preemption_cost=0, data=None): list_activation_dates=[], preemption_cost=0, data=None):
""" """
...@@ -320,9 +322,11 @@ class Configuration(object): ...@@ -320,9 +322,11 @@ class Configuration(object):
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): def add_fault(self, fault_type: str, start_time, end_time, target, value=None, parameter=None):
""" """
Helper method to create a FaultInfo and add it to the list of faults. Helper method to create a FaultInfo and add it to the list of faults.
""" """
fault = FaultInfo(start_time, end_time, fault_function) fault_info = FaultInfo(fault_type, start_time,
self.fault_info_list.append(fault) end_time, target, value, parameter)
self.fault_info_list.append(fault_info)
return fault_info
from simpy import Environment from simpy import Environment
from typing import Callable from typing import Callable
from simso.core.Processor import ProcInfo from simso.core.Processor import ProcInfo
from simso.core.Monitor import Monitor
from simso.core.FaultEvent import ProcessorFailureEvent, VoltageChangeEvent, TimingChangeEvent
class FaultFunction: class FaultFunction:
...@@ -18,72 +20,91 @@ class FaultInfo: ...@@ -18,72 +20,91 @@ class FaultInfo:
The FaultType class is responsible for causing the error. The FaultType class is responsible for causing the error.
""" """
def __init__(self, start_time: float, end_time: float, fault_function: FaultFunction): def __init__(self, fault_type: str, start_time: float, end_time: float,
fault_target, value, parameter: str):
self.fault_type = fault_type
self.start_time = start_time self.start_time = start_time
self.end_time = end_time self.end_time = end_time
self.fault_function = fault_function self.fault_target = fault_target
self.value = value
self.parameter = parameter
class Fault: class Fault:
""" """
The Fault class is the simpy process for triggering a certain error. The Fault base class is the simpy process for triggering a certain error.
""" """
def __init__(self, sim, fault_type: FaultInfo): def __init__(self, sim, fault_info: FaultInfo, start_function: Callable, end_function: Callable):
self._fault_type = fault_type self._start_function = start_function
self._end_function = end_function
self._fault_info = fault_info
self._sim = sim self._sim = sim
self._monitor = Monitor(name="Monitor" + fault_info.fault_type,
env=sim)
self.process = self._sim.process(self.release()) self.process = self._sim.process(self.release())
@property
def fault_info(self):
return self._fault_info
@property
def duration_ms(self):
return self._fault_info.start_time - self._fault_info.end_time
@property
def duration_cycles(self):
return (self._fault_info.start_time - self._fault_info.end_time) * self._sim.cycles_per_ms
def release(self): def release(self):
yield self._sim.timeout(self._fault_type.start_time) yield self._sim.timeout(self._fault_info.start_time * self._sim.cycles_per_ms)
self._fault_type.fault_function.start_function(self._sim) self._start_function(self._sim)
yield self._sim.timeout(self._fault_type.end_time - yield self._sim.timeout((self._fault_info.end_time -
self._fault_type.start_time) self._fault_info.start_time) * self._sim.y)
self._fault_type.fault_function.end_function(self._sim) self._end_function(self._sim)
class ProcessorFailure(FaultFunction): # TODO: Does not work when only 1 processor in model, maybe use speed = 0 ?
class ProcessorFailure(Fault):
""" """
The ProcessorFailure class simulates a complete stoppage of a processor. The ProcessorFailure class simulates a complete stoppage of a processor.
""" """
fields = ['fault_target']
def __init__(self, proc_info: ProcInfo): def __init__(self, sim, fault_info):
super().__init__(self.stop_processor, self.start_processor) super().__init__(sim, fault_info, self.stop_processor, self.start_processor)
self._proc_info = proc_info
self._processor = None self._processor = None
def stop_processor(self, model): def stop_processor(self, model):
self._processor = next( self._processor = next(
p for p in model.processors if p.identifier == self._proc_info.identifier) p for p in model.processors if p.identifier == self._fault_info.fault_target.identifier)
self._processor.fail(self) self._processor.fail(self)
self._monitor.observe(ProcessorFailureEvent(self))
def start_processor(self, model): def start_processor(self, model):
self._processor.fail() self._processor.fail()
class VoltageChange(FaultFunction): class VoltageChange(Fault):
def __init__(self, proc_info_list, scaling: float): fields = ['fault_target', 'value']
super().__init__(self.start_voltage_change, self.end_voltage_change)
self._proc_info_list = proc_info_list def __init__(self, sim, fault_info):
self._processor_list = [] super().__init__(sim, fault_info, self.start_voltage_change, self.end_voltage_change)
self._scaling = scaling self._processor = None
def start_voltage_change(self, model): def start_voltage_change(self, model):
affected_ids = [p.identifier for p in self._proc_info_list] self._processor = next(
self._processor_list = [ p for p in model.processors if p.identifier == self._fault_info.fault_target.identifier)
p for p in model.processors if p.identifier in affected_ids] self._processor.set_speed(
for p in self._processor_list: self._fault_info.value * self._processor.speed)
p.set_speed(self._scaling * p.speed) self._monitor.observe(VoltageChangeEvent(self))
def end_voltage_change(self, model): def end_voltage_change(self, model):
for p in self._processor_list: self._processor.set_speed(self._fault_info.fault_target.speed)
speed = next(
pi for pi in self._proc_info_list if pi.identifier == p.identifier).speed
p.set_speed(speed)
class VoltageDrop(VoltageChange): class VoltageDrop(VoltageChange):
...@@ -91,9 +112,9 @@ class VoltageDrop(VoltageChange): ...@@ -91,9 +112,9 @@ class VoltageDrop(VoltageChange):
The VoltageDrop class simulates the slowdown of one or more processors due to voltage drops. The VoltageDrop class simulates the slowdown of one or more processors due to voltage drops.
""" """
def __init__(self, proc_info_list, scaling: float): def __init__(self, sim, fault_info):
assert scaling >= 0 and scaling <= 1.0, "Voltage drop reduces the speed of a processor, i.e. scaling has to be >= 0 and <= 1" assert fault_info.value >= 0 and fault_info.value <= 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) super().__init__(sim, fault_info)
# TODO: rethink this class # TODO: rethink this class
...@@ -126,23 +147,26 @@ class PriorityInversion(FaultFunction): ...@@ -126,23 +147,26 @@ class PriorityInversion(FaultFunction):
pass pass
class TimingChange(FaultFunction): class TimingChange(Fault):
""" """
The TimingError class simulates changes in the timing parameters, e.g. deadline, period etc. The TimingError class simulates changes in the timing parameters, e.g. deadline, period etc.
""" """
def __init__(self, task_info, parameter: str, value: float): fields = ['fault_target', 'parameter', 'value']
super().__init__(self.start_timing_change, self.end_timing_change)
self._task_info = task_info def __init__(self, sim, fault_info):
self._parameter = parameter super().__init__(sim, fault_info, self.start_timing_change, self.end_timing_change)
self._value = value self._old_value = getattr(
self._old_value = getattr(self._task_info, parameter) self._fault_info.fault_target, fault_info.parameter)
def start_timing_change(self, model): def start_timing_change(self, model):
setattr(self._task_info, self._parameter, self._value) setattr(self._fault_info.fault_target, self._fault_info.parameter,
self._fault_info.value)
self._monitor.observe(TimingChangeEvent(self))
def end_timing_change(self, model): def end_timing_change(self, model):
setattr(self._task_info, self._parameter, self._old_value) setattr(self._fault_info.fault_target,
self._fault_info.parameter, self._old_value)
class TimingError(TimingChange): class TimingError(TimingChange):
...@@ -150,11 +174,34 @@ class TimingError(TimingChange): ...@@ -150,11 +174,34 @@ class TimingError(TimingChange):
The TimingError class simulates changes in the timing parameters, e.g. deadline, period etc. The TimingError class simulates changes in the timing parameters, e.g. deadline, period etc.
""" """
def __init__(self, task_info, parameter: str, value: float): def __init__(self, sim, fault_info):
super().__init__(task_info, parameter, value) super().__init__(sim, fault_info)
class Redundancy(TimingChange): class Redundancy(TimingChange):
def __init__(self, task_info, value: float): def __init__(self, sim, fault_info):
super().__init__(task_info, "wcet", task_info.wcet + value) fault_info.parameter = "wcet"
fault_info.value = fault_info.fault_target.wcet + fault_info.value
super().__init__(sim, fault_info)
fault_types = {
"TimingError": TimingError,
"TimingChange": TimingChange,
"Redundancy": Redundancy,
"VoltageChange": VoltageChange,
"VoltageDrop": VoltageDrop,
"ProcessorFailure": ProcessorFailure
}
fault_types_names = ["TimingError", "TimingChange", "Redundancy",
"VoltageChange", "VoltageDrop", "ProcessorFailure"]
def FaultFactory(sim, fault_info):
"""
Task factory. Return and instantiate the correct class according to the
task_info.
"""
return fault_types[fault_info.fault_type](sim, fault_info)
class FaultEvent:
PROCESSOR_FAILURE = 1
VOLTAGE_DROP = 2
VOLTAGE_CHANGE = 3
TIMING_ERROR = 4
TIMING_CHANGE = 5
REDUNDANCY = 6
def __init__(self, event=0, args=None):
self.event = event
self.args = args
class ProcessorFailureEvent(FaultEvent):
def __init__(self, fault):
FaultEvent.__init__(self, FaultEvent.PROCESSOR_FAILURE, fault)
class VoltageChangeEvent(FaultEvent):
def __init__(self, fault):
FaultEvent.__init__(self, FaultEvent.VOLTAGE_CHANGE, fault)
class TimingChangeEvent(FaultEvent):
def __init__(self, fault):
FaultEvent.__init__(self, FaultEvent.TIMING_CHANGE, fault)
...@@ -8,7 +8,7 @@ from simso.core.Timer import Timer ...@@ -8,7 +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 from simso.core.Fault import FaultFactory
class Model(Environment): class Model(Environment):
...@@ -63,7 +63,7 @@ class Model(Environment): ...@@ -63,7 +63,7 @@ class Model(Environment):
self._fault_list = [] self._fault_list = []
for fault_info in fault_info_list: for fault_info in fault_info_list:
self._fault_list.append(Fault(self, fault_info)) self._fault_list.append(FaultFactory(self, fault_info))
# XXX: too specific. # XXX: too specific.
self.penalty_preemption = configuration.penalty_preemption self.penalty_preemption = configuration.penalty_preemption
...@@ -124,6 +124,13 @@ class Model(Environment): ...@@ -124,6 +124,13 @@ class Model(Environment):
return self._task_list return self._task_list
@property @property
def fault_list(self):
"""
List of all faults
"""
return self._fault_list
@property
def duration(self): def duration(self):
""" """
Duration of the simulation. Duration of the simulation.
...@@ -140,12 +147,6 @@ class Model(Environment): ...@@ -140,12 +147,6 @@ class Model(Environment):
self.scheduler.init() self.scheduler.init()
self.progress.start() self.progress.start()
# for cpu in self._processors:
# self.process(cpu.run())
# for task in self._task_list:
# self.process(task.execute())
try: try:
self.run(until=self._duration) self.run(until=self._duration)
finally: finally:
......
...@@ -5,6 +5,7 @@ class ProcEvent(object): ...@@ -5,6 +5,7 @@ class ProcEvent(object):
RUN = 1 RUN = 1
IDLE = 2 IDLE = 2
OVERHEAD = 3 OVERHEAD = 3
FAILED = 4
def __init__(self, event=0, args=None): def __init__(self, event=0, args=None):
self.event = event self.event = event
...@@ -20,6 +21,9 @@ class ProcIdleEvent(ProcEvent): ...@@ -20,6 +21,9 @@ class ProcIdleEvent(ProcEvent):
def __init__(self): def __init__(self):
ProcEvent.__init__(self, ProcEvent.IDLE) ProcEvent.__init__(self, ProcEvent.IDLE)
class ProcFailedEvent(ProcEvent):
def __init__(self, fault):
ProcEvent.__init__(self, ProcEvent.FAILED, fault)
class ProcOverheadEvent(ProcEvent): class ProcOverheadEvent(ProcEvent):
def __init__(self, type_overhead): def __init__(self, type_overhead):
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
from collections import deque from collections import deque
from simpy import Process from simpy import Process
# from SimPy.Simulation import Process, Monitor, hold, waituntil # from SimPy.Simulation import Process, Monitor, hold, waituntil
from simso.core.ProcEvent import ProcRunEvent, ProcIdleEvent, \ from simso.core.ProcEvent import ProcRunEvent, ProcIdleEvent, ProcFailedEvent, \
ProcOverheadEvent, ProcCxtSaveEvent, ProcCxtLoadEvent ProcOverheadEvent, ProcCxtSaveEvent, ProcCxtLoadEvent
from simso.core.Monitor import Monitor from simso.core.Monitor import Monitor
from simso.core.EventQueue import EventQueue from simso.core.EventQueue import EventQueue
...@@ -210,6 +210,8 @@ class Processor: ...@@ -210,6 +210,8 @@ class Processor:
elif evt[0] == FAIL: elif evt[0] == FAIL:
if self._fault is not None: if self._fault is not None:
self.sched.processors.remove(self) self.sched.processors.remove(self)
self.monitor.observe(ProcFailedEvent(self._fault))
# self._model.timeout()
elif not self in self.sched.processors: elif not self in self.sched.processors:
self.sched.processors.append(self) self.sched.processors.append(self)
......
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