Commit b7a117cf by Michael Schmid

added probabilistic model

parent 60517189
# The default ``config.py``
# flake8: noqa
def set_prefs(prefs):
"""This function is called before opening the project"""
# Specify which files and folders to ignore in the project.
# Changes to ignored resources are not added to the history and
# VCSs. Also they are not returned in `Project.get_files()`.
# Note that ``?`` and ``*`` match all characters but slashes.
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
# '.svn': matches 'pkg/.svn' and all of its children
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
'.hg', '.svn', '_svn', '.git', '.tox']
# Specifies which files should be considered python files. It is
# useful when you have scripts inside your project. Only files
# ending with ``.py`` are considered to be python files by
# default.
# prefs['python_files'] = ['*.py']
# Custom source folders: By default rope searches the project
# for finding source folders (folders that should be searched
# for finding modules). You can add paths to that list. Note
# that rope guesses project source folders correctly most of the
# time; use this if you have any problems.
# The folders should be relative to project root and use '/' for
# separating folders regardless of the platform rope is running on.
# 'src/my_source_folder' for instance.
# prefs.add('source_folders', 'src')
# You can extend python path for looking up modules
# prefs.add('python_path', '~/python/')
# Should rope save object information or not.
prefs['save_objectdb'] = True
prefs['compress_objectdb'] = False
# If `True`, rope analyzes each module when it is being saved.
prefs['automatic_soa'] = True
# The depth of calls to follow in static object analysis
prefs['soa_followed_calls'] = 0
# If `False` when running modules or unit tests "dynamic object
# analysis" is turned off. This makes them much faster.
prefs['perform_doa'] = True
# Rope can check the validity of its object DB when running.
prefs['validate_objectdb'] = True
# How many undos to hold?
prefs['max_history_items'] = 32
# Shows whether to save history across sessions.
prefs['save_history'] = True
prefs['compress_history'] = False
# Set the number spaces used for indenting. According to
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
# unit-tests use 4 spaces it is more reliable, too.
prefs['indent_size'] = 4
# Builtin and c-extension modules that are allowed to be imported
# and inspected by rope.
prefs['extension_modules'] = []
# Add all standard c-extensions to extension_modules list.
prefs['import_dynload_stdmods'] = True
# If `True` modules with syntax errors are considered to be empty.
# The default value is `False`; When `False` syntax errors raise
# `rope.base.exceptions.ModuleSyntaxError` exception.
prefs['ignore_syntax_errors'] = False
# If `True`, rope ignores unresolvable imports. Otherwise, they
# appear in the importing namespace.
prefs['ignore_bad_imports'] = False
# If `True`, rope will insert new module imports as
# `from <package> import <module>` by default.
prefs['prefer_module_from_imports'] = False
# If `True`, rope will transform a comma list of imports into
# multiple separate import statements when organizing
# imports.
prefs['split_imports'] = False
# If `True`, rope will remove all top-level import statements and
# reinsert them at the top of the module when making changes.
prefs['pull_imports_to_top'] = True
# If `True`, rope will sort imports alphabetically by module name instead
# of alphabetically by import statement, with from imports after normal
# imports.
prefs['sort_imports_alphabetically'] = False
# Location of implementation of
# rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general
# case, you don't have to change this value, unless you're an rope expert.
# Change this value to inject you own implementations of interfaces
# listed in module rope.base.oi.type_hinting.providers.interfaces
# For example, you can add you own providers for Django Models, or disable
# the search type-hinting in a class hierarchy, etc.
prefs['type_hinting_factory'] = (
'rope.base.oi.type_hinting.factory.default_type_hinting_factory')
def project_opened(project):
"""This function is called after opening the project"""
# Do whatever you like here!
...@@ -17,15 +17,17 @@ def main(argv): ...@@ -17,15 +17,17 @@ def main(argv):
# Manual configuration: # Manual configuration:
configuration = Configuration() configuration = Configuration()
configuration.cycles_per_ms = 1
configuration.duration = 420 * configuration.cycles_per_ms configuration.duration = 420 * 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=7,
activation_date=0, wcet=3, deadline=7) activation_date=0, wcet=3, 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=12) activation_date=0, wcet=3, deadline=8)
configuration.add_task(name="T3", identifier=3, period=20, configuration.add_task(name="T3", identifier=3, period=20,
activation_date=0, wcet=5, deadline=20) activation_date=0, wcet=5, deadline=9)
# Add a processor: # Add a processor:
configuration.add_processor(name="CPU 1", identifier=1) configuration.add_processor(name="CPU 1", identifier=1)
......
#!/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=6, 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=[(5,0.5), (7, 0.5)], deadline=7, task_type = "Probabilistic",abort_on_miss=True)
# Add a processor:
configuration.add_processor(name="CPU 1", identifier=1)
# Add a scheduler:
configuration.scheduler_info.filename = "./simso/schedulers/DM_mono.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,9 +17,10 @@ setup( ...@@ -17,9 +17,10 @@ setup(
'Topic :: Scientific/Engineering', 'Topic :: Scientific/Engineering',
'Development Status :: 5 - Production/Stable' 'Development Status :: 5 - Production/Stable'
], ],
python_requires='>=3.6',
packages=find_packages(), packages=find_packages(),
install_requires=[ install_requires=[
'SimPy==2.3.1', 'SimPy>=4.0.1',
'numpy>=1.6' 'numpy>=1.6'
], ],
long_description="""\ long_description="""\
......
...@@ -8,6 +8,8 @@ from simso.core.Scheduler import SchedulerInfo ...@@ -8,6 +8,8 @@ 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.generator.task_generator import gen_probabilistic_arrivals
from simso.generator.task_generator import cdf
from .GenerateConfiguration import generate from .GenerateConfiguration import generate
from .parser import Parser from .parser import Parser
...@@ -38,6 +40,7 @@ class Configuration(object): ...@@ -38,6 +40,7 @@ class Configuration(object):
of this class will be passed to the constructor of the of this class will be passed to the constructor of the
:class:`Model <simso.core.Model.Model>` class. :class:`Model <simso.core.Model.Model>` class.
""" """
def __init__(self, filename=None): def __init__(self, filename=None):
""" """
Args: Args:
...@@ -279,7 +282,7 @@ class Configuration(object): ...@@ -279,7 +282,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, n_instr=0, mix=0.5, stack_file="", wcet=0, acet=0, pwcet=(0, 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):
""" """
...@@ -288,9 +291,14 @@ class Configuration(object): ...@@ -288,9 +291,14 @@ class Configuration(object):
if data is None: if data is None:
data = dict((k, None) for k in self.task_data_fields) data = dict((k, None) for k in self.task_data_fields)
if task_type == "Probabilistic":
list_activation_dates = gen_probabilistic_arrivals(
pmit, activation_date, self.duration, False)
pwcet = cdf(pwcet)
task = TaskInfo(name, identifier, task_type, abort_on_miss, period, task = TaskInfo(name, identifier, task_type, abort_on_miss, period,
activation_date, n_instr, mix, activation_date, n_instr, mix,
(stack_file, self.cur_dir), wcet, acet, et_stddev, (stack_file, self.cur_dir), wcet, acet, pwcet, et_stddev,
deadline, base_cpi, followed_by, list_activation_dates, deadline, base_cpi, followed_by, list_activation_dates,
preemption_cost, data) preemption_cost, data)
self.task_info_list.append(task) self.task_info_list.append(task)
......
...@@ -112,6 +112,7 @@ def generate_tasks(top, task_info_list, fields): ...@@ -112,6 +112,7 @@ def generate_tasks(top, task_info_list, fields):
'mix': str(task.mix), 'mix': str(task.mix),
'WCET': str(task.wcet), 'WCET': str(task.wcet),
'ACET': str(task.acet), 'ACET': str(task.acet),
'PWCET': str(task.pwcet),
'preemption_cost': str(task.preemption_cost), 'preemption_cost': str(task.preemption_cost),
'et_stddev': str(task.et_stddev)}) 'et_stddev': str(task.et_stddev)})
if task.followed_by is not None: if task.followed_by is not None:
......
...@@ -44,6 +44,7 @@ class Job(Process): ...@@ -44,6 +44,7 @@ class Job(Process):
self._monitor = monitor self._monitor = monitor
self._etm = etm self._etm = etm
self._was_running_on = task.cpu self._was_running_on = task.cpu
self._wcet = task.wcet
self._on_activate() self._on_activate()
...@@ -106,7 +107,8 @@ class Job(Process): ...@@ -106,7 +107,8 @@ class Job(Process):
self._monitor.observe(JobEvent(self, JobEvent.ABORTED)) self._monitor.observe(JobEvent(self, JobEvent.ABORTED))
self._task.end_job(self) self._task.end_job(self)
self._task.cpu.terminate(self) self._task.cpu.terminate(self)
self._sim.logger.log("Job " + str(self.name) + " aborted! ret:" + str(self.ret)) self._sim.logger.log("Job " + str(self.name) +
" aborted! ret:" + str(self.ret))
def is_running(self): def is_running(self):
""" """
...@@ -243,7 +245,11 @@ class Job(Process): ...@@ -243,7 +245,11 @@ class Job(Process):
Worst-Case Execution Time in milliseconds. Worst-Case Execution Time in milliseconds.
Equivalent to ``self.task.wcet``. Equivalent to ``self.task.wcet``.
""" """
return self._task.wcet return self._wcet
@wcet.setter
def wcet(self, value):
self._wcet = value
@property @property
def activation_date(self): def activation_date(self):
...@@ -314,3 +320,11 @@ class Job(Process): ...@@ -314,3 +320,11 @@ class Job(Process):
else: else:
self.interruptReset() self.interruptReset()
class SequentialJob(Job):
pass
class ParallelJob(Job):
pass
...@@ -7,6 +7,7 @@ from simso.core.Timer import Timer ...@@ -7,6 +7,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
import SimPy as SPPc
class Model(Simulation): class Model(Simulation):
...@@ -26,6 +27,7 @@ class Model(Simulation): ...@@ -26,6 +27,7 @@ class Model(Simulation):
Methods: Methods:
""" """
print(SPPc.__version__)
Simulation.__init__(self) Simulation.__init__(self)
self._logger = Logger(self) self._logger = Logger(self)
task_info_list = configuration.task_info_list task_info_list = configuration.task_info_list
......
...@@ -18,7 +18,7 @@ class TaskInfo(object): ...@@ -18,7 +18,7 @@ class TaskInfo(object):
""" """
def __init__(self, name, identifier, task_type, abort_on_miss, period, def __init__(self, name, identifier, task_type, abort_on_miss, period,
activation_date, n_instr, mix, stack_file, wcet, acet, activation_date, n_instr, mix, stack_file, wcet, acet, pwcet,
et_stddev, deadline, base_cpi, followed_by, et_stddev, deadline, base_cpi, followed_by,
list_activation_dates, preemption_cost, data): list_activation_dates, preemption_cost, data):
""" """
...@@ -33,6 +33,7 @@ class TaskInfo(object): ...@@ -33,6 +33,7 @@ class TaskInfo(object):
:type stack_file: str :type stack_file: str
:type wcet: float :type wcet: float
:type acet: float :type acet: float
:type pwcet: list
:type et_stddev: float :type et_stddev: float
:type deadline: float :type deadline: float
:type base_cpi: float :type base_cpi: float
...@@ -62,6 +63,7 @@ class TaskInfo(object): ...@@ -62,6 +63,7 @@ class TaskInfo(object):
self.list_activation_dates = list_activation_dates self.list_activation_dates = list_activation_dates
self.data = data self.data = data
self.preemption_cost = preemption_cost self.preemption_cost = preemption_cost
self._pwcet = pwcet
@property @property
def csdp(self): def csdp(self):
...@@ -316,7 +318,7 @@ class PTask(GenericTask): ...@@ -316,7 +318,7 @@ class PTask(GenericTask):
self._sim.cycles_per_ms) self._sim.cycles_per_ms)
while True: while True:
#print self.sim.now(), "activate", self.name # print self.sim.now(), "activate", self.name
self.create_job() self.create_job()
yield hold, self, int(self.period * self._sim.cycles_per_ms) yield hold, self, int(self.period * self._sim.cycles_per_ms)
...@@ -341,13 +343,38 @@ class SporadicTask(GenericTask): ...@@ -341,13 +343,38 @@ class SporadicTask(GenericTask):
return self._task_info.list_activation_dates return self._task_info.list_activation_dates
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']
def execute(self):
self._init()
for ndate in self.list_activation_dates:
yield hold, self, int(ndate * self._sim.cycles_per_ms) \
- self._sim.now()
self.create_job()
@property
def list_activation_dates(self):
return self._task_info.list_activation_dates
@property
def pwcet(self):
return self._task_info._pwcet
task_types = { task_types = {
"Periodic": PTask, "Periodic": PTask,
"APeriodic": ATask, "APeriodic": ATask,
"Sporadic": SporadicTask "Sporadic": SporadicTask,
"Probabilistic": ProbabilisticTask
} }
task_types_names = ["Periodic", "APeriodic", "Sporadic"] task_types_names = ["Periodic", "APeriodic", "Sporadic", "Probabilistic"]
def Task(sim, task_info): def Task(sim, task_info):
...@@ -355,5 +382,4 @@ def Task(sim, task_info): ...@@ -355,5 +382,4 @@ def Task(sim, task_info):
Task factory. Return and instantiate the correct class according to the Task factory. Return and instantiate the correct class according to the
task_info. task_info.
""" """
return task_types[task_info.task_type](sim, task_info) return task_types[task_info.task_type](sim, task_info)
import random
from simso.core.etm.AbstractExecutionTimeModel \
import AbstractExecutionTimeModel
class PWCET(AbstractExecutionTimeModel):
def __init__(self, sim, _):
self.sim = sim
self.executed = {}
self.on_execute_date = {}
def init(self):
pass
def update_executed(self, job):
if job in self.on_execute_date:
self.executed[job] += (self.sim.now() - self.on_execute_date[job]
) * job.cpu.speed
del self.on_execute_date[job]
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
def on_execute(self, job):
self.on_execute_date[job] = self.sim.now()
def on_preempted(self, job):
self.update_executed(job)
def on_terminated(self, job):
self.update_executed(job)
def on_abort(self, job):
self.update_executed(job)
def get_executed(self, job):
if job in self.on_execute_date:
c = (self.sim.now() - self.on_execute_date[job]) * job.cpu.speed
else:
c = 0
return self.executed[job] + c
def get_ret(self, job):
wcet_cycles = int(job.wcet * self.sim.cycles_per_ms)
return int(wcet_cycles - self.get_executed(job))
def update(self):
for job in list(self.on_execute_date.keys()):
self.update_executed(job)
from .WCET import WCET from .WCET import WCET
from .ACET import ACET from .ACET import ACET
from .PWCET import PWCET
from .CacheModel import CacheModel from .CacheModel import CacheModel
from .FixedPenalty import FixedPenalty from .FixedPenalty import FixedPenalty
...@@ -7,12 +8,14 @@ execution_time_models = { ...@@ -7,12 +8,14 @@ execution_time_models = {
'wcet': WCET, 'wcet': WCET,
'acet': ACET, 'acet': ACET,
'cache': CacheModel, 'cache': CacheModel,
'fixedpenalty': FixedPenalty 'fixedpenalty': FixedPenalty,
'pwcet': PWCET
} }
execution_time_model_names = { execution_time_model_names = {
'WCET': 'wcet', 'WCET': 'wcet',
'ACET': 'acet', 'ACET': 'acet',
'Cache Model': 'cache', 'Cache Model': 'cache',
'Fixed Penalty': 'fixedpenalty' 'Fixed Penalty': 'fixedpenalty',
'Probabilistic WCET': 'pwcet'
} }
...@@ -5,6 +5,7 @@ Tools for generating task sets. ...@@ -5,6 +5,7 @@ Tools for generating task sets.
import numpy as np import numpy as np
import random import random
import math import math
from functools import reduce
def UUniFastDiscard(n, u, nsets): def UUniFastDiscard(n, u, nsets):
...@@ -68,7 +69,7 @@ def StaffordRandFixedSum(n, u, nsets): ...@@ -68,7 +69,7 @@ def StaffordRandFixedSum(n, u, nsets):
if n < u: if n < u:
return None return None
#deal with n=1 case # deal with n=1 case
if n == 1: if n == 1:
return np.tile(np.array([u]), [nsets, 1]) return np.tile(np.array([u]), [nsets, 1])
...@@ -113,8 +114,8 @@ def StaffordRandFixedSum(n, u, nsets): ...@@ -113,8 +114,8 @@ def StaffordRandFixedSum(n, u, nsets):
x[n - 1, ...] = sm + pr * s x[n - 1, ...] = sm + pr * s
#iterated in fixed dimension order but needs to be randomised # iterated in fixed dimension order but needs to be randomised
#permute x row order within each column # permute x row order within each column
for i in range(0, nsets): for i in range(0, nsets):
x[..., i] = x[np.random.permutation(n), i] x[..., i] = x[np.random.permutation(n), i]
...@@ -218,10 +219,11 @@ def next_arrival_poisson(period): ...@@ -218,10 +219,11 @@ def next_arrival_poisson(period):
return -math.log(1.0 - random.random()) * period return -math.log(1.0 - random.random()) * period
def gen_arrivals(period, min_, max_, round_to_int=False): def trunc(x, p):
def trunc(x, p): return int(x * 10 ** p) / float(10 ** p)
return int(x * 10 ** p) / float(10 ** p)
def gen_arrivals(period, min_, max_, round_to_int=False):
dates = [] dates = []
n = min_ - period n = min_ - period
while True: while True:
...@@ -236,6 +238,28 @@ def gen_arrivals(period, min_, max_, round_to_int=False): ...@@ -236,6 +238,28 @@ def gen_arrivals(period, min_, max_, round_to_int=False):
return dates return dates
def cdf(tuple_array):
sorted_tuples = sorted(tuple_array, key=lambda x: x[0])
return [reduce(lambda x, y: (y[0], x[1]+y[1]), sorted_tuples[:i+1]) for i in range(0, len(sorted_tuples))]
def gen_probabilistic_arrivals(pmit, min_, max_, round_to_int=False):
dates = [min_]
cdf_mit = cdf(pmit)
n = 0
while True:
n += next(x[0] for x in cdf_mit if random.random() < x[1])
if round_to_int:
n = int(round(n))
else:
n = trunc(n, 6)
if n > max_:
break
dates.append(n)
return dates
def gen_periods_loguniform(n, nsets, min_, max_, round_to_int=False): def gen_periods_loguniform(n, nsets, min_, max_, round_to_int=False):
""" """
Generate a list of `nsets` sets containing each `n` random periods using a Generate a list of `nsets` sets containing each `n` random periods using a
......
"""
Deadline Monotonic algorithm for uniprocessor architectures.
"""
from simso.core import Scheduler
from simso.schedulers import scheduler
@scheduler("simso.schedulers.DM_mono")
class DM_mono(Scheduler):
def init(self):
self.ready_list = []
def on_activate(self, job):
self.ready_list.append(job)
job.cpu.resched()
def on_terminated(self, job):
self.ready_list.remove(job)
job.cpu.resched()
def schedule(self, cpu):
if self.ready_list:
# job with the highest priority based on deadline
job = min(self.ready_list, key=lambda x: x.task.deadline)
else:
job = None
return (job, 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