Commit 67af12be by Maxime Chéramy

Initial commit with SimSo 0.7 (core only).

parent 71f2ef17
This diff is collapsed. Click to expand it.
include COPYING.txt
recursive-include docs *.html *.css *.js *.png *.gif *.inv
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = .
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean doc
default: doc
doc:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dist: doc
scp -r html/* mcheramy@homepages.laas.fr:~/simso/doc/
clean:
-rm -rf $(BUILDDIR)/html
# -*- coding: utf-8 -*-
#
# SimSo documentation build configuration file, created by
# sphinx-quickstart on Sat Dec 7 12:49:07 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
add_module_names=False
autoclass_content='both'
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'SimSo'
copyright = u'2013, Maxime Chéramy'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'nature'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {'nosidebar': True}
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = "SimSo documentation"
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
html_show_copyright = False
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'SimSodoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'SimSo.tex', u'SimSo Documentation',
u'Maxime Chéramy', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'simso', u'SimSo Documentation',
[u'Maxime Chéramy'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'SimSo', u'SimSo Documentation',
u'Maxime Chéramy', 'SimSo', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
sys.path.append('..')
Frequently Asked Questions
==========================
(please send me your questions in order to complete this list.)
Does it work on my operating system?
------------------------------------
SimSo is fully written in Python and depends on libraries that are available for Linux, Mac OS and Windows. If you install the dependencies, you can install SimSo using the source code. Otherwise, I also provide a debian/ubuntu package and a windows installer.
Can I use my own task generator?
--------------------------------
If you are using SimSo from a Python script, you can create the tasks easily with the characteristics of your choice.
If you are using the graphical user interface, you can generate an XML file compatible with SimSo. The XSD schema is shipped with the source code (it is incomplete though).
Does SimSo support sporadic tasks?
----------------------------------
This was implemented in July 2014. With sporadic tasks, you must specify the list of activation dates. This allows you to use an external generator to control the arrival of the jobs.
Do you handle uniform and/or heterogeneous processors?
------------------------------------------------------
It is possible to set a speed for each processor (uniform) but you can't specify task execution speed in function of the processor (heterogeneous). However, this could be done by adding a new Execution Time Model.
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 0f051803cb376160792863ce353e53c6
tags: 645f666f9bcd5a90fca523b33c5a78b7
Frequently Asked Questions
==========================
(please send me your questions in order to complete this list.)
Does it work on my operating system?
------------------------------------
SimSo is fully written in Python and depends on libraries that are available for Linux, Mac OS and Windows. If you install the dependencies, you can install SimSo using the source code. Otherwise, I also provide a debian/ubuntu package and a windows installer.
Can I use my own task generator?
--------------------------------
If you are using SimSo from a Python script, you can create the tasks easily with the characteristics of your choice.
If you are using the graphical user interface, you can generate an XML file compatible with SimSo. The XSD schema is shipped with the source code (it is incomplete though).
Does SimSo support sporadic tasks?
----------------------------------
This was implemented in July 2014. With sporadic tasks, you must specify the list of activation dates. This allows you to use an external generator to control the arrival of the jobs.
Do you handle uniform and/or heterogeneous processors?
------------------------------------------------------
It is possible to set a speed for each processor (uniform) but you can't specify task execution speed in function of the processor (heterogeneous). However, this could be done by adding a new Execution Time Model.
SimSo documentation
===================
.. toctree::
:maxdepth: 2
introduction.rst
faq.rst
write_scheduler.rst
text_mode.rst
modules.rst
licenses.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Introduction
============
What is SimSo?
--------------
SimSo is a scheduling simulator for real-time multiprocessor architectures that takes into account some scheduling overheads (scheduling decisions, context switches) and the impact of caches through statistical models. Based on a Discrete-Event Simulator (SimPy), it allows quick simulations and a fast prototyping of scheduling policies using Python.
SimSo is an open source software, available under the `CeCILL license <licenses.html>`_, a GPL compatible license.
Download
--------
You can find the last version of SimSo on the `SimSo Website`_.
.. _Simso Website: http://homepages.laas.fr/mcheramy/simso/
Installation
------------
SimSo is available for the main platforms and so is its source code. The archive containing the source code is more often updated and should be used when possible.
In order to install SimSo from the souce code, the dependences must be installed first. Then, type "python setup.py install" to install SimSo.
Dependencies
""""""""""""
When using SimSo from the sources, the following softwares and librairies are required:
- Python 2.7+
- SimPy 2.3.1 (not compatible with SimPy 3)
- NumPy 1.6+
- PyQt4 4.9+
If you are using a binary, everything should be packed in the binary.
First step
----------
SimSo is provided with a graphical user interface that aims to be very easy to use. This is a good way to develop and test a scheduler. See `How to write a scheduling policy <write_scheduler.html>`_.
It is also possible to use SimSo as a library. This allows in particular to run simulations in text mode with a maximum of flexibility.
Available Schedulers
--------------------
Currently, the following schedulers are available:
**Uniprocessor schedulers**
- Earliest Deadline First (EDF)
- Rate Monotonic (RM)
- Fixed Priority (FP)
- Static-EDF (A DVFS EDF)
- CC-EDF: Real-Time dynamic voltage scaling for low-power embedded operating systems by P. Pillai et al.
**Uniprocessor schedulers adapted to multiprocessor**
- Global-EDF
- Global-RM
- Earliest Deadline Zero Laxity (EDZL)
- Least Laxity First (LLF)
- Modified Least Laxity First (MLLF): A Modified Least-Laxity-First Scheduling Algorithm for Real-Time Tasks by S.-H. Oh and S.-M. Yang.
- PriD: Real-time scheduling on multiprocessors by J., Baruah, S., & Funk, S.
- EDF-US
- G-FL: Fair lateness scheduling: Reducing maximum lateness in G-EDF-like scheduling by Erickson and Anderson.
**Partitionned**
Any uniprocessor scheduler using a partitionning algorithm. The following heuristics are provided:
- First-Fit and Decreasing-First-Fit
- Next-Fit and Decreasing-Next-Fit
- Best-Fit and Decreasing-Best-Fit
- Worst-Fit and Decreasing-Worst-Fit
**PFair**
- Earliest Pseudo-Deadline First (EPDF)
- PD2 and ER-PD2: Early-Release Fair Scheduling. In Proceedings of the Euromicro Conference on Real-Time Systems by J. H. Anderson et al.
**DPFair**
- LLREF: An Optimal Real-Time Scheduling Algorithm for Multiprocessors by Cho et al.
- LRE-TL: An Optimal Multiprocessor Scheduling Algorithm for Sporadic Task Sets by S. Funk et al.
- DP-WRAP: DP-FAIR: A Simple Model for Understanding Optimal Multiprocessor Scheduling by Levin et al.
- BF: Multiple-resource periodic scheduling problem: how much fairness is necessary? by Zhu et al.
- NVNLF: Work-Conversing Optimal Real-Time Scheduling on Multiprocessors by Funaoka et al.
**Semi-partitionned**
- EKG: Multiprocessor Scheduling with Few Preemptions by B. Andersson and E. Tovar.
- EDHS: Semi-Partitioning Technique for Multiprocessor Real-Time Scheduling by Kato et al.
**Other**
- RUN: Optimal Multiprocessor Real-Time Scheduling via Reduction to Uniprocessor by Regnier et al.
- U-EDF: an Unfair but Optimal Multiprocessor Scheduling Algorithm for Sporadic Tasks by Nelissen et al.
Licenses
========
SimSo
-----
SimSo is distributed under the CeCILL license::
Copyright LAAS-CNRS (2012-2015)
maxime.cheramy@laas.fr
This software is a computer program whose purpose is to provide a
simulator for Multiprocessor Real-Time Scheduling with Overheads.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
Dependencies
------------
SimPy
^^^^^
SimPy is an object-oriented, process-based discrete-event simulation language for Python.
SimPy 2 is released under the GNU Lesser GPL (LGPL) license.
NumPy
^^^^^
Numpy is licensed under the BSD license, enabling reuse with few restrictions.
PyQt
^^^^
The Graphical User Interface of SimSo relies on the GPL version of PyQt. Qt itself is available
in GPL and LGPL versions.
Main modules
============
.. contents:: Table of Contents
simso.core module
-----------------
.. automodule:: simso.core
Scheduler
^^^^^^^^^
.. automodule:: simso.core.Scheduler
:members:
Task
^^^^
.. automodule:: simso.core.Task
:members:
Job
^^^
.. automodule:: simso.core.Job
:members:
Model
^^^^^
.. automodule:: simso.core.Model
:members:
Processor
^^^^^^^^^
.. automodule:: simso.core.Processor
:members:
Timer
^^^^^
.. automodule:: simso.core.Timer
:members:
Logger
^^^^^^
.. automodule:: simso.core.Logger
:members:
results
^^^^^^^
.. automodule:: simso.core.results
:members:
simso.configuration module
--------------------------
.. automodule:: simso.configuration
Configuration
^^^^^^^^^^^^^
.. automodule:: simso.configuration.Configuration
:members:
simso.generator module
----------------------
.. automodule:: simso.generator.task_generator
:members:
simso.utils module
------------------
PartitionedScheduler
^^^^^^^^^^^^^^^^^^^^
.. automodule:: simso.utils.PartitionedScheduler
:members:
Using SimSo in script mode
==========================
SimSo can be used as a library in order to automatize wide experimentations and have a maximum of flexibility on the analysis of the results. In this tutorial, a few examples are provided.
.. contents:: Table of Contents
Loading a configuration using a simulation file
-----------------------------------------------
A :class:`Configuration <simso.configuration.Configuration>` can be initialized with a file passed to its constructor::
configuration = Configuration(argv[0])
The configuration could also be partial and completed by the script. Finally, the configuration can be checked for correctness using the :meth:`check_all <simso.configuration.Configuration.check_all>` method::
configuration.check_all()
This method will raise an exception if something is not correct.
Creating a configuration from scratch
-------------------------------------
It is also possible to create a new configuration from an empty configuration. This is done by instantiating a :class:`Configuration <simso.configuration.Configuration>` object without argument. Then, its attributes can be changed::
configuration = Configuration()
configuration.duration = 100 * configuration.cycles_per_ms
It is also possible to add tasks::
configuration.add_task(name="T1", identifier=1, period=7,
activation_date=0, wcet=3, deadline=7)
And of course processors::
configuration.add_processor(name="CPU 1", identifier=1)
Finally, a scheduler is also required::
configuration.scheduler_info.set_name("examples/RM.py",
configuration.cur_dir)
Creating the Model
------------------
A :class:`configuration <simso.configuration.Configuration>` is an object grouping every characteristics of the system (tasks, processors, schedulers, etc). Such a configuration can be passed to the :class:`Model <simso.core.Model.Model>` constructor in order to create the simulation::
model = Model(configuration)
And the simulation can be run with the :meth:`run_model <simso.core.Model.Model.run_model>` method::
model.run_model()
Some basic logs can be get through the :meth:`logs <simso.core.Model.Model.logs>` attribute::
for log in model.logs:
print(log)
First Example
-------------
The following script simulate a system loading from a simulation file or configured from scratch::
import sys
from simso.core import Model
from simso.configuration import Configuration
def main(argv):
if len(argv) == 1:
# Configuration load from a file.
configuration = Configuration(argv[0])
else:
# Manual configuration:
configuration = Configuration()
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)
configuration.add_task(name="T3", identifier=3, period=20,
activation_date=0, wcet=5, deadline=20)
# Add a processor:
configuration.add_processor(name="CPU 1", identifier=1)
# Add a scheduler:
configuration.scheduler_info.set_name("examples/RM.py",
configuration.cur_dir)
# 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)
More details
------------
It is possible to get more information from the tasks using :class:`Results <simso.core.results.Results>` class. For example we could get the computation time of the jobs::
for task in model.results.tasks:
print(task.name + ":")
for job in task.jobs:
print("%s %.3f ms" % (job.name, job.computation_time))
Or the number of preemptions per task::
for task in model.results.task_list:
print("%s %d" % (task.name, sum([job.preemption_count for job in task.jobs])))
You can get all the metrics provided in the :class:`TaskR <simso.core.results.TaskR>` and :class:`JobR <simso.core.results.JobR>` objects. Read the documentation of these classes to know exactly what is directly accessible.
It is also possible to get the monitor object from each processors. This is a very detail history of the system. For example, you can count the number of context switches, where a context switch is something that happen when the previous task running on the same processor is different::
cxt = 0
for processor in model.processors:
prev = None
for evt in processor.monitor:
if evt[1].event == ProcEvent.RUN:
if prev is not None and prev != evt[1].args.identifier:
cxt += 1
prev = evt[1].args.identifier
print("Number of context switches (without counting the OS): " + str(cxt))
How to write a scheduling policy
================================
This tutorial explains through minimalist examples how to write a scheduler.
.. contents:: Table of Contents
Example 1: uniprocessor EDF
---------------------------
This example shows how to write an Earliest Deadline First scheduler for a single processor. As a reminder, the Earliest Deadline First prioritizes the tasks with the closest absolute deadline among all the ready tasks. A task is ready when it is activated and not finished.
Creation of the file
""""""""""""""""""""
A scheduler for SimSo is a Python class that inherits from the :class:`simso.core.Scheduler` class. The first step is to write the skeleton of our scheduler. Create a file named "EDF_mono.py" and write the following code::
from simso.core import Scheduler
class EDF_mono(Scheduler):
def init(self):
pass
def on_activate(self, job):
pass
def on_terminated(self, job):
pass
def schedule(self, cpu):
pass
It is mandatory for the class name to be identical to the file name.
Explanation of the skeleton
"""""""""""""""""""""""""""
The first thing done here is importing the :class:`Scheduler <simso.core.Scheduler>` class. Then we define the `EDF_mono` class as a subclass of the `Scheduler`.
Four methods are redifined:
- The :meth:`init <simso.core.Scheduler.Scheduler.init>` method is called when the simulation is ready to start, this is where the structures used by the scheduler should be initialized. The usual Python constructor is not guaranteed to be called before each simulation run and the :class:`Task <simso.core.Task.Task>` and :class:`Processors <simso.core.Processor.Processor>` are not instantiated yet when the scheduler is created.
- The :meth:`on_activate <simso.core.Scheduler.Scheduler.on_activate>` method is called on task activations.
- The :meth:`on_terminated <simso.core.Scheduler.Scheduler.on_terminated>` method is called when a job finished its execution.
- The :meth:`schedule <simso.core.Scheduler.Scheduler.schedule>` method is called by the processor when it needs to run the scheduler. This method should not be called directly.
Implementation
""""""""""""""
In a nutshell, the algorithm is the following: a list of ready jobs is kept up-to-date using the `on_activate` and `on_terminated` methods. When the schedule method is called, the ready job with the closest absolute deadline is chosen.
So, the first step is to define a `ready_list`, and to append the jobs and remove them respectively when the jobs are activated and when they finish. The code should looks like that::
from core import Scheduler
class EDF_mono(Scheduler):
def init(self):
self.ready_list = []
def on_activate(self, job):
self.ready_list.append(job)
def on_terminated(self, job):
self.ready_list.remove(job)
def schedule(self, cpu):
pass
The second step is to write the schedule logic. Selecting the job with the closest absolute deadline is pretty easy. But we need to be sure that there is at least one ready job. One possible implementation is::
def schedule(self, cpu):
if self.ready_list: # If at least one job is ready:
# job with the highest priority
job = min(self.ready_list, key=lambda x: x.absolute_deadline)
else:
job = None
return (job, cpu)
At this point, we are still missing a very important thing: calling the scheduler! This is not done by invoking the `schedule` method. As a reminder, that's the processor which is responsible to call the `scheduler`. The reason is that if an overhead must be applied, it is done on the processor running the scheduler. The good way to call the scheduler is by sending a message to the processor using the :meth:`resched <simso.core.Processor.Processor.resched>` method.
Any job is affected to a processor. This is the last processor on which the task was running or an arbitrary processor on the first execution. The scheduler can be called indirectly using ``job.cpu.resched()`` when a scheduling event occurs. We could also use ``self.processors[0].resched`` to run the scheduler on the first (and only) processor of the system.
This is the full code::
from simso.core import Scheduler
class EDF_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: # If at least one job is ready:
# job with the highest priority
job = min(self.ready_list, key=lambda x: x.absolute_deadline)
else:
job = None
return (job, cpu)
Example 2: Partitionned EDF
---------------------------
The simplest method to handle multiprocessor architectures is to use partitionning. This approach consists in allocating the tasks to the processors and executing a mono-processor scheduler on each processor.
In order to ease the work for the developer of a scheduler, an helping class, named :class:`PartitionedScheduler <simso.utils.PartitionedScheduler>`, is provided.
Initializing the scheduler
""""""""""""""""""""""""""
The :class:`PartitionedScheduler <simso.utils.PartitionedScheduler>` is defined in the `simso.utils` module. It is also necessary to load the :class:`SchedulerInfo <simso.core.Scheduler.SchedulerInfo>` class in order to give to the `PartitionedScheduler <simso.utils.PartitionedScheduler>` the mono-processor scheduler to use. The first thing to do is importing these classes::
from simso.utils import PartitionedScheduler
from simso.core.Scheduler import SchedulerInfo
Then the Scheduler can be initialized like this::
class P_EDF(PartitionedScheduler):
def init(self):
PartitionedScheduler.init(self, SchedulerInfo("EDF_mono", EDF_mono))
Defining the packing
""""""""""""""""""""
A First-Fit bin-packing can be used to affect the tasks to the processors. For that, the :meth:`packer` must be overriden::
def packer(self):
# First Fit
cpus = [[cpu, 0] for cpu in self.processors]
for task in self.task_list:
j = 0
# Find a processor with free space.
while cpus[j][1] + float(task.wcet) / task.period > 1.0:
j += 1
if j >= len(self.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
self.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
return True
Complete example
""""""""""""""""
Complete source code::
from simso.core.Scheduler import SchedulerInfo
from EDF_mono import EDF_mono
from simso.utils import PartitionedScheduler
class P_EDF(PartitionedScheduler):
def init(self):
PartitionedScheduler.init(self, SchedulerInfo("EDF_mono", EDF_mono))
def packer(self):
# First Fit
cpus = [[cpu, 0] for cpu in self.processors]
for task in self.task_list:
j = 0
# Find a processor with free space.
while cpus[j][1] + float(task.wcet) / task.period > 1.0:
j += 1
if j >= len(self.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
self.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
return True
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox input[type="text"] {
width: 170px;
}
div.sphinxsidebar #searchbox input[type="submit"] {
width: 30px;
}
img {
border: 0;
max-width: 100%;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- general body styles --------------------------------------------------- */
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.optional {
font-size: 1.3em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
tt.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
tt.descclassname {
background-color: transparent;
}
tt.xref, a tt {
background-color: transparent;
font-weight: bold;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}
\ No newline at end of file
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this);
});
}
}
return this.each(function() {
highlight(this);
});
};
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
if (!body.length) {
body = $('body');
}
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* nature.css_t
* ~~~~~~~~~~~~
*
* Sphinx stylesheet -- nature theme.
*
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: Arial, sans-serif;
font-size: 100%;
background-color: #111;
color: #555;
margin: 0;
padding: 0;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
hr {
border: 1px solid #B1B4B6;
}
div.document {
background-color: #eee;
}
div.body {
background-color: #ffffff;
color: #3E4349;
padding: 0 30px 30px 30px;
font-size: 0.9em;
}
div.footer {
color: #555;
width: 100%;
padding: 13px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #444;
text-decoration: underline;
}
div.related {
background-color: #6BA81E;
line-height: 32px;
color: #fff;
text-shadow: 0px 1px 0 #444;
font-size: 0.9em;
}
div.related a {
color: #E2F3CC;
}
div.sphinxsidebar {
font-size: 0.75em;
line-height: 1.5em;
}
div.sphinxsidebarwrapper{
padding: 20px 0;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4 {
font-family: Arial, sans-serif;
color: #222;
font-size: 1.2em;
font-weight: normal;
margin: 0;
padding: 5px 10px;
background-color: #ddd;
text-shadow: 1px 1px 0 white
}
div.sphinxsidebar h4{
font-size: 1.1em;
}
div.sphinxsidebar h3 a {
color: #444;
}
div.sphinxsidebar p {
color: #888;
padding: 5px 20px;
}
div.sphinxsidebar p.topless {
}
div.sphinxsidebar ul {
margin: 10px 20px;
padding: 0;
color: #000;
}
div.sphinxsidebar a {
color: #444;
}
div.sphinxsidebar input {
border: 1px solid #ccc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar input[type=text]{
margin-left: 20px;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #005B81;
text-decoration: none;
}
a:hover {
color: #E32E00;
text-decoration: underline;
}
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: Arial, sans-serif;
background-color: #BED4EB;
font-weight: normal;
color: #212224;
margin: 30px 0px 10px 0px;
padding: 5px 0 5px 10px;
text-shadow: 0px 1px 0 white
}
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
line-height: 1.5em;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.highlight{
background-color: white;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 10px;
background-color: White;
color: #222;
line-height: 1.2em;
border: 1px solid #C6C9CB;
font-size: 1.1em;
margin: 1.5em 0 1.5em 0;
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
-moz-box-shadow: 1px 1px 1px #d8d8d8;
}
tt {
background-color: #ecf0f3;
color: #222;
/* padding: 1px 2px; */
font-size: 1.1em;
font-family: monospace;
}
.viewcode-back {
font-family: Arial, sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
\ No newline at end of file
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #333333 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #208050 } /* Literal.Number.Bin */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Frequently Asked Questions &mdash; SimSo documentation</title>
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="SimSo documentation" href="index.html" />
<link rel="next" title="How to write a scheduling policy" href="write_scheduler.html" />
<link rel="prev" title="Introduction" href="introduction.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="write_scheduler.html" title="How to write a scheduling policy"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="introduction.html" title="Introduction"
accesskey="P">previous</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body">
<div class="section" id="frequently-asked-questions">
<h1>Frequently Asked Questions<a class="headerlink" href="#frequently-asked-questions" title="Permalink to this headline"></a></h1>
<p>(please send me your questions in order to complete this list.)</p>
<div class="section" id="does-it-work-on-my-operating-system">
<h2>Does it work on my operating system?<a class="headerlink" href="#does-it-work-on-my-operating-system" title="Permalink to this headline"></a></h2>
<p>SimSo is fully written in Python and depends on libraries that are available for Linux, Mac OS and Windows. If you install the dependencies, you can install SimSo using the source code. Otherwise, I also provide a debian/ubuntu package and a windows installer.</p>
</div>
<div class="section" id="can-i-use-my-own-task-generator">
<h2>Can I use my own task generator?<a class="headerlink" href="#can-i-use-my-own-task-generator" title="Permalink to this headline"></a></h2>
<p>If you are using SimSo from a Python script, you can create the tasks easily with the characteristics of your choice.</p>
<p>If you are using the graphical user interface, you can generate an XML file compatible with SimSo. The XSD schema is shipped with the source code (it is incomplete though).</p>
</div>
<div class="section" id="does-simso-support-sporadic-tasks">
<h2>Does SimSo support sporadic tasks?<a class="headerlink" href="#does-simso-support-sporadic-tasks" title="Permalink to this headline"></a></h2>
<p>This was implemented in July 2014. With sporadic tasks, you must specify the list of activation dates. This allows you to use an external generator to control the arrival of the jobs.</p>
</div>
<div class="section" id="do-you-handle-uniform-and-or-heterogeneous-processors">
<h2>Do you handle uniform and/or heterogeneous processors?<a class="headerlink" href="#do-you-handle-uniform-and-or-heterogeneous-processors" title="Permalink to this headline"></a></h2>
<p>It is possible to set a speed for each processor (uniform) but you can&#8217;t specify task execution speed in function of the processor (heterogeneous). However, this could be done by adding a new Execution Time Model.</p>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="write_scheduler.html" title="How to write a scheduling policy"
>next</a> |</li>
<li class="right" >
<a href="introduction.html" title="Introduction"
>previous</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SimSo documentation &mdash; SimSo documentation</title>
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="SimSo documentation" href="#" />
<link rel="next" title="Introduction" href="introduction.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="introduction.html" title="Introduction"
accesskey="N">next</a> |</li>
<li><a href="#">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body">
<div class="section" id="simso-documentation">
<h1>SimSo documentation<a class="headerlink" href="#simso-documentation" title="Permalink to this headline"></a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a><ul>
<li class="toctree-l2"><a class="reference internal" href="introduction.html#what-is-simso">What is SimSo?</a></li>
<li class="toctree-l2"><a class="reference internal" href="introduction.html#download">Download</a></li>
<li class="toctree-l2"><a class="reference internal" href="introduction.html#installation">Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="introduction.html#first-step">First step</a></li>
<li class="toctree-l2"><a class="reference internal" href="introduction.html#available-schedulers">Available Schedulers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l2"><a class="reference internal" href="faq.html#does-it-work-on-my-operating-system">Does it work on my operating system?</a></li>
<li class="toctree-l2"><a class="reference internal" href="faq.html#can-i-use-my-own-task-generator">Can I use my own task generator?</a></li>
<li class="toctree-l2"><a class="reference internal" href="faq.html#does-simso-support-sporadic-tasks">Does SimSo support sporadic tasks?</a></li>
<li class="toctree-l2"><a class="reference internal" href="faq.html#do-you-handle-uniform-and-or-heterogeneous-processors">Do you handle uniform and/or heterogeneous processors?</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="write_scheduler.html">How to write a scheduling policy</a><ul>
<li class="toctree-l2"><a class="reference internal" href="write_scheduler.html#example-1-uniprocessor-edf">Example 1: uniprocessor EDF</a></li>
<li class="toctree-l2"><a class="reference internal" href="write_scheduler.html#example-2-partitionned-edf">Example 2: Partitionned EDF</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="text_mode.html">Using SimSo in script mode</a><ul>
<li class="toctree-l2"><a class="reference internal" href="text_mode.html#loading-a-configuration-using-a-simulation-file">Loading a configuration using a simulation file</a></li>
<li class="toctree-l2"><a class="reference internal" href="text_mode.html#creating-a-configuration-from-scratch">Creating a configuration from scratch</a></li>
<li class="toctree-l2"><a class="reference internal" href="text_mode.html#creating-the-model">Creating the Model</a></li>
<li class="toctree-l2"><a class="reference internal" href="text_mode.html#first-example">First Example</a></li>
<li class="toctree-l2"><a class="reference internal" href="text_mode.html#more-details">More details</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="modules.html">Main modules</a><ul>
<li class="toctree-l2"><a class="reference internal" href="modules.html#module-simso.core">simso.core module</a></li>
<li class="toctree-l2"><a class="reference internal" href="modules.html#module-simso.configuration">simso.configuration module</a></li>
<li class="toctree-l2"><a class="reference internal" href="modules.html#module-simso.generator.task_generator">simso.generator module</a></li>
<li class="toctree-l2"><a class="reference internal" href="modules.html#simso-utils-module">simso.utils module</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="licenses.html">Licenses</a><ul>
<li class="toctree-l2"><a class="reference internal" href="licenses.html#simso">SimSo</a></li>
<li class="toctree-l2"><a class="reference internal" href="licenses.html#dependencies">Dependencies</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="indices-and-tables">
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><a class="reference internal" href="genindex.html"><em>Index</em></a></li>
<li><a class="reference internal" href="py-modindex.html"><em>Module Index</em></a></li>
<li><a class="reference internal" href="search.html"><em>Search Page</em></a></li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="introduction.html" title="Introduction"
>next</a> |</li>
<li><a href="#">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Introduction &mdash; SimSo documentation</title>
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="SimSo documentation" href="index.html" />
<link rel="next" title="Frequently Asked Questions" href="faq.html" />
<link rel="prev" title="SimSo documentation" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="faq.html" title="Frequently Asked Questions"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="index.html" title="SimSo documentation"
accesskey="P">previous</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body">
<div class="section" id="introduction">
<h1>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h1>
<div class="section" id="what-is-simso">
<h2>What is SimSo?<a class="headerlink" href="#what-is-simso" title="Permalink to this headline"></a></h2>
<p>SimSo is a scheduling simulator for real-time multiprocessor architectures that takes into account some scheduling overheads (scheduling decisions, context switches) and the impact of caches through statistical models. Based on a Discrete-Event Simulator (SimPy), it allows quick simulations and a fast prototyping of scheduling policies using Python.</p>
<p>SimSo is an open source software, available under the <a class="reference external" href="licenses.html">CeCILL license</a>, a GPL compatible license.</p>
</div>
<div class="section" id="download">
<h2>Download<a class="headerlink" href="#download" title="Permalink to this headline"></a></h2>
<p>You can find the last version of SimSo on the <a class="reference external" href="http://homepages.laas.fr/mcheramy/simso/">SimSo Website</a>.</p>
</div>
<div class="section" id="installation">
<h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline"></a></h2>
<p>SimSo is available for the main platforms and so is its source code. The archive containing the source code is more often updated and should be used when possible.</p>
<p>In order to install SimSo from the souce code, the dependences must be installed first. Then, type &#8220;python setup.py install&#8221; to install SimSo.</p>
<div class="section" id="dependencies">
<h3>Dependencies<a class="headerlink" href="#dependencies" title="Permalink to this headline"></a></h3>
<p>When using SimSo from the sources, the following softwares and librairies are required:</p>
<blockquote>
<div><ul class="simple">
<li>Python 2.7+</li>
<li>SimPy 2.3.1 (not compatible with SimPy 3)</li>
<li>NumPy 1.6+</li>
<li>PyQt4 4.9+</li>
</ul>
</div></blockquote>
<p>If you are using a binary, everything should be packed in the binary.</p>
</div>
</div>
<div class="section" id="first-step">
<h2>First step<a class="headerlink" href="#first-step" title="Permalink to this headline"></a></h2>
<p>SimSo is provided with a graphical user interface that aims to be very easy to use. This is a good way to develop and test a scheduler. See <a class="reference external" href="write_scheduler.html">How to write a scheduling policy</a>.</p>
<p>It is also possible to use SimSo as a library. This allows in particular to run simulations in text mode with a maximum of flexibility.</p>
</div>
<div class="section" id="available-schedulers">
<h2>Available Schedulers<a class="headerlink" href="#available-schedulers" title="Permalink to this headline"></a></h2>
<p>Currently, the following schedulers are available:</p>
<p><strong>Uniprocessor schedulers</strong></p>
<blockquote>
<div><ul class="simple">
<li>Earliest Deadline First (EDF)</li>
<li>Rate Monotonic (RM)</li>
<li>Fixed Priority (FP)</li>
<li>Static-EDF (A DVFS EDF)</li>
<li>CC-EDF: Real-Time dynamic voltage scaling for low-power embedded operating systems by P. Pillai et al.</li>
</ul>
</div></blockquote>
<dl class="docutils">
<dt><strong>Uniprocessor schedulers adapted to multiprocessor</strong></dt>
<dd><ul class="first last simple">
<li>Global-EDF</li>
<li>Global-RM</li>
<li>Earliest Deadline Zero Laxity (EDZL)</li>
<li>Least Laxity First (LLF)</li>
<li>Modified Least Laxity First (MLLF): A Modified Least-Laxity-First Scheduling Algorithm for Real-Time Tasks by S.-H. Oh and S.-M. Yang.</li>
<li>PriD: Real-time scheduling on multiprocessors by J., Baruah, S., &amp; Funk, S.</li>
<li>EDF-US</li>
<li>G-FL: Fair lateness scheduling: Reducing maximum lateness in G-EDF-like scheduling by Erickson and Anderson.</li>
</ul>
</dd>
<dt><strong>Partitionned</strong></dt>
<dd><p class="first">Any uniprocessor scheduler using a partitionning algorithm. The following heuristics are provided:</p>
<ul class="last simple">
<li>First-Fit and Decreasing-First-Fit</li>
<li>Next-Fit and Decreasing-Next-Fit</li>
<li>Best-Fit and Decreasing-Best-Fit</li>
<li>Worst-Fit and Decreasing-Worst-Fit</li>
</ul>
</dd>
<dt><strong>PFair</strong></dt>
<dd><ul class="first last simple">
<li>Earliest Pseudo-Deadline First (EPDF)</li>
<li>PD2 and ER-PD2: Early-Release Fair Scheduling. In Proceedings of the Euromicro Conference on Real-Time Systems by J. H. Anderson et al.</li>
</ul>
</dd>
<dt><strong>DPFair</strong></dt>
<dd><ul class="first last simple">
<li>LLREF: An Optimal Real-Time Scheduling Algorithm for Multiprocessors by Cho et al.</li>
<li>LRE-TL: An Optimal Multiprocessor Scheduling Algorithm for Sporadic Task Sets by S. Funk et al.</li>
<li>DP-WRAP: DP-FAIR: A Simple Model for Understanding Optimal Multiprocessor Scheduling by Levin et al.</li>
<li>BF: Multiple-resource periodic scheduling problem: how much fairness is necessary? by Zhu et al.</li>
<li>NVNLF: Work-Conversing Optimal Real-Time Scheduling on Multiprocessors by Funaoka et al.</li>
</ul>
</dd>
<dt><strong>Semi-partitionned</strong></dt>
<dd><ul class="first last simple">
<li>EKG: Multiprocessor Scheduling with Few Preemptions by B. Andersson and E. Tovar.</li>
<li>EDHS: Semi-Partitioning Technique for Multiprocessor Real-Time Scheduling by Kato et al.</li>
</ul>
</dd>
<dt><strong>Other</strong></dt>
<dd><ul class="first last simple">
<li>RUN: Optimal Multiprocessor Real-Time Scheduling via Reduction to Uniprocessor by Regnier et al.</li>
<li>U-EDF: an Unfair but Optimal Multiprocessor Scheduling Algorithm for Sporadic Tasks by Nelissen et al.</li>
</ul>
</dd>
</dl>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="faq.html" title="Frequently Asked Questions"
>next</a> |</li>
<li class="right" >
<a href="index.html" title="SimSo documentation"
>previous</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Licenses &mdash; SimSo documentation</title>
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="SimSo documentation" href="index.html" />
<link rel="prev" title="Main modules" href="modules.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="modules.html" title="Main modules"
accesskey="P">previous</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body">
<div class="section" id="licenses">
<h1>Licenses<a class="headerlink" href="#licenses" title="Permalink to this headline"></a></h1>
<div class="section" id="simso">
<h2>SimSo<a class="headerlink" href="#simso" title="Permalink to this headline"></a></h2>
<p>SimSo is distributed under the CeCILL license:</p>
<div class="highlight-python"><div class="highlight"><pre>Copyright LAAS-CNRS (2012-2015)
maxime.cheramy@laas.fr
This software is a computer program whose purpose is to provide a
simulator for Multiprocessor Real-Time Scheduling with Overheads.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
&quot;http://www.cecill.info&quot;.
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software&#39;s author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user&#39;s attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software&#39;s suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
</pre></div>
</div>
</div>
<div class="section" id="dependencies">
<h2>Dependencies<a class="headerlink" href="#dependencies" title="Permalink to this headline"></a></h2>
<div class="section" id="simpy">
<h3>SimPy<a class="headerlink" href="#simpy" title="Permalink to this headline"></a></h3>
<p>SimPy is an object-oriented, process-based discrete-event simulation language for Python.
SimPy 2 is released under the GNU Lesser GPL (LGPL) license.</p>
</div>
<div class="section" id="numpy">
<h3>NumPy<a class="headerlink" href="#numpy" title="Permalink to this headline"></a></h3>
<p>Numpy is licensed under the BSD license, enabling reuse with few restrictions.</p>
</div>
<div class="section" id="pyqt">
<h3>PyQt<a class="headerlink" href="#pyqt" title="Permalink to this headline"></a></h3>
<p>The Graphical User Interface of SimSo relies on the GPL version of PyQt. Qt itself is available
in GPL and LGPL versions.</p>
</div>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="modules.html" title="Main modules"
>previous</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Python Module Index &mdash; SimSo documentation</title>
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="SimSo documentation" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="#" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body">
<h1>Python Module Index</h1>
<div class="modindex-jumpbox">
<a href="#cap-s"><strong>s</strong></a>
</div>
<table class="indextable modindextable" cellspacing="0" cellpadding="2">
<tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
<tr class="cap" id="cap-s"><td></td><td>
<strong>s</strong></td><td></td></tr>
<tr>
<td><img src="_static/minus.png" class="toggler"
id="toggle-1" style="display: none" alt="-" /></td>
<td>
<tt class="xref">simso</tt></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.configuration"><tt class="xref">simso.configuration</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.configuration.Configuration"><tt class="xref">simso.configuration.Configuration</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core"><tt class="xref">simso.core</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.Job"><tt class="xref">simso.core.Job</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.Logger"><tt class="xref">simso.core.Logger</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.Model"><tt class="xref">simso.core.Model</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.Processor"><tt class="xref">simso.core.Processor</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.results"><tt class="xref">simso.core.results</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.Scheduler"><tt class="xref">simso.core.Scheduler</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.Task"><tt class="xref">simso.core.Task</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.core.Timer"><tt class="xref">simso.core.Timer</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.generator.task_generator"><tt class="xref">simso.generator.task_generator</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="modules.html#module-simso.utils.PartitionedScheduler"><tt class="xref">simso.utils.PartitionedScheduler</tt></a></td><td>
<em></em></td></tr>
</table>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="#" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &mdash; SimSo documentation</title>
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="top" title="SimSo documentation" href="index.html" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
<script type="text/javascript" id="searchindexloader"></script>
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body">
<h1 id="search-documentation">Search</h1>
<div id="fallback" class="admonition warning">
<script type="text/javascript">$('#fallback').hide();</script>
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
<p>
From here you can search these documents. Enter your search
words into the box below and click "search". Note that the search
function will automatically search for all of the words. Pages
containing fewer words won't appear in the result list.
</p>
<form action="" method="get">
<input type="text" name="q" value="" />
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">SimSo documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
</div>
</body>
</html>
\ No newline at end of file
SimSo documentation
===================
.. toctree::
:maxdepth: 2
introduction.rst
faq.rst
write_scheduler.rst
text_mode.rst
modules.rst
licenses.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Introduction
============
What is SimSo?
--------------
SimSo is a scheduling simulator for real-time multiprocessor architectures that takes into account some scheduling overheads (scheduling decisions, context switches) and the impact of caches through statistical models. Based on a Discrete-Event Simulator (SimPy), it allows quick simulations and a fast prototyping of scheduling policies using Python.
SimSo is an open source software, available under the `CeCILL license <licenses.html>`_, a GPL compatible license.
Download
--------
You can find the last version of SimSo on the `SimSo Website`_.
.. _Simso Website: http://homepages.laas.fr/mcheramy/simso/
Installation
------------
SimSo is available for the main platforms and so is its source code. The archive containing the source code is more often updated and should be used when possible.
In order to install SimSo from the souce code, the dependences must be installed first. Then, type "python setup.py install" to install SimSo.
Dependencies
""""""""""""
When using SimSo from the sources, the following softwares and librairies are required:
- Python 2.7+
- SimPy 2.3.1 (not compatible with SimPy 3)
- NumPy 1.6+
- PyQt4 4.9+
If you are using a binary, everything should be packed in the binary.
First step
----------
SimSo is provided with a graphical user interface that aims to be very easy to use. This is a good way to develop and test a scheduler. See `How to write a scheduling policy <write_scheduler.html>`_.
It is also possible to use SimSo as a library. This allows in particular to run simulations in text mode with a maximum of flexibility.
Available Schedulers
--------------------
Currently, the following schedulers are available:
**Uniprocessor schedulers**
- Earliest Deadline First (EDF)
- Rate Monotonic (RM)
- Fixed Priority (FP)
- Static-EDF (A DVFS EDF)
- CC-EDF: Real-Time dynamic voltage scaling for low-power embedded operating systems by P. Pillai et al.
**Uniprocessor schedulers adapted to multiprocessor**
- Global-EDF
- Global-RM
- Earliest Deadline Zero Laxity (EDZL)
- Least Laxity First (LLF)
- Modified Least Laxity First (MLLF): A Modified Least-Laxity-First Scheduling Algorithm for Real-Time Tasks by S.-H. Oh and S.-M. Yang.
- PriD: Real-time scheduling on multiprocessors by J., Baruah, S., & Funk, S.
- EDF-US
- G-FL: Fair lateness scheduling: Reducing maximum lateness in G-EDF-like scheduling by Erickson and Anderson.
**Partitionned**
Any uniprocessor scheduler using a partitionning algorithm. The following heuristics are provided:
- First-Fit and Decreasing-First-Fit
- Next-Fit and Decreasing-Next-Fit
- Best-Fit and Decreasing-Best-Fit
- Worst-Fit and Decreasing-Worst-Fit
**PFair**
- Earliest Pseudo-Deadline First (EPDF)
- PD2 and ER-PD2: Early-Release Fair Scheduling. In Proceedings of the Euromicro Conference on Real-Time Systems by J. H. Anderson et al.
**DPFair**
- LLREF: An Optimal Real-Time Scheduling Algorithm for Multiprocessors by Cho et al.
- LRE-TL: An Optimal Multiprocessor Scheduling Algorithm for Sporadic Task Sets by S. Funk et al.
- DP-WRAP: DP-FAIR: A Simple Model for Understanding Optimal Multiprocessor Scheduling by Levin et al.
- BF: Multiple-resource periodic scheduling problem: how much fairness is necessary? by Zhu et al.
- NVNLF: Work-Conversing Optimal Real-Time Scheduling on Multiprocessors by Funaoka et al.
**Semi-partitionned**
- EKG: Multiprocessor Scheduling with Few Preemptions by B. Andersson and E. Tovar.
- EDHS: Semi-Partitioning Technique for Multiprocessor Real-Time Scheduling by Kato et al.
**Other**
- RUN: Optimal Multiprocessor Real-Time Scheduling via Reduction to Uniprocessor by Regnier et al.
- U-EDF: an Unfair but Optimal Multiprocessor Scheduling Algorithm for Sporadic Tasks by Nelissen et al.
Licenses
========
SimSo
-----
SimSo is distributed under the CeCILL license::
Copyright LAAS-CNRS (2012-2015)
maxime.cheramy@laas.fr
This software is a computer program whose purpose is to provide a
simulator for Multiprocessor Real-Time Scheduling with Overheads.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
Dependencies
------------
SimPy
^^^^^
SimPy is an object-oriented, process-based discrete-event simulation language for Python.
SimPy 2 is released under the GNU Lesser GPL (LGPL) license.
NumPy
^^^^^
Numpy is licensed under the BSD license, enabling reuse with few restrictions.
PyQt
^^^^
The Graphical User Interface of SimSo relies on the GPL version of PyQt. Qt itself is available
in GPL and LGPL versions.
Main modules
============
.. contents:: Table of Contents
simso.core module
-----------------
.. automodule:: simso.core
Scheduler
^^^^^^^^^
.. automodule:: simso.core.Scheduler
:members:
Task
^^^^
.. automodule:: simso.core.Task
:members:
Job
^^^
.. automodule:: simso.core.Job
:members:
Model
^^^^^
.. automodule:: simso.core.Model
:members:
Processor
^^^^^^^^^
.. automodule:: simso.core.Processor
:members:
Timer
^^^^^
.. automodule:: simso.core.Timer
:members:
Logger
^^^^^^
.. automodule:: simso.core.Logger
:members:
results
^^^^^^^
.. automodule:: simso.core.results
:members:
simso.configuration module
--------------------------
.. automodule:: simso.configuration
Configuration
^^^^^^^^^^^^^
.. automodule:: simso.configuration.Configuration
:members:
simso.generator module
----------------------
.. automodule:: simso.generator.task_generator
:members:
simso.utils module
------------------
PartitionedScheduler
^^^^^^^^^^^^^^^^^^^^
.. automodule:: simso.utils.PartitionedScheduler
:members:
Using SimSo in script mode
==========================
SimSo can be used as a library in order to automatize wide experimentations and have a maximum of flexibility on the analysis of the results. In this tutorial, a few examples are provided.
.. contents:: Table of Contents
Loading a configuration using a simulation file
-----------------------------------------------
A :class:`Configuration <simso.configuration.Configuration>` can be initialized with a file passed to its constructor::
configuration = Configuration(argv[0])
The configuration could also be partial and completed by the script. Finally, the configuration can be checked for correctness using the :meth:`check_all <simso.configuration.Configuration.check_all>` method::
configuration.check_all()
This method will raise an exception if something is not correct.
Creating a configuration from scratch
-------------------------------------
It is also possible to create a new configuration from an empty configuration. This is done by instantiating a :class:`Configuration <simso.configuration.Configuration>` object without argument. Then, its attributes can be changed::
configuration = Configuration()
configuration.duration = 100 * configuration.cycles_per_ms
It is also possible to add tasks::
configuration.add_task(name="T1", identifier=1, period=7,
activation_date=0, wcet=3, deadline=7)
And of course processors::
configuration.add_processor(name="CPU 1", identifier=1)
Finally, a scheduler is also required::
configuration.scheduler_info.set_name("examples/RM.py",
configuration.cur_dir)
Creating the Model
------------------
A :class:`configuration <simso.configuration.Configuration>` is an object grouping every characteristics of the system (tasks, processors, schedulers, etc). Such a configuration can be passed to the :class:`Model <simso.core.Model.Model>` constructor in order to create the simulation::
model = Model(configuration)
And the simulation can be run with the :meth:`run_model <simso.core.Model.Model.run_model>` method::
model.run_model()
Some basic logs can be get through the :meth:`logs <simso.core.Model.Model.logs>` attribute::
for log in model.logs:
print(log)
First Example
-------------
The following script simulate a system loading from a simulation file or configured from scratch::
import sys
from simso.core import Model
from simso.configuration import Configuration
def main(argv):
if len(argv) == 1:
# Configuration load from a file.
configuration = Configuration(argv[0])
else:
# Manual configuration:
configuration = Configuration()
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)
configuration.add_task(name="T3", identifier=3, period=20,
activation_date=0, wcet=5, deadline=20)
# Add a processor:
configuration.add_processor(name="CPU 1", identifier=1)
# Add a scheduler:
configuration.scheduler_info.set_name("examples/RM.py",
configuration.cur_dir)
# 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)
More details
------------
It is possible to get more information from the tasks using :class:`Results <simso.core.results.Results>` class. For example we could get the computation time of the jobs::
for task in model.results.tasks:
print(task.name + ":")
for job in task.jobs:
print("%s %.3f ms" % (job.name, job.computation_time))
Or the number of preemptions per task::
for task in model.results.task_list:
print("%s %d" % (task.name, sum([job.preemption_count for job in task.jobs])))
You can get all the metrics provided in the :class:`TaskR <simso.core.results.TaskR>` and :class:`JobR <simso.core.results.JobR>` objects. Read the documentation of these classes to know exactly what is directly accessible.
It is also possible to get the monitor object from each processors. This is a very detail history of the system. For example, you can count the number of context switches, where a context switch is something that happen when the previous task running on the same processor is different::
cxt = 0
for processor in model.processors:
prev = None
for evt in processor.monitor:
if evt[1].event == ProcEvent.RUN:
if prev is not None and prev != evt[1].args.identifier:
cxt += 1
prev = evt[1].args.identifier
print("Number of context switches (without counting the OS): " + str(cxt))
How to write a scheduling policy
================================
This tutorial explains through minimalist examples how to write a scheduler.
.. contents:: Table of Contents
Example 1: uniprocessor EDF
---------------------------
This example shows how to write an Earliest Deadline First scheduler for a single processor. As a reminder, the Earliest Deadline First prioritizes the tasks with the closest absolute deadline among all the ready tasks. A task is ready when it is activated and not finished.
Creation of the file
""""""""""""""""""""
A scheduler for SimSo is a Python class that inherits from the :class:`simso.core.Scheduler` class. The first step is to write the skeleton of our scheduler. Create a file named "EDF_mono.py" and write the following code::
from simso.core import Scheduler
class EDF_mono(Scheduler):
def init(self):
pass
def on_activate(self, job):
pass
def on_terminated(self, job):
pass
def schedule(self, cpu):
pass
It is mandatory for the class name to be identical to the file name.
Explanation of the skeleton
"""""""""""""""""""""""""""
The first thing done here is importing the :class:`Scheduler <simso.core.Scheduler>` class. Then we define the `EDF_mono` class as a subclass of the `Scheduler`.
Four methods are redifined:
- The :meth:`init <simso.core.Scheduler.Scheduler.init>` method is called when the simulation is ready to start, this is where the structures used by the scheduler should be initialized. The usual Python constructor is not guaranteed to be called before each simulation run and the :class:`Task <simso.core.Task.Task>` and :class:`Processors <simso.core.Processor.Processor>` are not instantiated yet when the scheduler is created.
- The :meth:`on_activate <simso.core.Scheduler.Scheduler.on_activate>` method is called on task activations.
- The :meth:`on_terminated <simso.core.Scheduler.Scheduler.on_terminated>` method is called when a job finished its execution.
- The :meth:`schedule <simso.core.Scheduler.Scheduler.schedule>` method is called by the processor when it needs to run the scheduler. This method should not be called directly.
Implementation
""""""""""""""
In a nutshell, the algorithm is the following: a list of ready jobs is kept up-to-date using the `on_activate` and `on_terminated` methods. When the schedule method is called, the ready job with the closest absolute deadline is chosen.
So, the first step is to define a `ready_list`, and to append the jobs and remove them respectively when the jobs are activated and when they finish. The code should looks like that::
from core import Scheduler
class EDF_mono(Scheduler):
def init(self):
self.ready_list = []
def on_activate(self, job):
self.ready_list.append(job)
def on_terminated(self, job):
self.ready_list.remove(job)
def schedule(self, cpu):
pass
The second step is to write the schedule logic. Selecting the job with the closest absolute deadline is pretty easy. But we need to be sure that there is at least one ready job. One possible implementation is::
def schedule(self, cpu):
if self.ready_list: # If at least one job is ready:
# job with the highest priority
job = min(self.ready_list, key=lambda x: x.absolute_deadline)
else:
job = None
return (job, cpu)
At this point, we are still missing a very important thing: calling the scheduler! This is not done by invoking the `schedule` method. As a reminder, that's the processor which is responsible to call the `scheduler`. The reason is that if an overhead must be applied, it is done on the processor running the scheduler. The good way to call the scheduler is by sending a message to the processor using the :meth:`resched <simso.core.Processor.Processor.resched>` method.
Any job is affected to a processor. This is the last processor on which the task was running or an arbitrary processor on the first execution. The scheduler can be called indirectly using ``job.cpu.resched()`` when a scheduling event occurs. We could also use ``self.processors[0].resched`` to run the scheduler on the first (and only) processor of the system.
This is the full code::
from simso.core import Scheduler
class EDF_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: # If at least one job is ready:
# job with the highest priority
job = min(self.ready_list, key=lambda x: x.absolute_deadline)
else:
job = None
return (job, cpu)
Example 2: Partitionned EDF
---------------------------
The simplest method to handle multiprocessor architectures is to use partitionning. This approach consists in allocating the tasks to the processors and executing a mono-processor scheduler on each processor.
In order to ease the work for the developer of a scheduler, an helping class, named :class:`PartitionedScheduler <simso.utils.PartitionedScheduler>`, is provided.
Initializing the scheduler
""""""""""""""""""""""""""
The :class:`PartitionedScheduler <simso.utils.PartitionedScheduler>` is defined in the `simso.utils` module. It is also necessary to load the :class:`SchedulerInfo <simso.core.Scheduler.SchedulerInfo>` class in order to give to the `PartitionedScheduler <simso.utils.PartitionedScheduler>` the mono-processor scheduler to use. The first thing to do is importing these classes::
from simso.utils import PartitionedScheduler
from simso.core.Scheduler import SchedulerInfo
Then the Scheduler can be initialized like this::
class P_EDF(PartitionedScheduler):
def init(self):
PartitionedScheduler.init(self, SchedulerInfo("EDF_mono", EDF_mono))
Defining the packing
""""""""""""""""""""
A First-Fit bin-packing can be used to affect the tasks to the processors. For that, the :meth:`packer` must be overriden::
def packer(self):
# First Fit
cpus = [[cpu, 0] for cpu in self.processors]
for task in self.task_list:
j = 0
# Find a processor with free space.
while cpus[j][1] + float(task.wcet) / task.period > 1.0:
j += 1
if j >= len(self.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
self.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
return True
Complete example
""""""""""""""""
Complete source code::
from simso.core.Scheduler import SchedulerInfo
from EDF_mono import EDF_mono
from simso.utils import PartitionedScheduler
class P_EDF(PartitionedScheduler):
def init(self):
PartitionedScheduler.init(self, SchedulerInfo("EDF_mono", EDF_mono))
def packer(self):
# First Fit
cpus = [[cpu, 0] for cpu in self.processors]
for task in self.task_list:
j = 0
# Find a processor with free space.
while cpus[j][1] + float(task.wcet) / task.period > 1.0:
j += 1
if j >= len(self.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
self.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
return True
from setuptools import setup, find_packages
import simso
setup(
name='simso',
version=simso.__version__,
description='Simulation of Multiprocessor Real-Time Scheduling with Overheads',
author='Maxime Cheramy',
author_email='maxime.cheramy@laas.fr',
url='http://homepages.laas.fr/mcheramy/simso/',
classifiers=[
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'License :: OSI Approved',
'Operating System :: OS Independent',
'Topic :: Scientific/Engineering',
'Development Status :: 5 - Production/Stable'
],
packages=find_packages(),
install_requires=[
'SimPy==2.3.1',
'numpy>=1.6'
],
long_description="""\
SimSo is a scheduling simulator for real-time multiprocessor architectures that
takes into account some scheduling overheads (scheduling decisions, context-
switches) and the impact of caches through statistical models. Based on a
Discrete-Event Simulator, it allows quick simulations and a fast prototyping
of scheduling policies using Python."""
)
__version__ = '0.7'
#!/usr/bin/python
# coding=utf-8
from xml.etree.ElementTree import Element, SubElement
from xml.etree import ElementTree
from xml.dom import minidom
def prettify(elem):
"""Return a pretty-printed XML string for the Element.
"""
rough_string = ElementTree.tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent="\t")
def generate(configuration):
"""
Generate a string containing the XML version of the configuration.
"""
attrs = {'duration': str(int(configuration.duration)),
'cycles_per_ms': str(configuration.cycles_per_ms),
'etm': str(configuration.etm)}
top = Element('simulation', attrs)
generate_sched(top, configuration.scheduler_info)
generate_cache(
top, configuration.caches_list, configuration.memory_access_time)
generate_processors(
top, configuration.proc_info_list, configuration.proc_data_fields)
generate_tasks(
top, configuration.task_info_list, configuration.task_data_fields)
return prettify(top)
def generate_sched(top, sched_info):
sched = SubElement(top, 'sched', {
'className': sched_info.name,
'overhead': str(sched_info.overhead),
'overhead_activate': str(sched_info.overhead_activate),
'overhead_terminate': str(sched_info.overhead_terminate)
})
for field_name in sched_info.data.keys():
SubElement(sched, 'field', {'name': field_name,
'value': str(sched_info.data[field_name]),
'type': sched_info.fields_types[field_name]
})
return sched
def generate_cache(top, caches_list, memory_access_time):
caches = SubElement(top, 'caches',
{'memory_access_time': str(memory_access_time)})
for cache in caches_list:
SubElement(caches, 'cache', {'name': cache.name,
'id': str(cache.identifier),
'policy': "LRU", # TODO
'type': "data", # TODO
'size': str(cache.size),
'access_time': str(cache.access_time)})
return caches
def generate_processors(top, proc_info_list, fields):
processors = SubElement(top, 'processors')
for name, ftype in fields.items():
attrs = {'name': name, 'type': ftype}
SubElement(processors, 'field', attrs)
for proc in proc_info_list:
attrs = dict((k, str(proc.data[k])) for k in proc.data.keys())
attrs.update({
'name': proc.name,
'id': str(proc.identifier),
'cl_overhead': str(proc.cl_overhead),
'cs_overhead': str(proc.cs_overhead),
'speed': str(proc.speed)})
processor = SubElement(processors, 'processor', attrs)
for cache in proc.caches:
SubElement(processor, 'cache', {'ref': str(cache.identifier)})
def generate_tasks(top, task_info_list, fields):
tasks = SubElement(top, 'tasks')
for name, ftype in fields.items():
attrs = {'name': name, 'type': ftype}
SubElement(tasks, 'field', attrs)
for task in task_info_list:
attrs = dict((k, str(task.data[k])) for k in task.data.keys())
attrs.update({'name': task.name,
'id': str(task.identifier),
'task_type': task.task_type,
'abort_on_miss': 'yes' if task.abort_on_miss else 'no',
'period': str(task.period),
'activationDate': str(task.activation_date),
'list_activation_dates': ', '.join(
map(str, task.list_activation_dates)),
'deadline': str(task.deadline),
'base_cpi': str(task.base_cpi),
'instructions': str(task.n_instr),
'mix': str(task.mix),
'WCET': str(task.wcet),
'ACET': str(task.acet),
'preemption_cost': str(task.preemption_cost),
'et_stddev': str(task.et_stddev)})
if task.followed_by is not None:
attrs['followed_by'] = str(task.followed_by)
if task.stack_file:
# XXX: what if the path contain a non-ascii character?
attrs['stack'] = str(task.stack_file)
SubElement(tasks, 'task', attrs)
from .Configuration import Configuration
# coding=utf-8
from xml.dom.minidom import parse
import os.path
from simso.core.Task import TaskInfo, task_types
from simso.core.Processor import ProcInfo
from simso.core.Caches import Cache_LRU
from simso.core.Scheduler import SchedulerInfo
convert_function = {
'int': int,
'float': float,
'bool': bool,
'str': str
}
class Parser(object):
"""
Simulation file parser.
"""
def __init__(self, filename):
self.filename = filename
self.cur_dir = os.path.split(filename)[0]
if not self.cur_dir:
self.cur_dir = '.'
self._dom = parse(filename)
self._parse_etm()
self._parse_duration()
self._parse_cycles_per_ms()
self._parse_caches()
self._parse_tasks()
self._parse_processors()
self._parse_scheduler()
self._parse_penalty()
def _parse_caches(self):
self.caches_list = []
caches_element = self._dom.getElementsByTagName('caches')[0]
caches = caches_element.getElementsByTagName('cache')
attr = caches_element.attributes
self.memory_access_time = 100
if 'memory_access_time' in attr:
self.memory_access_time = int(attr['memory_access_time'].value)
for cache in caches:
attr = cache.attributes
if attr['policy'].value == 'LRU' and attr['type'].value == 'data':
access_time = 1
associativity = int(attr['size'].value)
if 'access_time' in attr:
access_time = int(attr['access_time'].value)
if 'associativity' in attr:
associativity = int(attr['associativity'].value)
cache = Cache_LRU(attr['name'].value, int(attr['id'].value),
int(attr['size'].value), associativity,
access_time)
self.caches_list.append(cache)
# TODO Généraliser aux autres types de cache.
def _parse_tasks(self):
tasks_el = self._dom.getElementsByTagName('tasks')[0]
self.task_data_fields = {}
for field in tasks_el.getElementsByTagName('field'):
attr = field.attributes
self.task_data_fields[attr['name'].value] = attr['type'].value
tasks = tasks_el.getElementsByTagName('task')
self.task_info_list = []
for task in tasks:
attr = task.attributes
data = dict(
(k, convert_function[self.task_data_fields[k]](attr[k].value))
for k in attr.keys() if k in self.task_data_fields)
task_type = 'Periodic'
if 'task_type' in attr and attr['task_type'].value in task_types:
task_type = attr['task_type'].value
elif 'periodic' in attr and attr['periodic'].value == 'no':
task_type = 'APeriodic'
list_activation_dates = []
if 'list_activation_dates' in attr and attr['list_activation_dates'].value != '':
list_activation_dates = sorted(
map(float, attr['list_activation_dates'].value.split(',')))
t = TaskInfo(
attr['name'].value,
int(attr['id'].value),
task_type,
'abort_on_miss' in attr
and attr['abort_on_miss'].value == 'yes',
float(attr['period'].value),
float(attr['activationDate'].value)
if 'activationDate' in attr else 0,
int(attr['instructions'].value),
float(attr['mix'].value),
(self.cur_dir + '/' + attr['stack'].value,
self.cur_dir) if 'stack' in attr else ("", self.cur_dir),
float(attr['WCET'].value),
float(attr['ACET'].value) if 'ACET' in attr else 0,
float(attr['et_stddev'].value) if 'et_stddev' in attr else 0,
float(attr['deadline'].value),
float(attr['base_cpi'].value),
int(attr['followed_by'].value)
if 'followed_by' in attr else None,
list_activation_dates,
int(float(attr['preemption_cost'].value))
if 'preemption_cost' in attr else 0,
data)
self.task_info_list.append(t)
def _parse_processors(self):
processors_el = self._dom.getElementsByTagName('processors')[0]
processors = self._dom.getElementsByTagName('processors')[0]
attr = processors.attributes
migration_overhead = 0
if 'migration_overhead' in attr:
migration_overhead = int(attr['migration_overhead'].value)
self.proc_data_fields = {}
for field in processors_el.getElementsByTagName('field'):
attr = field.attributes
self.proc_data_fields[attr['name'].value] = attr['type'].value
cpus = processors.getElementsByTagName('processor')
self.proc_info_list = []
for cpu in cpus:
attr = cpu.attributes
data = dict(
(k, convert_function[self.proc_data_fields[k]](attr[k].value))
for k in attr.keys() if k in self.proc_data_fields)
cl_overhead = 0
cs_overhead = 0
if 'cl_overhead' in attr:
cl_overhead = int(float(attr['cl_overhead'].value))
if 'cs_overhead' in attr:
cs_overhead = int(float(attr['cs_overhead'].value))
speed = 1.0
if 'speed' in attr:
speed = float(attr['speed'].value)
proc = ProcInfo(name=attr['name'].value,
identifier=int(attr['id'].value),
cs_overhead=cs_overhead,
cl_overhead=cl_overhead,
migration_overhead=migration_overhead,
speed=speed,
data=data)
caches = cpu.getElementsByTagName('cache')
for cache_element in caches:
attr = cache_element.attributes
for cache in self.caches_list:
if cache.identifier == int(attr['ref'].value):
proc.add_cache(cache)
self.proc_info_list.append(proc)
def _parse_etm(self):
simulation = self._dom.getElementsByTagName('simulation')[0]
if 'etm' in simulation.attributes:
self.etm = simulation.attributes['etm'].value
else:
use_wcet = True
if 'use_wcet' in simulation.attributes:
use_wcet = (simulation.attributes['use_wcet'].value
in ('true', 'yes'))
if use_wcet:
self.etm = "wcet"
else:
self.etm = "cache"
def _parse_duration(self):
simulation = self._dom.getElementsByTagName('simulation')[0]
if 'duration' in simulation.attributes:
self.duration = int(simulation.attributes['duration'].value)
else:
self.duration = 50000
def _parse_penalty(self):
simulation = self._dom.getElementsByTagName('simulation')[0]
if 'penalty_preemption' in simulation.attributes:
self.penalty_preemption = int(
simulation.attributes['penalty_preemption'].value)
else:
self.penalty_preemption = 100000
if 'penalty_migration' in simulation.attributes:
self.penalty_migration = int(
simulation.attributes['penalty_migration'].value)
else:
self.penalty_migration = 100000
def _parse_cycles_per_ms(self):
simulation = self._dom.getElementsByTagName('simulation')[0]
if 'cycles_per_ms' in simulation.attributes:
self.cycles_per_ms = int(
simulation.attributes['cycles_per_ms'].value)
else:
self.cycles_per_ms = 1000000
def _parse_scheduler(self):
overhead = 0
overhead_activate = 0
overhead_terminate = 0
sched = self._dom.getElementsByTagName('sched')[0]
attr = sched.attributes
filename = attr['className'].value
if 'overhead' in attr:
overhead = int(float(attr['overhead'].value))
if 'overhead_activate' in attr:
overhead_activate = int(float(attr['overhead_activate'].value))
if 'overhead_terminate' in attr:
overhead_terminate = int(float(attr['overhead_terminate'].value))
data = {}
fields = sched.getElementsByTagName('field')
for field in fields:
name = field.attributes['name'].value
type_ = field.attributes['type'].value
value = field.attributes['value'].value
data[name] = (convert_function[type_](value), type_)
self.scheduler_info = SchedulerInfo(
overhead=overhead, overhead_activate=overhead_activate,
overhead_terminate=overhead_terminate, fields=data)
if filename[0] != '/':
filename = self.cur_dir + '/' + filename
self.scheduler_info.set_name(filename, self.cur_dir)
# coding=utf-8
class CSDP(object):
def __init__(self, stack):
self._csdp = [0]
c = 0
s = 0.0
for dist, value in stack.items():
while c < dist:
self._csdp.append(s)
c += 1
s += value
self._csdp.append(s)
def get(self, dist):
if dist < len(self._csdp):
return self._csdp[dist]
else:
return self._csdp[-1]
class Cache(object):
def __init__(self, name, identifier, size, associativity, access_time):
self.name = name
self.identifier = identifier
self.size = size
self.access_time = access_time
self.associativity = associativity
self.penalty = 0
self.shared_with = None
def init(self):
self.shared_with = []
class Cache_LRU(Cache):
def __init__(self, name, identifier, size, associativity, penalty):
Cache.__init__(self, name, identifier, size, associativity, penalty)
self._groups = None
def init(self):
Cache.init(self)
self._groups = []
def update(self, task, lines):
self._groups = [x for x in self._groups if x[0] != task]
self._groups.append([task, lines])
usedlines = sum([x[1] for x in self._groups])
while usedlines > self.size:
if self._groups[0][1] <= usedlines - self.size:
usedlines -= self._groups.pop(0)[1]
else:
self._groups[0][1] -= usedlines - self.size
usedlines = self.size
def get_lines(self, task):
groups = [x for x in self._groups if x[0] == task]
return groups and groups[0][1] or 0
# coding=utf-8
from SimPy.Simulation import Process, hold, passivate
from simso.core.JobEvent import JobEvent
from math import ceil
class Job(Process):
"""The Job class simulate the behavior of a real Job. This *should* only be
instantiated by a Task."""
def __init__(self, task, name, pred, monitor, etm, sim):
"""
Args:
- `task`: The parent :class:`task <simso.core.Task.Task>`.
- `name`: The name for this job.
- `pred`: If the task is not periodic, pred is the job that \
released this one.
- `monitor`: A monitor is an object that log in time.
- `etm`: The execution time model.
- `sim`: :class:`Model <simso.core.Model>` instance.
:type task: GenericTask
:type name: str
:type pred: bool
:type monitor: Monitor
:type etm: AbstractExecutionTimeModel
:type sim: Model
"""
Process.__init__(self, name=name, sim=sim)
self._task = task
self._pred = pred
self.instr_count = 0 # Updated by the cache model.
self._computation_time = 0
self._last_exec = None
self._n_instr = task.n_instr
self._start_date = None
self._end_date = None
self._is_preempted = False
self._activation_date = self.sim.now_ms()
self._absolute_deadline = self.sim.now_ms() + task.deadline
self._aborted = False
self._sim = sim
self._monitor = monitor
self._etm = etm
self._was_running_on = task.cpu
self._on_activate()
self.context_ok = True # The context is ready to be loaded.
def is_active(self):
"""
Return True if the job is still active.
"""
return self._end_date is None
def _on_activate(self):
self._monitor.observe(JobEvent(self, JobEvent.ACTIVATE))
self._sim.logger.log(self.name + " Activated.", kernel=True)
self._etm.on_activate(self)
def _on_execute(self):
self._last_exec = self.sim.now()
self._etm.on_execute(self)
if self._is_preempted:
self._is_preempted = False
self.cpu.was_running = self
self._monitor.observe(JobEvent(self, JobEvent.EXECUTE, self.cpu))
self._sim.logger.log("{} Executing on {}".format(
self.name, self._task.cpu.name), kernel=True)
def _on_stop_exec(self):
if self._last_exec is not None:
self._computation_time += self.sim.now() - self._last_exec
self._last_exec = None
def _on_preempted(self):
self._on_stop_exec()
self._etm.on_preempted(self)
self._is_preempted = True
self._was_running_on = self.cpu
self._monitor.observe(JobEvent(self, JobEvent.PREEMPTED))
self._sim.logger.log(self.name + " Preempted! ret: " +
str(self.interruptLeft), kernel=True)
def _on_terminated(self):
self._on_stop_exec()
self._etm.on_terminated(self)
self._end_date = self.sim.now()
self._monitor.observe(JobEvent(self, JobEvent.TERMINATED))
self._task.end_job(self)
self._task.cpu.terminate(self)
self._sim.logger.log(self.name + " Terminated.", kernel=True)
def _on_abort(self):
self._on_stop_exec()
self._etm.on_abort(self)
self._end_date = self.sim.now()
self._aborted = True
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))
def is_running(self):
"""
Return True if the job is currently running on a processor.
Equivalent to ``self.cpu.running == self``.
:rtype: bool
"""
return self.cpu.running == self
def abort(self):
"""
Abort this job. Warning, this is currently only used by the Task when
the job exceeds its deadline. It has not be tested from outside, such
as from the scheduler.
"""
self._on_abort()
@property
def aborted(self):
"""
True if the job has been aborted.
:rtype: bool
"""
return self._aborted
@property
def exceeded_deadline(self):
"""
True if the end_date is greater than the deadline or if the job was
aborted.
"""
return (self._absolute_deadline * self._sim.cycles_per_ms <
self._end_date or self._aborted)
@property
def start_date(self):
"""
Date (in ms) when this job started executing
(different than the activation).
"""
return self._start_date
@property
def end_date(self):
"""
Date (in ms) when this job finished its execution.
"""
return self._end_date
@property
def response_time(self):
if self._end_date:
return (float(self._end_date) / self._sim.cycles_per_ms -
self._activation_date)
else:
return None
@property
def ret(self):
"""
Remaining execution time.
"""
return self.wcet - self.actual_computation_time
@property
def computation_time(self):
return float(self.computation_time_cycles) / self._sim.cycles_per_ms
@property
def computation_time_cycles(self):
if self._last_exec is None:
return int(self._computation_time)
else:
return (int(self._computation_time) +
self.sim.now() - self._last_exec)
@property
def actual_computation_time(self):
return float(
self.actual_computation_time_cycles) / self._sim.cycles_per_ms
@property
def actual_computation_time_cycles(self):
"""
Computation time as if the processor speed was 1.0 during the whole
execution.
"""
return self._etm.get_executed(self)
@property
def cpu(self):
"""
The :class:`processor <simso.core.Processor.Processor>` on which the
job is attached. Equivalent to ``self.task.cpu``.
"""
return self._task.cpu
@property
def task(self):
"""The :class:`task <simso.core.Task.Task>` for this job."""
return self._task
@property
def data(self):
"""
The extra data specified for the task. Equivalent to
``self.task.data``.
"""
return self._task.data
@property
def wcet(self):
"""
Worst-Case Execution Time in milliseconds.
Equivalent to ``self.task.wcet``.
"""
return self._task.wcet
@property
def activation_date(self):
"""
Activation date in milliseconds for this job.
"""
return self._activation_date
@property
def absolute_deadline(self):
"""
Absolute deadline in milliseconds for this job. This is the activation
date + the relative deadline.
"""
return self._absolute_deadline
@property
def absolute_deadline_cycles(self):
return self._absolute_deadline * self._sim.cycles_per_ms
@property
def period(self):
"""Period in milliseconds. Equivalent to ``self.task.period``."""
return self._task.period
@property
def deadline(self):
"""
Relative deadline in milliseconds.
Equivalent to ``self.task.deadline``.
"""
return self._task.deadline
@property
def pred(self):
return self._pred
def activate_job(self):
self._start_date = self.sim.now()
# Notify the OS.
self._task.cpu.activate(self)
# While the job's execution is not finished.
while self._end_date is None:
# Wait an execute order.
yield passivate, self
# Execute the job.
if not self.interrupted():
self._on_execute()
# ret is a duration lower than the remaining execution time.
ret = self._etm.get_ret(self)
while ret > 0:
yield hold, self, int(ceil(ret))
if not self.interrupted():
# If executed without interruption for ret cycles.
ret = self._etm.get_ret(self)
else:
self._on_preempted()
self.interruptReset()
break
if ret <= 0:
# End of job.
self._on_terminated()
else:
self.interruptReset()
# coding=utf-8
class JobEvent:
ACTIVATE = 1
EXECUTE = 2
PREEMPTED = 3
TERMINATED = 4
ABORTED = 5
count = 0
def __init__(self, job, event, cpu=None):
self.event = event
self.job = job
self.cpu = cpu
JobEvent.count += 1
self.id_ = JobEvent.count
# coding=utf-8
from SimPy.Simulation import Monitor
class Logger(object):
"""
Simple logger. Every message is logged with its date.
"""
def __init__(self, sim):
"""
Args:
- `sim`: The :class:`model <simso.core.Model.Model>` object.
"""
self.sim = sim
self._logs = Monitor(name="Logs", sim=sim)
def log(self, msg, kernel=False):
"""
Log the message `msg`.
Args:
- `msg`: The message to log.
- `kernel`: Allows to make a distinction between a message from \
the core of the simulation or from the scheduler.
"""
self._logs.observe((msg, kernel))
@property
def logs(self):
"""
The logs, a SimPy Monitor object.
"""
return self._logs
# coding=utf-8
from SimPy.Simulation import Simulation
from simso.core.Processor import Processor
from simso.core.Task import Task
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
class Model(Simulation):
"""
Main class for the simulation. It instantiate the various components
required by the simulation and run it.
"""
def __init__(self, configuration, callback=None):
"""
Args:
- `callback`: A callback can be specified. This function will be \
called to report the advance of the simulation (useful for a \
progression bar).
- `configuration`: The :class:`configuration \
<simso.configuration.Configuration>` of the simulation.
Methods:
"""
Simulation.__init__(self)
self._logger = Logger(self)
task_info_list = configuration.task_info_list
proc_info_list = configuration.proc_info_list
self._cycles_per_ms = configuration.cycles_per_ms
self.scheduler = configuration.scheduler_info.instantiate(self)
try:
self._etm = execution_time_models[configuration.etm](
self, len(proc_info_list)
)
except KeyError:
print("Unknowned Execution Time Model.", configuration.etm)
self._task_list = []
for task_info in task_info_list:
self._task_list.append(Task(self, task_info))
# Init the processor class. This will in particular reinit the
# identifiers to 0.
Processor.init()
# Initialization of the caches
for cache in configuration.caches_list:
cache.init()
self._processors = []
for proc_info in proc_info_list:
proc = Processor(self, proc_info)
proc.caches = proc_info.caches
self._processors.append(proc)
# XXX: too specific.
self.penalty_preemption = configuration.penalty_preemption
self.penalty_migration = configuration.penalty_migration
self._etm.init()
self._duration = configuration.duration
self.progress = Timer(self, Model._on_tick, (self,),
self.duration // 20 + 1, one_shot=False,
in_ms=False)
self._callback = callback
self.scheduler.task_list = self._task_list
self.scheduler.processors = self._processors
self.results = None
def now_ms(self):
return float(self.now()) / self._cycles_per_ms
@property
def logs(self):
"""
All the logs from the :class:`Logger <simso.core.Logger.Logger>`.
"""
return self._logger.logs
@property
def logger(self):
return self._logger
@property
def cycles_per_ms(self):
"""
Number of cycles per milliseconds. A cycle is the internal unit used
by SimSo. However, the tasks are defined using milliseconds.
"""
return self._cycles_per_ms
@property
def etm(self):
"""
Execution Time Model
"""
return self._etm
@property
def processors(self):
"""
List of all the processors.
"""
return self._processors
@property
def task_list(self):
"""
List of all the tasks.
"""
return self._task_list
@property
def duration(self):
"""
Duration of the simulation.
"""
return self._duration
def _on_tick(self):
if self._callback:
self._callback(self.now())
def run_model(self):
""" Execute the simulation."""
self.initialize()
self.scheduler.init()
self.progress.start()
for cpu in self._processors:
self.activate(cpu, cpu.run())
for task in self._task_list:
self.activate(task, task.execute())
try:
self.simulate(until=self._duration)
finally:
self._etm.update()
if self.now() > 0:
self.results = Results(self)
self.results.end()
# coding=utf-8
class ProcEvent(object):
RUN = 1
IDLE = 2
OVERHEAD = 3
def __init__(self, event=0, args=None):
self.event = event
self.args = args
class ProcRunEvent(ProcEvent):
def __init__(self, job):
ProcEvent.__init__(self, ProcEvent.RUN, job)
class ProcIdleEvent(ProcEvent):
def __init__(self):
ProcEvent.__init__(self, ProcEvent.IDLE)
class ProcOverheadEvent(ProcEvent):
def __init__(self, type_overhead):
ProcEvent.__init__(self, ProcEvent.OVERHEAD, type_overhead)
class ProcCxtSaveEvent(ProcOverheadEvent):
def __init__(self, terminated=False):
ProcOverheadEvent.__init__(self, "CS")
self.terminated = terminated
class ProcCxtLoadEvent(ProcOverheadEvent):
def __init__(self, terminated=False):
ProcOverheadEvent.__init__(self, "CL")
self.terminated = terminated
# coding=utf-8
from collections import deque
from SimPy.Simulation import Process, Monitor, hold, waituntil
from simso.core.ProcEvent import ProcRunEvent, ProcIdleEvent, \
ProcOverheadEvent, ProcCxtSaveEvent, ProcCxtLoadEvent
RESCHED = 1
ACTIVATE = 2
TERMINATE = 3
TIMER = 4
MIGRATE = 5
SPEED = 6
class ProcInfo(object):
def __init__(self, identifier, name, cs_overhead=0, cl_overhead=0,
migration_overhead=0, speed=1.0, data=None):
self.identifier = identifier
self.name = name
self.penalty = 0
self.caches = []
self.cs_overhead = cs_overhead
self.cl_overhead = cl_overhead
self.migration_overhead = migration_overhead
if data is None:
data = {}
self.data = data
self.speed = speed
def add_cache(self, cache):
self.caches.append(cache)
class Processor(Process):
"""
A processor is responsible of deciding whether the simulated processor
should execute a job or execute the scheduler. There is one instance of
Processor per simulated processor. Those are responsible to call the
scheduler methods.
When a scheduler needs to take a scheduling decision, it must invoke the
:meth:`resched` method. This is typically done in the :meth:`on_activate
<simso.core.Scheduler.Scheduler.on_activate>`, :meth:`on_terminated
<simso.core.Scheduler.Scheduler.on_terminated>` or in a :class:`timer
<simso.core.Timer.Timer>` handler.
"""
_identifier = 0
@classmethod
def init(cls):
cls._identifier = 0
def __init__(self, model, proc_info):
Process.__init__(self, name=proc_info.name, sim=model)
self._model = model
self._internal_id = Processor._identifier
Processor._identifier += 1
self.identifier = proc_info.identifier
self._running = None
self.was_running = None
self._evts = deque([])
self.sched = model.scheduler
self.monitor = Monitor(name="Monitor" + proc_info.name, sim=model)
self._caches = []
self._penalty = proc_info.penalty
self._cs_overhead = proc_info.cs_overhead
self._cl_overhead = proc_info.cl_overhead
self._migration_overhead = proc_info.migration_overhead
self.set_caches(proc_info.caches)
self.timer_monitor = Monitor(name="Monitor Timer" + proc_info.name,
sim=model)
self._speed = proc_info.speed
def resched(self):
"""
Add a resched event to the list of events to handle.
"""
self._evts.append((RESCHED,))
def migrate(self, job):
self._evts.append((MIGRATE, job))
self._running = job
def activate(self, job):
self._evts.append((ACTIVATE, job))
def terminate(self, job):
self._evts.append((TERMINATE, job))
self._running = None
def preempt(self):
if MIGRATE not in self._evts:
self._evts.append(("preempt",))
self._running = None
def timer(self, timer):
self._evts.append((TIMER, timer))
def set_speed(self, speed):
assert speed >= 0, "Speed must be positive."
self._evts.append((SPEED, speed))
@property
def speed(self):
return self._speed
def is_running(self):
"""
Return True if a job is currently running on that processor.
"""
return self._running is not None
def set_caches(self, caches):
self._caches = caches
for cache in caches:
cache.shared_with.append(self)
def get_caches(self):
return self._caches
caches = property(get_caches, set_caches)
@property
def penalty_memaccess(self):
return self._penalty
@property
def cs_overhead(self):
return self._cs_overhead
@property
def cl_overhead(self):
return self._cl_overhead
@property
def internal_id(self):
"""A unique, internal, id."""
return self._internal_id
@property
def running(self):
"""
The job currently running on that processor. None if no job is
currently running on the processor.
"""
return self._running
def run(self):
while True:
if not self._evts:
job = self._running
if job:
yield waituntil, self, lambda: job.context_ok
self.monitor.observe(ProcCxtLoadEvent())
yield hold, self, self.cl_overhead # overhead load context
self.monitor.observe(ProcCxtLoadEvent(terminated=True))
job.interruptReset()
self.sim.reactivate(job)
self.monitor.observe(ProcRunEvent(job))
job.context_ok = False
else:
self.monitor.observe(ProcIdleEvent())
# Wait event.
yield waituntil, self, lambda: self._evts
if job:
self.interrupt(job)
self.monitor.observe(ProcCxtSaveEvent())
yield hold, self, self.cs_overhead # overhead save context
self.monitor.observe(ProcCxtSaveEvent(terminated=True))
job.context_ok = True
evt = self._evts.popleft()
if evt[0] == RESCHED:
if any(x[0] != RESCHED for x in self._evts):
self._evts.append(evt)
continue
if evt[0] == ACTIVATE:
self.sched.on_activate(evt[1])
self.monitor.observe(ProcOverheadEvent("JobActivation"))
self.sched.monitor_begin_activate(self)
yield hold, self, self.sched.overhead_activate
self.sched.monitor_end_activate(self)
elif evt[0] == TERMINATE:
self.sched.on_terminated(evt[1])
self.monitor.observe(ProcOverheadEvent("JobTermination"))
self.sched.monitor_begin_terminate(self)
yield hold, self, self.sched.overhead_terminate
self.sched.monitor_end_terminate(self)
elif evt[0] == TIMER:
self.timer_monitor.observe(None)
if evt[1].overhead > 0:
print(self.sim.now(), "hold", evt[1].overhead)
yield hold, self, evt[1].overhead
evt[1].call_handler()
elif evt[0] == MIGRATE:
self._running = evt[1]
self.monitor.observe(ProcOverheadEvent("Migration"))
#yield hold, self, self._migration_overhead #overhead migration
elif evt[0] == SPEED:
self._speed = evt[1]
elif evt[0] == RESCHED:
self.monitor.observe(ProcOverheadEvent("Scheduling"))
self.sched.monitor_begin_schedule(self)
yield waituntil, self, self.sched.get_lock
decisions = self.sched.schedule(self)
yield hold, self, self.sched.overhead # overhead scheduling
if type(decisions) is not list:
decisions = [decisions]
for decision in decisions:
if decision is None:
continue
else:
job, cpu = decision
if cpu.running == job:
continue
if job is not None and not job.is_active():
print("Can't schedule a terminated job! ({})"
.format(job.name))
continue
# if the job was running somewhere else, stop it.
if job and job.cpu.running == job:
job.cpu.preempt()
# Send that job to processor cpu.
if job is None:
cpu.preempt()
else:
cpu.migrate(job)
if job:
job.task.cpu = cpu
running_tasks = [
cpu.running.name
for cpu in self._model.processors if cpu.running]
#if len(set(running_tasks)) != len(running_tasks):
# print(running_tasks)
assert len(set(running_tasks)) == len(running_tasks), \
"Try to run a job on 2 processors simultaneously!"
self.sched.release_lock()
self.sched.monitor_end_schedule(self)
from __future__ import print_function
import sys
import imp
import os.path
from simso.core.SchedulerEvent import SchedulerBeginScheduleEvent, \
SchedulerEndScheduleEvent, SchedulerBeginActivateEvent, \
SchedulerEndActivateEvent, SchedulerBeginTerminateEvent, \
SchedulerEndTerminateEvent
from SimPy.Simulation import Monitor
class SchedulerInfo(object):
"""
SchedulerInfo groups the data that characterize a Scheduler (such as the
scheduling overhead) and do the dynamic loading of the scheduler.
"""
def __init__(self, name='', cls=None, overhead=0, overhead_activate=0,
overhead_terminate=0, fields=None):
"""
Args:
- `name`: Name of the scheduler.
- `cls`: Class associated to this scheduler.
- `overhead`: Overhead associated to a scheduling decision.
Methods:
"""
self._name = name
self._filename = None
self._cls = cls
self.overhead = overhead
self.overhead_activate = overhead_activate
self.overhead_terminate = overhead_terminate
self.data = {}
self.fields_types = {}
if fields:
for key, value in fields.items():
self.data[key] = value[0]
self.fields_types[key] = value[1]
def set_fields(self, fields):
for key, value in fields.items():
self.data[key] = value[0]
self.fields_types[key] = value[1]
def set_name(self, filename, cur_dir=None):
"""
Set the scheduler from a file.
Args:
- `filename`: relative path to the Python source containing the \
Scheduler.
- `cur_dir`: current directory. Used to set the name relatively \
to the simulation file.
"""
if cur_dir is None:
cur_dir = os.curdir
self._name = os.path.relpath(filename, cur_dir)
self._filename = filename
@property
def name(self):
"""
The name of the Scheduler (its relative path to the XML).
"""
return self._name
@property
def filename(self):
"""
Path of the scheduler (absolute or relative to simso's working
directory).
"""
return self._filename
def get_cls(self):
"""
Get the class of this scheduler.
"""
if self._filename:
(path, name) = os.path.split(self._filename)
name = os.path.splitext(name)[0]
try:
fp, pathname, description = imp.find_module(name, [path])
if path not in sys.path:
sys.path.append(path)
self._cls = getattr(imp.load_module(name, fp, pathname,
description), name)
fp.close()
except ImportError as e:
print("ImportError: ", e)
print("name: ", name, "path: ", path)
return self._cls
def instantiate(self, model):
"""
Instantiate the :class:`Scheduler` class.
Args:
- `model`: The :class:`Model <simso.core.Model.Model>` object \
that is passed to the constructor.
"""
cls = self.get_cls()
return cls(model, self)
class Scheduler(object):
"""
The implementation of a scheduler is done by subclassing this abstract
class.
The scheduling events are modeled by method calls which take as arguments
the :class:`jobs <simso.core.Job.Job>` and the :class:`processors
<simso.core.Processor.Processor>`.
The following methods should be redefined in order to interact with the
simulation:
- :meth:`init` Called when the simulation is ready. The scheduler \
logic should be initialized here.
- :meth:`on_activate` Called upon a job activation.
- :meth:`on_terminated` Called when a job is terminated.
- :meth:`schedule` Take the scheduling decision. This method should \
not be called directly. A call to the :meth:`resched \
<simso.core.Processor.Processor.resched>` method is required.
By default, the scheduler can only run on a single processor at the same
simulation time. It is also possible to override this behavior by
overriding the :meth:`get_lock` and :meth:`release_lock` methods.
"""
def __init__(self, sim, scheduler_info, **kwargs):
"""
Args:
- `sim`: :class:`Model <simso.core.Model>` instance.
- `scheduler_info`: A :class:`SchedulerInfo` representing the \
scheduler.
Attributes:
- **sim**: :class:`Model <simso.core.Model.Model>` instance. \
Useful to get current time with ``sim.now_ms()`` (in ms) or \
``sim.now()`` (in cycles).
- **processors**: List of :class:`processors \
<simso.core.Processor.Processor>` handled by this scheduler.
- **task_list**: List of :class:`tasks <simso.core.Task.GenericTask>` \
handled by this scheduler.
Methods:
"""
self.sim = sim
self.processors = []
self.task_list = []
self._lock = False
self.overhead = scheduler_info.overhead
self.overhead_activate = scheduler_info.overhead_activate
self.overhead_terminate = scheduler_info.overhead_terminate
self.data = scheduler_info.data
self.monitor = Monitor(name="MonitorScheduler", sim=sim)
def init(self):
"""
This method is called when the system is ready to run. This method
should be used in lieu of the __init__ method. This method is
guaranteed to be called when the simulation starts, after the tasks
are instantiated
"""
pass
def on_activate(self, job):
"""
This method is called upon a job activation.
Args:
- `job`: The activated :class:`job <simso.core.Job.Job>`.
"""
pass
def on_terminated(self, job):
"""
This method is called when a job finish (termination or abortion).
Args:
- `job`: The :class:`job <simso.core.Job.Job>` that terminates .
"""
pass
def schedule(self, cpu):
"""
The schedule method must be redefined by the simulated scheduler.
It takes as argument the cpu on which the scheduler runs.
Args:
- `cpu`: The :class:`processor <simso.core.Processor.Processor>` \
on which the scheduler runs.
Returns a decision or a list of decisions. A decision is a couple
(job, cpu).
"""
raise NotImplementedError("Function schedule to override!")
def add_task(self, task):
"""
Add a task to the list of tasks handled by this scheduler.
Args:
- `task`: The :class:`task <simso.core.Task.GenericTask>` to add.
"""
self.task_list.append(task)
def add_processor(self, cpu):
"""
Add a processor to the list of processors handled by this scheduler.
Args:
- `processor`: The :class:`processor \
<simso.core.Processor.Processor>` to add.
"""
self.processors.append(cpu)
def get_lock(self):
"""
Implement a lock mechanism. Override it to remove the lock or change
its behavior.
"""
if not self._lock:
self._lock = True
else:
return False
return True
def release_lock(self):
"""
Release the lock. Goes in pair with :meth:`get_lock`.
"""
self._lock = False
def monitor_begin_schedule(self, cpu):
self.monitor.observe(SchedulerBeginScheduleEvent(cpu))
def monitor_end_schedule(self, cpu):
self.monitor.observe(SchedulerEndScheduleEvent(cpu))
def monitor_begin_activate(self, cpu):
self.monitor.observe(SchedulerBeginActivateEvent(cpu))
def monitor_end_activate(self, cpu):
self.monitor.observe(SchedulerEndActivateEvent(cpu))
def monitor_begin_terminate(self, cpu):
self.monitor.observe(SchedulerBeginTerminateEvent(cpu))
def monitor_end_terminate(self, cpu):
self.monitor.observe(SchedulerEndTerminateEvent(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