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):
# Manual configuration:
configuration = Configuration()
configuration.cycles_per_ms = 1
configuration.duration = 420 * configuration.cycles_per_ms
# Add tasks:
configuration.add_task(name="T1", identifier=1, period=7,
activation_date=0, wcet=3, deadline=7)
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,
activation_date=0, wcet=5, deadline=20)
activation_date=0, wcet=5, deadline=9)
# Add a processor:
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(
'Topic :: Scientific/Engineering',
'Development Status :: 5 - Production/Stable'
],
python_requires='>=3.6',
packages=find_packages(),
install_requires=[
'SimPy==2.3.1',
'SimPy>=4.0.1',
'numpy>=1.6'
],
long_description="""\
......
......@@ -8,6 +8,8 @@ from simso.core.Scheduler import SchedulerInfo
from simso.core import Scheduler
from simso.core.Task import TaskInfo
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 .parser import Parser
......@@ -38,6 +40,7 @@ class Configuration(object):
of this class will be passed to the constructor of the
:class:`Model <simso.core.Model.Model>` class.
"""
def __init__(self, filename=None):
"""
Args:
......@@ -279,7 +282,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=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,
list_activation_dates=[], preemption_cost=0, data=None):
"""
......@@ -288,9 +291,14 @@ class Configuration(object):
if data is None:
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,
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,
preemption_cost, data)
self.task_info_list.append(task)
......
......@@ -112,6 +112,7 @@ def generate_tasks(top, task_info_list, fields):
'mix': str(task.mix),
'WCET': str(task.wcet),
'ACET': str(task.acet),
'PWCET': str(task.pwcet),
'preemption_cost': str(task.preemption_cost),
'et_stddev': str(task.et_stddev)})
if task.followed_by is not None:
......
......@@ -44,6 +44,7 @@ class Job(Process):
self._monitor = monitor
self._etm = etm
self._was_running_on = task.cpu
self._wcet = task.wcet
self._on_activate()
......@@ -106,7 +107,8 @@ class Job(Process):
self._monitor.observe(JobEvent(self, JobEvent.ABORTED))
self._task.end_job(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):
"""
......@@ -243,7 +245,11 @@ class Job(Process):
Worst-Case Execution Time in milliseconds.
Equivalent to ``self.task.wcet``.
"""
return self._task.wcet
return self._wcet
@wcet.setter
def wcet(self, value):
self._wcet = value
@property
def activation_date(self):
......@@ -314,3 +320,11 @@ class Job(Process):
else:
self.interruptReset()
class SequentialJob(Job):
pass
class ParallelJob(Job):
pass
......@@ -7,6 +7,7 @@ from simso.core.Timer import Timer
from simso.core.etm import execution_time_models
from simso.core.Logger import Logger
from simso.core.results import Results
import SimPy as SPPc
class Model(Simulation):
......@@ -26,6 +27,7 @@ class Model(Simulation):
Methods:
"""
print(SPPc.__version__)
Simulation.__init__(self)
self._logger = Logger(self)
task_info_list = configuration.task_info_list
......
......@@ -18,7 +18,7 @@ class TaskInfo(object):
"""
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,
list_activation_dates, preemption_cost, data):
"""
......@@ -33,6 +33,7 @@ class TaskInfo(object):
:type stack_file: str
:type wcet: float
:type acet: float
:type pwcet: list
:type et_stddev: float
:type deadline: float
:type base_cpi: float
......@@ -62,6 +63,7 @@ class TaskInfo(object):
self.list_activation_dates = list_activation_dates
self.data = data
self.preemption_cost = preemption_cost
self._pwcet = pwcet
@property
def csdp(self):
......@@ -316,7 +318,7 @@ class PTask(GenericTask):
self._sim.cycles_per_ms)
while True:
#print self.sim.now(), "activate", self.name
# print self.sim.now(), "activate", self.name
self.create_job()
yield hold, self, int(self.period * self._sim.cycles_per_ms)
......@@ -341,13 +343,38 @@ class SporadicTask(GenericTask):
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 = {
"Periodic": PTask,
"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):
......@@ -355,5 +382,4 @@ def Task(sim, task_info):
Task factory. Return and instantiate the correct class according to the
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 .ACET import ACET
from .PWCET import PWCET
from .CacheModel import CacheModel
from .FixedPenalty import FixedPenalty
......@@ -7,12 +8,14 @@ execution_time_models = {
'wcet': WCET,
'acet': ACET,
'cache': CacheModel,
'fixedpenalty': FixedPenalty
'fixedpenalty': FixedPenalty,
'pwcet': PWCET
}
execution_time_model_names = {
'WCET': 'wcet',
'ACET': 'acet',
'Cache Model': 'cache',
'Fixed Penalty': 'fixedpenalty'
'Fixed Penalty': 'fixedpenalty',
'Probabilistic WCET': 'pwcet'
}
......@@ -5,6 +5,7 @@ Tools for generating task sets.
import numpy as np
import random
import math
from functools import reduce
def UUniFastDiscard(n, u, nsets):
......@@ -68,7 +69,7 @@ def StaffordRandFixedSum(n, u, nsets):
if n < u:
return None
#deal with n=1 case
# deal with n=1 case
if n == 1:
return np.tile(np.array([u]), [nsets, 1])
......@@ -113,8 +114,8 @@ def StaffordRandFixedSum(n, u, nsets):
x[n - 1, ...] = sm + pr * s
#iterated in fixed dimension order but needs to be randomised
#permute x row order within each column
# iterated in fixed dimension order but needs to be randomised
# permute x row order within each column
for i in range(0, nsets):
x[..., i] = x[np.random.permutation(n), i]
......@@ -218,10 +219,11 @@ def next_arrival_poisson(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)
def gen_arrivals(period, min_, max_, round_to_int=False):
dates = []
n = min_ - period
while True:
......@@ -236,6 +238,28 @@ def gen_arrivals(period, min_, max_, round_to_int=False):
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):
"""
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