Commit 67af12be by Maxime Chéramy

Initial commit with SimSo 0.7 (core only).

parent 71f2ef17
Copyright LAAS-CNRS (2012-2013)
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.
==========
CeCILL FREE SOFTWARE LICENSE AGREEMENT
Notice
This Agreement is a Free Software license agreement that is the result
of discussions between its authors in order to ensure compliance with
the two main principles guiding its drafting:
* firstly, compliance with the principles governing the distribution
of Free Software: access to source code, broad rights granted to
users,
* secondly, the election of a governing law, French law, with which
it is conformant, both as regards the law of torts and
intellectual property law, and the protection that it offers to
both authors and holders of the economic rights over software.
The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre])
license are:
Commissariat à l'Energie Atomique - CEA, a public scientific, technical
and industrial research establishment, having its principal place of
business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France.
Centre National de la Recherche Scientifique - CNRS, a public scientific
and technological establishment, having its principal place of business
at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
Institut National de Recherche en Informatique et en Automatique -
INRIA, a public scientific and technological establishment, having its
principal place of business at Domaine de Voluceau, Rocquencourt, BP
105, 78153 Le Chesnay cedex, France.
Preamble
The purpose of this Free Software license agreement is to grant users
the right to modify and redistribute the software governed by this
license within the framework of an open source distribution model.
The exercising of these rights is conditional upon certain obligations
for users so as to preserve this status for all subsequent redistributions.
In consideration of access to the source code and the 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 only have limited liability.
In this respect, the risks associated with loading, using, modifying
and/or developing or reproducing the software by the user are brought to
the user's attention, given its Free Software status, which may make it
complicated to use, with the result that its use is reserved for
developers and experienced professionals having in-depth computer
knowledge. Users are therefore encouraged to load and test the
suitability of the software 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 of
security. This Agreement may be freely reproduced and published,
provided it is not altered, and that no provisions are either added or
removed herefrom.
This Agreement may apply to any or all software for which the holder of
the economic rights decides to submit the use thereof to its provisions.
Article 1 - DEFINITIONS
For the purpose of this Agreement, when the following expressions
commence with a capital letter, they shall have the following meaning:
Agreement: means this license agreement, and its possible subsequent
versions and annexes.
Software: means the software in its Object Code and/or Source Code form
and, where applicable, its documentation, "as is" when the Licensee
accepts the Agreement.
Initial Software: means the Software in its Source Code and possibly its
Object Code form and, where applicable, its documentation, "as is" when
it is first distributed under the terms and conditions of the Agreement.
Modified Software: means the Software modified by at least one
Contribution.
Source Code: means all the Software's instructions and program lines to
which access is required so as to modify the Software.
Object Code: means the binary files originating from the compilation of
the Source Code.
Holder: means the holder(s) of the economic rights over the Initial
Software.
Licensee: means the Software user(s) having accepted the Agreement.
Contributor: means a Licensee having made at least one Contribution.
Licensor: means the Holder, or any other individual or legal entity, who
distributes the Software under the Agreement.
Contribution: means any or all modifications, corrections, translations,
adaptations and/or new functions integrated into the Software by any or
all Contributors, as well as any or all Internal Modules.
Module: means a set of sources files including their documentation that
enables supplementary functions or services in addition to those offered
by the Software.
External Module: means any or all Modules, not derived from the
Software, so that this Module and the Software run in separate address
spaces, with one calling the other when they are run.
Internal Module: means any or all Module, connected to the Software so
that they both execute in the same address space.
GNU GPL: means the GNU General Public License version 2 or any
subsequent version, as published by the Free Software Foundation Inc.
Parties: mean both the Licensee and the Licensor.
These expressions may be used both in singular and plural form.
Article 2 - PURPOSE
The purpose of the Agreement is the grant by the Licensor to the
Licensee of a non-exclusive, transferable and worldwide license for the
Software as set forth in Article 5 hereinafter for the whole term of the
protection granted by the rights over said Software.
Article 3 - ACCEPTANCE
3.1 The Licensee shall be deemed as having accepted the terms and
conditions of this Agreement upon the occurrence of the first of the
following events:
* (i) loading the Software by any or all means, notably, by
downloading from a remote server, or by loading from a physical
medium;
* (ii) the first time the Licensee exercises any of the rights
granted hereunder.
3.2 One copy of the Agreement, containing a notice relating to the
characteristics of the Software, to the limited warranty, and to the
fact that its use is restricted to experienced users has been provided
to the Licensee prior to its acceptance as set forth in Article 3.1
hereinabove, and the Licensee hereby acknowledges that it has read and
understood it.
Article 4 - EFFECTIVE DATE AND TERM
4.1 EFFECTIVE DATE
The Agreement shall become effective on the date when it is accepted by
the Licensee as set forth in Article 3.1.
4.2 TERM
The Agreement shall remain in force for the entire legal term of
protection of the economic rights over the Software.
Article 5 - SCOPE OF RIGHTS GRANTED
The Licensor hereby grants to the Licensee, who accepts, the following
rights over the Software for any or all use, and for the term of the
Agreement, on the basis of the terms and conditions set forth hereinafter.
Besides, if the Licensor owns or comes to own one or more patents
protecting all or part of the functions of the Software or of its
components, the Licensor undertakes not to enforce the rights granted by
these patents against successive Licensees using, exploiting or
modifying the Software. If these patents are transferred, the Licensor
undertakes to have the transferees subscribe to the obligations set
forth in this paragraph.
5.1 RIGHT OF USE
The Licensee is authorized to use the Software, without any limitation
as to its fields of application, with it being hereinafter specified
that this comprises:
1. permanent or temporary reproduction of all or part of the Software
by any or all means and in any or all form.
2. loading, displaying, running, or storing the Software on any or
all medium.
3. entitlement to observe, study or test its operation so as to
determine the ideas and principles behind any or all constituent
elements of said Software. This shall apply when the Licensee
carries out any or all loading, displaying, running, transmission
or storage operation as regards the Software, that it is entitled
to carry out hereunder.
5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS
The right to make Contributions includes the right to translate, adapt,
arrange, or make any or all modifications to the Software, and the right
to reproduce the resulting software.
The Licensee is authorized to make any or all Contributions to the
Software provided that it includes an explicit notice that it is the
author of said Contribution and indicates the date of the creation thereof.
5.3 RIGHT OF DISTRIBUTION
In particular, the right of distribution includes the right to publish,
transmit and communicate the Software to the general public on any or
all medium, and by any or all means, and the right to market, either in
consideration of a fee, or free of charge, one or more copies of the
Software by any means.
The Licensee is further authorized to distribute copies of the modified
or unmodified Software to third parties according to the terms and
conditions set forth hereinafter.
5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
The Licensee is authorized to distribute true copies of the Software in
Source Code or Object Code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's
warranty and liability as set forth in Articles 8 and 9,
and that, in the event that only the Object Code of the Software is
redistributed, the Licensee allows future Licensees unhindered access to
the full Source Code of the Software by indicating how to access it, it
being understood that the additional cost of acquiring the Source Code
shall not exceed the cost of transferring the data.
5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
When the Licensee makes a Contribution to the Software, the terms and
conditions for the distribution of the resulting Modified Software
become subject to all the provisions of this Agreement.
The Licensee is authorized to distribute the Modified Software, in
source code or object code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's
warranty and liability as set forth in Articles 8 and 9,
and that, in the event that only the object code of the Modified
Software is redistributed, the Licensee allows future Licensees
unhindered access to the full source code of the Modified Software by
indicating how to access it, it being understood that the additional
cost of acquiring the source code shall not exceed the cost of
transferring the data.
5.3.3 DISTRIBUTION OF EXTERNAL MODULES
When the Licensee has developed an External Module, the terms and
conditions of this Agreement do not apply to said External Module, that
may be distributed under a separate license agreement.
5.3.4 COMPATIBILITY WITH THE GNU GPL
The Licensee can include a code that is subject to the provisions of one
of the versions of the GNU GPL in the Modified or unmodified Software,
and distribute that entire code under the terms of the same version of
the GNU GPL.
The Licensee can include the Modified or unmodified Software in a code
that is subject to the provisions of one of the versions of the GNU GPL,
and distribute that entire code under the terms of the same version of
the GNU GPL.
Article 6 - INTELLECTUAL PROPERTY
6.1 OVER THE INITIAL SOFTWARE
The Holder owns the economic rights over the Initial Software. Any or
all use of the Initial Software is subject to compliance with the terms
and conditions under which the Holder has elected to distribute its work
and no one shall be entitled to modify the terms and conditions for the
distribution of said Initial Software.
The Holder undertakes that the Initial Software will remain ruled at
least by this Agreement, for the duration set forth in Article 4.2.
6.2 OVER THE CONTRIBUTIONS
The Licensee who develops a Contribution is the owner of the
intellectual property rights over this Contribution as defined by
applicable law.
6.3 OVER THE EXTERNAL MODULES
The Licensee who develops an External Module is the owner of the
intellectual property rights over this External Module as defined by
applicable law and is free to choose the type of agreement that shall
govern its distribution.
6.4 JOINT PROVISIONS
The Licensee expressly undertakes:
1. not to remove, or modify, in any manner, the intellectual property
notices attached to the Software;
2. to reproduce said notices, in an identical manner, in the copies
of the Software modified or not.
The Licensee undertakes not to directly or indirectly infringe the
intellectual property rights of the Holder and/or Contributors on the
Software and to take, where applicable, vis-à-vis its staff, any and all
measures required to ensure respect of said intellectual property rights
of the Holder and/or Contributors.
Article 7 - RELATED SERVICES
7.1 Under no circumstances shall the Agreement oblige the Licensor to
provide technical assistance or maintenance services for the Software.
However, the Licensor is entitled to offer this type of services. The
terms and conditions of such technical assistance, and/or such
maintenance, shall be set forth in a separate instrument. Only the
Licensor offering said maintenance and/or technical assistance services
shall incur liability therefor.
7.2 Similarly, any Licensor is entitled to offer to its licensees, under
its sole responsibility, a warranty, that shall only be binding upon
itself, for the redistribution of the Software and/or the Modified
Software, under terms and conditions that it is free to decide. Said
warranty, and the financial terms and conditions of its application,
shall be subject of a separate instrument executed between the Licensor
and the Licensee.
Article 8 - LIABILITY
8.1 Subject to the provisions of Article 8.2, the Licensee shall be
entitled to claim compensation for any direct loss it may have suffered
from the Software as a result of a fault on the part of the relevant
Licensor, subject to providing evidence thereof.
8.2 The Licensor's liability is limited to the commitments made under
this Agreement and shall not be incurred as a result of in particular:
(i) loss due the Licensee's total or partial failure to fulfill its
obligations, (ii) direct or consequential loss that is suffered by the
Licensee due to the use or performance of the Software, and (iii) more
generally, any consequential loss. In particular the Parties expressly
agree that any or all pecuniary or business loss (i.e. loss of data,
loss of profits, operating loss, loss of customers or orders,
opportunity cost, any disturbance to business activities) or any or all
legal proceedings instituted against the Licensee by a third party,
shall constitute consequential loss and shall not provide entitlement to
any or all compensation from the Licensor.
Article 9 - WARRANTY
9.1 The Licensee acknowledges that the scientific and technical
state-of-the-art when the Software was distributed did not enable all
possible uses to be tested and verified, nor for the presence of
possible defects to be detected. In this respect, the Licensee's
attention has been drawn to the risks associated with loading, using,
modifying and/or developing and reproducing the Software which are
reserved for experienced users.
The Licensee shall be responsible for verifying, by any or all means,
the suitability of the product for its requirements, its good working
order, and for ensuring that it shall not cause damage to either persons
or properties.
9.2 The Licensor hereby represents, in good faith, that it is entitled
to grant all the rights over the Software (including in particular the
rights set forth in Article 5).
9.3 The Licensee acknowledges that the Software is supplied "as is" by
the Licensor without any other express or tacit warranty, other than
that provided for in Article 9.2 and, in particular, without any warranty
as to its commercial value, its secured, safe, innovative or relevant
nature.
Specifically, the Licensor does not warrant that the Software is free
from any error, that it will operate without interruption, that it will
be compatible with the Licensee's own equipment and software
configuration, nor that it will meet the Licensee's requirements.
9.4 The Licensor does not either expressly or tacitly warrant that the
Software does not infringe any third party intellectual property right
relating to a patent, software or any other property right. Therefore,
the Licensor disclaims any and all liability towards the Licensee
arising out of any or all proceedings for infringement that may be
instituted in respect of the use, modification and redistribution of the
Software. Nevertheless, should such proceedings be instituted against
the Licensee, the Licensor shall provide it with technical and legal
assistance for its defense. Such technical and legal assistance shall be
decided on a case-by-case basis between the relevant Licensor and the
Licensee pursuant to a memorandum of understanding. The Licensor
disclaims any and all liability as regards the Licensee's use of the
name of the Software. No warranty is given as regards the existence of
prior rights over the name of the Software or as regards the existence
of a trademark.
Article 10 - TERMINATION
10.1 In the event of a breach by the Licensee of its obligations
hereunder, the Licensor may automatically terminate this Agreement
thirty (30) days after notice has been sent to the Licensee and has
remained ineffective.
10.2 A Licensee whose Agreement is terminated shall no longer be
authorized to use, modify or distribute the Software. However, any
licenses that it may have granted prior to termination of the Agreement
shall remain valid subject to their having been granted in compliance
with the terms and conditions hereof.
Article 11 - MISCELLANEOUS
11.1 EXCUSABLE EVENTS
Neither Party shall be liable for any or all delay, or failure to
perform the Agreement, that may be attributable to an event of force
majeure, an act of God or an outside cause, such as defective
functioning or interruptions of the electricity or telecommunications
networks, network paralysis following a virus attack, intervention by
government authorities, natural disasters, water damage, earthquakes,
fire, explosions, strikes and labor unrest, war, etc.
11.2 Any failure by either Party, on one or more occasions, to invoke
one or more of the provisions hereof, shall under no circumstances be
interpreted as being a waiver by the interested Party of its right to
invoke said provision(s) subsequently.
11.3 The Agreement cancels and replaces any or all previous agreements,
whether written or oral, between the Parties and having the same
purpose, and constitutes the entirety of the agreement between said
Parties concerning said purpose. No supplement or modification to the
terms and conditions hereof shall be effective as between the Parties
unless it is made in writing and signed by their duly authorized
representatives.
11.4 In the event that one or more of the provisions hereof were to
conflict with a current or future applicable act or legislative text,
said act or legislative text shall prevail, and the Parties shall make
the necessary amendments so as to comply with said act or legislative
text. All other provisions shall remain effective. Similarly, invalidity
of a provision of the Agreement, for any reason whatsoever, shall not
cause the Agreement as a whole to be invalid.
11.5 LANGUAGE
The Agreement is drafted in both French and English and both versions
are deemed authentic.
Article 12 - NEW VERSIONS OF THE AGREEMENT
12.1 Any person is authorized to duplicate and distribute copies of this
Agreement.
12.2 So as to ensure coherence, the wording of this Agreement is
protected and may only be modified by the authors of the License, who
reserve the right to periodically publish updates or new versions of the
Agreement, each with a separate number. These subsequent versions may
address new issues encountered by Free Software.
12.3 Any Software distributed under a given version of the Agreement may
only be subsequently distributed under the same version of the Agreement
or a subsequent version, subject to the provisions of Article 5.3.4.
Article 13 - GOVERNING LAW AND JURISDICTION
13.1 The Agreement is governed by French law. The Parties agree to
endeavor to seek an amicable solution to any disagreements or disputes
that may arise during the performance of the Agreement.
13.2 Failing an amicable solution within two (2) months as from their
occurrence, and unless emergency proceedings are necessary, the
disagreements or disputes shall be referred to the Paris Courts having
jurisdiction, by the more diligent Party.
Version 2.0 dated 2006-09-05.
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
/*
* searchtools.js_t
* ~~~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilties for the full-text search.
*
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* Porter Stemmer
*/
var Stemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
/**
* Simple result scoring code.
*/
var Scorer = {
// Implement the following function to further tweak the score for each result
// The function takes a result array [filename, title, anchor, descr, score]
// and returns the new score.
/*
score: function(result) {
return result[4];
},
*/
// query matches the full name of an object
objNameMatch: 11,
// or matches in the last dotted part of the object name
objPartialMatch: 6,
// Additive scores depending on the priority of the object
objPrio: {0: 15, // used to be importantResults
1: 5, // used to be objectResults
2: -5}, // used to be unimportantResults
// Used when the priority is not in the mapping.
objPrioDefault: 0,
// query found in title
title: 15,
// query found in terms
term: 5
};
/**
* Search Module
*/
var Search = {
_index : null,
_queued_query : null,
_pulse_status : -1,
init : function() {
var params = $.getQueryParameters();
if (params.q) {
var query = params.q[0];
$('input[name="q"]')[0].value = query;
this.performSearch(query);
}
},
loadIndex : function(url) {
$.ajax({type: "GET", url: url, data: null,
dataType: "script", cache: true,
complete: function(jqxhr, textstatus) {
if (textstatus != "success") {
document.getElementById("searchindexloader").src = url;
}
}});
},
setIndex : function(index) {
var q;
this._index = index;
if ((q = this._queued_query) !== null) {
this._queued_query = null;
Search.query(q);
}
},
hasIndex : function() {
return this._index !== null;
},
deferQuery : function(query) {
this._queued_query = query;
},
stopPulse : function() {
this._pulse_status = 0;
},
startPulse : function() {
if (this._pulse_status >= 0)
return;
function pulse() {
var i;
Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = '';
for (i = 0; i < Search._pulse_status; i++)
dotString += '.';
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
}
pulse();
},
/**
* perform a search for something (or wait until index is loaded)
*/
performSearch : function(query) {
// create the required interface elements
this.out = $('#search-results');
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
this.dots = $('<span></span>').appendTo(this.title);
this.status = $('<p style="display: none"></p>').appendTo(this.out);
this.output = $('<ul class="search"/>').appendTo(this.out);
$('#search-progress').text(_('Preparing search...'));
this.startPulse();
// index already loaded, the browser was quick!
if (this.hasIndex())
this.query(query);
else
this.deferQuery(query);
},
/**
* execute search (requires search index to be loaded)
*/
query : function(query) {
var i;
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
// stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = query.split(/\s+/);
var objectterms = [];
for (i = 0; i < tmp.length; i++) {
if (tmp[i] !== "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
tmp[i] === "") {
// skip this "word"
continue;
}
// stem the word
var word = stemmer.stemWord(tmp[i].toLowerCase());
var toAppend;
// select the correct list
if (word[0] == '-') {
toAppend = excluded;
word = word.substr(1);
}
else {
toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase());
}
// only add if not already in the list
if (!$u.contains(toAppend, word))
toAppend.push(word);
}
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:');
// console.info('required: ', searchterms);
// console.info('excluded: ', excluded);
// prepare search
var terms = this._index.terms;
var titleterms = this._index.titleterms;
// array of [filename, title, anchor, descr, score]
var results = [];
$('#search-progress').empty();
// lookup as object
for (i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0, i),
objectterms.slice(i+1, objectterms.length));
results = results.concat(this.performObjectSearch(objectterms[i], others));
}
// lookup as search terms in fulltext
results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
.concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
// let the scorer override scores with a custom scoring function
if (Scorer.score) {
for (i = 0; i < results.length; i++)
results[i][4] = Scorer.score(results[i]);
}
// now sort the results by score (in opposite order of appearance, since the
// display function below uses pop() to retrieve items) and then
// alphabetically
results.sort(function(a, b) {
var left = a[4];
var right = b[4];
if (left > right) {
return 1;
} else if (left < right) {
return -1;
} else {
// same score: sort alphabetically
left = a[1].toLowerCase();
right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0);
}
});
// for debugging
//Search.lastresults = results.slice(); // a copy
//console.info('search results:', Search.lastresults);
// print the results
var resultCount = results.length;
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li style="display:none"></li>');
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
// dirhtml builder
var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) {
dirname = dirname.substring(0, dirname.length-6);
} else if (dirname == 'index/') {
dirname = '';
}
listItem.append($('<a/>').attr('href',
DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
highlightstring + item[2]).html(item[1]));
} else {
// normal html builders
listItem.append($('<a/>').attr('href',
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
highlightstring + item[2]).html(item[1]));
}
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
$.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
dataType: "text",
complete: function(jqxhr, textstatus) {
var data = jqxhr.responseText;
if (data !== '') {
listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
}
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}});
} else {
// no source available, just display title
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
},
/**
* search for object names
*/
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
var i;
var results = [];
for (var prefix in objects) {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
var score = 0;
var parts = fullname.split('.');
// check for different match types: exact matches of full name or
// "last name" (i.e. last dotted part)
if (fullname == object || parts[parts.length - 1] == object) {
score += Scorer.objNameMatch;
// matches in last name
} else if (parts[parts.length - 1].indexOf(object) > -1) {
score += Scorer.objPartialMatch;
}
var match = objects[prefix][name];
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
var anchor = match[3];
if (anchor === '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
// add custom score for some objects according to scorer
if (Scorer.objPrio.hasOwnProperty(match[2])) {
score += Scorer.objPrio[match[2]];
} else {
score += Scorer.objPrioDefault;
}
results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
}
}
}
return results;
},
/**
* search for full-text terms in the index
*/
performTermsSearch : function(searchterms, excluded, terms, score) {
var filenames = this._index.filenames;
var titles = this._index.titles;
var i, j, file, files;
var fileMap = {};
var results = [];
// perform the search on the required terms
for (i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
// no match but word was a required one
if ((files = terms[word]) === undefined)
break;
if (files.length === undefined) {
files = [files];
}
// create the mapping
for (j = 0; j < files.length; j++) {
file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (file in fileMap) {
var valid = true;
// check if all requirements are matched
if (fileMap[file].length != searchterms.length)
continue;
// ensure that none of the excluded terms is in the search result
for (i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
$u.contains(terms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it to the result list
if (valid) {
results.push([filenames[file], titles[file], '', null, score]);
}
}
return results;
},
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurance, the
* latter for highlighting it.
*/
makeSearchSummary : function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
};
$(document).ready(function() {
Search.init();
});
\ No newline at end of file
// Underscore.js 1.7.0
// http://underscorejs.org
// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
(function() {
// Baseline setup
// --------------
// Establish the root object, `window` in the browser, or `exports` on the server.
var root = this;
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
// Create quick reference variables for speed access to core prototypes.
var
push = ArrayProto.push,
slice = ArrayProto.slice,
concat = ArrayProto.concat,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind;
// Create a safe reference to the Underscore object for use below.
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
// the browser, add `_` as a global object.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
root._ = _;
}
// Current version.
_.VERSION = '1.7.0';
// Internal function that returns an efficient (for current engines) version
// of the passed-in callback, to be repeatedly applied in other Underscore
// functions.
var createCallback = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) {
case 1: return function(value) {
return func.call(context, value);
};
case 2: return function(value, other) {
return func.call(context, value, other);
};
case 3: return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
// A mostly-internal function to generate callbacks that can be applied
// to each element in a collection, returning the desired result — either
// identity, an arbitrary callback, a property matcher, or a property accessor.
_.iteratee = function(value, context, argCount) {
if (value == null) return _.identity;
if (_.isFunction(value)) return createCallback(value, context, argCount);
if (_.isObject(value)) return _.matches(value);
return _.property(value);
};
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles raw objects in addition to array-likes. Treats all
// sparse array-likes as if they were dense.
_.each = _.forEach = function(obj, iteratee, context) {
if (obj == null) return obj;
iteratee = createCallback(iteratee, context);
var i, length = obj.length;
if (length === +length) {
for (i = 0; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
// Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) {
if (obj == null) return [];
iteratee = _.iteratee(iteratee, context);
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length,
results = Array(length),
currentKey;
for (var index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
var reduceError = 'Reduce of empty array with no initial value';
// **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`.
_.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
iteratee = createCallback(iteratee, context, 4);
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length,
index = 0, currentKey;
if (arguments.length < 3) {
if (!length) throw new TypeError(reduceError);
memo = obj[keys ? keys[index++] : index++];
}
for (; index < length; index++) {
currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
};
// The right-associative version of reduce, also known as `foldr`.
_.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
iteratee = createCallback(iteratee, context, 4);
var keys = obj.length !== + obj.length && _.keys(obj),
index = (keys || obj).length,
currentKey;
if (arguments.length < 3) {
if (!index) throw new TypeError(reduceError);
memo = obj[keys ? keys[--index] : --index];
}
while (index--) {
currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
};
// Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, predicate, context) {
var result;
predicate = _.iteratee(predicate, context);
_.some(obj, function(value, index, list) {
if (predicate(value, index, list)) {
result = value;
return true;
}
});
return result;
};
// Return all the elements that pass a truth test.
// Aliased as `select`.
_.filter = _.select = function(obj, predicate, context) {
var results = [];
if (obj == null) return results;
predicate = _.iteratee(predicate, context);
_.each(obj, function(value, index, list) {
if (predicate(value, index, list)) results.push(value);
});
return results;
};
// Return all the elements for which a truth test fails.
_.reject = function(obj, predicate, context) {
return _.filter(obj, _.negate(_.iteratee(predicate)), context);
};
// Determine whether all of the elements match a truth test.
// Aliased as `all`.
_.every = _.all = function(obj, predicate, context) {
if (obj == null) return true;
predicate = _.iteratee(predicate, context);
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length,
index, currentKey;
for (index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
if (!predicate(obj[currentKey], currentKey, obj)) return false;
}
return true;
};
// Determine if at least one element in the object matches a truth test.
// Aliased as `any`.
_.some = _.any = function(obj, predicate, context) {
if (obj == null) return false;
predicate = _.iteratee(predicate, context);
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length,
index, currentKey;
for (index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
if (predicate(obj[currentKey], currentKey, obj)) return true;
}
return false;
};
// Determine if the array or object contains a given value (using `===`).
// Aliased as `include`.
_.contains = _.include = function(obj, target) {
if (obj == null) return false;
if (obj.length !== +obj.length) obj = _.values(obj);
return _.indexOf(obj, target) >= 0;
};
// Invoke a method (with arguments) on every item in a collection.
_.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
var isFunc = _.isFunction(method);
return _.map(obj, function(value) {
return (isFunc ? method : value[method]).apply(value, args);
});
};
// Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) {
return _.map(obj, _.property(key));
};
// Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
_.where = function(obj, attrs) {
return _.filter(obj, _.matches(attrs));
};
// Convenience version of a common use case of `find`: getting the first object
// containing specific `key:value` pairs.
_.findWhere = function(obj, attrs) {
return _.find(obj, _.matches(attrs));
};
// Return the maximum element (or element-based computation).
_.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity,
value, computed;
if (iteratee == null && obj != null) {
obj = obj.length === +obj.length ? obj : _.values(obj);
for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i];
if (value > result) {
result = value;
}
}
} else {
iteratee = _.iteratee(iteratee, context);
_.each(obj, function(value, index, list) {
computed = iteratee(value, index, list);
if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
result = value;
lastComputed = computed;
}
});
}
return result;
};
// Return the minimum element (or element-based computation).
_.min = function(obj, iteratee, context) {
var result = Infinity, lastComputed = Infinity,
value, computed;
if (iteratee == null && obj != null) {
obj = obj.length === +obj.length ? obj : _.values(obj);
for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i];
if (value < result) {
result = value;
}
}
} else {
iteratee = _.iteratee(iteratee, context);
_.each(obj, function(value, index, list) {
computed = iteratee(value, index, list);
if (computed < lastComputed || computed === Infinity && result === Infinity) {
result = value;
lastComputed = computed;
}
});
}
return result;
};
// Shuffle a collection, using the modern version of the
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
_.shuffle = function(obj) {
var set = obj && obj.length === +obj.length ? obj : _.values(obj);
var length = set.length;
var shuffled = Array(length);
for (var index = 0, rand; index < length; index++) {
rand = _.random(0, index);
if (rand !== index) shuffled[index] = shuffled[rand];
shuffled[rand] = set[index];
}
return shuffled;
};
// Sample **n** random values from a collection.
// If **n** is not specified, returns a single random element.
// The internal `guard` argument allows it to work with `map`.
_.sample = function(obj, n, guard) {
if (n == null || guard) {
if (obj.length !== +obj.length) obj = _.values(obj);
return obj[_.random(obj.length - 1)];
}
return _.shuffle(obj).slice(0, Math.max(0, n));
};
// Sort the object's values by a criterion produced by an iteratee.
_.sortBy = function(obj, iteratee, context) {
iteratee = _.iteratee(iteratee, context);
return _.pluck(_.map(obj, function(value, index, list) {
return {
value: value,
index: index,
criteria: iteratee(value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria;
var b = right.criteria;
if (a !== b) {
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
return left.index - right.index;
}), 'value');
};
// An internal function used for aggregate "group by" operations.
var group = function(behavior) {
return function(obj, iteratee, context) {
var result = {};
iteratee = _.iteratee(iteratee, context);
_.each(obj, function(value, index) {
var key = iteratee(value, index, obj);
behavior(result, value, key);
});
return result;
};
};
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = group(function(result, value, key) {
if (_.has(result, key)) result[key].push(value); else result[key] = [value];
});
// Indexes the object's values by a criterion, similar to `groupBy`, but for
// when you know that your index values will be unique.
_.indexBy = group(function(result, value, key) {
result[key] = value;
});
// Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
_.countBy = group(function(result, value, key) {
if (_.has(result, key)) result[key]++; else result[key] = 1;
});
// Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
_.sortedIndex = function(array, obj, iteratee, context) {
iteratee = _.iteratee(iteratee, context, 1);
var value = iteratee(obj);
var low = 0, high = array.length;
while (low < high) {
var mid = low + high >>> 1;
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
// Safely create a real, live array from anything iterable.
_.toArray = function(obj) {
if (!obj) return [];
if (_.isArray(obj)) return slice.call(obj);
if (obj.length === +obj.length) return _.map(obj, _.identity);
return _.values(obj);
};
// Return the number of elements in an object.
_.size = function(obj) {
if (obj == null) return 0;
return obj.length === +obj.length ? obj.length : _.keys(obj).length;
};
// Split a collection into two arrays: one whose elements all satisfy the given
// predicate, and one whose elements all do not satisfy the predicate.
_.partition = function(obj, predicate, context) {
predicate = _.iteratee(predicate, context);
var pass = [], fail = [];
_.each(obj, function(value, key, obj) {
(predicate(value, key, obj) ? pass : fail).push(value);
});
return [pass, fail];
};
// Array Functions
// ---------------
// Get the first element of an array. Passing **n** will return the first N
// values in the array. Aliased as `head` and `take`. The **guard** check
// allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0;
if (n == null || guard) return array[0];
if (n < 0) return [];
return slice.call(array, 0, n);
};
// Returns everything but the last entry of the array. Especially useful on
// the arguments object. Passing **n** will return all the values in
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
_.initial = function(array, n, guard) {
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) {
if (array == null) return void 0;
if (n == null || guard) return array[array.length - 1];
return slice.call(array, Math.max(array.length - n, 0));
};
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
// Especially useful on the arguments object. Passing an **n** will return
// the rest N values in the array. The **guard**
// check allows it to work with `_.map`.
_.rest = _.tail = _.drop = function(array, n, guard) {
return slice.call(array, n == null || guard ? 1 : n);
};
// Trim out all falsy values from an array.
_.compact = function(array) {
return _.filter(array, _.identity);
};
// Internal implementation of a recursive `flatten` function.
var flatten = function(input, shallow, strict, output) {
if (shallow && _.every(input, _.isArray)) {
return concat.apply(output, input);
}
for (var i = 0, length = input.length; i < length; i++) {
var value = input[i];
if (!_.isArray(value) && !_.isArguments(value)) {
if (!strict) output.push(value);
} else if (shallow) {
push.apply(output, value);
} else {
flatten(value, shallow, strict, output);
}
}
return output;
};
// Flatten out an array, either recursively (by default), or just one level.
_.flatten = function(array, shallow) {
return flatten(array, shallow, false, []);
};
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
return _.difference(array, slice.call(arguments, 1));
};
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
if (array == null) return [];
if (!_.isBoolean(isSorted)) {
context = iteratee;
iteratee = isSorted;
isSorted = false;
}
if (iteratee != null) iteratee = _.iteratee(iteratee, context);
var result = [];
var seen = [];
for (var i = 0, length = array.length; i < length; i++) {
var value = array[i];
if (isSorted) {
if (!i || seen !== value) result.push(value);
seen = value;
} else if (iteratee) {
var computed = iteratee(value, i, array);
if (_.indexOf(seen, computed) < 0) {
seen.push(computed);
result.push(value);
}
} else if (_.indexOf(result, value) < 0) {
result.push(value);
}
}
return result;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
return _.uniq(flatten(arguments, true, true, []));
};
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
if (array == null) return [];
var result = [];
var argsLength = arguments.length;
for (var i = 0, length = array.length; i < length; i++) {
var item = array[i];
if (_.contains(result, item)) continue;
for (var j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
if (j === argsLength) result.push(item);
}
return result;
};
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
var rest = flatten(slice.call(arguments, 1), true, true, []);
return _.filter(array, function(value){
return !_.contains(rest, value);
});
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.zip = function(array) {
if (array == null) return [];
var length = _.max(arguments, 'length').length;
var results = Array(length);
for (var i = 0; i < length; i++) {
results[i] = _.pluck(arguments, i);
}
return results;
};
// Converts lists into objects. Pass either a single array of `[key, value]`
// pairs, or two parallel arrays of the same length -- one of keys, and one of
// the corresponding values.
_.object = function(list, values) {
if (list == null) return {};
var result = {};
for (var i = 0, length = list.length; i < length; i++) {
if (values) {
result[list[i]] = values[i];
} else {
result[list[i][0]] = list[i][1];
}
}
return result;
};
// Return the position of the first occurrence of an item in an array,
// or -1 if the item is not included in the array.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) {
if (array == null) return -1;
var i = 0, length = array.length;
if (isSorted) {
if (typeof isSorted == 'number') {
i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
} else {
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
}
for (; i < length; i++) if (array[i] === item) return i;
return -1;
};
_.lastIndexOf = function(array, item, from) {
if (array == null) return -1;
var idx = array.length;
if (typeof from == 'number') {
idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
}
while (--idx >= 0) if (array[idx] === item) return idx;
return -1;
};
// Generate an integer Array containing an arithmetic progression. A port of
// the native Python `range()` function. See
// [the Python documentation](http://docs.python.org/library/functions.html#range).
_.range = function(start, stop, step) {
if (arguments.length <= 1) {
stop = start || 0;
start = 0;
}
step = step || 1;
var length = Math.max(Math.ceil((stop - start) / step), 0);
var range = Array(length);
for (var idx = 0; idx < length; idx++, start += step) {
range[idx] = start;
}
return range;
};
// Function (ahem) Functions
// ------------------
// Reusable constructor function for prototype setting.
var Ctor = function(){};
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
// available.
_.bind = function(func, context) {
var args, bound;
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
args = slice.call(arguments, 2);
bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
Ctor.prototype = func.prototype;
var self = new Ctor;
Ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (_.isObject(result)) return result;
return self;
};
return bound;
};
// Partially apply a function by creating a version that has had some of its
// arguments pre-filled, without changing its dynamic `this` context. _ acts
// as a placeholder, allowing any combination of arguments to be pre-filled.
_.partial = function(func) {
var boundArgs = slice.call(arguments, 1);
return function() {
var position = 0;
var args = boundArgs.slice();
for (var i = 0, length = args.length; i < length; i++) {
if (args[i] === _) args[i] = arguments[position++];
}
while (position < arguments.length) args.push(arguments[position++]);
return func.apply(this, args);
};
};
// Bind a number of an object's methods to that object. Remaining arguments
// are the method names to be bound. Useful for ensuring that all callbacks
// defined on an object belong to it.
_.bindAll = function(obj) {
var i, length = arguments.length, key;
if (length <= 1) throw new Error('bindAll must be passed function names');
for (i = 1; i < length; i++) {
key = arguments[i];
obj[key] = _.bind(obj[key], obj);
}
return obj;
};
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memoize = function(key) {
var cache = memoize.cache;
var address = hasher ? hasher.apply(this, arguments) : key;
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
return cache[address];
};
memoize.cache = {};
return memoize;
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){
return func.apply(null, args);
}, wait);
};
// Defers a function, scheduling it to run after the current call stack has
// cleared.
_.defer = function(func) {
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
var later = function() {
var last = _.now() - timestamp;
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function() {
context = this;
args = arguments;
timestamp = _.now();
var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
};
// Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
return _.partial(wrapper, func);
};
// Returns a negated version of the passed-in predicate.
_.negate = function(predicate) {
return function() {
return !predicate.apply(this, arguments);
};
};
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
var args = arguments;
var start = args.length - 1;
return function() {
var i = start;
var result = args[start].apply(this, arguments);
while (i--) result = args[i].call(this, result);
return result;
};
};
// Returns a function that will only be executed after being called N times.
_.after = function(times, func) {
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
};
// Returns a function that will only be executed before being called N times.
_.before = function(times, func) {
var memo;
return function() {
if (--times > 0) {
memo = func.apply(this, arguments);
} else {
func = null;
}
return memo;
};
};
// Returns a function that will be executed at most one time, no matter how
// often you call it. Useful for lazy initialization.
_.once = _.partial(_.before, 2);
// Object Functions
// ----------------
// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = function(obj) {
if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
return keys;
};
// Retrieve the values of an object's properties.
_.values = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
var values = Array(length);
for (var i = 0; i < length; i++) {
values[i] = obj[keys[i]];
}
return values;
};
// Convert an object into a list of `[key, value]` pairs.
_.pairs = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
var pairs = Array(length);
for (var i = 0; i < length; i++) {
pairs[i] = [keys[i], obj[keys[i]]];
}
return pairs;
};
// Invert the keys and values of an object. The values must be serializable.
_.invert = function(obj) {
var result = {};
var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
result[obj[keys[i]]] = keys[i];
}
return result;
};
// Return a sorted list of the function names available on the object.
// Aliased as `methods`
_.functions = _.methods = function(obj) {
var names = [];
for (var key in obj) {
if (_.isFunction(obj[key])) names.push(key);
}
return names.sort();
};
// Extend a given object with all the properties in passed-in object(s).
_.extend = function(obj) {
if (!_.isObject(obj)) return obj;
var source, prop;
for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i];
for (prop in source) {
if (hasOwnProperty.call(source, prop)) {
obj[prop] = source[prop];
}
}
}
return obj;
};
// Return a copy of the object only containing the whitelisted properties.
_.pick = function(obj, iteratee, context) {
var result = {}, key;
if (obj == null) return result;
if (_.isFunction(iteratee)) {
iteratee = createCallback(iteratee, context);
for (key in obj) {
var value = obj[key];
if (iteratee(value, key, obj)) result[key] = value;
}
} else {
var keys = concat.apply([], slice.call(arguments, 1));
obj = new Object(obj);
for (var i = 0, length = keys.length; i < length; i++) {
key = keys[i];
if (key in obj) result[key] = obj[key];
}
}
return result;
};
// Return a copy of the object without the blacklisted properties.
_.omit = function(obj, iteratee, context) {
if (_.isFunction(iteratee)) {
iteratee = _.negate(iteratee);
} else {
var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
iteratee = function(value, key) {
return !_.contains(keys, key);
};
}
return _.pick(obj, iteratee, context);
};
// Fill in a given object with default properties.
_.defaults = function(obj) {
if (!_.isObject(obj)) return obj;
for (var i = 1, length = arguments.length; i < length; i++) {
var source = arguments[i];
for (var prop in source) {
if (obj[prop] === void 0) obj[prop] = source[prop];
}
}
return obj;
};
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
// Invokes interceptor with the obj, and then returns obj.
// The primary purpose of this method is to "tap into" a method chain, in
// order to perform operations on intermediate results within the chain.
_.tap = function(obj, interceptor) {
interceptor(obj);
return obj;
};
// Internal recursive comparison function for `isEqual`.
var eq = function(a, b, aStack, bStack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
if (a === b) return a !== 0 || 1 / a === 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
if (a instanceof _) a = a._wrapped;
if (b instanceof _) b = b._wrapped;
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className !== toString.call(b)) return false;
switch (className) {
// Strings, numbers, regular expressions, dates, and booleans are compared by value.
case '[object RegExp]':
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
return '' + a === '' + b;
case '[object Number]':
// `NaN`s are equivalent, but non-reflexive.
// Object(NaN) is equivalent to NaN
if (+a !== +a) return +b !== +b;
// An `egal` comparison is performed for other numeric values.
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
return +a === +b;
}
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = aStack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (aStack[length] === a) return bStack[length] === b;
}
// Objects with different constructors are not equivalent, but `Object`s
// from different frames are.
var aCtor = a.constructor, bCtor = b.constructor;
if (
aCtor !== bCtor &&
// Handle Object.create(x) cases
'constructor' in a && 'constructor' in b &&
!(_.isFunction(aCtor) && aCtor instanceof aCtor &&
_.isFunction(bCtor) && bCtor instanceof bCtor)
) {
return false;
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
bStack.push(b);
var size, result;
// Recursively compare objects and arrays.
if (className === '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
result = size === b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
if (!(result = eq(a[size], b[size], aStack, bStack))) break;
}
}
} else {
// Deep compare objects.
var keys = _.keys(a), key;
size = keys.length;
// Ensure that both objects contain the same number of properties before comparing deep equality.
result = _.keys(b).length === size;
if (result) {
while (size--) {
// Deep compare each member
key = keys[size];
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
}
}
}
// Remove the first object from the stack of traversed objects.
aStack.pop();
bStack.pop();
return result;
};
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
return eq(a, b, [], []);
};
// Is a given array, string, or object empty?
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {
if (obj == null) return true;
if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false;
return true;
};
// Is a given value a DOM element?
_.isElement = function(obj) {
return !!(obj && obj.nodeType === 1);
};
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
};
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
_['is' + name] = function(obj) {
return toString.call(obj) === '[object ' + name + ']';
};
});
// Define a fallback version of the method in browsers (ahem, IE), where
// there isn't any inspectable "Arguments" type.
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
return _.has(obj, 'callee');
};
}
// Optimize `isFunction` if appropriate. Work around an IE 11 bug.
if (typeof /./ !== 'function') {
_.isFunction = function(obj) {
return typeof obj == 'function' || false;
};
}
// Is a given object a finite number?
_.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
_.isNaN = function(obj) {
return _.isNumber(obj) && obj !== +obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};
// Is a given value equal to null?
_.isNull = function(obj) {
return obj === null;
};
// Is a given variable undefined?
_.isUndefined = function(obj) {
return obj === void 0;
};
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
return obj != null && hasOwnProperty.call(obj, key);
};
// Utility Functions
// -----------------
// Run Underscore.js in *noConflict* mode, returning the `_` variable to its
// previous owner. Returns a reference to the Underscore object.
_.noConflict = function() {
root._ = previousUnderscore;
return this;
};
// Keep the identity function around for default iteratees.
_.identity = function(value) {
return value;
};
_.constant = function(value) {
return function() {
return value;
};
};
_.noop = function(){};
_.property = function(key) {
return function(obj) {
return obj[key];
};
};
// Returns a predicate for checking whether an object has a given set of `key:value` pairs.
_.matches = function(attrs) {
var pairs = _.pairs(attrs), length = pairs.length;
return function(obj) {
if (obj == null) return !length;
obj = new Object(obj);
for (var i = 0; i < length; i++) {
var pair = pairs[i], key = pair[0];
if (pair[1] !== obj[key] || !(key in obj)) return false;
}
return true;
};
};
// Run a function **n** times.
_.times = function(n, iteratee, context) {
var accum = Array(Math.max(0, n));
iteratee = createCallback(iteratee, context, 1);
for (var i = 0; i < n; i++) accum[i] = iteratee(i);
return accum;
};
// Return a random integer between min and max (inclusive).
_.random = function(min, max) {
if (max == null) {
max = min;
min = 0;
}
return min + Math.floor(Math.random() * (max - min + 1));
};
// A (possibly faster) way to get the current timestamp as an integer.
_.now = Date.now || function() {
return new Date().getTime();
};
// List of HTML entities for escaping.
var escapeMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;',
'`': '&#x60;'
};
var unescapeMap = _.invert(escapeMap);
// Functions for escaping and unescaping strings to/from HTML interpolation.
var createEscaper = function(map) {
var escaper = function(match) {
return map[match];
};
// Regexes for identifying a key that needs to be escaped
var source = '(?:' + _.keys(map).join('|') + ')';
var testRegexp = RegExp(source);
var replaceRegexp = RegExp(source, 'g');
return function(string) {
string = string == null ? '' : '' + string;
return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
};
};
_.escape = createEscaper(escapeMap);
_.unescape = createEscaper(unescapeMap);
// If the value of the named `property` is a function then invoke it with the
// `object` as context; otherwise, return it.
_.result = function(object, property) {
if (object == null) return void 0;
var value = object[property];
return _.isFunction(value) ? object[property]() : value;
};
// Generate a unique integer id (unique within the entire client session).
// Useful for temporary DOM ids.
var idCounter = 0;
_.uniqueId = function(prefix) {
var id = ++idCounter + '';
return prefix ? prefix + id : id;
};
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a
// string literal.
var escapes = {
"'": "'",
'\\': '\\',
'\r': 'r',
'\n': 'n',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
var escapeChar = function(match) {
return '\\' + escapes[match];
};
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
// NB: `oldSettings` only exists for backwards compatibility.
_.template = function(text, settings, oldSettings) {
if (!settings && oldSettings) settings = oldSettings;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
var matcher = RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// Compile the template source, escaping string literals appropriately.
var index = 0;
var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
source += text.slice(index, offset).replace(escaper, escapeChar);
index = offset + match.length;
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
} else if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
} else if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
// Adobe VMs need the match returned to produce the correct offest.
return match;
});
source += "';\n";
// If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
source + 'return __p;\n';
try {
var render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
var template = function(data) {
return render.call(this, data, _);
};
// Provide the compiled source as a convenience for precompilation.
var argument = settings.variable || 'obj';
template.source = 'function(' + argument + '){\n' + source + '}';
return template;
};
// Add a "chain" function. Start chaining a wrapped Underscore object.
_.chain = function(obj) {
var instance = _(obj);
instance._chain = true;
return instance;
};
// OOP
// ---------------
// If Underscore is called as a function, it returns a wrapped object that
// can be used OO-style. This wrapper holds altered versions of all the
// underscore functions. Wrapped objects may be chained.
// Helper function to continue chaining intermediate results.
var result = function(obj) {
return this._chain ? _(obj).chain() : obj;
};
// Add your own custom functions to the Underscore object.
_.mixin = function(obj) {
_.each(_.functions(obj), function(name) {
var func = _[name] = obj[name];
_.prototype[name] = function() {
var args = [this._wrapped];
push.apply(args, arguments);
return result.call(this, func.apply(_, args));
};
});
};
// Add all of the Underscore functions to the wrapper object.
_.mixin(_);
// Add all mutator Array functions to the wrapper.
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
var obj = this._wrapped;
method.apply(obj, arguments);
if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
return result.call(this, obj);
};
});
// Add all accessor Array functions to the wrapper.
_.each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
return result.call(this, method.apply(this._wrapped, arguments));
};
});
// Extracts the result from a wrapped and chained object.
_.prototype.value = function() {
return this._wrapped;
};
// AMD registration happens at the end for compatibility with AMD loaders
// that may not enforce next-turn semantics on modules. Even though general
// practice for AMD registration is to be anonymous, underscore registers
// as a named module because, like jQuery, it is a base library that is
// popular enough to be bundled in a third party lib, but not be part of
// an AMD load request. Those cases could generate an error when an
// anonymous define() is called outside of a loader request.
if (typeof define === 'function' && define.amd) {
define('underscore', [], function() {
return _;
});
}
}.call(this));
/*
* websupport.js
* ~~~~~~~~~~~~~
*
* sphinx.websupport utilties for all documentation.
*
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
(function($) {
$.fn.autogrow = function() {
return this.each(function() {
var textarea = this;
$.fn.autogrow.resize(textarea);
$(textarea)
.focus(function() {
textarea.interval = setInterval(function() {
$.fn.autogrow.resize(textarea);
}, 500);
})
.blur(function() {
clearInterval(textarea.interval);
});
});
};
$.fn.autogrow.resize = function(textarea) {
var lineHeight = parseInt($(textarea).css('line-height'), 10);
var lines = textarea.value.split('\n');
var columns = textarea.cols;
var lineCount = 0;
$.each(lines, function() {
lineCount += Math.ceil(this.length / columns) || 1;
});
var height = lineHeight * (lineCount + 1);
$(textarea).css('height', height);
};
})(jQuery);
(function($) {
var comp, by;
function init() {
initEvents();
initComparator();
}
function initEvents() {
$('a.comment-close').live("click", function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
});
$('a.vote').live("click", function(event) {
event.preventDefault();
handleVote($(this));
});
$('a.reply').live("click", function(event) {
event.preventDefault();
openReply($(this).attr('id').substring(2));
});
$('a.close-reply').live("click", function(event) {
event.preventDefault();
closeReply($(this).attr('id').substring(2));
});
$('a.sort-option').live("click", function(event) {
event.preventDefault();
handleReSort($(this));
});
$('a.show-proposal').live("click", function(event) {
event.preventDefault();
showProposal($(this).attr('id').substring(2));
});
$('a.hide-proposal').live("click", function(event) {
event.preventDefault();
hideProposal($(this).attr('id').substring(2));
});
$('a.show-propose-change').live("click", function(event) {
event.preventDefault();
showProposeChange($(this).attr('id').substring(2));
});
$('a.hide-propose-change').live("click", function(event) {
event.preventDefault();
hideProposeChange($(this).attr('id').substring(2));
});
$('a.accept-comment').live("click", function(event) {
event.preventDefault();
acceptComment($(this).attr('id').substring(2));
});
$('a.delete-comment').live("click", function(event) {
event.preventDefault();
deleteComment($(this).attr('id').substring(2));
});
$('a.comment-markup').live("click", function(event) {
event.preventDefault();
toggleCommentMarkupBox($(this).attr('id').substring(2));
});
}
/**
* Set comp, which is a comparator function used for sorting and
* inserting comments into the list.
*/
function setComparator() {
// If the first three letters are "asc", sort in ascending order
// and remove the prefix.
if (by.substring(0,3) == 'asc') {
var i = by.substring(3);
comp = function(a, b) { return a[i] - b[i]; };
} else {
// Otherwise sort in descending order.
comp = function(a, b) { return b[by] - a[by]; };
}
// Reset link styles and format the selected sort option.
$('a.sel').attr('href', '#').removeClass('sel');
$('a.by' + by).removeAttr('href').addClass('sel');
}
/**
* Create a comp function. If the user has preferences stored in
* the sortBy cookie, use those, otherwise use the default.
*/
function initComparator() {
by = 'rating'; // Default to sort by rating.
// If the sortBy cookie is set, use that instead.
if (document.cookie.length > 0) {
var start = document.cookie.indexOf('sortBy=');
if (start != -1) {
start = start + 7;
var end = document.cookie.indexOf(";", start);
if (end == -1) {
end = document.cookie.length;
by = unescape(document.cookie.substring(start, end));
}
}
}
setComparator();
}
/**
* Show a comment div.
*/
function show(id) {
$('#ao' + id).hide();
$('#ah' + id).show();
var context = $.extend({id: id}, opts);
var popup = $(renderTemplate(popupTemplate, context)).hide();
popup.find('textarea[name="proposal"]').hide();
popup.find('a.by' + by).addClass('sel');
var form = popup.find('#cf' + id);
form.submit(function(event) {
event.preventDefault();
addComment(form);
});
$('#s' + id).after(popup);
popup.slideDown('fast', function() {
getComments(id);
});
}
/**
* Hide a comment div.
*/
function hide(id) {
$('#ah' + id).hide();
$('#ao' + id).show();
var div = $('#sc' + id);
div.slideUp('fast', function() {
div.remove();
});
}
/**
* Perform an ajax request to get comments for a node
* and insert the comments into the comments tree.
*/
function getComments(id) {
$.ajax({
type: 'GET',
url: opts.getCommentsURL,
data: {node: id},
success: function(data, textStatus, request) {
var ul = $('#cl' + id);
var speed = 100;
$('#cf' + id)
.find('textarea[name="proposal"]')
.data('source', data.source);
if (data.comments.length === 0) {
ul.html('<li>No comments yet.</li>');
ul.data('empty', true);
} else {
// If there are comments, sort them and put them in the list.
var comments = sortComments(data.comments);
speed = data.comments.length * 100;
appendComments(comments, ul);
ul.data('empty', false);
}
$('#cn' + id).slideUp(speed + 200);
ul.slideDown(speed);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem retrieving the comments.');
},
dataType: 'json'
});
}
/**
* Add a comment via ajax and insert the comment into the comment tree.
*/
function addComment(form) {
var node_id = form.find('input[name="node"]').val();
var parent_id = form.find('input[name="parent"]').val();
var text = form.find('textarea[name="comment"]').val();
var proposal = form.find('textarea[name="proposal"]').val();
if (text == '') {
showError('Please enter a comment.');
return;
}
// Disable the form that is being submitted.
form.find('textarea,input').attr('disabled', 'disabled');
// Send the comment to the server.
$.ajax({
type: "POST",
url: opts.addCommentURL,
dataType: 'json',
data: {
node: node_id,
parent: parent_id,
text: text,
proposal: proposal
},
success: function(data, textStatus, error) {
// Reset the form.
if (node_id) {
hideProposeChange(node_id);
}
form.find('textarea')
.val('')
.add(form.find('input'))
.removeAttr('disabled');
var ul = $('#cl' + (node_id || parent_id));
if (ul.data('empty')) {
$(ul).empty();
ul.data('empty', false);
}
insertComment(data.comment);
var ao = $('#ao' + node_id);
ao.find('img').attr({'src': opts.commentBrightImage});
if (node_id) {
// if this was a "root" comment, remove the commenting box
// (the user can get it back by reopening the comment popup)
$('#ca' + node_id).slideUp();
}
},
error: function(request, textStatus, error) {
form.find('textarea,input').removeAttr('disabled');
showError('Oops, there was a problem adding the comment.');
}
});
}
/**
* Recursively append comments to the main comment list and children
* lists, creating the comment tree.
*/
function appendComments(comments, ul) {
$.each(comments, function() {
var div = createCommentDiv(this);
ul.append($(document.createElement('li')).html(div));
appendComments(this.children, div.find('ul.comment-children'));
// To avoid stagnating data, don't store the comments children in data.
this.children = null;
div.data('comment', this);
});
}
/**
* After adding a new comment, it must be inserted in the correct
* location in the comment tree.
*/
function insertComment(comment) {
var div = createCommentDiv(comment);
// To avoid stagnating data, don't store the comments children in data.
comment.children = null;
div.data('comment', comment);
var ul = $('#cl' + (comment.node || comment.parent));
var siblings = getChildren(ul);
var li = $(document.createElement('li'));
li.hide();
// Determine where in the parents children list to insert this comment.
for(i=0; i < siblings.length; i++) {
if (comp(comment, siblings[i]) <= 0) {
$('#cd' + siblings[i].id)
.parent()
.before(li.html(div));
li.slideDown('fast');
return;
}
}
// If we get here, this comment rates lower than all the others,
// or it is the only comment in the list.
ul.append(li.html(div));
li.slideDown('fast');
}
function acceptComment(id) {
$.ajax({
type: 'POST',
url: opts.acceptCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
$('#cm' + id).fadeOut('fast');
$('#cd' + id).removeClass('moderate');
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem accepting the comment.');
}
});
}
function deleteComment(id) {
$.ajax({
type: 'POST',
url: opts.deleteCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
var div = $('#cd' + id);
if (data == 'delete') {
// Moderator mode: remove the comment and all children immediately
div.slideUp('fast', function() {
div.remove();
});
return;
}
// User mode: only mark the comment as deleted
div
.find('span.user-id:first')
.text('[deleted]').end()
.find('div.comment-text:first')
.text('[deleted]').end()
.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
.remove();
var comment = div.data('comment');
comment.username = '[deleted]';
comment.text = '[deleted]';
div.data('comment', comment);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem deleting the comment.');
}
});
}
function showProposal(id) {
$('#sp' + id).hide();
$('#hp' + id).show();
$('#pr' + id).slideDown('fast');
}
function hideProposal(id) {
$('#hp' + id).hide();
$('#sp' + id).show();
$('#pr' + id).slideUp('fast');
}
function showProposeChange(id) {
$('#pc' + id).hide();
$('#hc' + id).show();
var textarea = $('#pt' + id);
textarea.val(textarea.data('source'));
$.fn.autogrow.resize(textarea[0]);
textarea.slideDown('fast');
}
function hideProposeChange(id) {
$('#hc' + id).hide();
$('#pc' + id).show();
var textarea = $('#pt' + id);
textarea.val('').removeAttr('disabled');
textarea.slideUp('fast');
}
function toggleCommentMarkupBox(id) {
$('#mb' + id).toggle();
}
/** Handle when the user clicks on a sort by link. */
function handleReSort(link) {
var classes = link.attr('class').split(/\s+/);
for (var i=0; i<classes.length; i++) {
if (classes[i] != 'sort-option') {
by = classes[i].substring(2);
}
}
setComparator();
// Save/update the sortBy cookie.
var expiration = new Date();
expiration.setDate(expiration.getDate() + 365);
document.cookie= 'sortBy=' + escape(by) +
';expires=' + expiration.toUTCString();
$('ul.comment-ul').each(function(index, ul) {
var comments = getChildren($(ul), true);
comments = sortComments(comments);
appendComments(comments, $(ul).empty());
});
}
/**
* Function to process a vote when a user clicks an arrow.
*/
function handleVote(link) {
if (!opts.voting) {
showError("You'll need to login to vote.");
return;
}
var id = link.attr('id');
if (!id) {
// Didn't click on one of the voting arrows.
return;
}
// If it is an unvote, the new vote value is 0,
// Otherwise it's 1 for an upvote, or -1 for a downvote.
var value = 0;
if (id.charAt(1) != 'u') {
value = id.charAt(0) == 'u' ? 1 : -1;
}
// The data to be sent to the server.
var d = {
comment_id: id.substring(2),
value: value
};
// Swap the vote and unvote links.
link.hide();
$('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
.show();
// The div the comment is displayed in.
var div = $('div#cd' + d.comment_id);
var data = div.data('comment');
// If this is not an unvote, and the other vote arrow has
// already been pressed, unpress it.
if ((d.value !== 0) && (data.vote === d.value * -1)) {
$('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
$('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
}
// Update the comments rating in the local data.
data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
data.vote = d.value;
div.data('comment', data);
// Change the rating text.
div.find('.rating:first')
.text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
// Send the vote information to the server.
$.ajax({
type: "POST",
url: opts.processVoteURL,
data: d,
error: function(request, textStatus, error) {
showError('Oops, there was a problem casting that vote.');
}
});
}
/**
* Open a reply form used to reply to an existing comment.
*/
function openReply(id) {
// Swap out the reply link for the hide link
$('#rl' + id).hide();
$('#cr' + id).show();
// Add the reply li to the children ul.
var div = $(renderTemplate(replyTemplate, {id: id})).hide();
$('#cl' + id)
.prepend(div)
// Setup the submit handler for the reply form.
.find('#rf' + id)
.submit(function(event) {
event.preventDefault();
addComment($('#rf' + id));
closeReply(id);
})
.find('input[type=button]')
.click(function() {
closeReply(id);
});
div.slideDown('fast', function() {
$('#rf' + id).find('textarea').focus();
});
}
/**
* Close the reply form opened with openReply.
*/
function closeReply(id) {
// Remove the reply div from the DOM.
$('#rd' + id).slideUp('fast', function() {
$(this).remove();
});
// Swap out the hide link for the reply link
$('#cr' + id).hide();
$('#rl' + id).show();
}
/**
* Recursively sort a tree of comments using the comp comparator.
*/
function sortComments(comments) {
comments.sort(comp);
$.each(comments, function() {
this.children = sortComments(this.children);
});
return comments;
}
/**
* Get the children comments from a ul. If recursive is true,
* recursively include childrens' children.
*/
function getChildren(ul, recursive) {
var children = [];
ul.children().children("[id^='cd']")
.each(function() {
var comment = $(this).data('comment');
if (recursive)
comment.children = getChildren($(this).find('#cl' + comment.id), true);
children.push(comment);
});
return children;
}
/** Create a div to display a comment in. */
function createCommentDiv(comment) {
if (!comment.displayed && !opts.moderator) {
return $('<div class="moderate">Thank you! Your comment will show up '
+ 'once it is has been approved by a moderator.</div>');
}
// Prettify the comment rating.
comment.pretty_rating = comment.rating + ' point' +
(comment.rating == 1 ? '' : 's');
// Make a class (for displaying not yet moderated comments differently)
comment.css_class = comment.displayed ? '' : ' moderate';
// Create a div for this comment.
var context = $.extend({}, opts, comment);
var div = $(renderTemplate(commentTemplate, context));
// If the user has voted on this comment, highlight the correct arrow.
if (comment.vote) {
var direction = (comment.vote == 1) ? 'u' : 'd';
div.find('#' + direction + 'v' + comment.id).hide();
div.find('#' + direction + 'u' + comment.id).show();
}
if (opts.moderator || comment.text != '[deleted]') {
div.find('a.reply').show();
if (comment.proposal_diff)
div.find('#sp' + comment.id).show();
if (opts.moderator && !comment.displayed)
div.find('#cm' + comment.id).show();
if (opts.moderator || (opts.username == comment.username))
div.find('#dc' + comment.id).show();
}
return div;
}
/**
* A simple template renderer. Placeholders such as <%id%> are replaced
* by context['id'] with items being escaped. Placeholders such as <#id#>
* are not escaped.
*/
function renderTemplate(template, context) {
var esc = $(document.createElement('div'));
function handle(ph, escape) {
var cur = context;
$.each(ph.split('.'), function() {
cur = cur[this];
});
return escape ? esc.text(cur || "").html() : cur;
}
return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
return handle(arguments[2], arguments[1] == '%' ? true : false);
});
}
/** Flash an error message briefly. */
function showError(message) {
$(document.createElement('div')).attr({'class': 'popup-error'})
.append($(document.createElement('div'))
.attr({'class': 'error-message'}).text(message))
.appendTo('body')
.fadeIn("slow")
.delay(2000)
.fadeOut("slow");
}
/** Add a link the user uses to open the comments popup. */
$.fn.comment = function() {
return this.each(function() {
var id = $(this).attr('id').substring(1);
var count = COMMENT_METADATA[id];
var title = count + ' comment' + (count == 1 ? '' : 's');
var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
var addcls = count == 0 ? ' nocomment' : '';
$(this)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-open' + addcls,
id: 'ao' + id
})
.append($(document.createElement('img')).attr({
src: image,
alt: 'comment',
title: title
}))
.click(function(event) {
event.preventDefault();
show($(this).attr('id').substring(2));
})
)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-close hidden',
id: 'ah' + id
})
.append($(document.createElement('img')).attr({
src: opts.closeCommentImage,
alt: 'close',
title: 'close'
}))
.click(function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
})
);
});
};
var opts = {
processVoteURL: '/_process_vote',
addCommentURL: '/_add_comment',
getCommentsURL: '/_get_comments',
acceptCommentURL: '/_accept_comment',
deleteCommentURL: '/_delete_comment',
commentImage: '/static/_static/comment.png',
closeCommentImage: '/static/_static/comment-close.png',
loadingImage: '/static/_static/ajax-loader.gif',
commentBrightImage: '/static/_static/comment-bright.png',
upArrow: '/static/_static/up.png',
downArrow: '/static/_static/down.png',
upArrowPressed: '/static/_static/up-pressed.png',
downArrowPressed: '/static/_static/down-pressed.png',
voting: false,
moderator: false
};
if (typeof COMMENT_OPTIONS != "undefined") {
opts = jQuery.extend(opts, COMMENT_OPTIONS);
}
var popupTemplate = '\
<div class="sphinx-comments" id="sc<%id%>">\
<p class="sort-options">\
Sort by:\
<a href="#" class="sort-option byrating">best rated</a>\
<a href="#" class="sort-option byascage">newest</a>\
<a href="#" class="sort-option byage">oldest</a>\
</p>\
<div class="comment-header">Comments</div>\
<div class="comment-loading" id="cn<%id%>">\
loading comments... <img src="<%loadingImage%>" alt="" /></div>\
<ul id="cl<%id%>" class="comment-ul"></ul>\
<div id="ca<%id%>">\
<p class="add-a-comment">Add a comment\
(<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
<div class="comment-markup-box" id="mb<%id%>">\
reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
<tt>``code``</tt>, \
code blocks: <tt>::</tt> and an indented block after blank line</div>\
<form method="post" id="cf<%id%>" class="comment-form" action="">\
<textarea name="comment" cols="80"></textarea>\
<p class="propose-button">\
<a href="#" id="pc<%id%>" class="show-propose-change">\
Propose a change &#9657;\
</a>\
<a href="#" id="hc<%id%>" class="hide-propose-change">\
Propose a change &#9663;\
</a>\
</p>\
<textarea name="proposal" id="pt<%id%>" cols="80"\
spellcheck="false"></textarea>\
<input type="submit" value="Add comment" />\
<input type="hidden" name="node" value="<%id%>" />\
<input type="hidden" name="parent" value="" />\
</form>\
</div>\
</div>';
var commentTemplate = '\
<div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
<div class="vote">\
<div class="arrow">\
<a href="#" id="uv<%id%>" class="vote" title="vote up">\
<img src="<%upArrow%>" />\
</a>\
<a href="#" id="uu<%id%>" class="un vote" title="vote up">\
<img src="<%upArrowPressed%>" />\
</a>\
</div>\
<div class="arrow">\
<a href="#" id="dv<%id%>" class="vote" title="vote down">\
<img src="<%downArrow%>" id="da<%id%>" />\
</a>\
<a href="#" id="du<%id%>" class="un vote" title="vote down">\
<img src="<%downArrowPressed%>" />\
</a>\
</div>\
</div>\
<div class="comment-content">\
<p class="tagline comment">\
<span class="user-id"><%username%></span>\
<span class="rating"><%pretty_rating%></span>\
<span class="delta"><%time.delta%></span>\
</p>\
<div class="comment-text comment"><#text#></div>\
<p class="comment-opts comment">\
<a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
<a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
<a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
<a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
<a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
<span id="cm<%id%>" class="moderation hidden">\
<a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
</span>\
</p>\
<pre class="proposal" id="pr<%id%>">\
<#proposal_diff#>\
</pre>\
<ul class="comment-children" id="cl<%id%>"></ul>\
</div>\
<div class="clearleft"></div>\
</div>\
</div>';
var replyTemplate = '\
<li>\
<div class="reply-div" id="rd<%id%>">\
<form id="rf<%id%>">\
<textarea name="comment" cols="80"></textarea>\
<input type="submit" value="Add reply" />\
<input type="button" value="Cancel" />\
<input type="hidden" name="parent" value="<%id%>" />\
<input type="hidden" name="node" value="" />\
</form>\
</div>\
</li>';
$(document).ready(function() {
init();
});
})(jQuery);
$(document).ready(function() {
// add comment anchors for all paragraphs that are commentable
$('.sphinx-has-comment').comment();
// highlight search words in search results
$("div.context").each(function() {
var params = $.getQueryParameters();
var terms = (params.q) ? params.q[0].split(/\s+/) : [];
var result = $(this);
$.each(terms, function() {
result.highlightText(this.toLowerCase(), 'highlighted');
});
});
// directly open comment window if requested
var anchor = document.location.hash;
if (anchor.substring(0, 9) == '#comment-') {
$('#ao' + anchor.substring(9)).click();
document.location.hash = '#s' + anchor.substring(9);
}
});
<!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>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="#" 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="index">Index</h1>
<div class="genindex-jumpbox">
<a href="#A"><strong>A</strong></a>
| <a href="#B"><strong>B</strong></a>
| <a href="#C"><strong>C</strong></a>
| <a href="#D"><strong>D</strong></a>
| <a href="#E"><strong>E</strong></a>
| <a href="#F"><strong>F</strong></a>
| <a href="#G"><strong>G</strong></a>
| <a href="#I"><strong>I</strong></a>
| <a href="#J"><strong>J</strong></a>
| <a href="#L"><strong>L</strong></a>
| <a href="#M"><strong>M</strong></a>
| <a href="#N"><strong>N</strong></a>
| <a href="#O"><strong>O</strong></a>
| <a href="#P"><strong>P</strong></a>
| <a href="#R"><strong>R</strong></a>
| <a href="#S"><strong>S</strong></a>
| <a href="#T"><strong>T</strong></a>
| <a href="#W"><strong>W</strong></a>
</div>
<h2 id="A">A</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Job.Job.abort">abort() (Job method)</a>
</dt>
<dt><a href="modules.html#simso.core.Job.Job.aborted">aborted (Job attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Job.Job.absolute_deadline">absolute_deadline (Job attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Job.Job.activation_date">activation_date (Job attribute)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Job.Job.actual_computation_time_cycles">actual_computation_time_cycles (Job attribute)</a>
</dt>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.add_processor">add_processor() (Configuration method)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.add_processor">(Scheduler method)</a>
</dt>
</dl></dd>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.add_task">add_task() (Configuration method)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.add_task">(Scheduler method)</a>
</dt>
</dl></dd>
<dt><a href="modules.html#simso.core.Task.ATask">ATask (class in simso.core.Task)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="B">B</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.best_fit">best_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="C">C</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.results.Results.calc_load">calc_load() (Results method)</a>
</dt>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.check_all">check_all() (Configuration method)</a>
</dt>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration">Configuration (class in simso.configuration.Configuration)</a>
</dt>
<dt><a href="modules.html#simso.core.Job.Job.cpu">cpu (Job attribute)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.GenericTask.create_job">create_job() (GenericTask method)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.TaskInfo.csdp">csdp (TaskInfo attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Model.Model.cycles_per_ms">cycles_per_ms (Model attribute)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="D">D</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.GenericTask.data">data (GenericTask attribute)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Job.Job.data">(Job attribute)</a>
</dt>
</dl></dd>
<dt><a href="modules.html#simso.core.Task.GenericTask.deadline">deadline (GenericTask attribute)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Job.Job.deadline">(Job attribute)</a>
</dt>
</dl></dd>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.decreasing_best_fit">decreasing_best_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.decreasing_first_fit">decreasing_first_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.decreasing_next_fit">decreasing_next_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.decreasing_worst_fit">decreasing_worst_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
<dt><a href="modules.html#simso.core.Model.Model.duration">duration (Model attribute)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="E">E</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Job.Job.end_date">end_date (Job attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Model.Model.etm">etm (Model attribute)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Job.Job.exceeded_deadline">exceeded_deadline (Job attribute)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="F">F</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Scheduler.SchedulerInfo.filename">filename (SchedulerInfo attribute)</a>
</dt>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.first_fit">first_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.GenericTask.followed_by">followed_by (GenericTask attribute)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="G">G</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.generator.task_generator.gen_kato_utilizations">gen_kato_utilizations() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.generator.task_generator.gen_periods_discrete">gen_periods_discrete() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.generator.task_generator.gen_periods_loguniform">gen_periods_loguniform() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.generator.task_generator.gen_periods_uniform">gen_periods_uniform() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.generator.task_generator.gen_randfixedsum">gen_randfixedsum() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.generator.task_generator.gen_ripoll">gen_ripoll() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.generator.task_generator.gen_tasksets">gen_tasksets() (in module simso.generator.task_generator)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.generator.task_generator.gen_uunifastdiscard">gen_uunifastdiscard() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.GenericTask">GenericTask (class in simso.core.Task)</a>
</dt>
<dt><a href="modules.html#simso.core.Scheduler.SchedulerInfo.get_cls">get_cls() (SchedulerInfo method)</a>
</dt>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.get_hyperperiod">get_hyperperiod() (Configuration method)</a>
</dt>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.get_lock">get_lock() (Scheduler method)</a>
</dt>
<dt><a href="modules.html#simso.core.results.Results.get_observation_window">get_observation_window() (Results method)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="I">I</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.GenericTask.identifier">identifier (GenericTask attribute)</a>
</dt>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.PartitionedScheduler.init">init() (PartitionedScheduler method)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.init">(Scheduler method)</a>
</dt>
</dl></dd>
<dt><a href="modules.html#simso.core.Scheduler.SchedulerInfo.instantiate">instantiate() (SchedulerInfo method)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Processor.Processor.internal_id">internal_id (Processor attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Job.Job.is_active">is_active() (Job method)</a>
</dt>
<dt><a href="modules.html#simso.core.Job.Job.is_running">is_running() (Job method)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Processor.Processor.is_running">(Processor method)</a>
</dt>
</dl></dd>
</dl></td>
</tr></table>
<h2 id="J">J</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Job.Job">Job (class in simso.core.Job)</a>
</dt>
<dt><a href="modules.html#simso.core.results.JobR">JobR (class in simso.core.results)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.GenericTask.jobs">jobs (GenericTask attribute)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="L">L</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Logger.Logger.log">log() (Logger method)</a>
</dt>
<dt><a href="modules.html#simso.core.Logger.Logger">Logger (class in simso.core.Logger)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Logger.Logger.logs">logs (Logger attribute)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Model.Model.logs">(Model attribute)</a>
</dt>
</dl></dd>
</dl></td>
</tr></table>
<h2 id="M">M</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Model.Model">Model (class in simso.core.Model)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.GenericTask.monitor">monitor (GenericTask attribute)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="N">N</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Scheduler.SchedulerInfo.name">name (SchedulerInfo attribute)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.next_fit">next_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="O">O</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.results.Results.observation_window">observation_window (Results attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.on_activate">on_activate() (Scheduler method)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.on_terminated">on_terminated() (Scheduler method)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="P">P</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.PartitionedScheduler">PartitionedScheduler (class in simso.utils.PartitionedScheduler)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.GenericTask.period">period (GenericTask attribute)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Job.Job.period">(Job attribute)</a>
</dt>
</dl></dd>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.proc_info_list">proc_info_list (Configuration attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Processor.Processor">Processor (class in simso.core.Processor)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.results.ProcessorR">ProcessorR (class in simso.core.results)</a>
</dt>
<dt><a href="modules.html#simso.core.Model.Model.processors">processors (Model attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.PTask">PTask (class in simso.core.Task)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.release_lock">release_lock() (Scheduler method)</a>
</dt>
<dt><a href="modules.html#simso.core.Processor.Processor.resched">resched() (Processor method)</a>
</dt>
<dt><a href="modules.html#simso.core.results.Results">Results (class in simso.core.results)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Job.Job.ret">ret (Job attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Model.Model.run_model">run_model() (Model method)</a>
</dt>
<dt><a href="modules.html#simso.core.Processor.Processor.running">running (Processor attribute)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="S">S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.save">save() (Configuration method)</a>
</dt>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler.schedule">schedule() (Scheduler method)</a>
</dt>
<dt><a href="modules.html#simso.core.Scheduler.Scheduler">Scheduler (class in simso.core.Scheduler)</a>
</dt>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.scheduler_info">scheduler_info (Configuration attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Scheduler.SchedulerInfo">SchedulerInfo (class in simso.core.Scheduler)</a>
</dt>
<dt><a href="modules.html#simso.core.results.SchedulerR">SchedulerR (class in simso.core.results)</a>
</dt>
<dt><a href="modules.html#simso.core.Scheduler.SchedulerInfo.set_name">set_name() (SchedulerInfo method)</a>
</dt>
<dt><a href="modules.html#simso.core.results.Results.set_observation_window">set_observation_window() (Results method)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.TaskInfo.set_stack_file">set_stack_file() (TaskInfo method)</a>
</dt>
<dt><a href="modules.html#module-simso.configuration">simso.configuration (module)</a>
</dt>
<dt><a href="modules.html#module-simso.configuration.Configuration">simso.configuration.Configuration (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core">simso.core (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core.Job">simso.core.Job (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core.Logger">simso.core.Logger (module)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#module-simso.core.Model">simso.core.Model (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core.Processor">simso.core.Processor (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core.results">simso.core.results (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core.Scheduler">simso.core.Scheduler (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core.Task">simso.core.Task (module)</a>
</dt>
<dt><a href="modules.html#module-simso.core.Timer">simso.core.Timer (module)</a>
</dt>
<dt><a href="modules.html#module-simso.generator.task_generator">simso.generator.task_generator (module)</a>
</dt>
<dt><a href="modules.html#module-simso.utils.PartitionedScheduler">simso.utils.PartitionedScheduler (module)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.SporadicTask">SporadicTask (class in simso.core.Task)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.TaskInfo.stack_file">stack_file (TaskInfo attribute)</a>
</dt>
<dt><a href="modules.html#simso.generator.task_generator.StaffordRandFixedSum">StaffordRandFixedSum() (in module simso.generator.task_generator)</a>
</dt>
<dt><a href="modules.html#simso.core.Timer.Timer.start">start() (Timer method)</a>
</dt>
<dt><a href="modules.html#simso.core.Job.Job.start_date">start_date (Job attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Timer.Timer.stop">stop() (Timer method)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="T">T</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Job.Job.task">task (Job attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Task.Task">Task() (in module simso.core.Task)</a>
</dt>
<dt><a href="modules.html#simso.configuration.Configuration.Configuration.task_info_list">task_info_list (Configuration attribute)</a>
</dt>
<dt><a href="modules.html#simso.core.Model.Model.task_list">task_list (Model attribute)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.TaskInfo">TaskInfo (class in simso.core.Task)</a>
</dt>
<dt><a href="modules.html#simso.core.results.TaskR">TaskR (class in simso.core.results)</a>
</dt>
<dt><a href="modules.html#simso.core.results.Results.tasks_event">tasks_event() (Results method)</a>
</dt>
<dt><a href="modules.html#simso.core.Timer.Timer">Timer (class in simso.core.Timer)</a>
</dt>
</dl></td>
</tr></table>
<h2 id="W">W</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.core.Task.GenericTask.wcet">wcet (GenericTask attribute)</a>
</dt>
<dd><dl>
<dt><a href="modules.html#simso.core.Job.Job.wcet">(Job attribute)</a>
</dt>
</dl></dd>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="modules.html#simso.utils.PartitionedScheduler.worst_fit">worst_fit() (in module simso.utils.PartitionedScheduler)</a>
</dt>
</dl></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="#" 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
<!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>Main modules &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="Licenses" href="licenses.html" />
<link rel="prev" title="Using SimSo in script mode" href="text_mode.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="licenses.html" title="Licenses"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="text_mode.html" title="Using SimSo in script mode"
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="main-modules">
<h1><a class="toc-backref" href="#id3">Main modules</a><a class="headerlink" href="#main-modules" title="Permalink to this headline"></a></h1>
<div class="contents topic" id="table-of-contents">
<p class="topic-title first">Table of Contents</p>
<ul class="simple">
<li><a class="reference internal" href="#main-modules" id="id3">Main modules</a><ul>
<li><a class="reference internal" href="#module-simso.core" id="id4">simso.core module</a><ul>
<li><a class="reference internal" href="#module-simso.core.Scheduler" id="id5">Scheduler</a></li>
<li><a class="reference internal" href="#module-simso.core.Task" id="id6">Task</a></li>
<li><a class="reference internal" href="#module-simso.core.Job" id="id7">Job</a></li>
<li><a class="reference internal" href="#module-simso.core.Model" id="id8">Model</a></li>
<li><a class="reference internal" href="#module-simso.core.Processor" id="id9">Processor</a></li>
<li><a class="reference internal" href="#module-simso.core.Timer" id="id10">Timer</a></li>
<li><a class="reference internal" href="#module-simso.core.Logger" id="id11">Logger</a></li>
<li><a class="reference internal" href="#module-simso.core.results" id="id12">results</a></li>
</ul>
</li>
<li><a class="reference internal" href="#module-simso.configuration" id="id13">simso.configuration module</a><ul>
<li><a class="reference internal" href="#module-simso.configuration.Configuration" id="id14">Configuration</a></li>
</ul>
</li>
<li><a class="reference internal" href="#module-simso.generator.task_generator" id="id15">simso.generator module</a></li>
<li><a class="reference internal" href="#simso-utils-module" id="id16">simso.utils module</a><ul>
<li><a class="reference internal" href="#module-simso.utils.PartitionedScheduler" id="id17">PartitionedScheduler</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="module-simso.core">
<span id="simso-core-module"></span><h2><a class="toc-backref" href="#id4">simso.core module</a><a class="headerlink" href="#module-simso.core" title="Permalink to this headline"></a></h2>
<p>The core module include all the classes needed for the simulation.</p>
<div class="section" id="module-simso.core.Scheduler">
<span id="scheduler"></span><h3><a class="toc-backref" href="#id5">Scheduler</a><a class="headerlink" href="#module-simso.core.Scheduler" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.Scheduler.Scheduler">
<em class="property">class </em><tt class="descname">Scheduler</tt><big>(</big><em>sim</em>, <em>scheduler_info</em>, <em>**kwargs</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler" title="Permalink to this definition"></a></dt>
<dd><p>The implementation of a scheduler is done by subclassing this abstract
class.</p>
<p>The scheduling events are modeled by method calls which take as arguments
the <a class="reference internal" href="#simso.core.Job.Job" title="simso.core.Job.Job"><tt class="xref py py-class docutils literal"><span class="pre">jobs</span></tt></a> and the <a class="reference internal" href="#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">processors</span></tt></a>.</p>
<p>The following methods should be redefined in order to interact with the
simulation:</p>
<blockquote>
<div><ul class="simple">
<li><a class="reference internal" href="#simso.core.Scheduler.Scheduler.init" title="simso.core.Scheduler.Scheduler.init"><tt class="xref py py-meth docutils literal"><span class="pre">init()</span></tt></a> Called when the simulation is ready. The scheduler logic should be initialized here.</li>
<li><a class="reference internal" href="#simso.core.Scheduler.Scheduler.on_activate" title="simso.core.Scheduler.Scheduler.on_activate"><tt class="xref py py-meth docutils literal"><span class="pre">on_activate()</span></tt></a> Called upon a job activation.</li>
<li><a class="reference internal" href="#simso.core.Scheduler.Scheduler.on_terminated" title="simso.core.Scheduler.Scheduler.on_terminated"><tt class="xref py py-meth docutils literal"><span class="pre">on_terminated()</span></tt></a> Called when a job is terminated.</li>
<li><a class="reference internal" href="#simso.core.Scheduler.Scheduler.schedule" title="simso.core.Scheduler.Scheduler.schedule"><tt class="xref py py-meth docutils literal"><span class="pre">schedule()</span></tt></a> Take the scheduling decision. This method should not be called directly. A call to the <a class="reference internal" href="#simso.core.Processor.Processor.resched" title="simso.core.Processor.Processor.resched"><tt class="xref py py-meth docutils literal"><span class="pre">resched</span></tt></a> method is required.</li>
</ul>
</div></blockquote>
<p>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 <a class="reference internal" href="#simso.core.Scheduler.Scheduler.get_lock" title="simso.core.Scheduler.Scheduler.get_lock"><tt class="xref py py-meth docutils literal"><span class="pre">get_lock()</span></tt></a> and <a class="reference internal" href="#simso.core.Scheduler.Scheduler.release_lock" title="simso.core.Scheduler.Scheduler.release_lock"><tt class="xref py py-meth docutils literal"><span class="pre">release_lock()</span></tt></a> methods.</p>
<p>Args:</p>
<ul class="simple">
<li><cite>sim</cite>: <a class="reference internal" href="#module-simso.core.Model" title="simso.core.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance.</li>
<li><cite>scheduler_info</cite>: A <a class="reference internal" href="#simso.core.Scheduler.SchedulerInfo" title="simso.core.Scheduler.SchedulerInfo"><tt class="xref py py-class docutils literal"><span class="pre">SchedulerInfo</span></tt></a> representing the scheduler.</li>
</ul>
<p>Attributes:</p>
<ul class="simple">
<li><strong>sim</strong>: <a class="reference internal" href="#simso.core.Model.Model" title="simso.core.Model.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance. Useful to get current time with <tt class="docutils literal"><span class="pre">sim.now_ms()</span></tt> (in ms) or <tt class="docutils literal"><span class="pre">sim.now()</span></tt> (in cycles).</li>
<li><strong>processors</strong>: List of <a class="reference internal" href="#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">processors</span></tt></a> handled by this scheduler.</li>
<li><strong>task_list</strong>: List of <a class="reference internal" href="#simso.core.Task.GenericTask" title="simso.core.Task.GenericTask"><tt class="xref py py-class docutils literal"><span class="pre">tasks</span></tt></a> handled by this scheduler.</li>
</ul>
<p>Methods:</p>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.add_processor">
<tt class="descname">add_processor</tt><big>(</big><em>cpu</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.add_processor" title="Permalink to this definition"></a></dt>
<dd><p>Add a processor to the list of processors handled by this scheduler.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>processor</cite>: The <a class="reference internal" href="#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">processor</span></tt></a> to add.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.add_task">
<tt class="descname">add_task</tt><big>(</big><em>task</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.add_task" title="Permalink to this definition"></a></dt>
<dd><p>Add a task to the list of tasks handled by this scheduler.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>task</cite>: The <a class="reference internal" href="#simso.core.Task.GenericTask" title="simso.core.Task.GenericTask"><tt class="xref py py-class docutils literal"><span class="pre">task</span></tt></a> to add.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.get_lock">
<tt class="descname">get_lock</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.get_lock" title="Permalink to this definition"></a></dt>
<dd><p>Implement a lock mechanism. Override it to remove the lock or change
its behavior.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.init">
<tt class="descname">init</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.init" title="Permalink to this definition"></a></dt>
<dd><p>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</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.on_activate">
<tt class="descname">on_activate</tt><big>(</big><em>job</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.on_activate" title="Permalink to this definition"></a></dt>
<dd><p>This method is called upon a job activation.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>job</cite>: The activated <a class="reference internal" href="#simso.core.Job.Job" title="simso.core.Job.Job"><tt class="xref py py-class docutils literal"><span class="pre">job</span></tt></a>.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.on_terminated">
<tt class="descname">on_terminated</tt><big>(</big><em>job</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.on_terminated" title="Permalink to this definition"></a></dt>
<dd><p>This method is called when a job finish (termination or abortion).</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>job</cite>: The <a class="reference internal" href="#simso.core.Job.Job" title="simso.core.Job.Job"><tt class="xref py py-class docutils literal"><span class="pre">job</span></tt></a> that terminates .</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.release_lock">
<tt class="descname">release_lock</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.release_lock" title="Permalink to this definition"></a></dt>
<dd><p>Release the lock. Goes in pair with <a class="reference internal" href="#simso.core.Scheduler.Scheduler.get_lock" title="simso.core.Scheduler.Scheduler.get_lock"><tt class="xref py py-meth docutils literal"><span class="pre">get_lock()</span></tt></a>.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.Scheduler.schedule">
<tt class="descname">schedule</tt><big>(</big><em>cpu</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.Scheduler.schedule" title="Permalink to this definition"></a></dt>
<dd><p>The schedule method must be redefined by the simulated scheduler.
It takes as argument the cpu on which the scheduler runs.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>cpu</cite>: The <a class="reference internal" href="#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">processor</span></tt></a> on which the scheduler runs.</li>
</ul>
</dd>
</dl>
<p>Returns a decision or a list of decisions. A decision is a couple
(job, cpu).</p>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="simso.core.Scheduler.SchedulerInfo">
<em class="property">class </em><tt class="descname">SchedulerInfo</tt><big>(</big><em>name=''</em>, <em>cls=None</em>, <em>overhead=0</em>, <em>overhead_activate=0</em>, <em>overhead_terminate=0</em>, <em>fields=None</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.SchedulerInfo" title="Permalink to this definition"></a></dt>
<dd><p>SchedulerInfo groups the data that characterize a Scheduler (such as the
scheduling overhead) and do the dynamic loading of the scheduler.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>name</cite>: Name of the scheduler.</li>
<li><cite>cls</cite>: Class associated to this scheduler.</li>
<li><cite>overhead</cite>: Overhead associated to a scheduling decision.</li>
</ul>
</dd>
</dl>
<p>Methods:</p>
<dl class="attribute">
<dt id="simso.core.Scheduler.SchedulerInfo.filename">
<tt class="descname">filename</tt><a class="headerlink" href="#simso.core.Scheduler.SchedulerInfo.filename" title="Permalink to this definition"></a></dt>
<dd><p>Path of the scheduler (absolute or relative to simso&#8217;s working
directory).</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.SchedulerInfo.get_cls">
<tt class="descname">get_cls</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Scheduler.SchedulerInfo.get_cls" title="Permalink to this definition"></a></dt>
<dd><p>Get the class of this scheduler.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.SchedulerInfo.instantiate">
<tt class="descname">instantiate</tt><big>(</big><em>model</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.SchedulerInfo.instantiate" title="Permalink to this definition"></a></dt>
<dd><p>Instantiate the <a class="reference internal" href="#simso.core.Scheduler.Scheduler" title="simso.core.Scheduler.Scheduler"><tt class="xref py py-class docutils literal"><span class="pre">Scheduler</span></tt></a> class.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>model</cite>: The <a class="reference internal" href="#simso.core.Model.Model" title="simso.core.Model.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> object that is passed to the constructor.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Scheduler.SchedulerInfo.name">
<tt class="descname">name</tt><a class="headerlink" href="#simso.core.Scheduler.SchedulerInfo.name" title="Permalink to this definition"></a></dt>
<dd><p>The name of the Scheduler (its relative path to the XML).</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Scheduler.SchedulerInfo.set_name">
<tt class="descname">set_name</tt><big>(</big><em>filename</em>, <em>cur_dir=None</em><big>)</big><a class="headerlink" href="#simso.core.Scheduler.SchedulerInfo.set_name" title="Permalink to this definition"></a></dt>
<dd><p>Set the scheduler from a file.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>filename</cite>: relative path to the Python source containing the Scheduler.</li>
<li><cite>cur_dir</cite>: current directory. Used to set the name relatively to the simulation file.</li>
</ul>
</dd>
</dl>
</dd></dl>
</dd></dl>
</div>
<div class="section" id="module-simso.core.Task">
<span id="task"></span><h3><a class="toc-backref" href="#id6">Task</a><a class="headerlink" href="#module-simso.core.Task" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.Task.ATask">
<em class="property">class </em><tt class="descname">ATask</tt><big>(</big><em>sim</em>, <em>task_info</em><big>)</big><a class="headerlink" href="#simso.core.Task.ATask" title="Permalink to this definition"></a></dt>
<dd><p>Non-periodic Task process. Inherits from <a class="reference internal" href="#simso.core.Task.GenericTask" title="simso.core.Task.GenericTask"><tt class="xref py py-class docutils literal"><span class="pre">GenericTask</span></tt></a>. The job is
created by another task.</p>
<p>Args:</p>
<ul class="simple">
<li><cite>sim</cite>: <a class="reference internal" href="#module-simso.core.Model" title="simso.core.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance.</li>
<li><cite>task_info</cite>: A <a class="reference internal" href="#simso.core.Task.TaskInfo" title="simso.core.Task.TaskInfo"><tt class="xref py py-class docutils literal"><span class="pre">TaskInfo</span></tt></a> representing the Task.</li>
</ul>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
</tbody>
</table>
</dd></dl>
<dl class="class">
<dt id="simso.core.Task.GenericTask">
<em class="property">class </em><tt class="descname">GenericTask</tt><big>(</big><em>sim</em>, <em>task_info</em><big>)</big><a class="headerlink" href="#simso.core.Task.GenericTask" title="Permalink to this definition"></a></dt>
<dd><p>Abstract class for Tasks. <a class="reference internal" href="#simso.core.Task.ATask" title="simso.core.Task.ATask"><tt class="xref py py-class docutils literal"><span class="pre">ATask</span></tt></a> and <a class="reference internal" href="#simso.core.Task.PTask" title="simso.core.Task.PTask"><tt class="xref py py-class docutils literal"><span class="pre">PTask</span></tt></a> inherits from
this class.</p>
<p>These classes simulate the behavior of the simulated task. It controls the
release of the jobs and is able to abort the jobs that exceed their
deadline.</p>
<p>The majority of the task_info attributes are available through this class
too. A set of metrics such as the number of preemptions and migrations are
available for analysis.</p>
<p>Args:</p>
<ul class="simple">
<li><cite>sim</cite>: <a class="reference internal" href="#module-simso.core.Model" title="simso.core.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance.</li>
<li><cite>task_info</cite>: A <a class="reference internal" href="#simso.core.Task.TaskInfo" title="simso.core.Task.TaskInfo"><tt class="xref py py-class docutils literal"><span class="pre">TaskInfo</span></tt></a> representing the Task.</li>
</ul>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
</tbody>
</table>
<dl class="method">
<dt id="simso.core.Task.GenericTask.create_job">
<tt class="descname">create_job</tt><big>(</big><em>pred=None</em><big>)</big><a class="headerlink" href="#simso.core.Task.GenericTask.create_job" title="Permalink to this definition"></a></dt>
<dd><p>Create a new job from this task. This should probably not be used
directly by a scheduler.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.data">
<tt class="descname">data</tt><a class="headerlink" href="#simso.core.Task.GenericTask.data" title="Permalink to this definition"></a></dt>
<dd><p>Extra data to characterize the task. Only used by the scheduler.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.deadline">
<tt class="descname">deadline</tt><a class="headerlink" href="#simso.core.Task.GenericTask.deadline" title="Permalink to this definition"></a></dt>
<dd><p>Deadline in milliseconds.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.followed_by">
<tt class="descname">followed_by</tt><a class="headerlink" href="#simso.core.Task.GenericTask.followed_by" title="Permalink to this definition"></a></dt>
<dd><p>Task that is activated by the end of a job from this task.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.identifier">
<tt class="descname">identifier</tt><a class="headerlink" href="#simso.core.Task.GenericTask.identifier" title="Permalink to this definition"></a></dt>
<dd><p>Identifier of the task.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.jobs">
<tt class="descname">jobs</tt><a class="headerlink" href="#simso.core.Task.GenericTask.jobs" title="Permalink to this definition"></a></dt>
<dd><p>List of the jobs.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.monitor">
<tt class="descname">monitor</tt><a class="headerlink" href="#simso.core.Task.GenericTask.monitor" title="Permalink to this definition"></a></dt>
<dd><p>The monitor for this Task. Similar to a log mechanism (see Monitor in
SimPy doc).</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.period">
<tt class="descname">period</tt><a class="headerlink" href="#simso.core.Task.GenericTask.period" title="Permalink to this definition"></a></dt>
<dd><p>Period of the task.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.GenericTask.wcet">
<tt class="descname">wcet</tt><a class="headerlink" href="#simso.core.Task.GenericTask.wcet" title="Permalink to this definition"></a></dt>
<dd><p>Worst-Case Execution Time in milliseconds.</p>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="simso.core.Task.PTask">
<em class="property">class </em><tt class="descname">PTask</tt><big>(</big><em>sim</em>, <em>task_info</em><big>)</big><a class="headerlink" href="#simso.core.Task.PTask" title="Permalink to this definition"></a></dt>
<dd><p>Periodic Task process. Inherits from <a class="reference internal" href="#simso.core.Task.GenericTask" title="simso.core.Task.GenericTask"><tt class="xref py py-class docutils literal"><span class="pre">GenericTask</span></tt></a>. The jobs are
created periodically.</p>
<p>Args:</p>
<ul class="simple">
<li><cite>sim</cite>: <a class="reference internal" href="#module-simso.core.Model" title="simso.core.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance.</li>
<li><cite>task_info</cite>: A <a class="reference internal" href="#simso.core.Task.TaskInfo" title="simso.core.Task.TaskInfo"><tt class="xref py py-class docutils literal"><span class="pre">TaskInfo</span></tt></a> representing the Task.</li>
</ul>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
</tbody>
</table>
</dd></dl>
<dl class="class">
<dt id="simso.core.Task.SporadicTask">
<em class="property">class </em><tt class="descname">SporadicTask</tt><big>(</big><em>sim</em>, <em>task_info</em><big>)</big><a class="headerlink" href="#simso.core.Task.SporadicTask" title="Permalink to this definition"></a></dt>
<dd><p>Sporadic Task process. Inherits from <a class="reference internal" href="#simso.core.Task.GenericTask" title="simso.core.Task.GenericTask"><tt class="xref py py-class docutils literal"><span class="pre">GenericTask</span></tt></a>. The jobs are
created using a list of activation dates.</p>
<p>Args:</p>
<ul class="simple">
<li><cite>sim</cite>: <a class="reference internal" href="#module-simso.core.Model" title="simso.core.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance.</li>
<li><cite>task_info</cite>: A <a class="reference internal" href="#simso.core.Task.TaskInfo" title="simso.core.Task.TaskInfo"><tt class="xref py py-class docutils literal"><span class="pre">TaskInfo</span></tt></a> representing the Task.</li>
</ul>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
</tbody>
</table>
</dd></dl>
<dl class="function">
<dt id="simso.core.Task.Task">
<tt class="descname">Task</tt><big>(</big><em>sim</em>, <em>task_info</em><big>)</big><a class="headerlink" href="#simso.core.Task.Task" title="Permalink to this definition"></a></dt>
<dd><p>Task factory. Return and instantiate the correct class according to the
task_info.</p>
</dd></dl>
<dl class="class">
<dt id="simso.core.Task.TaskInfo">
<em class="property">class </em><tt class="descname">TaskInfo</tt><big>(</big><em>name</em>, <em>identifier</em>, <em>task_type</em>, <em>abort_on_miss</em>, <em>period</em>, <em>activation_date</em>, <em>n_instr</em>, <em>mix</em>, <em>stack_file</em>, <em>wcet</em>, <em>acet</em>, <em>et_stddev</em>, <em>deadline</em>, <em>base_cpi</em>, <em>followed_by</em>, <em>list_activation_dates</em>, <em>preemption_cost</em>, <em>data</em><big>)</big><a class="headerlink" href="#simso.core.Task.TaskInfo" title="Permalink to this definition"></a></dt>
<dd><p>TaskInfo is mainly a container class grouping the data that characterize
a Task. A list of TaskInfo objects are passed to the Model so that
<a class="reference internal" href="#simso.core.Task.Task" title="simso.core.Task.Task"><tt class="xref py py-class docutils literal"><span class="pre">Task</span></tt></a> instances can be created.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
</tbody>
</table>
<dl class="attribute">
<dt id="simso.core.Task.TaskInfo.csdp">
<tt class="descname">csdp</tt><a class="headerlink" href="#simso.core.Task.TaskInfo.csdp" title="Permalink to this definition"></a></dt>
<dd><p>Accumulated Stack Distance Profile. Used by the cache models instead of
the Stack Distance Profile for optimization matters.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Task.TaskInfo.set_stack_file">
<tt class="descname">set_stack_file</tt><big>(</big><em>stack_file</em>, <em>cur_dir</em><big>)</big><a class="headerlink" href="#simso.core.Task.TaskInfo.set_stack_file" title="Permalink to this definition"></a></dt>
<dd><p>Set the stack distance profile.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Task.TaskInfo.stack_file">
<tt class="descname">stack_file</tt><a class="headerlink" href="#simso.core.Task.TaskInfo.stack_file" title="Permalink to this definition"></a></dt>
<dd><p>Stack distance profile input file.</p>
</dd></dl>
</dd></dl>
</div>
<div class="section" id="module-simso.core.Job">
<span id="job"></span><h3><a class="toc-backref" href="#id7">Job</a><a class="headerlink" href="#module-simso.core.Job" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.Job.Job">
<em class="property">class </em><tt class="descname">Job</tt><big>(</big><em>task</em>, <em>name</em>, <em>pred</em>, <em>monitor</em>, <em>etm</em>, <em>sim</em><big>)</big><a class="headerlink" href="#simso.core.Job.Job" title="Permalink to this definition"></a></dt>
<dd><p>The Job class simulate the behavior of a real Job. This <em>should</em> only be
instantiated by a Task.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>task</cite>: The parent <a class="reference internal" href="#simso.core.Task.Task" title="simso.core.Task.Task"><tt class="xref py py-class docutils literal"><span class="pre">task</span></tt></a>.</li>
<li><cite>name</cite>: The name for this job.</li>
<li><cite>pred</cite>: If the task is not periodic, pred is the job that released this one.</li>
<li><cite>monitor</cite>: A monitor is an object that log in time.</li>
<li><cite>etm</cite>: The execution time model.</li>
<li><cite>sim</cite>: <a class="reference internal" href="#module-simso.core.Model" title="simso.core.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance.</li>
</ul>
</dd>
</dl>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
</tbody>
</table>
<dl class="method">
<dt id="simso.core.Job.Job.abort">
<tt class="descname">abort</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Job.Job.abort" title="Permalink to this definition"></a></dt>
<dd><p>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.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.aborted">
<tt class="descname">aborted</tt><a class="headerlink" href="#simso.core.Job.Job.aborted" title="Permalink to this definition"></a></dt>
<dd><p>True if the job has been aborted.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body">bool</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.absolute_deadline">
<tt class="descname">absolute_deadline</tt><a class="headerlink" href="#simso.core.Job.Job.absolute_deadline" title="Permalink to this definition"></a></dt>
<dd><p>Absolute deadline in milliseconds for this job. This is the activation
date + the relative deadline.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.activation_date">
<tt class="descname">activation_date</tt><a class="headerlink" href="#simso.core.Job.Job.activation_date" title="Permalink to this definition"></a></dt>
<dd><p>Activation date in milliseconds for this job.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.actual_computation_time_cycles">
<tt class="descname">actual_computation_time_cycles</tt><a class="headerlink" href="#simso.core.Job.Job.actual_computation_time_cycles" title="Permalink to this definition"></a></dt>
<dd><p>Computation time as if the processor speed was 1.0 during the whole
execution.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.cpu">
<tt class="descname">cpu</tt><a class="headerlink" href="#simso.core.Job.Job.cpu" title="Permalink to this definition"></a></dt>
<dd><p>The <a class="reference internal" href="#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">processor</span></tt></a> on which the
job is attached. Equivalent to <tt class="docutils literal"><span class="pre">self.task.cpu</span></tt>.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.data">
<tt class="descname">data</tt><a class="headerlink" href="#simso.core.Job.Job.data" title="Permalink to this definition"></a></dt>
<dd><p>The extra data specified for the task. Equivalent to
<tt class="docutils literal"><span class="pre">self.task.data</span></tt>.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.deadline">
<tt class="descname">deadline</tt><a class="headerlink" href="#simso.core.Job.Job.deadline" title="Permalink to this definition"></a></dt>
<dd><p>Relative deadline in milliseconds.
Equivalent to <tt class="docutils literal"><span class="pre">self.task.deadline</span></tt>.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.end_date">
<tt class="descname">end_date</tt><a class="headerlink" href="#simso.core.Job.Job.end_date" title="Permalink to this definition"></a></dt>
<dd><p>Date (in ms) when this job finished its execution.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.exceeded_deadline">
<tt class="descname">exceeded_deadline</tt><a class="headerlink" href="#simso.core.Job.Job.exceeded_deadline" title="Permalink to this definition"></a></dt>
<dd><p>True if the end_date is greater than the deadline or if the job was
aborted.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Job.Job.is_active">
<tt class="descname">is_active</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Job.Job.is_active" title="Permalink to this definition"></a></dt>
<dd><p>Return True if the job is still active.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Job.Job.is_running">
<tt class="descname">is_running</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Job.Job.is_running" title="Permalink to this definition"></a></dt>
<dd><p>Return True if the job is currently running on a processor.
Equivalent to <tt class="docutils literal"><span class="pre">self.cpu.running</span> <span class="pre">==</span> <span class="pre">self</span></tt>.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body">bool</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.period">
<tt class="descname">period</tt><a class="headerlink" href="#simso.core.Job.Job.period" title="Permalink to this definition"></a></dt>
<dd><p>Period in milliseconds. Equivalent to <tt class="docutils literal"><span class="pre">self.task.period</span></tt>.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.ret">
<tt class="descname">ret</tt><a class="headerlink" href="#simso.core.Job.Job.ret" title="Permalink to this definition"></a></dt>
<dd><p>Remaining execution time.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.start_date">
<tt class="descname">start_date</tt><a class="headerlink" href="#simso.core.Job.Job.start_date" title="Permalink to this definition"></a></dt>
<dd><p>Date (in ms) when this job started executing
(different than the activation).</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.task">
<tt class="descname">task</tt><a class="headerlink" href="#simso.core.Job.Job.task" title="Permalink to this definition"></a></dt>
<dd><p>The <a class="reference internal" href="#simso.core.Task.Task" title="simso.core.Task.Task"><tt class="xref py py-class docutils literal"><span class="pre">task</span></tt></a> for this job.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Job.Job.wcet">
<tt class="descname">wcet</tt><a class="headerlink" href="#simso.core.Job.Job.wcet" title="Permalink to this definition"></a></dt>
<dd><p>Worst-Case Execution Time in milliseconds.
Equivalent to <tt class="docutils literal"><span class="pre">self.task.wcet</span></tt>.</p>
</dd></dl>
</dd></dl>
</div>
<div class="section" id="module-simso.core.Model">
<span id="model"></span><h3><a class="toc-backref" href="#id8">Model</a><a class="headerlink" href="#module-simso.core.Model" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.Model.Model">
<em class="property">class </em><tt class="descname">Model</tt><big>(</big><em>configuration</em>, <em>callback=None</em><big>)</big><a class="headerlink" href="#simso.core.Model.Model" title="Permalink to this definition"></a></dt>
<dd><p>Main class for the simulation. It instantiate the various components
required by the simulation and run it.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>callback</cite>: A callback can be specified. This function will be called to report the advance of the simulation (useful for a progression bar).</li>
<li><cite>configuration</cite>: The <a class="reference internal" href="#module-simso.configuration.Configuration" title="simso.configuration.Configuration"><tt class="xref py py-class docutils literal"><span class="pre">configuration</span></tt></a> of the simulation.</li>
</ul>
</dd>
</dl>
<p>Methods:</p>
<dl class="attribute">
<dt id="simso.core.Model.Model.cycles_per_ms">
<tt class="descname">cycles_per_ms</tt><a class="headerlink" href="#simso.core.Model.Model.cycles_per_ms" title="Permalink to this definition"></a></dt>
<dd><p>Number of cycles per milliseconds. A cycle is the internal unit used
by SimSo. However, the tasks are defined using milliseconds.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Model.Model.duration">
<tt class="descname">duration</tt><a class="headerlink" href="#simso.core.Model.Model.duration" title="Permalink to this definition"></a></dt>
<dd><p>Duration of the simulation.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Model.Model.etm">
<tt class="descname">etm</tt><a class="headerlink" href="#simso.core.Model.Model.etm" title="Permalink to this definition"></a></dt>
<dd><p>Execution Time Model</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Model.Model.logs">
<tt class="descname">logs</tt><a class="headerlink" href="#simso.core.Model.Model.logs" title="Permalink to this definition"></a></dt>
<dd><p>All the logs from the <a class="reference internal" href="#simso.core.Logger.Logger" title="simso.core.Logger.Logger"><tt class="xref py py-class docutils literal"><span class="pre">Logger</span></tt></a>.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Model.Model.processors">
<tt class="descname">processors</tt><a class="headerlink" href="#simso.core.Model.Model.processors" title="Permalink to this definition"></a></dt>
<dd><p>List of all the processors.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Model.Model.run_model">
<tt class="descname">run_model</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Model.Model.run_model" title="Permalink to this definition"></a></dt>
<dd><p>Execute the simulation.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Model.Model.task_list">
<tt class="descname">task_list</tt><a class="headerlink" href="#simso.core.Model.Model.task_list" title="Permalink to this definition"></a></dt>
<dd><p>List of all the tasks.</p>
</dd></dl>
</dd></dl>
</div>
<div class="section" id="module-simso.core.Processor">
<span id="processor"></span><h3><a class="toc-backref" href="#id9">Processor</a><a class="headerlink" href="#module-simso.core.Processor" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.Processor.Processor">
<em class="property">class </em><tt class="descname">Processor</tt><big>(</big><em>model</em>, <em>proc_info</em><big>)</big><a class="headerlink" href="#simso.core.Processor.Processor" title="Permalink to this definition"></a></dt>
<dd><p>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.</p>
<p>When a scheduler needs to take a scheduling decision, it must invoke the
<a class="reference internal" href="#simso.core.Processor.Processor.resched" title="simso.core.Processor.Processor.resched"><tt class="xref py py-meth docutils literal"><span class="pre">resched()</span></tt></a> method. This is typically done in the <a class="reference internal" href="#simso.core.Scheduler.Scheduler.on_activate" title="simso.core.Scheduler.Scheduler.on_activate"><tt class="xref py py-meth docutils literal"><span class="pre">on_activate</span></tt></a>, <a class="reference internal" href="#simso.core.Scheduler.Scheduler.on_terminated" title="simso.core.Scheduler.Scheduler.on_terminated"><tt class="xref py py-meth docutils literal"><span class="pre">on_terminated</span></tt></a> or in a <a class="reference internal" href="#simso.core.Timer.Timer" title="simso.core.Timer.Timer"><tt class="xref py py-class docutils literal"><span class="pre">timer</span></tt></a> handler.</p>
<dl class="attribute">
<dt id="simso.core.Processor.Processor.internal_id">
<tt class="descname">internal_id</tt><a class="headerlink" href="#simso.core.Processor.Processor.internal_id" title="Permalink to this definition"></a></dt>
<dd><p>A unique, internal, id.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Processor.Processor.is_running">
<tt class="descname">is_running</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Processor.Processor.is_running" title="Permalink to this definition"></a></dt>
<dd><p>Return True if a job is currently running on that processor.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Processor.Processor.resched">
<tt class="descname">resched</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Processor.Processor.resched" title="Permalink to this definition"></a></dt>
<dd><p>Add a resched event to the list of events to handle.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Processor.Processor.running">
<tt class="descname">running</tt><a class="headerlink" href="#simso.core.Processor.Processor.running" title="Permalink to this definition"></a></dt>
<dd><p>The job currently running on that processor. None if no job is
currently running on the processor.</p>
</dd></dl>
</dd></dl>
</div>
<div class="section" id="module-simso.core.Timer">
<span id="timer"></span><h3><a class="toc-backref" href="#id10">Timer</a><a class="headerlink" href="#module-simso.core.Timer" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.Timer.Timer">
<em class="property">class </em><tt class="descname">Timer</tt><big>(</big><em>sim</em>, <em>function</em>, <em>args</em>, <em>delay</em>, <em>one_shot=True</em>, <em>prior=False</em>, <em>cpu=None</em>, <em>in_ms=True</em>, <em>overhead=0</em><big>)</big><a class="headerlink" href="#simso.core.Timer.Timer" title="Permalink to this definition"></a></dt>
<dd><p>Allow to declare a timer. A timer is a mechanism that allows to call a
function after a certain amount of time, periodically or single shot.</p>
<p>A Timer can be used with or without specifying a processor. If a processor
is specified, when the timer fire, if a job was running on the processor,
it is temporarly interrupted. This is more realistic, even if for the
moment there is no overhead associated to this action. A scheduler using a
timer should define on which processor the callback will execute.</p>
<p>The delay is expressed in milliseconds by default but it can also be given
in cycles.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>sim</cite>: The <a class="reference internal" href="#simso.core.Model.Model" title="simso.core.Model.Model"><tt class="xref py py-class docutils literal"><span class="pre">model</span></tt></a> object.</li>
<li><cite>function</cite>: Callback function, called when the delay expires.</li>
<li><cite>args</cite>: Arguments passed to the callback function.</li>
<li><cite>delay</cite>: Time to wait before calling the function.</li>
<li><cite>one_shot</cite>: True if the timer should execute only once.</li>
<li><cite>prior</cite>: If true, for the same date, the simulation should start by handling the timer (should probably not be True).</li>
<li><cite>cpu</cite>: On which <a class="reference internal" href="#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">processor</span></tt></a> the function is virtually executing.</li>
<li><cite>in_ms</cite>: True if the delay is expressed in millisecond. In cycles otherwise.</li>
</ul>
</dd>
</dl>
<p>Methods:</p>
<dl class="method">
<dt id="simso.core.Timer.Timer.start">
<tt class="descname">start</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Timer.Timer.start" title="Permalink to this definition"></a></dt>
<dd><p>Start the timer.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.Timer.Timer.stop">
<tt class="descname">stop</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.Timer.Timer.stop" title="Permalink to this definition"></a></dt>
<dd><p>Stop the timer.</p>
</dd></dl>
</dd></dl>
</div>
<div class="section" id="module-simso.core.Logger">
<span id="logger"></span><h3><a class="toc-backref" href="#id11">Logger</a><a class="headerlink" href="#module-simso.core.Logger" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.Logger.Logger">
<em class="property">class </em><tt class="descname">Logger</tt><big>(</big><em>sim</em><big>)</big><a class="headerlink" href="#simso.core.Logger.Logger" title="Permalink to this definition"></a></dt>
<dd><p>Simple logger. Every message is logged with its date.</p>
<p>Args:
- <cite>sim</cite>: The <a class="reference internal" href="#simso.core.Model.Model" title="simso.core.Model.Model"><tt class="xref py py-class docutils literal"><span class="pre">model</span></tt></a> object.</p>
<dl class="method">
<dt id="simso.core.Logger.Logger.log">
<tt class="descname">log</tt><big>(</big><em>msg</em>, <em>kernel=False</em><big>)</big><a class="headerlink" href="#simso.core.Logger.Logger.log" title="Permalink to this definition"></a></dt>
<dd><p>Log the message <cite>msg</cite>.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>msg</cite>: The message to log.</li>
<li><cite>kernel</cite>: Allows to make a distinction between a message from the core of the simulation or from the scheduler.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.Logger.Logger.logs">
<tt class="descname">logs</tt><a class="headerlink" href="#simso.core.Logger.Logger.logs" title="Permalink to this definition"></a></dt>
<dd><p>The logs, a SimPy Monitor object.</p>
</dd></dl>
</dd></dl>
</div>
<div class="section" id="module-simso.core.results">
<span id="results"></span><h3><a class="toc-backref" href="#id12">results</a><a class="headerlink" href="#module-simso.core.results" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.core.results.JobR">
<em class="property">class </em><tt class="descname">JobR</tt><big>(</big><em>date</em>, <em>job</em><big>)</big><a class="headerlink" href="#simso.core.results.JobR" title="Permalink to this definition"></a></dt>
<dd><p>Add a set of metrics to a job. Such metrics include: preemption count,
migration count, response time, etc.</p>
</dd></dl>
<dl class="class">
<dt id="simso.core.results.ProcessorR">
<em class="property">class </em><tt class="descname">ProcessorR</tt><a class="headerlink" href="#simso.core.results.ProcessorR" title="Permalink to this definition"></a></dt>
<dd><p>Add information about a processor such as the number of CxtSave and
CxtLoad and their total overhead.</p>
</dd></dl>
<dl class="class">
<dt id="simso.core.results.Results">
<em class="property">class </em><tt class="descname">Results</tt><big>(</big><em>model</em><big>)</big><a class="headerlink" href="#simso.core.results.Results" title="Permalink to this definition"></a></dt>
<dd><p>This class embeds and analyzes all the results from the simulation.
This allows to retrieve the usual metrics.</p>
<dl class="docutils">
<dt>The Results instance object contains the following attributes:</dt>
<dd><ul class="first last simple">
<li><cite>tasks</cite>: a dictionary of TaskR where the key is the original Task.</li>
<li><cite>scheduler</cite>: a SchedulerR instance.</li>
<li><cite>processors</cite>: a dictionary of ProcessorR where the key is the original Processor.</li>
</ul>
</dd>
</dl>
<p>.</p>
<dl class="method">
<dt id="simso.core.results.Results.calc_load">
<tt class="descname">calc_load</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.results.Results.calc_load" title="Permalink to this definition"></a></dt>
<dd><p>Yield a tuple (proc, load, overhead) for each processor.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.results.Results.get_observation_window">
<tt class="descname">get_observation_window</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.results.Results.get_observation_window" title="Permalink to this definition"></a></dt>
<dd><p>Get the observation window.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.core.results.Results.observation_window">
<tt class="descname">observation_window</tt><a class="headerlink" href="#simso.core.results.Results.observation_window" title="Permalink to this definition"></a></dt>
<dd><p>Get the observation window.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.results.Results.set_observation_window">
<tt class="descname">set_observation_window</tt><big>(</big><em>window</em><big>)</big><a class="headerlink" href="#simso.core.results.Results.set_observation_window" title="Permalink to this definition"></a></dt>
<dd><p>Set the observation window. The events that occurs outside of the
observation window are discarded.</p>
</dd></dl>
<dl class="method">
<dt id="simso.core.results.Results.tasks_event">
<tt class="descname">tasks_event</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.core.results.Results.tasks_event" title="Permalink to this definition"></a></dt>
<dd><p>Generator of the tasks events sorted by their date.</p>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="simso.core.results.SchedulerR">
<em class="property">class </em><tt class="descname">SchedulerR</tt><a class="headerlink" href="#simso.core.results.SchedulerR" title="Permalink to this definition"></a></dt>
<dd><p>Add information about the scheduler such as the number of scheduling
events and their total overhead.</p>
</dd></dl>
<dl class="class">
<dt id="simso.core.results.TaskR">
<em class="property">class </em><tt class="descname">TaskR</tt><big>(</big><em>task</em>, <em>delta_preemption=100</em><big>)</big><a class="headerlink" href="#simso.core.results.TaskR" title="Permalink to this definition"></a></dt>
<dd><p>Add a set of metrics to a task. These metrics include: task_migrations,
abortion count, etc.</p>
<p>The attribute jobs contains a list of JobR, sorted by activation date.</p>
</dd></dl>
</div>
</div>
<div class="section" id="module-simso.configuration">
<span id="simso-configuration-module"></span><h2><a class="toc-backref" href="#id13">simso.configuration module</a><a class="headerlink" href="#module-simso.configuration" title="Permalink to this headline"></a></h2>
<div class="section" id="module-simso.configuration.Configuration">
<span id="configuration"></span><h3><a class="toc-backref" href="#id14">Configuration</a><a class="headerlink" href="#module-simso.configuration.Configuration" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.configuration.Configuration.Configuration">
<em class="property">class </em><tt class="descname">Configuration</tt><big>(</big><em>filename=None</em><big>)</big><a class="headerlink" href="#simso.configuration.Configuration.Configuration" title="Permalink to this definition"></a></dt>
<dd><p>The configuration class store all the details about a system. An instance
of this class will be passed to the constructor of the
<a class="reference internal" href="#simso.core.Model.Model" title="simso.core.Model.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> class.</p>
<p>Args:
- <cite>filename</cite> A file can be used to initialize the configuration.</p>
<dl class="method">
<dt id="simso.configuration.Configuration.Configuration.add_processor">
<tt class="descname">add_processor</tt><big>(</big><em>name</em>, <em>identifier</em>, <em>cs_overhead=0</em>, <em>cl_overhead=0</em>, <em>migration_overhead=0</em>, <em>speed=1.0</em><big>)</big><a class="headerlink" href="#simso.configuration.Configuration.Configuration.add_processor" title="Permalink to this definition"></a></dt>
<dd><p>Helper method to create a ProcInfo and add it to the list of
processors.</p>
</dd></dl>
<dl class="method">
<dt id="simso.configuration.Configuration.Configuration.add_task">
<tt class="descname">add_task</tt><big>(</big><em>name</em>, <em>identifier</em>, <em>task_type='Periodic'</em>, <em>abort_on_miss=False</em>, <em>period=10</em>, <em>activation_date=0</em>, <em>n_instr=0</em>, <em>mix=0.5</em>, <em>stack_file=''</em>, <em>wcet=0</em>, <em>acet=0</em>, <em>et_stddev=0</em>, <em>deadline=10</em>, <em>base_cpi=1.0</em>, <em>followed_by=None</em>, <em>list_activation_dates=[]</em>, <em>preemption_cost=0</em>, <em>data=None</em><big>)</big><a class="headerlink" href="#simso.configuration.Configuration.Configuration.add_task" title="Permalink to this definition"></a></dt>
<dd><p>Helper method to create a TaskInfo and add it to the list of tasks.</p>
</dd></dl>
<dl class="method">
<dt id="simso.configuration.Configuration.Configuration.check_all">
<tt class="descname">check_all</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.configuration.Configuration.Configuration.check_all" title="Permalink to this definition"></a></dt>
<dd><p>Check the correctness of the configuration (without simulating it).</p>
</dd></dl>
<dl class="method">
<dt id="simso.configuration.Configuration.Configuration.get_hyperperiod">
<tt class="descname">get_hyperperiod</tt><big>(</big><big>)</big><a class="headerlink" href="#simso.configuration.Configuration.Configuration.get_hyperperiod" title="Permalink to this definition"></a></dt>
<dd><p>Compute and return the hyperperiod of the tasks.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.configuration.Configuration.Configuration.proc_info_list">
<tt class="descname">proc_info_list</tt><a class="headerlink" href="#simso.configuration.Configuration.Configuration.proc_info_list" title="Permalink to this definition"></a></dt>
<dd><p>List of processors (ProcInfo objects).</p>
</dd></dl>
<dl class="method">
<dt id="simso.configuration.Configuration.Configuration.save">
<tt class="descname">save</tt><big>(</big><em>simulation_file=None</em><big>)</big><a class="headerlink" href="#simso.configuration.Configuration.Configuration.save" title="Permalink to this definition"></a></dt>
<dd><p>Save the current configuration in a file. If no file is given as
argument, the previous file used to write or read the configuration is
used again.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.configuration.Configuration.Configuration.scheduler_info">
<tt class="descname">scheduler_info</tt><a class="headerlink" href="#simso.configuration.Configuration.Configuration.scheduler_info" title="Permalink to this definition"></a></dt>
<dd><p>SchedulerInfo object.</p>
</dd></dl>
<dl class="attribute">
<dt id="simso.configuration.Configuration.Configuration.task_info_list">
<tt class="descname">task_info_list</tt><a class="headerlink" href="#simso.configuration.Configuration.Configuration.task_info_list" title="Permalink to this definition"></a></dt>
<dd><p>List of tasks (TaskInfo objects).</p>
</dd></dl>
</dd></dl>
</div>
</div>
<div class="section" id="module-simso.generator.task_generator">
<span id="simso-generator-module"></span><h2><a class="toc-backref" href="#id15">simso.generator module</a><a class="headerlink" href="#module-simso.generator.task_generator" title="Permalink to this headline"></a></h2>
<p>Tools for generating task sets.</p>
<dl class="function">
<dt id="simso.generator.task_generator.StaffordRandFixedSum">
<tt class="descname">StaffordRandFixedSum</tt><big>(</big><em>n</em>, <em>u</em>, <em>nsets</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.StaffordRandFixedSum" title="Permalink to this definition"></a></dt>
<dd><p>Copyright 2010 Paul Emberson, Roger Stafford, Robert Davis.
All rights reserved.</p>
<p>Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:</p>
<ol class="arabic">
<li><dl class="first docutils">
<dt>Redistributions of source code must retain the above copyright notice,</dt>
<dd><p class="first last">this list of conditions and the following disclaimer.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Redistributions in binary form must reproduce the above copyright notice,</dt>
<dd><p class="first last">this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.</p>
</dd>
</dl>
</li>
</ol>
<p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS <a href="#id1"><span class="problematic" id="id2">``</span></a>AS IS&#8217;&#8217; AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>
<p>The views and conclusions contained in the software and documentation are
those of the authors and should not be interpreted as representing official
policies, either expressed or implied, of Paul Emberson, Roger Stafford or
Robert Davis.</p>
<p>Includes Python implementation of Roger Stafford&#8217;s randfixedsum implementation
<a class="reference external" href="http://www.mathworks.com/matlabcentral/fileexchange/9700">http://www.mathworks.com/matlabcentral/fileexchange/9700</a>
Adapted specifically for the purpose of taskset generation with fixed
total utilisation value</p>
<p>Please contact <a class="reference external" href="mailto:paule&#37;&#52;&#48;rapitasystems&#46;com">paule<span>&#64;</span>rapitasystems<span>&#46;</span>com</a> or <a class="reference external" href="mailto:robdavis&#37;&#52;&#48;cs&#46;york&#46;ac&#46;uk">robdavis<span>&#64;</span>cs<span>&#46;</span>york<span>&#46;</span>ac<span>&#46;</span>uk</a> if you have
any questions regarding this software.</p>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_kato_utilizations">
<tt class="descname">gen_kato_utilizations</tt><big>(</big><em>nsets</em>, <em>umin</em>, <em>umax</em>, <em>target_util</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_kato_utilizations" title="Permalink to this definition"></a></dt>
<dd><p>Kato et al. tasksets generator.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>nsets</cite>: Number of tasksets to generate.</li>
<li><cite>umin</cite>: Minimum task utilization.</li>
<li><cite>umax</cite>: Maximum task utilization.</li>
<li><cite>target_util</cite>:</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_periods_discrete">
<tt class="descname">gen_periods_discrete</tt><big>(</big><em>n</em>, <em>nsets</em>, <em>periods</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_periods_discrete" title="Permalink to this definition"></a></dt>
<dd><p>Generate a matrix of (nsets x n) random periods chosen randomly in the
list of periods.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>n</cite>: The number of tasks in a task set.</li>
<li><cite>nsets</cite>: Number of sets to generate.</li>
<li><cite>periods</cite>: A list of available periods.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_periods_loguniform">
<tt class="descname">gen_periods_loguniform</tt><big>(</big><em>n</em>, <em>nsets</em>, <em>min_</em>, <em>max_</em>, <em>round_to_int=False</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_periods_loguniform" title="Permalink to this definition"></a></dt>
<dd><p>Generate a list of <cite>nsets</cite> sets containing each <cite>n</cite> random periods using a
loguniform distribution.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>n</cite>: The number of tasks in a task set.</li>
<li><cite>nsets</cite>: Number of sets to generate.</li>
<li><cite>min_</cite>: Period min.</li>
<li><cite>max_</cite>: Period max.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_periods_uniform">
<tt class="descname">gen_periods_uniform</tt><big>(</big><em>n</em>, <em>nsets</em>, <em>min_</em>, <em>max_</em>, <em>round_to_int=False</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_periods_uniform" title="Permalink to this definition"></a></dt>
<dd><p>Generate a list of <cite>nsets</cite> sets containing each <cite>n</cite> random periods using a
uniform distribution.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>n</cite>: The number of tasks in a task set.</li>
<li><cite>nsets</cite>: Number of sets to generate.</li>
<li><cite>min_</cite>: Period min.</li>
<li><cite>max_</cite>: Period max.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_randfixedsum">
<tt class="descname">gen_randfixedsum</tt><big>(</big><em>nsets</em>, <em>u</em>, <em>n</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_randfixedsum" title="Permalink to this definition"></a></dt>
<dd><p>Stafford&#8217;s RandFixedSum algorithm implementated in Python.</p>
<p>Based on the Python implementation given by Paul Emberson, Roger Stafford,
and Robert Davis. Available under the Simplified BSD License.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>n</cite>: The number of tasks in a task set.</li>
<li><cite>u</cite>: Total utilization of the task set.</li>
<li><cite>nsets</cite>: Number of sets to generate.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_ripoll">
<tt class="descname">gen_ripoll</tt><big>(</big><em>nsets</em>, <em>compute</em>, <em>deadline</em>, <em>period</em>, <em>target_util</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_ripoll" title="Permalink to this definition"></a></dt>
<dd><p>Ripoll et al. tasksets generator.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>nsets</cite>: Number of tasksets to generate.</li>
<li><cite>compute</cite>: Maximum computation time of a task.</li>
<li><cite>deadline</cite>: Maximum slack time.</li>
<li><cite>period</cite>: Maximum delay after the deadline.</li>
<li><cite>target_util</cite>: Total utilization to reach.</li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_tasksets">
<tt class="descname">gen_tasksets</tt><big>(</big><em>utilizations</em>, <em>periods</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_tasksets" title="Permalink to this definition"></a></dt>
<dd><p>Take a list of task utilization sets and a list of task period sets and
return a list of couples (c, p) sets. The computation times are truncated
at a precision of 10^-10 to avoid floating point precision errors.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last">
<li><p class="first"><cite>utilization</cite>: The list of task utilization sets. For example:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="p">[[</span><span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">]]</span>
</pre></div>
</div>
</li>
<li><p class="first"><cite>periods</cite>: The list of task period sets. For examples:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="p">[[</span><span class="mi">100</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">1000</span><span class="p">],</span> <span class="p">[</span><span class="mi">200</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="mi">10</span><span class="p">]]</span>
</pre></div>
</div>
</li>
</ul>
</dd>
<dt>Returns:</dt>
<dd><p class="first">For the above example, it returns:</p>
<div class="last highlight-python"><div class="highlight"><pre><span class="p">[[(</span><span class="mf">30.0</span><span class="p">,</span> <span class="mi">100</span><span class="p">),</span> <span class="p">(</span><span class="mf">20.0</span><span class="p">,</span> <span class="mi">50</span><span class="p">),</span> <span class="p">(</span><span class="mf">800.0</span><span class="p">,</span> <span class="mi">1000</span><span class="p">)],</span>
<span class="p">[(</span><span class="mf">20.0</span><span class="p">,</span> <span class="mi">200</span><span class="p">),</span> <span class="p">(</span><span class="mf">450.0</span><span class="p">,</span> <span class="mi">500</span><span class="p">),</span> <span class="p">(</span><span class="mf">5.0</span><span class="p">,</span> <span class="mi">10</span><span class="p">)]]</span>
</pre></div>
</div>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="simso.generator.task_generator.gen_uunifastdiscard">
<tt class="descname">gen_uunifastdiscard</tt><big>(</big><em>nsets</em>, <em>u</em>, <em>n</em><big>)</big><a class="headerlink" href="#simso.generator.task_generator.gen_uunifastdiscard" title="Permalink to this definition"></a></dt>
<dd><p>The UUniFast algorithm was proposed by Bini for generating task
utilizations on uniprocessor architectures.</p>
<p>The UUniFast-Discard algorithm extends it to multiprocessor by
discarding task sets containing any utilization that exceeds 1.</p>
<p>This algorithm is easy and widely used. However, it suffers from very
long computation times when n is close to u. Stafford&#8217;s algorithm is
faster.</p>
<dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>n</cite>: The number of tasks in a task set.</li>
<li><cite>u</cite>: Total utilization of the task set.</li>
<li><cite>nsets</cite>: Number of sets to generate.</li>
</ul>
</dd>
</dl>
<p>Returns <cite>nsets</cite> of <cite>n</cite> task utilizations.</p>
</dd></dl>
</div>
<div class="section" id="simso-utils-module">
<h2><a class="toc-backref" href="#id16">simso.utils module</a><a class="headerlink" href="#simso-utils-module" title="Permalink to this headline"></a></h2>
<div class="section" id="module-simso.utils.PartitionedScheduler">
<span id="partitionedscheduler"></span><h3><a class="toc-backref" href="#id17">PartitionedScheduler</a><a class="headerlink" href="#module-simso.utils.PartitionedScheduler" title="Permalink to this headline"></a></h3>
<dl class="class">
<dt id="simso.utils.PartitionedScheduler.PartitionedScheduler">
<em class="property">class </em><tt class="descname">PartitionedScheduler</tt><big>(</big><em>sim</em>, <em>scheduler_info</em>, <em>**kwargs</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.PartitionedScheduler" title="Permalink to this definition"></a></dt>
<dd><p>The PartitionedScheduler class provide facilities to create a new
Partitioned Scheduler. Only the packing phase is not done and should
be overriden.</p>
<p>Args:</p>
<ul class="simple">
<li><cite>sim</cite>: <a class="reference internal" href="#module-simso.core.Model" title="simso.core.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance.</li>
<li><cite>scheduler_info</cite>: A <tt class="xref py py-class docutils literal"><span class="pre">SchedulerInfo</span></tt> representing the scheduler.</li>
</ul>
<p>Attributes:</p>
<ul class="simple">
<li><strong>sim</strong>: <a class="reference internal" href="#simso.core.Model.Model" title="simso.core.Model.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> instance. Useful to get current time with <tt class="docutils literal"><span class="pre">sim.now_ms()</span></tt> (in ms) or <tt class="docutils literal"><span class="pre">sim.now()</span></tt> (in cycles).</li>
<li><strong>processors</strong>: List of <a class="reference internal" href="#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">processors</span></tt></a> handled by this scheduler.</li>
<li><strong>task_list</strong>: List of <a class="reference internal" href="#simso.core.Task.GenericTask" title="simso.core.Task.GenericTask"><tt class="xref py py-class docutils literal"><span class="pre">tasks</span></tt></a> handled by this scheduler.</li>
</ul>
<p>Methods:</p>
<dl class="method">
<dt id="simso.utils.PartitionedScheduler.PartitionedScheduler.init">
<tt class="descname">init</tt><big>(</big><em>scheduler_info</em>, <em>packer=None</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.PartitionedScheduler.init" title="Permalink to this definition"></a></dt>
<dd><dl class="docutils">
<dt>Args:</dt>
<dd><ul class="first last simple">
<li><cite>scheduler_info</cite>: A <a class="reference internal" href="#simso.core.Scheduler.SchedulerInfo" title="simso.core.Scheduler.SchedulerInfo"><tt class="xref py py-class docutils literal"><span class="pre">SchedulerInfo</span></tt></a> object. One scheduler from this SchedulerInfo will be instantiated for each processor.</li>
</ul>
</dd>
</dl>
</dd></dl>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.best_fit">
<tt class="descname">best_fit</tt><big>(</big><em>scheduler</em>, <em>task_list=None</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.best_fit" title="Permalink to this definition"></a></dt>
<dd><p>Best-Fit heuristic. Put the tasks somewhere it fits but with the least
spare place.</p>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.decreasing_best_fit">
<tt class="descname">decreasing_best_fit</tt><big>(</big><em>scheduler</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.decreasing_best_fit" title="Permalink to this definition"></a></dt>
<dd><p>Best-Fit with tasks inversely sorted by their u_i.</p>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.decreasing_first_fit">
<tt class="descname">decreasing_first_fit</tt><big>(</big><em>scheduler</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.decreasing_first_fit" title="Permalink to this definition"></a></dt>
<dd><p>First-Fit with tasks inversely sorted by their u_i.</p>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.decreasing_next_fit">
<tt class="descname">decreasing_next_fit</tt><big>(</big><em>scheduler</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.decreasing_next_fit" title="Permalink to this definition"></a></dt>
<dd><p>Next-Fit with tasks inversely sorted by their u_i.</p>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.decreasing_worst_fit">
<tt class="descname">decreasing_worst_fit</tt><big>(</big><em>scheduler</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.decreasing_worst_fit" title="Permalink to this definition"></a></dt>
<dd><p>Worst-Fit with tasks inversely sorted by their u_i.</p>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.first_fit">
<tt class="descname">first_fit</tt><big>(</big><em>scheduler</em>, <em>task_list=None</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.first_fit" title="Permalink to this definition"></a></dt>
<dd><p>First-Fit heuristic. Put each task on the first processor with enough
space.</p>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.next_fit">
<tt class="descname">next_fit</tt><big>(</big><em>scheduler</em>, <em>task_list=None</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.next_fit" title="Permalink to this definition"></a></dt>
<dd><p>Next-Fit heuristic. Put each task on the next processor with enough space.</p>
</dd></dl>
<dl class="function">
<dt id="simso.utils.PartitionedScheduler.worst_fit">
<tt class="descname">worst_fit</tt><big>(</big><em>scheduler</em>, <em>task_list=None</em><big>)</big><a class="headerlink" href="#simso.utils.PartitionedScheduler.worst_fit" title="Permalink to this definition"></a></dt>
<dd><p>Worst-Fit heuristic. Put the tasks somewhere it fits with the largest
spare place.</p>
</dd></dl>
</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="licenses.html" title="Licenses"
>next</a> |</li>
<li class="right" >
<a href="text_mode.html" title="Using SimSo in script mode"
>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
Search.setIndex({envversion:42,terms:{all:[0,5,4],code:[2,5,6,3,4],edf:[],reproduc:[6,4],scratch:[],edh:2,global:2,affect_task_to_processor:5,is_act:4,worst_fit:4,subclass:[5,4],kato:[2,4],tovar:2,follow:[0,2,6,5,4],hyperperiod:4,llf:2,abid:6,millisecond:4,whose:6,decid:4,procur:4,depend:[],specif:[6,4],send:[5,3],init:[0,5,4],program:6,decis:[2,4],under:[2,6,4],set_stack_fil:4,aris:4,stafford:4,neglig:4,adapt:[2,4],merchant:4,sourc:[2,5,6,3,4],lre:2,risk:6,fals:[5,4],account:2,util:[],worst:[2,4],whether:4,govern:6,veri:[0,2,5,4],appar:[],four:5,computation_tim:0,observation_window:4,proc:4,button:[],list:[5,3,4],factori:4,"try":0,schedulerinfo:[5,4],progress:4,team:[],quick:2,evt:0,pleas:[3,4],impli:4,direct:4,rate:2,pass:[0,5,4],download:[],click:[],append:5,compat:[2,3],index:1,what:[],stack_fil:4,sum:0,abl:4,invok:[5,4],current:[2,4],experiment:0,encourag:6,"new":[0,3,4],abort_on_miss:4,method:[0,5,4],laxiti:2,xml:[3,4],full:5,utilis:4,deriv:[],french:6,dpfair:2,met:4,lgpl:6,modif:4,free:[5,6],ubuntu:3,path:4,modifi:[2,6],interpret:4,wait:4,search:1,convers:2,overhead_termin:4,ekg:2,precis:4,prior:4,amount:4,overriden:[5,4],action:4,implement:[],uunifast:4,overrid:4,taskr:[0,4],via:2,extra:4,appli:5,modul:[],put:4,heurist:[2,4],task_typ:4,instal:[],total:4,unit:4,from:[],proceed:2,distinct:4,pred:4,doubl:[],cho:2,websit:2,few:[0,2,6],handler:4,overhead:[2,5,6,4],taken:[],prev:0,type:[2,4],more:[],sort:4,list_activation_d:4,notic:4,start_dat:4,warn:4,exce:4,prototyp:2,particular:[2,4],decreasing_next_fit:4,cach:[2,4],must:[2,5,3,4],none:[0,5,4],graphic:[2,6,3],retriev:4,left:[],setup:2,uniqu:4,histori:0,remain:4,minimum:4,purpos:[6,4],exceeded_deadlin:4,def:[0,5],control:[3,4],give:5,process:[6,4],lock:4,add_processor:[0,4],accept:6,had:6,abort:4,umin:4,everi:[0,4],occur:[5,4],delai:4,cours:0,multipl:2,ripol:4,anoth:4,write:[],pair:4,cur_dir:[0,4],instead:4,voltag:2,config:0,sim:4,updat:[2,5],product:[],resourc:2,still:[5,4],max:4,decreasing_first_fit:4,after:4,laa:6,befor:[0,5,4],mac:3,attent:6,mai:6,end:4,law:6,associ:[6,4],alloc:5,bini:4,third:[],is_run:4,light:6,secur:6,explicit:[],caus:4,callback:4,"switch":[0,2],allow:[2,3,4],mechan:4,lambda:5,order:[0,2,3,4,5],gen_periods_discret:4,help:5,softwar:[2,6,4],offici:4,gen_uunifastdiscard:4,cxtsave:4,through:[0,2,5,4],is_period:[],affect:5,uniprocessor:[],suffer:4,mainli:4,dynam:[2,4],busi:4,group:[0,4],obviou:[],fit:[2,5,4],chosen:[5,4],fix:[2,4],et_stddev:4,late:2,platform:2,matlabcentr:4,main:[],non:4,good:[2,5,4],"return":[5,4],greater:4,cea:6,python:[2,5,6,3,4],epdf:2,inria:6,simpi:[],interrupt:4,now:4,nor:[],introduct:[],choic:3,term:6,somewher:4,name:[0,5,4],delta_preempt:4,edit:[],simpl:[2,4],easili:3,mode:[],each:[0,5,3,4],fulli:3,complet:[],truncat:4,mean:6,monoton:2,ensur:6,contributor:4,redistribut:[6,4],finish:[5,4],"static":2,p_edf:5,our:5,happen:0,reduct:2,special:4,out:4,fileexchang:4,matrix:4,space:[5,4],profit:4,miss:5,robert:4,access:[0,6],ret:4,profil:4,uunifastdiscard:[],suitabl:6,rel:4,print:[0,5],correct:[0,4],statist:2,prioriti:[2,5],advanc:4,migrat:4,manipul:6,given:4,argv:0,reason:5,base:[2,6,4],theori:4,dictionari:4,releas:[2,6,4],earliest:[2,5],could:[0,5,3],llref:2,counterpart:6,thing:5,place:4,outsid:4,retain:4,interact:4,end_dat:4,first:[],origin:4,endors:[],major:4,simulation_fil:4,internal_id:4,onc:4,csdp:4,number:[0,4],proc_info:4,restrict:6,date:[5,3,4],task_info:4,done:[0,5,3,4],messag:[5,4],owner:[],round_to_int:4,open:2,gpl:[2,6],differ:[0,4],script:[],data:[6,4],licens:[],anderson:2,least:[2,5,4],stack:4,attach:4,atask:4,too:4,termin:4,white:[],"final":0,store:4,schema:3,juli:3,copi:6,specifi:[3,4],pyqt4:2,mathwork:4,cxtload:4,exactli:0,holder:[6,4],than:4,mllf:2,wide:[0,4],erickson:2,slack:4,provid:[0,2,3,4,5,6],andersson:2,second:5,structur:5,project:[],matter:4,reus:6,redifin:5,str:0,deadlin:[0,2,5,4],randomli:4,"function":[3,4],comput:[0,6,4],max_:4,robdavi:4,arg:[0,4],argument:[0,4],packag:3,expir:4,have:[0,6,4],reserv:[6,4],need:[5,4],cecil:[2,6],loguniform:4,get_cl:4,techniqu:2,zero:2,inform:[0,4],self:[5,4],euromicro:2,now_m:4,contact:4,also:[0,2,3,4,5,6],discret:[2,6],take:[2,4],advis:4,min_:4,tasks_ev:4,tool:4,singl:[5,4],even:4,sure:5,distribut:[6,4],n_instr:4,though:3,object:[0,6,4],reach:4,decreasing_best_fit:4,phase:4,followed_bi:4,everyth:2,schedulerr:4,url:6,doc:4,yang:2,resch:[5,4],usual:[5,4],fact:6,run_model:[0,4],preemption_count:0,gen_periods_uniform:4,shot:4,show:5,text:2,random:4,prid:2,directli:[0,5,4],permiss:[],find:[2,5],impact:2,absolut:[5,4],onli:[5,6,4],just:[],facil:4,iep:[],explain:5,next_fit:4,activ:[5,3,4],written:3,should:[2,5,4],configur:[],version:[2,6],analyz:4,info:6,variou:4,get:[0,4],express:4,stop:4,aim:2,ptask:4,procev:0,report:4,on_termin:[5,4],event:[0,2,6,5,4],neither:[],requir:[0,2,6,4],first_fit:4,overhead_activ:4,add_task:[0,4],bar:4,enabl:6,emb:4,yield:4,migration_overhead:4,roger:4,decreasing_worst_fit:4,partit:[],contain:[2,4],where:[0,5,4],remov:[5,4],view:4,user:[2,6,3],kernel:4,fair:2,packer:[5,4],knowledg:6,see:[2,4],mandatori:5,respons:[5,4],fail:5,close:4,best:[2,4],subject:[],statu:6,flexibl:[0,2],preemption_cost:4,kei:[5,4],someth:0,pd2:2,cs_overhead:4,enough:4,between:4,"import":[0,5],ready_list:5,approach:5,best_fit:4,attribut:[0,4],accord:4,pretti:5,jobr:[0,4],extend:4,nelissen:2,cycl:4,job:[],spare:4,here:[5,4],nset:4,problem:2,monitor:[0,4],disclaim:4,last:[2,5],cycles_per_m:[0,4],mono:5,howev:[3,4],incident:4,contract:4,len:[0,5],polici:[],instanc:4,present:6,context:[0,2],logic:[5,4],get_hyperperiod:4,whole:4,etm:4,load:[],among:5,cxt:0,author:[6,4],point:[5,4],instanti:[0,5,4],priorit:5,pfair:2,scheduler_info:[0,4],period:[0,2,5,4],exemplari:4,linux:3,respect:[5,6],damag:4,liabil:[6,4],coupl:4,tort:4,numpi:[],window:[3,4],been:4,compon:4,accumul:4,much:2,valu:4,basic:0,calc_load:4,gen_kato_util:4,"abstract":4,partial:0,on_activ:[5,4],field:4,emberson:4,fire:4,consequenti:4,ani:[2,5,4],understand:2,input:4,those:4,real:[2,6,4],"case":4,ident:5,look:5,gnu:6,servic:4,durat:[0,4],lesser:6,defin:[],"while":5,abov:4,error:4,edzl:2,observ:4,pack:[],earli:2,helper:4,readi:[5,4],metric:[0,4],therefor:6,them:5,nvnlf:2,kwarg:4,gen_randfixedsum:4,"__init__":4,scienc:[],parent:4,develop:[2,5,6],thei:5,grant:6,parti:[],make:4,econom:6,same:[0,6,4],check:[0,4],binari:[2,4],tutori:[0,5],funk:2,largest:4,probabl:4,taskinfo:4,edf_mono:5,archiv:2,closest:5,optim:[2,4],target_util:4,permit:4,upon:4,moment:4,rais:0,initi:[],extern:3,typic:4,funaoka:2,redefin:4,kept:5,equival:4,com:4,sporadictask:4,min:[5,4],itself:6,inherit:[5,4],without:[0,4],exampl:[],thi:[0,2,3,4,5,6],model:[],propos:4,twent:[],distanc:4,identifi:[0,4],fast:2,execut:[0,5,3,4],unfair:2,paul:4,speed:[3,4],yet:5,languag:6,york:4,gen_periods_loguniform:4,easi:[2,5,4],mix:4,baruah:2,character:4,except:0,add:[0,4],other:[2,4],els:[0,5],save:4,task_list:[0,5,4],bin:5,cherami:6,which:[5,4],minimalist:5,read:[0,6,4],arriv:3,know:0,librairi:2,circul:6,characterist:[0,3],get_observation_window:4,like:[2,5],loss:4,success:6,semi:2,arbitrari:5,generictask:4,manual:0,pillai:2,necessari:[2,5],either:4,xsd:3,page:1,actual_computation_time_cycl:4,www:[6,4],right:[6,4],often:2,simplifi:4,in_m:4,some:[0,2],maxim:6,intern:4,wcet:[0,5,4],guarante:[5,4],indirect:4,librari:[0,2,3],u_i:4,scale:2,cnr:6,remind:5,avoid:4,shall:4,per:[0,4],substitut:4,select:5,condit:[6,4],complic:6,core:[],set_nam:[0,4],previou:[0,4],run:[0,2,5,4],randfixedsum:4,check_al:[0,4],processorr:4,confer:2,step:[],nutshel:5,promot:[],taskset:4,drawn:6,about:4,materi:4,http:[6,4],simul:[],includ:4,constructor:[0,5,4],discard:4,univers:[],base_cpi:4,cl_overhead:4,"float":[5,4],profession:6,automat:0,invers:4,warranti:[6,4],bsd:[6,4],one_shot:4,empti:0,liabl:4,lieu:4,wrap:2,chang:[0,4],next:[2,4],your:3,preemption:[0,2,4],log:[0,4],wai:[2,5,4],"long":4,"class":[0,5,4],avail:[],start:[5,4],reli:6,interfac:[2,6,3],editor:[],call:[5,4],strict:4,etc:[0,4],analysi:[0,4],form:4,tupl:4,regard:[6,4],proc_info_list:4,msg:4,multiprocessor:[2,5,6,4],low:2,gen_ripol:4,eas:5,highest:5,"true":[5,4],conclus:4,count:[0,4],zhu:2,consist:5,possibl:[0,2,3,4,5],"default":4,levin:2,realist:4,maximum:[0,2,4],release_lock:4,limit:[6,4],otherwis:[3,4],embed:2,similar:4,dvf:2,procinfo:4,creat:[],certain:4,dure:4,filenam:4,repres:4,incomplet:3,decreas:2,file:[],behavior:4,umax:4,ship:3,simplest:5,acet:4,again:4,when:[0,2,5,4],detail:[],virtual:4,orient:6,power:2,gen_taskset:4,create_job:4,declar:4,bool:4,copyright:[6,4],task_info_list:4,test:[2,6,4],regnier:2,davi:4,staffordrandfixedsum:4,task_migr:4,architectur:[2,5,4],souc:2,absolute_deadlin:[5,4],get_lock:4,debian:3,reduc:2,set_observation_window:4,experienc:6,faster:4,algorithm:[2,5,4],directori:4,temporarli:4,pseudo:2,indirectli:5,rule:6,goe:4,depth:6,activation_d:[0,4],time:[0,2,6,3,4],rapitasystem:4,licensor:6,cpu:[0,5,4],oop:5},objtypes:{"0":"py:module","1":"py:attribute","2":"py:method","3":"py:function","4":"py:class"},objnames:{"0":["py","module","Python module"],"1":["py","attribute","Python attribute"],"2":["py","method","Python method"],"3":["py","function","Python function"],"4":["py","class","Python class"]},filenames:["text_mode","index","introduction","faq","modules","write_scheduler","licenses"],titles:["Using SimSo in script mode","SimSo documentation","Introduction","Frequently Asked Questions","Main modules","How to write a scheduling policy","Licenses"],objects:{"simso.utils":{PartitionedScheduler:[4,0,0,"-"]},"simso.core.Scheduler.SchedulerInfo":{get_cls:[4,2,1,""],set_name:[4,2,1,""],instantiate:[4,2,1,""],name:[4,1,1,""],filename:[4,1,1,""]},"simso.core.Model.Model":{run_model:[4,2,1,""],logs:[4,1,1,""],cycles_per_ms:[4,1,1,""],task_list:[4,1,1,""],duration:[4,1,1,""],etm:[4,1,1,""],processors:[4,1,1,""]},"simso.configuration":{Configuration:[4,0,0,"-"]},"simso.generator.task_generator":{gen_periods_uniform:[4,3,1,""],gen_periods_loguniform:[4,3,1,""],gen_uunifastdiscard:[4,3,1,""],gen_kato_utilizations:[4,3,1,""],gen_tasksets:[4,3,1,""],gen_periods_discrete:[4,3,1,""],gen_randfixedsum:[4,3,1,""],gen_ripoll:[4,3,1,""],StaffordRandFixedSum:[4,3,1,""]},"simso.core.Task.GenericTask":{jobs:[4,1,1,""],monitor:[4,1,1,""],followed_by:[4,1,1,""],period:[4,1,1,""],create_job:[4,2,1,""],deadline:[4,1,1,""],wcet:[4,1,1,""],identifier:[4,1,1,""],data:[4,1,1,""]},"simso.core.Task.TaskInfo":{csdp:[4,1,1,""],stack_file:[4,1,1,""],set_stack_file:[4,2,1,""]},"simso.core.Timer.Timer":{start:[4,2,1,""],stop:[4,2,1,""]},"simso.generator":{task_generator:[4,0,0,"-"]},"simso.configuration.Configuration.Configuration":{save:[4,2,1,""],add_task:[4,2,1,""],check_all:[4,2,1,""],scheduler_info:[4,1,1,""],add_processor:[4,2,1,""],proc_info_list:[4,1,1,""],task_info_list:[4,1,1,""],get_hyperperiod:[4,2,1,""]},"simso.core.Logger":{Logger:[4,4,1,""]},"simso.utils.PartitionedScheduler.PartitionedScheduler":{init:[4,2,1,""]},"simso.core.results.Results":{set_observation_window:[4,2,1,""],tasks_event:[4,2,1,""],calc_load:[4,2,1,""],get_observation_window:[4,2,1,""],observation_window:[4,1,1,""]},"simso.core.Scheduler.Scheduler":{add_task:[4,2,1,""],schedule:[4,2,1,""],on_terminated:[4,2,1,""],add_processor:[4,2,1,""],init:[4,2,1,""],release_lock:[4,2,1,""],on_activate:[4,2,1,""],get_lock:[4,2,1,""]},"simso.core.Scheduler":{SchedulerInfo:[4,4,1,""],Scheduler:[4,4,1,""]},"simso.core.Processor.Processor":{running:[4,1,1,""],resched:[4,2,1,""],is_running:[4,2,1,""],internal_id:[4,1,1,""]},"simso.core.Job.Job":{task:[4,1,1,""],end_date:[4,1,1,""],is_running:[4,2,1,""],is_active:[4,2,1,""],period:[4,1,1,""],ret:[4,1,1,""],exceeded_deadline:[4,1,1,""],abort:[4,2,1,""],deadline:[4,1,1,""],start_date:[4,1,1,""],aborted:[4,1,1,""],activation_date:[4,1,1,""],absolute_deadline:[4,1,1,""],data:[4,1,1,""],cpu:[4,1,1,""],actual_computation_time_cycles:[4,1,1,""],wcet:[4,1,1,""]},"simso.core.Logger.Logger":{logs:[4,1,1,""],log:[4,2,1,""]},"simso.core.Job":{Job:[4,4,1,""]},"simso.core.Processor":{Processor:[4,4,1,""]},"simso.core":{Task:[4,0,0,"-"],results:[4,0,0,"-"],Timer:[4,0,0,"-"],Processor:[4,0,0,"-"],Job:[4,0,0,"-"],Scheduler:[4,0,0,"-"],Model:[4,0,0,"-"],Logger:[4,0,0,"-"]},"simso.configuration.Configuration":{Configuration:[4,4,1,""]},"simso.utils.PartitionedScheduler":{PartitionedScheduler:[4,4,1,""],decreasing_first_fit:[4,3,1,""],next_fit:[4,3,1,""],decreasing_best_fit:[4,3,1,""],worst_fit:[4,3,1,""],decreasing_worst_fit:[4,3,1,""],decreasing_next_fit:[4,3,1,""],best_fit:[4,3,1,""],first_fit:[4,3,1,""]},simso:{core:[4,0,0,"-"],configuration:[4,0,0,"-"]},"simso.core.Task":{Task:[4,3,1,""],GenericTask:[4,4,1,""],SporadicTask:[4,4,1,""],PTask:[4,4,1,""],ATask:[4,4,1,""],TaskInfo:[4,4,1,""]},"simso.core.Model":{Model:[4,4,1,""]},"simso.core.results":{TaskR:[4,4,1,""],Results:[4,4,1,""],ProcessorR:[4,4,1,""],SchedulerR:[4,4,1,""],JobR:[4,4,1,""]},"simso.core.Timer":{Timer:[4,4,1,""]}},titleterms:{oper:3,load:0,set:[],edf:5,skeleton:5,creat:0,can:3,schedul:[2,5,4],modul:4,creation:5,indic:1,system:3,sporad:3,result:4,file:[0,5],tabl:[0,1,5,4],download:2,instal:2,doe:3,partitionedschedul:4,avail:2,what:2,processor:[3,4],depend:[2,6],script:0,polici:5,parti:[],support:3,configur:[0,4],question:3,detail:0,pyqt:6,uniform:3,content:[0,5,4],how:5,exampl:[0,5],explan:5,scratch:0,simpi:6,you:3,main:4,complet:5,core:4,handl:3,gener:[3,4],first:[0,2],initi:5,model:[0,4],util:4,step:2,numpi:6,ask:3,from:0,heterogen:3,logger:4,introduct:2,task:[3,4],simso:[0,1,2,3,4,6],third:[],document:1,uniprocessor:5,work:3,job:4,timer:4,simul:0,defin:5,codeeditor:[],write:5,mode:0,partit:5,own:3,implement:5,more:0,licens:6,frequent:3,pack:5}})
\ 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>Using SimSo in script mode &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="Main modules" href="modules.html" />
<link rel="prev" title="How to write a scheduling policy" href="write_scheduler.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="N">next</a> |</li>
<li class="right" >
<a href="write_scheduler.html" title="How to write a scheduling policy"
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="using-simso-in-script-mode">
<h1><a class="toc-backref" href="#id1">Using SimSo in script mode</a><a class="headerlink" href="#using-simso-in-script-mode" title="Permalink to this headline"></a></h1>
<p>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.</p>
<div class="contents topic" id="table-of-contents">
<p class="topic-title first">Table of Contents</p>
<ul class="simple">
<li><a class="reference internal" href="#using-simso-in-script-mode" id="id1">Using SimSo in script mode</a><ul>
<li><a class="reference internal" href="#loading-a-configuration-using-a-simulation-file" id="id2">Loading a configuration using a simulation file</a></li>
<li><a class="reference internal" href="#creating-a-configuration-from-scratch" id="id3">Creating a configuration from scratch</a></li>
<li><a class="reference internal" href="#creating-the-model" id="id4">Creating the Model</a></li>
<li><a class="reference internal" href="#first-example" id="id5">First Example</a></li>
<li><a class="reference internal" href="#more-details" id="id6">More details</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="loading-a-configuration-using-a-simulation-file">
<h2><a class="toc-backref" href="#id2">Loading a configuration using a simulation file</a><a class="headerlink" href="#loading-a-configuration-using-a-simulation-file" title="Permalink to this headline"></a></h2>
<p>A <a class="reference internal" href="modules.html#module-simso.configuration.Configuration" title="simso.configuration.Configuration"><tt class="xref py py-class docutils literal"><span class="pre">Configuration</span></tt></a> can be initialized with a file passed to its constructor:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">configuration</span> <span class="o">=</span> <span class="n">Configuration</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</pre></div>
</div>
<p>The configuration could also be partial and completed by the script. Finally, the configuration can be checked for correctness using the <tt class="xref py py-meth docutils literal"><span class="pre">check_all</span></tt> method:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">configuration</span><span class="o">.</span><span class="n">check_all</span><span class="p">()</span>
</pre></div>
</div>
<p>This method will raise an exception if something is not correct.</p>
</div>
<div class="section" id="creating-a-configuration-from-scratch">
<h2><a class="toc-backref" href="#id3">Creating a configuration from scratch</a><a class="headerlink" href="#creating-a-configuration-from-scratch" title="Permalink to this headline"></a></h2>
<p>It is also possible to create a new configuration from an empty configuration. This is done by instantiating a <a class="reference internal" href="modules.html#module-simso.configuration.Configuration" title="simso.configuration.Configuration"><tt class="xref py py-class docutils literal"><span class="pre">Configuration</span></tt></a> object without argument. Then, its attributes can be changed:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">configuration</span> <span class="o">=</span> <span class="n">Configuration</span><span class="p">()</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">duration</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">*</span> <span class="n">configuration</span><span class="o">.</span><span class="n">cycles_per_ms</span>
</pre></div>
</div>
<p>It is also possible to add tasks:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">configuration</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&quot;T1&quot;</span><span class="p">,</span> <span class="n">identifier</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">period</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span>
<span class="n">activation_date</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">wcet</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">deadline</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
</pre></div>
</div>
<p>And of course processors:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">configuration</span><span class="o">.</span><span class="n">add_processor</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&quot;CPU 1&quot;</span><span class="p">,</span> <span class="n">identifier</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
<p>Finally, a scheduler is also required:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">configuration</span><span class="o">.</span><span class="n">scheduler_info</span><span class="o">.</span><span class="n">set_name</span><span class="p">(</span><span class="s">&quot;examples/RM.py&quot;</span><span class="p">,</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">cur_dir</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="creating-the-model">
<h2><a class="toc-backref" href="#id4">Creating the Model</a><a class="headerlink" href="#creating-the-model" title="Permalink to this headline"></a></h2>
<p>A <a class="reference internal" href="modules.html#module-simso.configuration.Configuration" title="simso.configuration.Configuration"><tt class="xref py py-class docutils literal"><span class="pre">configuration</span></tt></a> is an object grouping every characteristics of the system (tasks, processors, schedulers, etc). Such a configuration can be passed to the <a class="reference internal" href="modules.html#simso.core.Model.Model" title="simso.core.Model.Model"><tt class="xref py py-class docutils literal"><span class="pre">Model</span></tt></a> constructor in order to create the simulation:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">model</span> <span class="o">=</span> <span class="n">Model</span><span class="p">(</span><span class="n">configuration</span><span class="p">)</span>
</pre></div>
</div>
<p>And the simulation can be run with the <a class="reference internal" href="modules.html#simso.core.Model.Model.run_model" title="simso.core.Model.Model.run_model"><tt class="xref py py-meth docutils literal"><span class="pre">run_model</span></tt></a> method:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">model</span><span class="o">.</span><span class="n">run_model</span><span class="p">()</span>
</pre></div>
</div>
<p>Some basic logs can be get through the <a class="reference internal" href="modules.html#simso.core.Model.Model.logs" title="simso.core.Model.Model.logs"><tt class="xref py py-meth docutils literal"><span class="pre">logs</span></tt></a> attribute:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">log</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">logs</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">log</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="first-example">
<h2><a class="toc-backref" href="#id5">First Example</a><a class="headerlink" href="#first-example" title="Permalink to this headline"></a></h2>
<p>The following script simulate a system loading from a simulation file or configured from scratch:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">simso.core</span> <span class="kn">import</span> <span class="n">Model</span>
<span class="kn">from</span> <span class="nn">simso.configuration</span> <span class="kn">import</span> <span class="n">Configuration</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">argv</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">argv</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="c"># Configuration load from a file.</span>
<span class="n">configuration</span> <span class="o">=</span> <span class="n">Configuration</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="c"># Manual configuration:</span>
<span class="n">configuration</span> <span class="o">=</span> <span class="n">Configuration</span><span class="p">()</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">duration</span> <span class="o">=</span> <span class="mi">420</span> <span class="o">*</span> <span class="n">configuration</span><span class="o">.</span><span class="n">cycles_per_ms</span>
<span class="c"># Add tasks:</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&quot;T1&quot;</span><span class="p">,</span> <span class="n">identifier</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">period</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span>
<span class="n">activation_date</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">wcet</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">deadline</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&quot;T2&quot;</span><span class="p">,</span> <span class="n">identifier</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">period</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span>
<span class="n">activation_date</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">wcet</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">deadline</span><span class="o">=</span><span class="mi">12</span><span class="p">)</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&quot;T3&quot;</span><span class="p">,</span> <span class="n">identifier</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">period</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span>
<span class="n">activation_date</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">wcet</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">deadline</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span>
<span class="c"># Add a processor:</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">add_processor</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&quot;CPU 1&quot;</span><span class="p">,</span> <span class="n">identifier</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="c"># Add a scheduler:</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">scheduler_info</span><span class="o">.</span><span class="n">set_name</span><span class="p">(</span><span class="s">&quot;examples/RM.py&quot;</span><span class="p">,</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">cur_dir</span><span class="p">)</span>
<span class="c"># Check the config before trying to run it.</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">check_all</span><span class="p">()</span>
<span class="c"># Init a model from the configuration.</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">Model</span><span class="p">(</span><span class="n">configuration</span><span class="p">)</span>
<span class="c"># Execute the simulation.</span>
<span class="n">model</span><span class="o">.</span><span class="n">run_model</span><span class="p">()</span>
<span class="c"># Print logs.</span>
<span class="k">for</span> <span class="n">log</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">logs</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">log</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="more-details">
<h2><a class="toc-backref" href="#id6">More details</a><a class="headerlink" href="#more-details" title="Permalink to this headline"></a></h2>
<p>It is possible to get more information from the tasks using <a class="reference internal" href="modules.html#simso.core.results.Results" title="simso.core.results.Results"><tt class="xref py py-class docutils literal"><span class="pre">Results</span></tt></a> class. For example we could get the computation time of the jobs:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s">&quot;:&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">job</span> <span class="ow">in</span> <span class="n">task</span><span class="o">.</span><span class="n">jobs</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%.3f</span><span class="s"> ms&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">job</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">job</span><span class="o">.</span><span class="n">computation_time</span><span class="p">))</span>
</pre></div>
</div>
<p>Or the number of preemptions per task:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">task_list</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%d</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="nb">sum</span><span class="p">([</span><span class="n">job</span><span class="o">.</span><span class="n">preemption_count</span> <span class="k">for</span> <span class="n">job</span> <span class="ow">in</span> <span class="n">task</span><span class="o">.</span><span class="n">jobs</span><span class="p">])))</span>
</pre></div>
</div>
<p>You can get all the metrics provided in the <a class="reference internal" href="modules.html#simso.core.results.TaskR" title="simso.core.results.TaskR"><tt class="xref py py-class docutils literal"><span class="pre">TaskR</span></tt></a> and <a class="reference internal" href="modules.html#simso.core.results.JobR" title="simso.core.results.JobR"><tt class="xref py py-class docutils literal"><span class="pre">JobR</span></tt></a> objects. Read the documentation of these classes to know exactly what is directly accessible.</p>
<p>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:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">cxt</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">processor</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">processors</span><span class="p">:</span>
<span class="n">prev</span> <span class="o">=</span> <span class="bp">None</span>
<span class="k">for</span> <span class="n">evt</span> <span class="ow">in</span> <span class="n">processor</span><span class="o">.</span><span class="n">monitor</span><span class="p">:</span>
<span class="k">if</span> <span class="n">evt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">event</span> <span class="o">==</span> <span class="n">ProcEvent</span><span class="o">.</span><span class="n">RUN</span><span class="p">:</span>
<span class="k">if</span> <span class="n">prev</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="ow">and</span> <span class="n">prev</span> <span class="o">!=</span> <span class="n">evt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">identifier</span><span class="p">:</span>
<span class="n">cxt</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">prev</span> <span class="o">=</span> <span class="n">evt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">identifier</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;Number of context switches (without counting the OS): &quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">cxt</span><span class="p">))</span>
</pre></div>
</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"
>next</a> |</li>
<li class="right" >
<a href="write_scheduler.html" title="How to write a scheduling policy"
>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>How to write a scheduling policy &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="Using SimSo in script mode" href="text_mode.html" />
<link rel="prev" title="Frequently Asked Questions" href="faq.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="text_mode.html" title="Using SimSo in script mode"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="faq.html" title="Frequently Asked Questions"
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="how-to-write-a-scheduling-policy">
<h1><a class="toc-backref" href="#id1">How to write a scheduling policy</a><a class="headerlink" href="#how-to-write-a-scheduling-policy" title="Permalink to this headline"></a></h1>
<p>This tutorial explains through minimalist examples how to write a scheduler.</p>
<div class="contents topic" id="table-of-contents">
<p class="topic-title first">Table of Contents</p>
<ul class="simple">
<li><a class="reference internal" href="#how-to-write-a-scheduling-policy" id="id1">How to write a scheduling policy</a><ul>
<li><a class="reference internal" href="#example-1-uniprocessor-edf" id="id2">Example 1: uniprocessor EDF</a><ul>
<li><a class="reference internal" href="#creation-of-the-file" id="id3">Creation of the file</a></li>
<li><a class="reference internal" href="#explanation-of-the-skeleton" id="id4">Explanation of the skeleton</a></li>
<li><a class="reference internal" href="#implementation" id="id5">Implementation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#example-2-partitionned-edf" id="id6">Example 2: Partitionned EDF</a><ul>
<li><a class="reference internal" href="#initializing-the-scheduler" id="id7">Initializing the scheduler</a></li>
<li><a class="reference internal" href="#defining-the-packing" id="id8">Defining the packing</a></li>
<li><a class="reference internal" href="#complete-example" id="id9">Complete example</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="example-1-uniprocessor-edf">
<h2><a class="toc-backref" href="#id2">Example 1: uniprocessor EDF</a><a class="headerlink" href="#example-1-uniprocessor-edf" title="Permalink to this headline"></a></h2>
<p>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.</p>
<div class="section" id="creation-of-the-file">
<h3><a class="toc-backref" href="#id3">Creation of the file</a><a class="headerlink" href="#creation-of-the-file" title="Permalink to this headline"></a></h3>
<p>A scheduler for SimSo is a Python class that inherits from the <a class="reference internal" href="modules.html#module-simso.core.Scheduler" title="simso.core.Scheduler"><tt class="xref py py-class docutils literal"><span class="pre">simso.core.Scheduler</span></tt></a> class. The first step is to write the skeleton of our scheduler. Create a file named &#8220;EDF_mono.py&#8221; and write the following code:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">simso.core</span> <span class="kn">import</span> <span class="n">Scheduler</span>
<span class="k">class</span> <span class="nc">EDF_mono</span><span class="p">(</span><span class="n">Scheduler</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">on_activate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">job</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">on_terminated</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">job</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">schedule</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cpu</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>It is mandatory for the class name to be identical to the file name.</p>
</div>
<div class="section" id="explanation-of-the-skeleton">
<h3><a class="toc-backref" href="#id4">Explanation of the skeleton</a><a class="headerlink" href="#explanation-of-the-skeleton" title="Permalink to this headline"></a></h3>
<p>The first thing done here is importing the <a class="reference internal" href="modules.html#module-simso.core.Scheduler" title="simso.core.Scheduler"><tt class="xref py py-class docutils literal"><span class="pre">Scheduler</span></tt></a> class. Then we define the <cite>EDF_mono</cite> class as a subclass of the <cite>Scheduler</cite>.</p>
<p>Four methods are redifined:</p>
<ul class="simple">
<li>The <a class="reference internal" href="modules.html#simso.core.Scheduler.Scheduler.init" title="simso.core.Scheduler.Scheduler.init"><tt class="xref py py-meth docutils literal"><span class="pre">init</span></tt></a> 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 <a class="reference internal" href="modules.html#simso.core.Task.Task" title="simso.core.Task.Task"><tt class="xref py py-class docutils literal"><span class="pre">Task</span></tt></a> and <a class="reference internal" href="modules.html#simso.core.Processor.Processor" title="simso.core.Processor.Processor"><tt class="xref py py-class docutils literal"><span class="pre">Processors</span></tt></a> are not instantiated yet when the scheduler is created.</li>
<li>The <a class="reference internal" href="modules.html#simso.core.Scheduler.Scheduler.on_activate" title="simso.core.Scheduler.Scheduler.on_activate"><tt class="xref py py-meth docutils literal"><span class="pre">on_activate</span></tt></a> method is called on task activations.</li>
<li>The <a class="reference internal" href="modules.html#simso.core.Scheduler.Scheduler.on_terminated" title="simso.core.Scheduler.Scheduler.on_terminated"><tt class="xref py py-meth docutils literal"><span class="pre">on_terminated</span></tt></a> method is called when a job finished its execution.</li>
<li>The <a class="reference internal" href="modules.html#simso.core.Scheduler.Scheduler.schedule" title="simso.core.Scheduler.Scheduler.schedule"><tt class="xref py py-meth docutils literal"><span class="pre">schedule</span></tt></a> method is called by the processor when it needs to run the scheduler. This method should not be called directly.</li>
</ul>
</div>
<div class="section" id="implementation">
<h3><a class="toc-backref" href="#id5">Implementation</a><a class="headerlink" href="#implementation" title="Permalink to this headline"></a></h3>
<p>In a nutshell, the algorithm is the following: a list of ready jobs is kept up-to-date using the <cite>on_activate</cite> and <cite>on_terminated</cite> methods. When the schedule method is called, the ready job with the closest absolute deadline is chosen.</p>
<p>So, the first step is to define a <cite>ready_list</cite>, and to append the jobs and remove them respectively when the jobs are activated and when they finish. The code should looks like that:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">core</span> <span class="kn">import</span> <span class="n">Scheduler</span>
<span class="k">class</span> <span class="nc">EDF_mono</span><span class="p">(</span><span class="n">Scheduler</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">on_activate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">job</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">job</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">on_terminated</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">job</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">job</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">schedule</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cpu</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>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:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">schedule</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cpu</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="p">:</span> <span class="c"># If at least one job is ready:</span>
<span class="c"># job with the highest priority</span>
<span class="n">job</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">absolute_deadline</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">job</span> <span class="o">=</span> <span class="bp">None</span>
<span class="k">return</span> <span class="p">(</span><span class="n">job</span><span class="p">,</span> <span class="n">cpu</span><span class="p">)</span>
</pre></div>
</div>
<p>At this point, we are still missing a very important thing: calling the scheduler! This is not done by invoking the <cite>schedule</cite> method. As a reminder, that&#8217;s the processor which is responsible to call the <cite>scheduler</cite>. 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 <a class="reference internal" href="modules.html#simso.core.Processor.Processor.resched" title="simso.core.Processor.Processor.resched"><tt class="xref py py-meth docutils literal"><span class="pre">resched</span></tt></a> method.</p>
<p>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 <tt class="docutils literal"><span class="pre">job.cpu.resched()</span></tt> when a scheduling event occurs. We could also use <tt class="docutils literal"><span class="pre">self.processors[0].resched</span></tt> to run the scheduler on the first (and only) processor of the system.</p>
<p>This is the full code:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">simso.core</span> <span class="kn">import</span> <span class="n">Scheduler</span>
<span class="k">class</span> <span class="nc">EDF_mono</span><span class="p">(</span><span class="n">Scheduler</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">on_activate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">job</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">job</span><span class="p">)</span>
<span class="n">job</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">resched</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">on_terminated</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">job</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">job</span><span class="p">)</span>
<span class="n">job</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">resched</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">schedule</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cpu</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="p">:</span> <span class="c"># If at least one job is ready:</span>
<span class="c"># job with the highest priority</span>
<span class="n">job</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ready_list</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">absolute_deadline</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">job</span> <span class="o">=</span> <span class="bp">None</span>
<span class="k">return</span> <span class="p">(</span><span class="n">job</span><span class="p">,</span> <span class="n">cpu</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="example-2-partitionned-edf">
<h2><a class="toc-backref" href="#id6">Example 2: Partitionned EDF</a><a class="headerlink" href="#example-2-partitionned-edf" title="Permalink to this headline"></a></h2>
<p>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.</p>
<p>In order to ease the work for the developer of a scheduler, an helping class, named <a class="reference internal" href="modules.html#module-simso.utils.PartitionedScheduler" title="simso.utils.PartitionedScheduler"><tt class="xref py py-class docutils literal"><span class="pre">PartitionedScheduler</span></tt></a>, is provided.</p>
<div class="section" id="initializing-the-scheduler">
<h3><a class="toc-backref" href="#id7">Initializing the scheduler</a><a class="headerlink" href="#initializing-the-scheduler" title="Permalink to this headline"></a></h3>
<p>The <a class="reference internal" href="modules.html#module-simso.utils.PartitionedScheduler" title="simso.utils.PartitionedScheduler"><tt class="xref py py-class docutils literal"><span class="pre">PartitionedScheduler</span></tt></a> is defined in the <cite>simso.utils</cite> module. It is also necessary to load the <a class="reference internal" href="modules.html#simso.core.Scheduler.SchedulerInfo" title="simso.core.Scheduler.SchedulerInfo"><tt class="xref py py-class docutils literal"><span class="pre">SchedulerInfo</span></tt></a> class in order to give to the <cite>PartitionedScheduler &lt;simso.utils.PartitionedScheduler&gt;</cite> the mono-processor scheduler to use. The first thing to do is importing these classes:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">simso.utils</span> <span class="kn">import</span> <span class="n">PartitionedScheduler</span>
<span class="kn">from</span> <span class="nn">simso.core.Scheduler</span> <span class="kn">import</span> <span class="n">SchedulerInfo</span>
</pre></div>
</div>
<p>Then the Scheduler can be initialized like this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">P_EDF</span><span class="p">(</span><span class="n">PartitionedScheduler</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">PartitionedScheduler</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">SchedulerInfo</span><span class="p">(</span><span class="s">&quot;EDF_mono&quot;</span><span class="p">,</span> <span class="n">EDF_mono</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="section" id="defining-the-packing">
<h3><a class="toc-backref" href="#id8">Defining the packing</a><a class="headerlink" href="#defining-the-packing" title="Permalink to this headline"></a></h3>
<p>A First-Fit bin-packing can be used to affect the tasks to the processors. For that, the <tt class="xref py py-meth docutils literal"><span class="pre">packer()</span></tt> must be overriden:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">packer</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c"># First Fit</span>
<span class="n">cpus</span> <span class="o">=</span> <span class="p">[[</span><span class="n">cpu</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">cpu</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">processors</span><span class="p">]</span>
<span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">task_list</span><span class="p">:</span>
<span class="n">j</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c"># Find a processor with free space.</span>
<span class="k">while</span> <span class="n">cpus</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="nb">float</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">wcet</span><span class="p">)</span> <span class="o">/</span> <span class="n">task</span><span class="o">.</span><span class="n">period</span> <span class="o">&gt;</span> <span class="mf">1.0</span><span class="p">:</span>
<span class="n">j</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">processors</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;oops bin packing failed.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="c"># Affect it to the task.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">affect_task_to_processor</span><span class="p">(</span><span class="n">task</span><span class="p">,</span> <span class="n">cpus</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
<span class="c"># Update utilization.</span>
<span class="n">cpus</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="nb">float</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">wcet</span><span class="p">)</span> <span class="o">/</span> <span class="n">task</span><span class="o">.</span><span class="n">period</span>
<span class="k">return</span> <span class="bp">True</span>
</pre></div>
</div>
</div>
<div class="section" id="complete-example">
<h3><a class="toc-backref" href="#id9">Complete example</a><a class="headerlink" href="#complete-example" title="Permalink to this headline"></a></h3>
<p>Complete source code:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">simso.core.Scheduler</span> <span class="kn">import</span> <span class="n">SchedulerInfo</span>
<span class="kn">from</span> <span class="nn">EDF_mono</span> <span class="kn">import</span> <span class="n">EDF_mono</span>
<span class="kn">from</span> <span class="nn">simso.utils</span> <span class="kn">import</span> <span class="n">PartitionedScheduler</span>
<span class="k">class</span> <span class="nc">P_EDF</span><span class="p">(</span><span class="n">PartitionedScheduler</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">PartitionedScheduler</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">SchedulerInfo</span><span class="p">(</span><span class="s">&quot;EDF_mono&quot;</span><span class="p">,</span> <span class="n">EDF_mono</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">packer</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c"># First Fit</span>
<span class="n">cpus</span> <span class="o">=</span> <span class="p">[[</span><span class="n">cpu</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">cpu</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">processors</span><span class="p">]</span>
<span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">task_list</span><span class="p">:</span>
<span class="n">j</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c"># Find a processor with free space.</span>
<span class="k">while</span> <span class="n">cpus</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="nb">float</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">wcet</span><span class="p">)</span> <span class="o">/</span> <span class="n">task</span><span class="o">.</span><span class="n">period</span> <span class="o">&gt;</span> <span class="mf">1.0</span><span class="p">:</span>
<span class="n">j</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">processors</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;oops bin packing failed.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="c"># Affect it to the task.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">affect_task_to_processor</span><span class="p">(</span><span class="n">task</span><span class="p">,</span> <span class="n">cpus</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
<span class="c"># Update utilization.</span>
<span class="n">cpus</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="nb">float</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">wcet</span><span class="p">)</span> <span class="o">/</span> <span class="n">task</span><span class="o">.</span><span class="n">period</span>
<span class="k">return</span> <span class="bp">True</span>
</pre></div>
</div>
</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="text_mode.html" title="Using SimSo in script mode"
>next</a> |</li>
<li class="right" >
<a href="faq.html" title="Frequently Asked Questions"
>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
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
import os
import re
from xml.dom import minidom
from simso.core.Scheduler import SchedulerInfo
from simso.core import Scheduler
from simso.core.Task import TaskInfo
from simso.core.Processor import ProcInfo
from .GenerateConfiguration import generate
from .parser import Parser
# Hack for Python2
if not hasattr(minidom.NamedNodeMap, '__contains__'):
minidom.NamedNodeMap.__contains__ = minidom.NamedNodeMap.has_key
def _gcd(*numbers):
"""Return the greatest common divisor of the given integers"""
from fractions import gcd
return reduce(gcd, numbers)
# Least common multiple is not in standard libraries?
def _lcm(numbers):
"""Return lowest common multiple."""
def lcm(a, b):
return (a * b) // _gcd(a, b)
return reduce(lcm, numbers, 1)
class Configuration(object):
"""
The configuration class store all the details about a system. An instance
of this class will be passed to the constructor of the
:class:`Model <simso.core.Model.Model>` class.
"""
def __init__(self, filename=None):
"""
Args:
- `filename` A file can be used to initialize the configuration.
"""
if filename:
parser = Parser(filename)
self.etm = parser.etm
self.duration = parser.duration
self.cycles_per_ms = parser.cycles_per_ms
self._caches_list = parser.caches_list
self.memory_access_time = parser.memory_access_time
self._task_info_list = parser.task_info_list
self.task_data_fields = parser.task_data_fields
self._proc_info_list = parser.proc_info_list
self.proc_data_fields = parser.proc_data_fields
self._scheduler_info = parser.scheduler_info
self.penalty_preemption = parser.penalty_preemption
self.penalty_migration = parser.penalty_migration
else:
self.etm = "wcet"
self.duration = 100000000
self.penalty_preemption = 0
self.penalty_migration = 0
self.cycles_per_ms = 1000000
self._caches_list = []
self._task_info_list = []
self.task_data_fields = {}
self._proc_info_list = []
self.proc_data_fields = {}
self.memory_access_time = 100
self._scheduler_info = SchedulerInfo()
self.calc_penalty_cache()
self._set_filename(filename)
def _set_filename(self, filename):
self._simulation_file = filename
if filename:
self._cur_dir = os.path.split(filename)[0]
if not self._cur_dir:
self._cur_dir = os.curdir
else:
self._cur_dir = os.curdir
def save(self, simulation_file=None):
"""
Save the current configuration in a file. If no file is given as
argument, the previous file used to write or read the configuration is
used again.
"""
if simulation_file:
old_dir = self._cur_dir
self._cur_dir = os.path.split(simulation_file)[0] or '.'
# Update relative paths.
self._scheduler_info.set_name(
old_dir + '/' + self._scheduler_info.name, self._cur_dir)
for task in self._task_info_list:
if task.stack_file:
task.set_stack_file(
old_dir + '/' + task.stack_file, self._cur_dir)
self._simulation_file = simulation_file
conf_file = open(self._simulation_file, 'w')
conf_file.write(generate(self))
def calc_penalty_cache(self):
for proc in self.proc_info_list:
access_time = self.memory_access_time
for cache in reversed(proc.caches):
cache.penalty = access_time - cache.access_time
access_time = cache.access_time
proc.penalty = access_time
def check_all(self):
"""
Check the correctness of the configuration (without simulating it).
"""
self.check_general()
self.check_scheduler()
self.check_processors()
self.check_tasks()
self.check_caches()
def check_general(self):
assert self.duration >= 0, \
"Simulation duration must be a positive number."
assert self.cycles_per_ms >= 0, \
"Cycles / ms must be a positive number."
assert self.memory_access_time >= 0, \
"The memory access time must be a positive number."
def check_scheduler(self):
cls = self._scheduler_info.get_cls()
assert cls is not None, \
"A scheduler is needed."
assert issubclass(cls, Scheduler), \
"Must inherits from Scheduler."
assert self._scheduler_info.overhead >= 0, \
"An overhead must not be negative."
def check_processors(self):
# At least one processor:
assert len(self._proc_info_list) > 0, \
"At least one processor is needed."
# Caches inclusifs :
succ = {}
for proc in self._proc_info_list:
cur = None
for cache in reversed(proc.caches):
assert not (cache in succ and succ[cache] != cur), \
"Caches must be inclusives."
succ[cache] = cur
cur = cache
for index, proc in enumerate(self._proc_info_list):
# Nom correct :
assert re.match('^[a-zA-Z][a-zA-Z0-9 _-]*$', proc.name), \
"A processor name must begins with a letter and must not "\
"contains any special character."
# Id unique :
assert proc.identifier not in [
x.identifier for x in self._proc_info_list[index + 1:]], \
"Processors' identifiers must be uniques."
# Overheads positifs :
assert proc.cs_overhead >= 0, \
"Context Save overhead can't be negative."
assert proc.cl_overhead >= 0, \
"Context Load overhead can't be negative."
def check_tasks(self):
assert len(self._task_info_list) > 0, "At least one task is needed."
for index, task in enumerate(self._task_info_list):
# Id unique :
assert task.identifier not in [
x.identifier for x in self._task_info_list[index + 1:]], \
"Tasks' identifiers must be uniques."
# Nom correct :
assert re.match('^[a-zA-Z][a-zA-Z0-9 _-]*$', task.name), "A task "\
"name must begins with a letter and must not contains any "\
"special character."
# Activation date >= 0:
assert task.activation_date >= 0, \
"Activation date must be positive."
# Period >= 0:
assert task.period >= 0, "Tasks' periods must be positives."
# Deadline >= 0:
assert task.deadline >= 0, "Tasks' deadlines must be positives."
# N_instr >= 0:
assert task.n_instr >= 0, \
"A number of instructions must be positive."
# WCET >= 0:
assert task.wcet >= 0, "WCET must be positive."
# ACET >= 0:
assert task.acet >= 0, "ACET must be positive."
# ET-STDDEV >= 0:
assert task.et_stddev >= 0, \
"A standard deviation is a positive number."
# mix in [0.0, 2.0]
assert 0.0 <= task.mix <= 2.0, \
"A mix must be positive and less or equal than 2.0"
if self.etm == "cache":
# stack
assert task.stack_file, "A task needs a stack profile."
# stack ok
assert task.csdp, "Stack not found or empty."
def check_caches(self):
for index, cache in enumerate(self._caches_list):
# Id unique :
assert cache.identifier not in [
x.identifier for x in self._caches_list[index + 1:]], \
"Caches' identifiers must be uniques."
# Nom correct :
assert re.match('^[a-zA-Z][a-zA-Z0-9_-]*$', cache.name), \
"A cache name must begins with a letter and must not " \
"contains any spacial character nor space."
# Taille positive :
assert cache.size >= 0, "A cache size must be positive."
# Access time >= 0:
assert cache.access_time >= 0, "An access time must be positive."
def get_hyperperiod(self):
"""
Compute and return the hyperperiod of the tasks.
"""
return _lcm([x.period for x in self.task_info_list])
@property
def duration_ms(self):
return self.duration / self.cycles_per_ms
@property
def simulation_file(self):
return self._simulation_file
@property
def cur_dir(self):
return self._cur_dir
@property
def caches_list(self):
return self._caches_list
@property
def task_info_list(self):
"""
List of tasks (TaskInfo objects).
"""
return self._task_info_list
@property
def proc_info_list(self):
"""
List of processors (ProcInfo objects).
"""
return self._proc_info_list
@property
def scheduler_info(self):
"""
SchedulerInfo object.
"""
return self._scheduler_info
def add_task(self, name, identifier, task_type="Periodic",
abort_on_miss=False, period=10, activation_date=0,
n_instr=0, mix=0.5, stack_file="", wcet=0, acet=0,
et_stddev=0, deadline=10, base_cpi=1.0, followed_by=None,
list_activation_dates=[], preemption_cost=0, data=None):
"""
Helper method to create a TaskInfo and add it to the list of tasks.
"""
if data is None:
data = dict((k, None) for k in self.task_data_fields)
task = TaskInfo(name, identifier, task_type, abort_on_miss, period,
activation_date, n_instr, mix,
(stack_file, self.cur_dir), wcet, acet, et_stddev,
deadline, base_cpi, followed_by, list_activation_dates,
preemption_cost, data)
self.task_info_list.append(task)
return task
def add_processor(self, name, identifier, cs_overhead=0,
cl_overhead=0, migration_overhead=0, speed=1.0):
"""
Helper method to create a ProcInfo and add it to the list of
processors.
"""
proc = ProcInfo(
identifier, name, cs_overhead, cl_overhead, migration_overhead,
speed)
self.proc_info_list.append(proc)
return proc
#!/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))
# coding=utf-8
class SchedulerEvent(object):
BEGIN_SCHEDULE = 1
END_SCHEDULE = 2
BEGIN_ACTIVATE = 3
END_ACTIVATE = 4
BEGIN_TERMINATE = 5
END_TERMINATE = 6
def __init__(self, cpu):
self.event = 0
self.cpu = cpu
class SchedulerBeginScheduleEvent(SchedulerEvent):
def __init__(self, cpu):
SchedulerEvent.__init__(self, cpu)
self.event = SchedulerEvent.BEGIN_SCHEDULE
class SchedulerEndScheduleEvent(SchedulerEvent):
def __init__(self, cpu):
SchedulerEvent.__init__(self, cpu)
self.event = SchedulerEvent.END_SCHEDULE
class SchedulerBeginActivateEvent(SchedulerEvent):
def __init__(self, cpu):
SchedulerEvent.__init__(self, cpu)
self.event = SchedulerEvent.BEGIN_ACTIVATE
class SchedulerEndActivateEvent(SchedulerEvent):
def __init__(self, cpu):
SchedulerEvent.__init__(self, cpu)
self.event = SchedulerEvent.END_ACTIVATE
class SchedulerBeginTerminateEvent(SchedulerEvent):
def __init__(self, cpu):
SchedulerEvent.__init__(self, cpu)
self.event = SchedulerEvent.BEGIN_TERMINATE
class SchedulerEndTerminateEvent(SchedulerEvent):
def __init__(self, cpu):
SchedulerEvent.__init__(self, cpu)
self.event = SchedulerEvent.END_TERMINATE
# coding=utf-8
from collections import deque
from SimPy.Simulation import Process, Monitor, hold, passivate
from simso.core.Job import Job
from simso.core.Timer import Timer
from .CSDP import CSDP
import os
import os.path
class TaskInfo(object):
"""
TaskInfo is mainly a container class grouping the data that characterize
a Task. A list of TaskInfo objects are passed to the Model so that
:class:`Task` instances can be created.
"""
def __init__(self, name, identifier, task_type, abort_on_miss, period,
activation_date, n_instr, mix, stack_file, wcet, acet,
et_stddev, deadline, base_cpi, followed_by,
list_activation_dates, preemption_cost, data):
"""
:type name: str
:type identifier: int
:type task_type: str
:type abort_on_miss: bool
:type period: float
:type activation_date: float
:type n_instr: int
:type mix: float
:type stack_file: str
:type wcet: float
:type acet: float
:type et_stddev: float
:type deadline: float
:type base_cpi: float
:type followed_by: int
:type list_activation_dates: list
:type preemption_cost: int
:type data: dict
"""
self.name = name
self.identifier = identifier
self.task_type = task_type
self.period = period
self.activation_date = activation_date
self.n_instr = n_instr
self.mix = mix
self.wcet = wcet
self.acet = acet
self.et_stddev = et_stddev
self.base_cpi = base_cpi
self._stack = None
self._csdp = None
self._stack_file = ''
self.set_stack_file(*stack_file)
self.deadline = deadline
self.followed_by = followed_by
self.abort_on_miss = abort_on_miss
self.list_activation_dates = list_activation_dates
self.data = data
self.preemption_cost = preemption_cost
@property
def csdp(self):
"""
Accumulated Stack Distance Profile. Used by the cache models instead of
the Stack Distance Profile for optimization matters.
"""
return self._csdp
@property
def stack_file(self):
"""
Stack distance profile input file.
"""
return self._stack_file
def set_stack_file(self, stack_file, cur_dir):
"""
Set the stack distance profile.
"""
if stack_file:
try:
self._stack = TaskInfo._parse_stack(stack_file)
self._csdp = CSDP(self._stack)
self._stack_file = os.path.relpath(stack_file, cur_dir)
except Exception as e:
print("set_stack_file failed:", e)
@staticmethod
def _parse_stack(stack_file):
stack = {}
if stack_file and os.path.isfile(stack_file):
for line in open(stack_file):
dist, value = line.split()
stack[int(dist)] = float(value)
else:
stack = None
return stack
class GenericTask(Process):
"""
Abstract class for Tasks. :class:`ATask` and :class:`PTask` inherits from
this class.
These classes simulate the behavior of the simulated task. It controls the
release of the jobs and is able to abort the jobs that exceed their
deadline.
The majority of the task_info attributes are available through this class
too. A set of metrics such as the number of preemptions and migrations are
available for analysis.
"""
fields = []
def __init__(self, sim, task_info):
"""
Args:
- `sim`: :class:`Model <simso.core.Model>` instance.
- `task_info`: A :class:`TaskInfo` representing the Task.
:type sim: Model
:type task_info: TaskInfo
"""
Process.__init__(self, name=task_info.name, sim=sim)
self.name = task_info.name
self._task_info = task_info
self._monitor = Monitor(name="Monitor" + self.name + "_states",
sim=sim)
self._activations_fifo = deque([])
self._sim = sim
self.cpu = None
self._etm = sim.etm
self._job_count = 0
self._last_cpu = None
self._cpi_alone = {}
self._jobs = []
self.job = None
def __lt__(self, other):
return self.identifier < other.identifier
def is_active(self):
return self.job is not None and self.job.is_active()
def set_cpi_alone(self, proc, cpi):
self._cpi_alone[proc] = cpi
def get_cpi_alone(self, proc=None):
if proc is None:
proc = self.cpu
return self._cpi_alone[proc]
@property
def base_cpi(self):
return self._task_info.base_cpi
@property
def data(self):
"""
Extra data to characterize the task. Only used by the scheduler.
"""
return self._task_info.data
@property
def deadline(self):
"""
Deadline in milliseconds.
"""
return self._task_info.deadline
@property
def n_instr(self):
return self._task_info.n_instr
@property
def mix(self):
return self._task_info.mix
@property
def csdp(self):
return self._task_info.csdp
@property
def preemption_cost(self):
return self._task_info.preemption_cost
@property
def footprint(self):
return int(self._task_info.n_instr * self._task_info.mix *
(1 - self._task_info.csdp.get(-1)))
@property
def wcet(self):
"""Worst-Case Execution Time in milliseconds."""
return self._task_info.wcet
@property
def acet(self):
return self._task_info.acet
@property
def et_stddev(self):
return self._task_info.et_stddev
@property
def period(self):
"""
Period of the task.
"""
return self._task_info.period
@property
def identifier(self):
"""
Identifier of the task.
"""
return self._task_info.identifier
@property
def monitor(self):
"""
The monitor for this Task. Similar to a log mechanism (see Monitor in
SimPy doc).
"""
return self._monitor
@property
def followed_by(self):
"""
Task that is activated by the end of a job from this task.
"""
if self._task_info.followed_by is not None:
followed = [x for x in self._sim.task_list
if (x.identifier == self._task_info.followed_by)]
if followed:
return followed[0]
return None
@property
def jobs(self):
"""
List of the jobs.
"""
return self._jobs
def end_job(self, job):
self._last_cpu = self.cpu
if self.followed_by:
self.followed_by.create_job(job)
if len(self._activations_fifo) > 0:
self._activations_fifo.popleft()
if len(self._activations_fifo) > 0:
self.job = self._activations_fifo[0]
self.sim.activate(self.job, self.job.activate_job())
def _job_killer(self, job):
if job.end_date is None and job.computation_time < job.wcet:
if self._task_info.abort_on_miss:
self.cancel(job)
job.abort()
def create_job(self, pred=None):
"""
Create a new job from this task. This should probably not be used
directly by a scheduler.
"""
self._job_count += 1
job = Job(self, "{}_{}".format(self.name, self._job_count), pred,
monitor=self._monitor, etm=self._etm, sim=self.sim)
if len(self._activations_fifo) == 0:
self.job = job
self.sim.activate(job, job.activate_job())
self._activations_fifo.append(job)
self._jobs.append(job)
timer_deadline = Timer(self.sim, GenericTask._job_killer,
(self, job), self.deadline)
timer_deadline.start()
def _init(self):
if self.cpu is None:
self.cpu = self._sim.processors[0]
class ATask(GenericTask):
"""
Non-periodic Task process. Inherits from :class:`GenericTask`. The job is
created by another task.
"""
fields = ['deadline', 'wcet']
def execute(self):
self._init()
yield passivate, self
class PTask(GenericTask):
"""
Periodic Task process. Inherits from :class:`GenericTask`. The jobs are
created periodically.
"""
fields = ['activation_date', 'period', 'deadline', 'wcet']
def execute(self):
self._init()
# wait the activation date.
yield hold, self, int(self._task_info.activation_date *
self._sim.cycles_per_ms)
while True:
#print self.sim.now(), "activate", self.name
self.create_job()
yield hold, self, int(self.period * self._sim.cycles_per_ms)
class SporadicTask(GenericTask):
"""
Sporadic Task process. Inherits from :class:`GenericTask`. The jobs are
created using a list of activation dates.
"""
fields = ['list_activation_dates', 'deadline', 'wcet']
def execute(self):
self._init()
for ndate in self.list_activation_dates:
yield hold, self, int(ndate * self._sim.cycles_per_ms) \
- self._sim.now()
self.create_job()
@property
def list_activation_dates(self):
return self._task_info.list_activation_dates
task_types = {
"Periodic": PTask,
"APeriodic": ATask,
"Sporadic": SporadicTask
}
task_types_names = ["Periodic", "APeriodic", "Sporadic"]
def Task(sim, task_info):
"""
Task factory. Return and instantiate the correct class according to the
task_info.
"""
return task_types[task_info.task_type](sim, task_info)
# coding=utf-8
from SimPy.Simulation import Process, hold
# TODO: allow the user to specify an overhead.
class InstanceTimer(Process):
def __init__(self, timer):
Process.__init__(self, name="Timer", sim=timer.sim)
self.function = timer.function
self.args = timer.args
self.delay = timer.delay
self.one_shot = timer.one_shot
self.cpu = timer.cpu
self.running = False
self.overhead = timer.overhead
def call_handler(self):
if self.running:
self.function(*self.args)
def run(self):
self.running = True
while self.running:
yield hold, self, self.delay
if self.interrupted() or not self.running:
break
if self.cpu:
self.cpu.timer(self)
else:
self.call_handler()
if self.one_shot:
break
class Timer(object):
"""
Allow to declare a timer. A timer is a mechanism that allows to call a
function after a certain amount of time, periodically or single shot.
A Timer can be used with or without specifying a processor. If a processor
is specified, when the timer fire, if a job was running on the processor,
it is temporarly interrupted. This is more realistic, even if for the
moment there is no overhead associated to this action. A scheduler using a
timer should define on which processor the callback will execute.
The delay is expressed in milliseconds by default but it can also be given
in cycles.
"""
def __init__(self, sim, function, args, delay, one_shot=True, prior=False,
cpu=None, in_ms=True, overhead=0):
"""
Args:
- `sim`: The :class:`model <simso.core.Model.Model>` object.
- `function`: Callback function, called when the delay expires.
- `args`: Arguments passed to the callback function.
- `delay`: Time to wait before calling the function.
- `one_shot`: True if the timer should execute only once.
- `prior`: If true, for the same date, the simulation should \
start by handling the timer (should probably not be True).
- `cpu`: On which :class:`processor \
<simso.core.Processor.Processor>` the function is virtually \
executing.
- `in_ms`: True if the delay is expressed in millisecond. In \
cycles otherwise.
Methods:
"""
self.sim = sim
self.function = function
self.args = args
if in_ms:
self.delay = int(delay * sim.cycles_per_ms)
else:
self.delay = int(delay)
self.one_shot = one_shot
self.prior = prior
self.cpu = cpu
self.instance = None
if in_ms:
self.overhead = int(overhead * sim.cycles_per_ms)
else:
self.overhead = int(overhead)
assert self.delay >= 0, "delay must be >= 0"
def start(self):
"""
Start the timer.
"""
self.instance = InstanceTimer(self)
self.sim.activate(self.instance, self.instance.run(), self.prior)
def stop(self):
"""
Stop the timer.
"""
if self.instance:
self.instance.running = False
"""
The core module include all the classes needed for the simulation.
"""
from simso.core.JobEvent import JobEvent
from simso.core.ProcEvent import ProcEvent
from simso.core.Model import Model
from simso.core.Processor import Processor
from simso.core.Scheduler import Scheduler
from simso.core.Timer import Timer
from simso.core.results import Results
\ No newline at end of file
from simso.core.etm.AbstractExecutionTimeModel \
import AbstractExecutionTimeModel
import random
# TODO: the seed should be specified in order to evaluate on identical systems.
# More precisely, the computation time of the jobs should remain the same.
class ACET(AbstractExecutionTimeModel):
def __init__(self, sim, _):
self.sim = sim
self.et = {}
self.executed = {}
self.on_execute_date = {}
def init(self):
pass
def update_executed(self, job):
if job in self.on_execute_date:
self.executed[job] += (self.sim.now() - self.on_execute_date[job]
) * job.cpu.speed
del self.on_execute_date[job]
def on_activate(self, job):
self.executed[job] = 0
self.et[job] = min(
job.task.wcet,
random.normalvariate(job.task.acet, job.task.et_stddev)
) * self.sim.cycles_per_ms
def on_execute(self, job):
self.on_execute_date[job] = self.sim.now()
def on_preempted(self, job):
self.update_executed(job)
def on_terminated(self, job):
self.update_executed(job)
del self.et[job]
def on_abort(self, job):
self.update_executed(job)
del self.et[job]
def get_executed(self, job):
if job in self.on_execute_date:
c = (self.sim.now() - self.on_execute_date[job]) * job.cpu.speed
else:
c = 0
return self.executed[job] + c
def get_ret(self, job):
return int(self.et[job] - self.get_executed(job))
def update(self):
for job in list(self.on_execute_date.keys()):
self.update_executed(job)
import abc
class AbstractExecutionTimeModel(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def init(self):
pass
@abc.abstractmethod
def on_activate(self, _):
pass
@abc.abstractmethod
def update(self):
pass
@abc.abstractmethod
def on_execute(self, _):
pass
@abc.abstractmethod
def on_preempted(self, _):
pass
@abc.abstractmethod
def on_terminated(self, _):
pass
@abc.abstractmethod
def on_abort(self, _):
pass
@abc.abstractmethod
def get_ret(self, _):
return
def get_executed(self, job):
return job.computation_time_cycles
# coding=utf-8
from simso.core.etm.AbstractExecutionTimeModel \
import AbstractExecutionTimeModel
def calc_cpi(base_cpi, mix, miss_rates, penalties):
"""
Compute the CPI using the miss_rates and penalties.
"""
penalty_per_memaccess = penalties[0]
for mp, mr in zip(penalties[1:], miss_rates):
penalty_per_memaccess += mp * mr
return base_cpi + mix * penalty_per_memaccess
def capacity_miss_LRU(csdp, cache_size):
"""
Capacity miss rate using an LRU cache.
"""
return 1.0 - csdp.get(int(cache_size + .5))
def cpi_alone(task, cache_sizes, penalties):
miss_rates = [capacity_miss_LRU(task.csdp, cache_size)
for cache_size in cache_sizes]
return calc_cpi(task.base_cpi, task.mix, miss_rates, penalties)
def calc_cache_sizes(caches, task, running_jobs):
"""
Compute the virtual size of the cache taking into account the other running
tasks (FOA model).
"""
result = []
for cache in caches:
shared_jobs = [j for j in running_jobs if j.cpu in cache.shared_with]
sum_af = sum(j.task.mix / j.task.get_cpi_alone() for j in shared_jobs)
proportion = (task.mix / task.get_cpi_alone()) / sum_af
result.append(cache.size * proportion)
return result
def compute_instructions(task, running_jobs, duration):
caches = task.cpu.caches
penalties = [task.cpu.penalty_memaccess] + [c.penalty for c in caches]
sizes = calc_cache_sizes(caches, task, running_jobs)
miss_rates = [capacity_miss_LRU(task.csdp, size) for size in sizes]
return duration / calc_cpi(task.base_cpi, task.mix, miss_rates, penalties)
class CacheModel(AbstractExecutionTimeModel):
def __init__(self, sim, nb_processors):
self.sim = sim
self._nb_processors = nb_processors
def init(self):
self._last_update = 0
self._running_jobs = set()
self._instr_jobs = {}
self._total_preemptions_cost = 0
self.running = {}
self.penalty = {}
self.was_running_on = {}
# precompute cpi_alone for each task on each cpu
for task in self.sim.task_list:
for proc in self.sim.processors:
caches = proc.caches
task.set_cpi_alone(
proc,
cpi_alone(task, [c.size for c in caches],
[proc.penalty_memaccess] +
[c.penalty for c in caches])
)
def update(self):
self._update_instructions()
def _update_instructions(self):
for job in self._running_jobs:
# Compute number of instr for self.sim.now() - last_update
instr = compute_instructions(job.task, self._running_jobs,
self.sim.now() - self._last_update)
# Update the number of instr for this job
self._instr_jobs[job] = self._instr_jobs.get(job, 0) + instr
# Update last_update
self._last_update = self.sim.now()
def on_activate(self, job):
self.penalty[job] = 0
def on_execute(self, job):
# Compute penalty.
if job in self.was_running_on:
# resume on the same processor.
if self.was_running_on[job] is job.cpu:
if self.running[job.cpu] is not job:
self.penalty[job] += job.task.preemption_cost
else: # migration.
self.penalty[job] += job.task.preemption_cost
self.running[job.cpu] = job
self.was_running_on[job] = job.cpu
# Update the number of instructions executed for the running jobs.
self._update_instructions()
# Add the job in the list of running jobs.
self._running_jobs.add(job)
def _stop_job(self, job):
# Update the number of instructions executed for the running jobs.
self._update_instructions()
# Remove the job from the list of running jobs.
self._running_jobs.remove(job)
def on_preempted(self, job):
self._stop_job(job)
def on_terminated(self, job):
self._stop_job(job)
def on_abort(self, job):
self._stop_job(job)
def get_ret(self, job):
self._update_instructions()
penalty = self.penalty[job]
return (job.task.n_instr - self._instr_jobs[job]) \
* job.task.get_cpi_alone() + penalty
from simso.core.etm.AbstractExecutionTimeModel \
import AbstractExecutionTimeModel
class FixedPenalty(AbstractExecutionTimeModel):
def __init__(self, sim, _):
self.sim = sim
self.running = {}
self.penalty = {}
self.was_running_on = {}
self.executed = {}
self.on_execute_date = {}
def init(self):
pass
def update_executed(self, job):
if job in self.on_execute_date:
self.executed[job] += (self.sim.now() - self.on_execute_date[job]
) * job.cpu.speed
del self.on_execute_date[job]
def on_activate(self, job):
self.penalty[job] = 0
self.executed[job] = 0
def on_execute(self, job):
self.on_execute_date[job] = self.sim.now()
if job in self.was_running_on:
# resume on the same processor.
if self.was_running_on[job] is job.cpu:
if self.running[job.cpu] is not job:
self.penalty[job] += self.sim.penalty_preemption
else: # migration.
self.penalty[job] += self.sim.penalty_migration
self.running[job.cpu] = job
self.was_running_on[job] = job.cpu
def on_preempted(self, job):
self.executed[job] += (self.sim.now() - self.on_execute_date[job]
) * job.cpu.speed
def on_terminated(self, job):
if job in self.on_execute_date:
del self.on_execute_date[job]
def on_abort(self, job):
if job in self.on_execute_date:
del self.on_execute_date[job]
def get_executed(self, job):
if job in self.on_execute_date:
c = (self.sim.now() - self.on_execute_date[job]) * job.cpu.speed
else:
c = 0
return self.executed[job] + c
def get_ret(self, job):
wcet_cycles = int(job.wcet * self.sim.cycles_per_ms)
penalty = self.penalty[job]
return int(wcet_cycles + penalty - job.computation_time_cycles)
def update(self):
for job in list(self.on_execute_date.keys()):
self.update_executed(job)
from simso.core.etm.AbstractExecutionTimeModel \
import AbstractExecutionTimeModel
class WCET(AbstractExecutionTimeModel):
def __init__(self, sim, _):
self.sim = sim
self.executed = {}
self.on_execute_date = {}
def init(self):
pass
def update_executed(self, job):
if job in self.on_execute_date:
self.executed[job] += (self.sim.now() - self.on_execute_date[job]
) * job.cpu.speed
del self.on_execute_date[job]
def on_activate(self, job):
self.executed[job] = 0
def on_execute(self, job):
self.on_execute_date[job] = self.sim.now()
def on_preempted(self, job):
self.update_executed(job)
def on_terminated(self, job):
self.update_executed(job)
def on_abort(self, job):
self.update_executed(job)
def get_executed(self, job):
if job in self.on_execute_date:
c = (self.sim.now() - self.on_execute_date[job]) * job.cpu.speed
else:
c = 0
return self.executed[job] + c
def get_ret(self, job):
wcet_cycles = int(job.wcet * self.sim.cycles_per_ms)
return int(wcet_cycles - self.get_executed(job))
def update(self):
for job in list(self.on_execute_date.keys()):
self.update_executed(job)
from .WCET import WCET
from .ACET import ACET
from .CacheModel import CacheModel
from .FixedPenalty import FixedPenalty
execution_time_models = {
'wcet': WCET,
'acet': ACET,
'cache': CacheModel,
'fixedpenalty': FixedPenalty
}
execution_time_model_names = {
'WCET': 'wcet',
'ACET': 'acet',
'Cache Model': 'cache',
'Fixed Penalty': 'fixedpenalty'
}
from simso.core.ProcEvent import ProcEvent
from simso.core.JobEvent import JobEvent
from simso.core.SchedulerEvent import SchedulerEvent
class ProcessorR(object):
"""
Add information about a processor such as the number of CxtSave and
CxtLoad and their total overhead.
"""
def __init__(self):
self.context_save_overhead = 0
self.context_save_count = 0
self.context_load_overhead = 0
self.context_load_count = 0
class SchedulerR(object):
"""
Add information about the scheduler such as the number of scheduling
events and their total overhead.
"""
def __init__(self):
self.schedule_overhead = 0
self.activate_overhead = 0
self.terminate_overhead = 0
self.schedule_count = 0
self.activate_count = 0
self.terminate_count = 0
class TaskR(object):
"""
Add a set of metrics to a task. These metrics include: task_migrations,
abortion count, etc.
The attribute jobs contains a list of JobR, sorted by activation date.
"""
def __init__(self, task, delta_preemption=100):
self.task = task
self.delta_preemption = delta_preemption
self.jobs = []
self.waiting_jobs = []
self.resumptions = []
self.task_migrations = []
self.abort_count = 0
self.execute_date = None
self.preempt_date = None
self.cpu = None
self.other_executed = False
def add_job(self, date, job):
jobr = JobR(date, job)
self.jobs.append(jobr)
self.waiting_jobs.append(jobr)
if len(self.waiting_jobs) == 1:
jobr.start(date)
def terminate_job(self, date):
if self.waiting_jobs:
self.preempt(date)
self.waiting_jobs[0].terminate(date)
self.waiting_jobs.pop(0)
if self.waiting_jobs:
self.waiting_jobs[0].start(date)
self.preempt_date = None
def abort_job(self, date):
if self.waiting_jobs:
self.preempt(date)
self.waiting_jobs[0].abort(date)
self.waiting_jobs.pop(0)
self.abort_count += 1
if self.waiting_jobs:
self.waiting_jobs[0].start(date)
self.preempt_date = None
def execute(self, date, cpu):
if self.waiting_jobs:
if self.waiting_jobs[0].computation_time == 0:
if self.cpu == cpu or self.cpu is None:
self.resumptions.append((date, self.waiting_jobs[0]))
else:
self.task_migrations.append((date, self.waiting_jobs[0]))
else:
if self.cpu == cpu:
self.waiting_jobs[0].preemption_count += 1
if date - self.preempt_date > self.delta_preemption:
self.waiting_jobs[0].preemption_delta_count += 1
if self.other_executed:
self.waiting_jobs[0].preemption_inter_count += 1
else:
self.waiting_jobs[0].migration_count += 1
if date - self.preempt_date > self.delta_preemption:
self.waiting_jobs[0].migration_delta_count += 1
self.execute_date = date
self.cpu = cpu
self.preempt_date = None
def preempt(self, date):
if (self.execute_date is not None
and self.execute_date < date and self.waiting_jobs):
self.waiting_jobs[0].add_exec_time(date - self.execute_date)
self.execute_date = None
self.preempt_date = date
self.other_executed = False
@property
def resumption_count(self):
return len(self.resumptions)
@property
def task_migration_count(self):
return len(self.task_migrations)
@property
def exceeded_count(self):
count = 0
for job in self.jobs:
if job.exceeded_deadline:
count += 1
return count
@property
def migration_count(self):
return sum(job.migration_count for job in self.jobs)
@property
def preemption_count(self):
return sum(job.preemption_count for job in self.jobs)
@property
def preemption_inter_count(self):
return sum(job.preemption_inter_count for job in self.jobs)
@property
def name(self):
return self.task.name
class JobR(object):
"""
Add a set of metrics to a job. Such metrics include: preemption count,
migration count, response time, etc.
"""
def __init__(self, date, job):
self.job = job
self.preemption_count = 0
self.preemption_delta_count = 0
self.preemption_inter_count = 0
self.migration_count = 0
self.migration_delta_count = 0
self.activation_date = date
self.aborted = False
self.computation_time = 0
self.end_date = None
self.response_time = None
self.start_date = None
self.absolute_deadline = job.absolute_deadline_cycles
def terminate(self, date):
self.end_date = date
self.response_time = date - self.activation_date
def abort(self, date):
self.aborted = True
self.end_date = date
self.response_time = date - self.activation_date
def add_exec_time(self, duration):
self.computation_time += duration
def start(self, date):
self.start_date = date
@property
def name(self):
return self.job.name
@property
def exceeded_deadline(self):
return self.end_date and (self.end_date > self.absolute_deadline
or self.aborted)
@property
def normalized_laxity(self):
return ((self.job.task.deadline - float(self.response_time)
/ self.job.sim.cycles_per_ms) / self.job.task.period)
@property
def task(self):
return self.job.task
class Results(object):
"""
This class embeds and analyzes all the results from the simulation.
This allows to retrieve the usual metrics.
The Results instance object contains the following attributes:
- `tasks`: a dictionary of TaskR where the key is the original Task.
- `scheduler`: a SchedulerR instance.
- `processors`: a dictionary of ProcessorR where the key is the \
original Processor.
.
"""
def __init__(self, model):
self.model = model
self.error = None
self._observation_window = None
self.tasks = {}
self.scheduler = None
self.processors = {}
self.total_timers = 0
self.timers = None
def end(self):
self._analyze()
def tasks_event(self):
"""
Generator of the tasks events sorted by their date.
"""
monitors = {}
indices = {}
for task in self.model.task_list:
monitors[task] = task.monitor
indices[task] = 0
while True:
m = None
for task in self.model.task_list:
if indices[task] < len(monitors[task]):
evt = monitors[task][indices[task]]
if m is None or evt[1].id_ < m[0][1].id_:
m = (evt, task)
if m is None:
break
indices[m[1]] += 1
yield m
def _generate_tasks(self):
self.tasks = {}
for task in self.model.task_list:
self.tasks[task] = TaskR(task)
for evt, task in self.tasks_event():
if (evt[0] < self.observation_window[0] or
evt[0] > self.observation_window[1]):
# The events that start before the observation window should
# maybe be stored...
continue
if evt[1].event == JobEvent.ACTIVATE:
self.tasks[task].add_job(evt[0], evt[1].job)
elif evt[1].event == JobEvent.TERMINATED:
self.tasks[task].terminate_job(evt[0])
elif evt[1].event == JobEvent.ABORTED:
self.tasks[task].abort_job(evt[0])
elif evt[1].event == JobEvent.EXECUTE:
self.tasks[task].execute(evt[0], evt[1].cpu)
for rt in self.tasks.values():
if rt.preempt_date and evt[1].cpu == rt.cpu:
rt.other_executed = True
elif evt[1].event == JobEvent.PREEMPTED:
self.tasks[task].preempt(evt[0])
def _generate_scheduler(self):
self.scheduler = SchedulerR()
last = self.observation_window[0]
for t, evt in self.model.scheduler.monitor:
if (t < self.observation_window[0] or
t > self.observation_window[1]):
continue
if evt.event == SchedulerEvent.BEGIN_SCHEDULE:
self.scheduler.schedule_count += 1
elif evt.event == SchedulerEvent.END_SCHEDULE:
self.scheduler.schedule_overhead += t - last
elif evt.event == SchedulerEvent.BEGIN_ACTIVATE:
self.scheduler.activate_count += 1
elif evt.event == SchedulerEvent.END_ACTIVATE:
self.scheduler.activate_overhead += t - last
elif evt.event == SchedulerEvent.BEGIN_TERMINATE:
self.scheduler.terminate_count += 1
elif evt.event == SchedulerEvent.END_TERMINATE:
self.scheduler.terminate_overhead += t - last
last = t
def _generate_processors(self):
self.processors = {}
for proc in self.model.processors:
proc_r = ProcessorR()
self.processors[proc] = proc_r
last = self.observation_window[0]
for t, evt in proc.monitor:
if (t < self.observation_window[0] or
t > self.observation_window[1]):
continue
if evt.event == ProcEvent.OVERHEAD and evt.args == "CS":
if evt.terminated:
proc_r.context_save_overhead += t - last
else:
proc_r.context_save_count += 1
if evt.event == ProcEvent.OVERHEAD and evt.args == "CL":
if evt.terminated:
proc_r.context_load_overhead += t - last
else:
proc_r.context_load_count += 1
last = t
def _compute_timers(self):
self.total_timers = 0
self.timers = {}
for proc in self.model.processors:
self.timers[proc] = 0
for t, evt in proc.timer_monitor:
if (t < self.observation_window[0] or
t > self.observation_window[1]):
continue
self.total_timers += 1
self.timers[proc] += 1
def _analyze(self):
self._generate_tasks()
self._generate_scheduler()
self._generate_processors()
self._compute_timers()
def get_observation_window(self):
"""
Get the observation window.
"""
if self._observation_window is None:
self._observation_window = (0, self.model.now())
return self._observation_window
def set_observation_window(self, window):
"""
Set the observation window. The events that occurs outside of the
observation window are discarded.
"""
self._observation_window = window
self._analyze()
observation_window = property(get_observation_window,
set_observation_window)
@property
def observation_window_duration(self):
return self.observation_window[1] - self.observation_window[0]
@property
def total_migrations(self):
migrations = 0
for task in self.tasks.values():
migrations += task.migration_count
return migrations
@property
def total_preemptions(self):
preemptions = 0
for task in self.tasks.values():
preemptions += task.preemption_count
return preemptions
@property
def total_task_migrations(self):
migrations = 0
for task in self.tasks.values():
migrations += task.task_migration_count
return migrations
@property
def total_task_resumptions(self):
resumptions = 0
for task in self.tasks.values():
resumptions += task.resumption_count
return resumptions
@property
def total_exceeded_count(self):
count = 0
for task in self.tasks.values():
count += task.exceeded_count
return count
def calc_load(self):
"""
Yield a tuple (proc, load, overhead) for each processor.
"""
for proc in self.model.processors:
sum_run = 0
sum_overhead = 0
last_event = ProcEvent.IDLE
x1 = self.observation_window[0]
for evt in proc.monitor:
current_date = evt[0]
if current_date < self.observation_window[0]:
last_event = evt[1].event
continue
if current_date >= self.observation_window[1]:
break
if last_event == ProcEvent.RUN:
sum_run += current_date - x1
elif last_event == ProcEvent.OVERHEAD:
sum_overhead += current_date - x1
x1 = current_date
last_event = evt[1].event
if last_event == ProcEvent.RUN:
sum_run += self.observation_window[1] - x1
elif last_event == ProcEvent.OVERHEAD:
sum_overhead += self.observation_window[1] - x1
yield (proc,
float(sum_run) / self.observation_window_duration,
float(sum_overhead) / self.observation_window_duration)
"""
Tools for generating task sets.
"""
import numpy as np
import random
import math
def UUniFastDiscard(n, u, nsets):
sets = []
while len(sets) < nsets:
# Classic UUniFast algorithm:
utilizations = []
sumU = u
for i in range(1, n):
nextSumU = sumU * random.random() ** (1.0 / (n - i))
utilizations.append(sumU - nextSumU)
sumU = nextSumU
utilizations.append(nextSumU)
# If no task utilization exceeds 1:
if not [ut for ut in utilizations if ut > 1]:
sets.append(utilizations)
return sets
def StaffordRandFixedSum(n, u, nsets):
"""
Copyright 2010 Paul Emberson, Roger Stafford, Robert Davis.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are
those of the authors and should not be interpreted as representing official
policies, either expressed or implied, of Paul Emberson, Roger Stafford or
Robert Davis.
Includes Python implementation of Roger Stafford's randfixedsum implementation
http://www.mathworks.com/matlabcentral/fileexchange/9700
Adapted specifically for the purpose of taskset generation with fixed
total utilisation value
Please contact paule@rapitasystems.com or robdavis@cs.york.ac.uk if you have
any questions regarding this software.
"""
if n < u:
return None
#deal with n=1 case
if n == 1:
return np.tile(np.array([u]), [nsets, 1])
k = min(int(u), n - 1)
s = u
s1 = s - np.arange(k, k - n, -1.)
s2 = np.arange(k + n, k, -1.) - s
tiny = np.finfo(float).tiny
huge = np.finfo(float).max
w = np.zeros((n, n + 1))
w[0, 1] = huge
t = np.zeros((n - 1, n))
for i in np.arange(2, n + 1):
tmp1 = w[i - 2, np.arange(1, i + 1)] * s1[np.arange(0, i)] / float(i)
tmp2 = w[i - 2, np.arange(0, i)] * s2[np.arange(n - i, n)] / float(i)
w[i - 1, np.arange(1, i + 1)] = tmp1 + tmp2
tmp3 = w[i - 1, np.arange(1, i + 1)] + tiny
tmp4 = s2[np.arange(n - i, n)] > s1[np.arange(0, i)]
t[i - 2, np.arange(0, i)] = (tmp2 / tmp3) * tmp4 + \
(1 - tmp1 / tmp3) * (np.logical_not(tmp4))
x = np.zeros((n, nsets))
rt = np.random.uniform(size=(n - 1, nsets)) # rand simplex type
rs = np.random.uniform(size=(n - 1, nsets)) # rand position in simplex
s = np.repeat(s, nsets)
j = np.repeat(k + 1, nsets)
sm = np.repeat(0, nsets)
pr = np.repeat(1, nsets)
for i in np.arange(n - 1, 0, -1): # iterate through dimensions
# decide which direction to move in this dimension (1 or 0):
e = rt[(n - i) - 1, ...] <= t[i - 1, j - 1]
sx = rs[(n - i) - 1, ...] ** (1.0 / i) # next simplex coord
sm = sm + (1.0 - sx) * pr * s / (i + 1)
pr = sx * pr
x[(n - i) - 1, ...] = sm + pr * e
s = s - e
j = j - e # change transition table column if required
x[n - 1, ...] = sm + pr * s
#iterated in fixed dimension order but needs to be randomised
#permute x row order within each column
for i in range(0, nsets):
x[..., i] = x[np.random.permutation(n), i]
return x.T.tolist()
def gen_ripoll(nsets, compute, deadline, period, target_util):
"""
Ripoll et al. tasksets generator.
Args:
- `nsets`: Number of tasksets to generate.
- `compute`: Maximum computation time of a task.
- `deadline`: Maximum slack time.
- `period`: Maximum delay after the deadline.
- `target_util`: Total utilization to reach.
"""
sets = []
for i in range(nsets):
task_set = []
total_util = 0.0
while total_util < target_util:
c = random.randint(1, compute)
d = c + random.randint(0, deadline)
p = d + random.randint(0, period)
task_set.append((c, d, p))
total_util += c / p
sets.append(task_set)
return sets
def gen_uunifastdiscard(nsets, u, n):
"""
The UUniFast algorithm was proposed by Bini for generating task
utilizations on uniprocessor architectures.
The UUniFast-Discard algorithm extends it to multiprocessor by
discarding task sets containing any utilization that exceeds 1.
This algorithm is easy and widely used. However, it suffers from very
long computation times when n is close to u. Stafford's algorithm is
faster.
Args:
- `n`: The number of tasks in a task set.
- `u`: Total utilization of the task set.
- `nsets`: Number of sets to generate.
Returns `nsets` of `n` task utilizations.
"""
return UUniFastDiscard(u, n, nsets)
def gen_randfixedsum(nsets, u, n):
"""
Stafford's RandFixedSum algorithm implementated in Python.
Based on the Python implementation given by Paul Emberson, Roger Stafford,
and Robert Davis. Available under the Simplified BSD License.
Args:
- `n`: The number of tasks in a task set.
- `u`: Total utilization of the task set.
- `nsets`: Number of sets to generate.
"""
return StaffordRandFixedSum(u, n, nsets)
def gen_kato_utilizations(nsets, umin, umax, target_util):
"""
Kato et al. tasksets generator.
Args:
- `nsets`: Number of tasksets to generate.
- `umin`: Minimum task utilization.
- `umax`: Maximum task utilization.
- `target_util`:
"""
sets = []
for i in range(nsets):
task_set = []
total_util = 0.0
while total_util < target_util:
u = random.uniform(umin, umax)
if u + total_util > target_util:
u = target_util - total_util
total_util += u
task_set.append(u)
sets.append(task_set)
return sets
def next_arrival_poisson(period):
return -math.log(1.0 - random.random()) * period
def gen_arrivals(period, min_, max_, round_to_int=False):
def trunc(x, p):
return int(x * 10 ** p) / float(10 ** p)
dates = []
n = min_ - period
while True:
n += next_arrival_poisson(period) + period
if round_to_int:
n = int(round(n))
else:
n = trunc(n, 6)
if n > max_:
break
dates.append(n)
return dates
def gen_periods_loguniform(n, nsets, min_, max_, round_to_int=False):
"""
Generate a list of `nsets` sets containing each `n` random periods using a
loguniform distribution.
Args:
- `n`: The number of tasks in a task set.
- `nsets`: Number of sets to generate.
- `min_`: Period min.
- `max_`: Period max.
"""
periods = np.exp(np.random.uniform(low=np.log(min_), high=np.log(max_),
size=(nsets, n)))
if round_to_int:
return np.rint(periods).tolist()
else:
return periods.tolist()
def gen_periods_uniform(n, nsets, min_, max_, round_to_int=False):
"""
Generate a list of `nsets` sets containing each `n` random periods using a
uniform distribution.
Args:
- `n`: The number of tasks in a task set.
- `nsets`: Number of sets to generate.
- `min_`: Period min.
- `max_`: Period max.
"""
periods = np.random.uniform(low=min_, high=max_, size=(nsets, n))
if round_to_int:
return np.rint(periods).tolist()
else:
return periods.tolist()
def gen_periods_discrete(n, nsets, periods):
"""
Generate a matrix of (nsets x n) random periods chosen randomly in the
list of periods.
Args:
- `n`: The number of tasks in a task set.
- `nsets`: Number of sets to generate.
- `periods`: A list of available periods.
"""
try:
return np.random.choice(periods, size=(nsets, n)).tolist()
except AttributeError:
# Numpy < 1.7:
p = np.array(periods)
return p[np.random.randint(len(p), size=(nsets, n))].tolist()
def gen_tasksets(utilizations, periods):
"""
Take a list of task utilization sets and a list of task period sets and
return a list of couples (c, p) sets. The computation times are truncated
at a precision of 10^-10 to avoid floating point precision errors.
Args:
- `utilization`: The list of task utilization sets. For example::
[[0.3, 0.4, 0.8], [0.1, 0.9, 0.5]]
- `periods`: The list of task period sets. For examples::
[[100, 50, 1000], [200, 500, 10]]
Returns:
For the above example, it returns::
[[(30.0, 100), (20.0, 50), (800.0, 1000)],
[(20.0, 200), (450.0, 500), (5.0, 10)]]
"""
def trunc(x, p):
return int(x * 10 ** p) / float(10 ** p)
return [[(trunc(ui * pi, 6), trunc(pi, 6)) for ui, pi in zip(us, ps)]
for us, ps in zip(utilizations, periods)]
from simso.core import Scheduler
def best_fit(scheduler, task_list=None):
"""
Best-Fit heuristic. Put the tasks somewhere it fits but with the least
spare place.
"""
cpus = [[cpu, 0] for cpu in scheduler.processors]
if task_list is None:
task_list = scheduler.task_list
for task in task_list:
j = 0
# Find a processor with free space.
while cpus[j][1] * task.period + float(task.wcet) > task.period:
j += 1
if j >= len(scheduler.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
scheduler.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
cpus[:] = sorted(cpus, key=lambda c: -c[1])
return True
def worst_fit(scheduler, task_list=None):
"""
Worst-Fit heuristic. Put the tasks somewhere it fits with the largest
spare place.
"""
cpus = [[cpu, 0] for cpu in scheduler.processors]
if task_list is None:
task_list = scheduler.task_list
for task in task_list:
j = 0
# Find a processor with free space.
while cpus[j][1] * task.period + float(task.wcet) > task.period:
j += 1
if j >= len(scheduler.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
scheduler.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
cpus[:] = sorted(cpus, key=lambda c: c[1])
return True
def next_fit(scheduler, task_list=None):
"""
Next-Fit heuristic. Put each task on the next processor with enough space.
"""
cpus = [[cpu, 0] for cpu in scheduler.processors]
if task_list is None:
task_list = scheduler.task_list
j = 0
for task in task_list:
k = 0
# Find a processor with free space.
while cpus[j][1] * task.period + float(task.wcet) > task.period:
j = (j + 1) % len(scheduler.processors)
k += 1
if k >= len(scheduler.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
scheduler.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
return True
def first_fit(scheduler, task_list=None):
"""
First-Fit heuristic. Put each task on the first processor with enough
space.
"""
cpus = [[cpu, 0] for cpu in scheduler.processors]
if task_list is None:
task_list = scheduler.task_list
for task in task_list:
j = 0
# Find a processor with free space.
while cpus[j][1] * task.period + float(task.wcet) > task.period:
j += 1
if j >= len(scheduler.processors):
print("oops bin packing failed.")
return False
# Affect it to the task.
scheduler.affect_task_to_processor(task, cpus[j][0])
# Update utilization.
cpus[j][1] += float(task.wcet) / task.period
return True
def decreasing_first_fit(scheduler):
"""
First-Fit with tasks inversely sorted by their u_i.
"""
return first_fit(
scheduler, sorted(scheduler.task_list,
key=lambda t: -float(t.wcet) / t.period))
def decreasing_next_fit(scheduler):
"""
Next-Fit with tasks inversely sorted by their u_i.
"""
return next_fit(
scheduler, sorted(scheduler.task_list,
key=lambda t: -float(t.wcet) / t.period))
def decreasing_best_fit(scheduler):
"""
Best-Fit with tasks inversely sorted by their u_i.
"""
return next_fit(
scheduler, sorted(scheduler.task_list,
key=lambda t: -float(t.wcet) / t.period))
def decreasing_worst_fit(scheduler):
"""
Worst-Fit with tasks inversely sorted by their u_i.
"""
return next_fit(
scheduler, sorted(scheduler.task_list,
key=lambda t: -float(t.wcet) / t.period))
class PartitionedScheduler(Scheduler):
"""
The PartitionedScheduler class provide facilities to create a new
Partitioned Scheduler. Only the packing phase is not done and should
be overriden.
"""
def init(self, scheduler_info, packer=None):
"""
Args:
- `scheduler_info`: A :class:`SchedulerInfo \
<simso.core.Scheduler.SchedulerInfo>` object. One scheduler from \
this SchedulerInfo will be instantiated for each processor.
"""
assert scheduler_info is not None, \
"PartitionedScheduler requires a monoprocessor scheduler to " \
"instantiate."
# Mapping processor to scheduler.
self.map_cpu_sched = {}
# Mapping task to scheduler.
self.map_task_sched = {}
for cpu in self.processors:
# Instantiate a scheduler.
sched = scheduler_info.instantiate(self.sim)
sched.add_processor(cpu)
# Affect the scheduler to the processor.
self.map_cpu_sched[cpu.identifier] = sched
self._packer = packer
assert self.packer(), "Packing failed"
for cpu in self.processors:
self.map_cpu_sched[cpu.identifier].init()
def packer(self):
if self._packer:
return self._packer(self)
raise Exception("A bin packing method is required.")
def affect_task_to_processor(self, task, proc):
# Get the scheduler for this processor.
sched = self.map_cpu_sched[proc.identifier]
self.map_task_sched[task.identifier] = sched
sched.add_task(task)
# Put the task on that processor.
task.cpu = proc
def get_lock(self):
# No lock mechanism is needed.
return True
def schedule(self, cpu):
return self.map_cpu_sched[cpu.identifier].schedule(cpu)
def on_activate(self, job):
self.map_task_sched[job.task.identifier].on_activate(job)
def on_terminated(self, job):
self.map_task_sched[job.task.identifier].on_terminated(job)
def GFB(configuration):
"""
Sufficient test for Global-EDF.
"""
umax = max(t.wcet / t.deadline for t in configuration.task_info_list)
utot = sum(t.wcet / t.deadline for t in configuration.task_info_list)
m = len(configuration.proc_info_list)
return utot <= m * (1 - umax) + umax
def BAK(configuration):
"""
Sufficient test for Global-EDF. This code is untested.
"""
m = len(configuration.proc_info_list)
def b(task, task_k):
lk = task_k.wcet / task_k.deadline
ui = task.wcet / task.period
if lk >= ui:
return ui * (1 + (task.period - task.deadline) / task_k.deadline)
else:
return ui * (1 + (task.period - task.deadline) / task_k.deadline) \
+ (task.wcet - lk * task.period) / task_k.deadline
def cond(task):
s = sum(min(1, b(i, task)) for i in configuration.task_info_list)
lk = task.wcet / task.deadline
return s <= m * (1 - lk) + lk
return all(cond(k) for k in configuration.task_info_list)
from .PartitionedScheduler import PartitionedScheduler
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