Simulation framework for online packet scheduling algorithms.
Framework simulates a scheduling algorithm against some adversary, who has control over packet arrivals and error injections. When algorithm under test makes a scheduling decision, adversary is asked to schedule an error.
Note
|
It is required to implement an algorithm and an adversary in a special form. |
Work is based on following research papers:
The simulation framework works on all major platforms. It depends on:
-
Install Homebrew
-
Install Python 3
brew install python3
-
Execute
pip3 install matplotlib
-
Install latest Python 3 from www.python.org.
-
Open Command Line and go to
C:\Python34\Scripts
(assuming default installation path). -
Execute
pip.exe install matplotlib
. This step may fail if Visual C++ 2010 (part of Visual Studio 2010) is not installed. Visual C++ is available here.
Each experiment constists of few steps. First, a file describing model has to be created. Based on the model file, a sequence on packet arrival events is generated. The sequence is used in simulation of both algorithms (algorithm under test and adversary’s).
A model file contains all model parameters:
-
packet lengths; separated with spaces,
-
parameter λ; has to be ≥ 0.0,
-
length distribution; separated with spaces (i-th element on the list corresponds to i-th packet length),
-
speedup; has to be ≥ 1.0.
Example model file may look like this:
3 5 7 5.0 0.33 0.17 0.5 1.5
In this example new packets appear with rate 5. The propability of length 5 is 17%, length 3 — 33% and half of packets have length 7. Simulation using this model gives an algorithm a 1.5 speedup.
To generate a sequence of inject events use:
generate.py <generator> <n> <model-file>
<generator>
is the name of one of available generators,
<n>
is the number of events to generate
and <model-file>
points to a file with model description.
-
sirocco_thm9
— generates an inject event sequance using the strategy described in Theorem 9 (distribution parameters are ignored). -
stochastic
— generates inject events according to Poisson process with parameter λ. Packet length is randomly chosen with the probability from model file.
The result is a sequence of pairs (time and the length of a packet). Without loss of generality time starts with the arrival of first packet. An example result looks like this:
0.0 10.0 2.459899742060707 1.0 5.383135023609432 5.0 6.710508745166248 10.0 9.397366473753106 5.0 11.41576280873459 1.0 12.265779790163247 10.0 12.433092337654008 10.0 17.43791330370601 10.0 19.84048150554071 1.0 ...
To run a simulation of an algorithm use:
simulate.py <algorithm> <adversary> <events-file> <model-file>
<algorithm>
is the name of one of available algorithms,
<adversary>
is the name of one of available adversaries,
<events-file>
is the file with packet arrival events generated in the previous step
and <model-file>
points to a file with model description.
-
SL
— Shortest Length, -
LL
— Longest Length, -
SLPreamble
— the algorithm[1] defined in section 3.2 in [sirocco]; it starts each phase with a preamble of short packets (if there are at leastfloor(l_2 / l_1)
short packets in the queue) and then usesLL
, -
CSLPreamble
— the conditional variant of theSLPreamble
algorithm; depending on model parameters it usesSL
orSLPreamble
, -
Greedy
— the Algorithm 1 from the paper, shown to achieve throughput at most 0.5 in a model with an arbitrary number of packet lengths and adversarial arrivals; if the algorithm is about to transmit a packetl_i
it checks whether there are enough shorter packets in the queue to cover lengthl_i
and schedules them instead, -
Prudent
--the Algorithm 5 from the paper, shown to achieve throughput 1, when run with speedup 2 in a model with an arbitrary number of packet lengths and adversarial arrivals; it sends the special preamble and then switches toLL
, -
ESLPreamble
— a generalized version[2] of theSLPreamble
algorithm; it uses two preambles (one of lengthl_2
and one of lengthl_3
) before switching toLL
, -
OnlySL
— an algorithm that schedules packets of the shrotest length only.
ESLPreamble
algorithm// queue[l_i] := the number of l_i packets in the queue loop // first preamble if (queue[l_1] * l_1 >= l_2) transmit packets l_1 up to the length of l_2 // second preamble if (queue[l_1] * l_1 + queue[l_2] * l_2 >= l_3) transmit packets l_1 and l_2 up to the length of l_3 loop transmit longest unsent packet
-
NoErrors
— an adversary that does not inject any jamming errors, -
SiroccoThm9
— the adversary from the proof of Theorem 9 in [sirocco], used to show an upper bound for the throughput of algorithm SL under adversarial arrivals, -
SiroccoThm11
— the adversary from the proof of Theorem 11 in [sirocco], used to show that algorithm LL cannot achieve relative throughput larger than 0, even under stochastic arrivals, -
Sirocco
— the adversary defined in section 4.1 in [sirocco], used to show an upper bound for the throughput of any algorithm in a model with two packet lengths, -
SiroccoL
— the modified version of theSirocco
adversary that extends phases as much as possible, -
ESirocco
— Adversary from part 3.2.1 in thesis
The simulation produces a log that contains records what the algorithm and the adversary were doing over time. It includes information about packet arrivals, error injections, successful and unsuccessful packet transmissions. An example log of a simulation looks like this:
... 138.68732775266903 inject 1.0 138.68732775266903 error 138.68732775266903 error 138.68732775266903 schedule ALG 1.0 138.68732775266903 schedule ADV 5.0 139.68732775266903 sent ALG 139.68732775266903 schedule ALG 5.0 143.68732775266903 sent ADV 143.68732775266903 error ...
There are several utilities for log analysis. They offer a graphical representation of data from a log file. Only the throughput metric and the size of the queue are supported.
We are interested in the value of the long term relative throughput.
It is the ratio between
the total length of packets transmitted up to time t
by an algorithm under test
and adversary’s algorithm
as t
goes to infinity.
Utilities from our framework calculate that ratio in provided samples.
To obtain only the value of the throughput use:
throughput.py <log-file>
<log-file>
is a log created during a simulation.
It is possible to draw a plot how the throughput ratio changes in time. To obtain the plot use:
plot-throughput.py <log-file>
<log-file>
is a log created during a simulation.
One might want to add a reference value to the plot. It is possible to do so by using:
plot-throughput.py <log-file> <reference-value>
<reference-value>
is a float value.
It is used to draw a horizontal line y = reference value.
Another way to characterize an algorithm is by looking at the size of the queue. Competitiveness can be expressed in terms of the size of the queues of a specified packet length. It allows us to detect which packet accumulate over time. To obtain a plot use:
plot-queuesize.py <log-file>
<log-file>
is a log created during a simulation.
The visualization utility allows to see what an algorithm under test was doing at given point in time. Whether it was transmitting a packet and if that transmission ended with a success or was jammed. To obtain such plot use:
visualize.py <log-file>
or
visualize.py <log-file> <from> <to>
<log-file>
is a log created during a simulation
and parameters from
and to
can be provide to restrict visualization
to specified interval [from, to].
Figure shows an example visualization. Each packet length has its own color. Segments drew with a solid line denote transmission that ended with a success. A dashed line denotes a try to send one. Vertical gray dashed lines show when jamming errors occurred.
Hence drawing thousands of packets is inefficient, it is a good idea to restrict the plot to some interval. It speeds up preparing the plot and makes it more readable.
Our framework can be extended by adding new implementations of algorithms and adversaries. The only requirement is to add methods allowing our simulation framework to execute them.
The main part of an algorithm is the schedule
method.
Is is called every time the algorithm is asked to make a scheduling decision.
The method should return the length of a packet that
the algorithm schedules now or None
if it does not schedule anything.
class Algorithm:
def schedule(self): # (1)
yield ...
-
schedule
method — yields the length of the scheduled packet orNone
Note
|
Handling packets queue is done internally. The framework guarantees that the method gets called only when the algorithm has to make a scheduling decision. |
Besides the schedule
method like an algorithm has,
an adversary has two methods algorithmSchedules
and adversarySchedules
that are used to schedule jamming errors.
class NewAdversary(Adversary):
def schedule(self): # (1)
yield ...
def algorithmSchedules(self, packet): # (2)
return ...
def adversarySchedules(self, packet): # (3)
return ...
-
schedule
method — yields the length of the scheduled packet orNone
-
algorithmSchedules
method — returns time in which next error occurs (in reaction on packet scheduled by algorithm) -
adversarySchedules
method — returns time in which next error occurs (in reaction on packet scheduled by adversary)
The schedule
method behaves exactly like in the algorithm.
The algorithmSchedules
method is called when
the algorithm schedules a packet.
The length of the scheduled packet is passed to it.
It is used to schedule a jamming error in reaction on the packet schedules by the algorithm.
It should return time in which the next jamming error occurs or
None
if the adversary decides not to cause an error.
The adversarySchedules
method is called when
the adversary’s algorithm makes a scheduling decision.
It receives the length of the scheduled packet and
returns time in which the next jamming error occurs.
It may be used to inject errors in the middle of a phase
to eliminate unproductive time in the phase for the adversary’s algorithm.
Note
|
Handling packet queue is done internally. The framework guarantees that the methods get called only when the adversary has to make a scheduling decision. |