### Attribute Types
class Types:
+ """ Allowed types for the Attribute value
+ """
String = "STRING"
Bool = "BOOL"
Enumerate = "ENUM"
### Attribute Flags
class Flags:
- """ Differents flags to characterize an attribute
-
+ """ Flags to characterize the scope of an Attribute
"""
# Attribute value can not be read (it is hidden to the user)
NoRead = 1 # 1
class Attribute(object):
+ """ An Attribute exposes a configuration parameter of a resource
"""
- .. class:: Class Args :
- An Attribute reflects a configuration parameter for
- a particular resource. Attributes might be read only or
- not.
-
- :param name: Name of the attribute
+ def __init__(self, name, help, type = Types.String,
+ flags = None, default = None, allowed = None,
+ range = None, set_hook = None):
+ """
+ :param name: Name of the Attribute
:type name: str
- :param help: Attribute description
+ :param help: Description of the Attribute
:type help: str
- :param type: The type expected for the attribute value.
- Should be one of Attribute.Types .
+ :param type: The type expected for the Attribute value.
+ Should be one of Attribute.Types
:type type: str
- :param flags: Defines attribute behavior (i.e. whether it is read-only,
- read and write, etc). This parameter should take its values from
- Attribute.Flags. Flags values can be bitwised.
+ :param flags: Defines Attribute behavior (i.e. whether it is read-only,
+ read and write, etc). This parameter must take its values from
+ Attribute.Flags. Flags values can be bitwised
:type flags: hex
- :param default: Default value of the attribute
- :type default: depends on the type of attribute
+ :param default: Default value for the Attribute
+ :type default: Depends on the type of Attribute
- :param allowed: List of values that the attribute can take.
- This parameter is only meaningful for Enumerate type attributes.
+ :param allowed: List of values that the Attribute can take.
+ This parameter is only meaningful for Enumerate type Attributes
:type allowed: list
:param range: (max, min) tuple with range of possible values for
- attributes.
+ Attributes.
This parameter is only meaningful for Integer or Double type
- attributes.
+ Attributes
:type range: (int, int) or (float, float)
:param set_hook: Function that will be executed whenever a new
- value is set for the attribute.
+ value is set for the Attribute.
:type set_hook: function
"""
- def __init__(self, name, help, type = Types.String,
- flags = None, default = None, allowed = None,
- range = None, set_hook = None):
self._name = name
self._help = help
self._type = type
@property
def name(self):
- """ Returns the name of the attribute """
+ """ Returns the name of the Attribute """
return self._name
@property
def default(self):
- """ Returns the default value of the attribute """
+ """ Returns the default value of the Attribute """
return self._default
@property
def type(self):
- """ Returns the type of the attribute """
+ """ Returns the type of the Attribute """
return self._type
@property
def help(self):
- """ Returns the help of the attribute """
+ """ Returns the description of the Attribute """
return self._help
@property
def flags(self):
- """ Returns the flags of the attribute """
+ """ Returns the flags of the Attribute """
return self._flags
@property
def allowed(self):
- """ Returns the allowed value for this attribute """
+ """ Returns the set of allowed values for the Attribute """
return self._allowed
@property
def range(self):
- """ Returns the range of the attribute """
+ """ Returns the range of allowed numerical values for the Attribute """
return self._range
def has_flag(self, flag):
- """ Returns true if the attribute has the flag 'flag'
+ """ Returns True if the Attribute has the flag 'flag'
:param flag: Flag to be checked
:type flag: Flags
return (self._flags & flag) == flag
def get_value(self):
- """ Returns the value of the attribute """
+ """ Returns the value of the Attribute """
return self._value
def set_value(self, value):
- """ Change the value of the attribute after checking the type """
+ """ Configure a new value for the Attribute """
valid = True
if self.type == Types.Enumerate:
@property
def has_changed(self):
- """ Returns true if the value has changed from the default """
+ """ Returns True if the value has changed from the default """
return self.value != self.default
+
import weakref
class FailureLevel(object):
- """ Describes the system failure state """
+ """ Possible failure states for the experiment """
OK = 1
RM_FAILURE = 2
EC_FAILURE = 3
class FailureManager(object):
""" The FailureManager is responsible for handling errors
and deciding whether an experiment should be aborted or not
-
"""
- def __init__(self, ec):
- self._ec = weakref.ref(ec)
+ def __init__(self):
+ self._ec = None
self._failure_level = FailureLevel.OK
self._abort = False
+ def set_ec(self, ec):
+ self._ec = weakref.ref(ec)
+
@property
def ec(self):
""" Returns the ExperimentController associated to this FailureManager
-
"""
-
return self._ec()
@property
return self._abort
def eval_failure(self, guid):
+ """ Implements failure policy and sets the abort state of the
+ experiment based on the failure state and criticality of
+ the RM
+
+ :param guid: Guid of the RM upon which the failure of the experiment
+ is evaluated
+ :type guid: int
+
+ """
if self._failure_level == FailureLevel.OK:
rm = self.ec.get_resource(guid)
state = rm.state
self._failure_level = FailureLevel.EC_FAILURE
class ECState(object):
- """ Possible states for an ExperimentController
+ """ Possible states of the ExperimentController
"""
RUNNING = 1
class ExperimentController(object):
"""
- .. class:: Class Args :
-
- :param exp_id: Human readable identifier for the experiment scenario.
- :type exp_id: str
-
.. note::
An experiment, or scenario, is defined by a concrete set of resources,
return ec
def __init__(self, exp_id = None, local_dir = None, persist = False,
- add_node_callback = None, add_edge_callback = None, **kwargs):
+ fm = None, add_node_callback = None, add_edge_callback = None,
+ **kwargs):
""" ExperimentController entity to model an execute a network
experiment.
completion at local_dir
:type persist: bool
+ :param fm: FailureManager object. If None is given, the default
+ FailureManager class will be used
+ :type fm: FailureManager
+
:param add_node_callback: Callback to invoke for node instantiation
when automatic topology creation mode is used
:type add_node_callback: function
self._stop = False
# Entity in charge of managing system failures
- self._fm = FailureManager(self)
+ if not fm:
+ self._fm = FailureManager()
+ self._fm.set_ec(self)
# EC state
self._state = ECState.RUNNING
import time
class ExperimentRunner(object):
- """ The ExperimentRunner entity is reponsible of
+ """ The ExperimentRunner entity is responsible of
re-running an experiment described by an ExperimentController
- multiple time.
+ multiple time
"""
def __init__(self):
def run(self, ec, min_runs = 1, max_runs = -1, wait_time = 0,
wait_guids = [], compute_metric_callback = None,
evaluate_convergence_callback = None ):
- """ Re-runs a same experiment multiple times
+ """ Run a same experiment independently multiple times, until the
+ evaluate_convergence_callback function returns True
- :param ec: Experiment description of experiment to run
+ :param ec: Description of experiment to replicate.
+ The runner takes care of deploying the EC, so ec.deploy()
+ must not be invoked directly before or after invoking
+ runner.run().
:type ec: ExperimentController
- :param min_runs: Minimum number of repetitions for experiment
+ :param min_runs: Minimum number of times the experiment must be
+ replicated
:type min_runs: int
- :param max_runs: Maximum number of repetitions for experiment
+ :param max_runs: Maximum number of times the experiment can be
+ replicated
:type max_runs: int
- :param wait_time: Time to wait in seconds between invoking
- ec.deploy() and ec.release()
+ :param wait_time: Time to wait in seconds on each run between invoking
+ ec.deploy() and ec.release().
:type wait_time: float
- :param wait_guids: List of guids to pass to ec.wait_finished
- after invoking ec.deploy()
+ :param wait_guids: List of guids wait for finalization on each run.
+ This list is passed to ec.wait_finished()
:type wait_guids: list
- :param compute_metric_callback: function to invoke after each
- experiment run, to compute an experiment metric.
- It will be invoked with the ec and the run count as arguments,
- and it must return the metric value(s) computed for the run
+ :param compute_metric_callback: User defined function invoked after
+ each experiment run to compute a metric. The metric is usually
+ a network measurement obtained from the data collected
+ during experiment execution.
+ The function is invoked passing the ec and the run number as arguments.
+ It must return the value for the computed metric(s) (usually a single
+ numerical value, but it can be several).
metric = compute_metric_callback(ec, run)
:type compute_metric_callback: function
- :param evaluate_convergence_callback: function to evaluate whether the
- collected metric samples have converged and the experiment runner
- can stop. It will be invoked with the ec, the run count and the
- list of collected metric samples as argument, and it must return
- either True or False
+ :param evaluate_convergence_callback: User defined function invoked after
+ computing the metric on each run, to evaluate the experiment was
+ run enough times. It takes the list of cumulated metrics produced by
+ the compute_metric_callback up to the current run, and decided
+ whether the metrics have statistically converged to a meaningful value
+ or not. It must return either True or False.
stop = evaluate_convergence_callback(ec, run, metrics)
return run
- def evaluate_normal_convergence(self, ec, run, samples):
- if len(samples) == 0:
+ def evaluate_normal_convergence(self, ec, run, metrics):
+ """ Returns True when the confidence interval of the sample mean is
+ less than 5% of the mean value, for a 95% confidence level,
+ assuming normal distribution of the data
+ """
+
+ if len(metrics) == 0:
msg = "0 samples collected"
raise RuntimeError, msg
- x = numpy.array(samples)
- n = len(samples)
+ x = numpy.array(metrics)
+ n = len(metrics)
std = x.std()
se = std / math.sqrt(n)
m = x.mean()
- # confidence interval for 95% confidence level.
- # Asuming samples are normally distributed
+ # Confidence interval for 95% confidence level,
+ # assuming normally distributed data.
ci95 = se * 2
ec.logger.info(" RUN %d - SAMPLES %d MEAN %.2f STD %.2f CI (95%%) %.2f \n" % (
return m * 0.05 >= ci95
- def run_experiment(self, filepath, wait_time, wait_guids):
+ def run_experiment(self, filepath, wait_time, wait_guids):
+ """ Run an experiment based on the description stored
+ in filepath.
+
+ """
ec = ExperimentController.load(filepath)
ec.deploy()
import heapq
class TaskStatus:
+ """ Execution state of the Task
+ """
NEW = 0
DONE = 1
ERROR = 2
class Task(object):
- """ This class is to define a task, that is represented by an id,
- an execution time 'timestamp' and an action 'callback """
+ """ A Task represents an operation to be executed by the
+ ExperimentController scheduler
+ """
def __init__(self, timestamp, callback):
+ """
+ :param timestamp: Future execution date of the operation
+ :type timestamp: str
+
+ :param callback: A function to invoke in order to execute the operation
+ :type callback: function
+
+ """
self.id = None
self.timestamp = timestamp
self.callback = callback
self.status = TaskStatus.NEW
class HeapScheduler(object):
- """ Create a Heap Scheduler.
+ """ Create a Heap Scheduler
.. note::
return self._valid
def schedule(self, task):
- """ Add the task 'task' in the heap of the scheduler
+ """ Add a task to the queue ordered by task.timestamp and arrival order
- :param task: task that need to be schedule
+ :param task: task to schedule
:type task: task
"""
if task.id == None:
return task
def remove(self, tid):
- """ Remove a task form the heap
+ """ Remove a task form the queue
- :param tid: Id of the task that need to be removed
+ :param tid: Id of the task to be removed
:type tid: int
+
"""
try:
self._valid.remove(tid)
pass
def next(self):
- """ Get the next task in the scheduler
-
+ """ Get the next task in the queue by timestamp and arrival order
"""
while self._queue:
try:
# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
class TraceAttr:
- """ Trace attributes represent different information
- aspects that can be retrieved from a trace.
+ """A Trace attribute defines information about a Trace that can
+ be queried
"""
- ALL = 'all'
- STREAM = 'stream'
- PATH = 'path'
- SIZE = 'size'
+ ALL = "all"
+ STREAM = "stream"
+ PATH = "path"
+ SIZE = "size"
class Trace(object):
- """
- .. class:: Class Args :
-
- :param name: Name of the trace
- :type name: str
- :param help: Help about the trace
- :type help: str
-
+ """ A Trace represents information about a Resource that can
+ be collected
"""
def __init__(self, name, help, enabled = False):
+ """
+ :param name: Name of the Trace
+ :type name: str
+
+ :param help: Description of the Trace
+ :type help: str
+
+ :param enabled: Sets activation state of Trace
+ :type enabled: bool
+ """
self._name = name
self._help = help
self.enabled = enabled
attr_linkacknowledgment = Attribute("LinkAcknowledgment",
"Enable Link layer acknowledgment mechanism",
type = Types.Bool,
- default = "False",
+ default = "True",
allowed = None,
range = None,
flags = Flags.Reserved | Flags.Construct)
from nepi.execution.trace import Trace, TraceAttr
from nepi.execution.resource import ResourceManager, clsinit_copy, \
ResourceState, reschedule_delay
-from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
+from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice
@clsinit_copy
-class NS3FdNetDevice(NS3BaseNetDevice):
+class NS3FdNetDevice(NS3BaseFdNetDevice):
_rtype = "ns3::FdNetDevice"
@classmethod
attr_bounds = Attribute("Bounds",
"Bounds of the area to cruise.",
type = Types.String,
- default = "0|0|100|100",
+ default = "0|100|0|100",
allowed = None,
range = None,
flags = Flags.Reserved | Flags.Construct)
cls._register_attribute(attr_maxmissedbeacons)
+ attr_activeprobing = Attribute("ActiveProbing",
+ "If true, we send probe requests. If false, we don\'t. NOTE: if more than one STA in your simulation is using active probing, you should enable it at a different simulation time for each STA, otherwise all the STAs will start sending probes at the same time resulting in collisions. See bug 1060 for more info.",
+ type = Types.Bool,
+ default = "False",
+ allowed = None,
+ range = None,
+ flags = Flags.Reserved | Flags.Construct)
+
+ cls._register_attribute(attr_activeprobing)
+
attr_qossupported = Attribute("QosSupported",
"This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA",
type = Types.Bool,
@property
def _rms_to_wait(self):
- rms = set()
-
- node = self.node
- rms.add(node)
-
- ipv4 = node.ipv4
- if node.ipv4:
- rms.add(ipv4)
-
+ rms = set([self.node, self.node.ipv4])
return rms
def _configure_mac_address(self):
#
# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+#
+# Instructions to automatically generate ns-3 ResourceManagers
#
-# Instructions. Run with:
+# Configure the ns-3 enviorment (e.g.):
+#
+# export PYTHONPATH=~/.nepi/nepi-usr/bin/ns-3/ns-3.20/optimized/build/lib/python/site-packages
+# export LD_LIBRARY_PATH=~/.nepi/nepi-usr/bin/ns-3/ns-3.20/optimized/build/lib
+#
+# Run the RM generator:
#
# PYTHONPATH=$PYTHONPATH:~/repos/nepi/src python src/nepi/resources/ns3/resource_manager_generator.py
#
"ns3::ErrorModel",
"ns3::ErrorRateModel",
"ns3::Application",
+ "ns3::FdNetDevice",
#"ns3::DceApplication",
"ns3::NetDevice",
"ns3::Channel",