data collection documentation
This commit is contained in:
@@ -39,6 +39,15 @@ SOURCES = \
|
||||
source/tests.rst \
|
||||
source/tracing.rst \
|
||||
source/troubleshoot.rst \
|
||||
${SRC}/stats/doc/data-collection.rst \
|
||||
${SRC}/stats/doc/data-collection-overview.rst \
|
||||
${SRC}/stats/doc/statistics.rst \
|
||||
${SRC}/stats/doc/data-collection-helpers.rst \
|
||||
${SRC}/stats/doc/probe.rst \
|
||||
${SRC}/stats/doc/collector.rst \
|
||||
${SRC}/stats/doc/aggregator.rst \
|
||||
${SRC}/stats/doc/adaptor.rst \
|
||||
${SRC}/stats/doc/scope-and-limitations.rst \
|
||||
|
||||
# list all manual figure files that need to be copied to
|
||||
# $SOURCETEMP/figures. For each figure to be included in all
|
||||
@@ -52,11 +61,22 @@ SOURCEFIGS = \
|
||||
figures/plot-2d.png \
|
||||
figures/plot-2d-with-error-bars.png \
|
||||
figures/plot-3d.png \
|
||||
${SRC}/stats/doc/Stat-framework-arch.png \
|
||||
${SRC}/stats/doc/Wifi-default.png \
|
||||
${SRC}/stats/doc/dcf-overview.dia \
|
||||
${SRC}/stats/doc/dcf-overview-with-aggregation.dia \
|
||||
${SRC}/stats/doc/gnuplot-example.png \
|
||||
${SRC}/stats/doc/file-example.png \
|
||||
${SRC}/stats/doc/seventh-packet-byte-count.png \
|
||||
${SRC}/stats/doc/gnuplot-helper-example.png \
|
||||
${SRC}/stats/doc/gnuplot-aggregator.png \
|
||||
|
||||
# specify figures from which .png and .pdf figures need to be
|
||||
# generated (all dia and eps figures)
|
||||
IMAGES_EPS = \
|
||||
$(FIGURES)/software-organization.eps \
|
||||
$(FIGURES)/dcf-overview.eps \
|
||||
$(FIGURES)/dcf-overview-with-aggregation.eps \
|
||||
|
||||
# rescale pdf figures as necessary
|
||||
$(FIGURES)/software-organization.pdf_width = 5in
|
||||
|
||||
@@ -26,6 +26,8 @@ This document is written in `reStructuredText <http://docutils.sourceforge.net/r
|
||||
object-names
|
||||
logging
|
||||
tracing
|
||||
data-collection
|
||||
statistics
|
||||
realtime
|
||||
helpers
|
||||
gnuplot
|
||||
|
||||
48
src/stats/doc/adaptor.rst
Normal file
48
src/stats/doc/adaptor.rst
Normal file
@@ -0,0 +1,48 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
.. heading hierarchy:
|
||||
************* Section (#.#)
|
||||
============= Subsection (#.#.#)
|
||||
############# Paragraph (no number)
|
||||
~~~~~~~~~~~~~ Sub-paragraph (no number)
|
||||
|
||||
Adaptors
|
||||
********
|
||||
|
||||
This section details the functionalities provided by the Adaptor
|
||||
class to an |ns3| simulation. This section is meant for users
|
||||
interested in developing simulations with the |ns3| tools and using
|
||||
the Data Collection Framework, of which the Adaptor class is a
|
||||
part, to generate data output with their simulation's results.
|
||||
|
||||
Note: the term 'adaptor' may also be spelled 'adapter'; we chose
|
||||
the spelling aligned with the C++ standard.
|
||||
|
||||
Adaptor Overview
|
||||
================
|
||||
|
||||
An Adaptor is used to make connections between different types of DCF
|
||||
objects.
|
||||
|
||||
To date, one Adaptor has been implemented:
|
||||
|
||||
- TimeSeriesAdaptor
|
||||
|
||||
Time Series Adaptor
|
||||
===================
|
||||
|
||||
The TimeSeriesAdaptor lets Probes connect directly to Aggregators
|
||||
without needing any Collector in between.
|
||||
|
||||
Both of the implemented DCF helpers utilize TimeSeriesAdaptors
|
||||
in order to take probed values of different types and output the
|
||||
current time plus the value with both converted to doubles.
|
||||
|
||||
The role of the TimeSeriesAdaptor class is that of an adaptor, which
|
||||
takes raw-valued probe data of different types and outputs a tuple of
|
||||
two double values. The first is a timestamp, which may be set to
|
||||
different resolutions (e.g. Seconds, Milliseconds, etc.) in the future
|
||||
but which is presently hardcoded to Seconds.
|
||||
The second is the conversion of a non-double
|
||||
value to a double value (possibly with loss of precision).
|
||||
|
||||
398
src/stats/doc/aggregator.rst
Normal file
398
src/stats/doc/aggregator.rst
Normal file
@@ -0,0 +1,398 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
.. heading hierarchy:
|
||||
************* Section (#.#)
|
||||
============= Subsection (#.#.#)
|
||||
############# Paragraph (no number)
|
||||
~~~~~~~~~~~~~ Sub-paragraph (no number)
|
||||
|
||||
Aggregators
|
||||
***********
|
||||
|
||||
This section details the functionalities provided by the Aggregator
|
||||
class to an |ns3| simulation. This section is meant for users
|
||||
interested in developing simulations with the |ns3| tools and using
|
||||
the Data Collection Framework, of which the Aggregator class is a
|
||||
part, to generate data output with their simulation's results.
|
||||
|
||||
Aggregator Overview
|
||||
===================
|
||||
|
||||
An Aggregator object is supposed to be hooked to one or more trace
|
||||
sources in order to receive input. Aggregators are the end point of
|
||||
the data collected by the network of Probes and Collectors during the
|
||||
simulation. It is the Aggregator's job to take these values and
|
||||
transform them into their final output format such as plain text
|
||||
files, spreadsheet files, plots, or databases.
|
||||
|
||||
Typically, an aggregator is connected to one or more Collectors. In
|
||||
this manner, whenever the Collectors' trace sources export new values,
|
||||
the Aggregator can process the value so that it can be used in the
|
||||
final output format where the data values will reside after the
|
||||
simulation.
|
||||
|
||||
Note the following about Aggregators:
|
||||
|
||||
* Aggregators may be dynamically turned on and off during the
|
||||
simulation with calls to ``Enable()`` and ``Disable()``. For
|
||||
example, the aggregating of data may be turned off during the
|
||||
simulation warmup phase, which means those values won't be included
|
||||
in the final output medium.
|
||||
* Aggregators receive data from Collectors via callbacks. When a
|
||||
Collector is associated to an aggregator, a call to TraceConnect is
|
||||
made to establish the Aggregator's trace sink method as a callback.
|
||||
|
||||
To date, two Aggregators have been implemented:
|
||||
|
||||
- GnuplotAggregator
|
||||
- FileAggregator
|
||||
|
||||
GnuplotAggregator
|
||||
=================
|
||||
|
||||
The GnuplotAggregator produces output files used to make gnuplots.
|
||||
|
||||
The GnuplotAggregator will create 3 different files at the end of the
|
||||
simulation:
|
||||
|
||||
- A space separated gnuplot data file
|
||||
- A gnuplot control file
|
||||
- A shell script to generate the gnuplot
|
||||
|
||||
Creation
|
||||
########
|
||||
|
||||
An object of type GnuplotAggregator will be created here to show what needs
|
||||
to be done.
|
||||
|
||||
One declares a GnuplotAggregator in dynamic memory by using the smart
|
||||
pointer class (Ptr<T>). To create a GnuplotAggregator in dynamic
|
||||
memory with smart pointers, one just needs to call the |ns3| method
|
||||
``CreateObject()``. The following code from
|
||||
``src/stats/examples/gnuplot-aggregator-example.cc`` shows
|
||||
how to do this:
|
||||
|
||||
::
|
||||
|
||||
string fileNameWithoutExtension = "gnuplot-aggregator";
|
||||
|
||||
// Create an aggregator.
|
||||
Ptr<GnuplotAggregator> aggregator =
|
||||
CreateObject<GnuplotAggregator> (fileNameWithoutExtension);
|
||||
|
||||
The first argument for the constructor, fileNameWithoutExtension, is
|
||||
the name of the gnuplot related files to write with no extension.
|
||||
This GnuplotAggregator will create a space separated gnuplot data file
|
||||
named "gnuplot-aggregator.dat", a gnuplot control file named
|
||||
"gnuplot-aggregator.plt", and a shell script to generate the gnuplot
|
||||
named + "gnuplot-aggregator.sh".
|
||||
|
||||
The gnuplot that is created can have its key in 4 different locations:
|
||||
|
||||
- No key
|
||||
- Key inside the plot (the default)
|
||||
- Key above the plot
|
||||
- Key below the plot
|
||||
|
||||
The following gnuplot key location enum values are allowed to specify the key's position:
|
||||
|
||||
::
|
||||
|
||||
enum KeyLocation {
|
||||
NO_KEY,
|
||||
KEY_INSIDE,
|
||||
KEY_ABOVE,
|
||||
KEY_BELOW
|
||||
};
|
||||
|
||||
If it was desired to have the key below rather than the default position of inside, then you could do the following.
|
||||
|
||||
::
|
||||
|
||||
aggregator->SetKeyLocation(GnuplotAggregator::KEY_BELOW);
|
||||
|
||||
Examples
|
||||
########
|
||||
|
||||
One example will be discussed in detail here:
|
||||
|
||||
- Gnuplot Aggregator Example
|
||||
|
||||
Gnuplot Aggregator Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An example that exercises the GnuplotAggregator can be found in
|
||||
``src/stats/examples/gnuplot-aggregator-example.cc``.
|
||||
|
||||
The following 2-D gnuplot was created using the example.
|
||||
|
||||
.. _gnuplot-aggregator:
|
||||
|
||||
.. figure:: figures/gnuplot-aggregator.png
|
||||
|
||||
2-D Gnuplot Created by gnuplot-aggregator-example.cc Example.
|
||||
|
||||
This code from the example shows how to construct the
|
||||
GnuplotAggregator as was discussed above.
|
||||
|
||||
::
|
||||
|
||||
void Create2dPlot ()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
string fileNameWithoutExtension = "gnuplot-aggregator";
|
||||
string plotTitle = "Gnuplot Aggregator Plot";
|
||||
string plotXAxisHeading = "Time (seconds)";
|
||||
string plotYAxisHeading = "Double Values";
|
||||
string plotDatasetLabel = "Data Values";
|
||||
string datasetContext = "Dataset/Context/String";
|
||||
|
||||
// Create an aggregator.
|
||||
Ptr<GnuplotAggregator> aggregator =
|
||||
CreateObject<GnuplotAggregator> (fileNameWithoutExtension);
|
||||
|
||||
Various GnuplotAggregator attributes are set including the 2-D dataset
|
||||
that will be plotted.
|
||||
|
||||
::
|
||||
|
||||
// Set the aggregator's properties.
|
||||
aggregator->SetTerminal ("png");
|
||||
aggregator->SetTitle (plotTitle);
|
||||
aggregator->SetLegend (plotXAxisHeading, plotYAxisHeading);
|
||||
|
||||
// Add a data set to the aggregator.
|
||||
aggregator->Add2dDataset (datasetContext, plotDatasetLabel);
|
||||
|
||||
// aggregator must be turned on
|
||||
aggregator->Enable ();
|
||||
|
||||
Next, the 2-D values are calculated, and each one is individually
|
||||
written to the GnuplotAggregator using the ``Write2d()`` function.
|
||||
|
||||
::
|
||||
|
||||
double time;
|
||||
double value;
|
||||
|
||||
// Create the 2-D dataset.
|
||||
for (time = -5.0; time <= +5.0; time += 1.0)
|
||||
{
|
||||
// Calculate the 2-D curve
|
||||
//
|
||||
// 2
|
||||
// value = time .
|
||||
//
|
||||
value = time * time;
|
||||
|
||||
// Add this point to the plot.
|
||||
aggregator->Write2d (datasetContext, time, value);
|
||||
}
|
||||
|
||||
// Disable logging of data for the aggregator.
|
||||
aggregator->Disable ();
|
||||
}
|
||||
|
||||
FileAggregator
|
||||
==============
|
||||
|
||||
The FileAggregator sends the values it receives to a file.
|
||||
|
||||
The FileAggregator can create 4 different types of files:
|
||||
|
||||
- Formatted
|
||||
- Space separated (the default)
|
||||
- Comma separated
|
||||
- Tab separated
|
||||
|
||||
Formatted files use C-style format strings and the sprintf() function
|
||||
to print their values in the file being written.
|
||||
|
||||
Creation
|
||||
########
|
||||
|
||||
An object of type FileAggregator will be created here to show what needs
|
||||
to be done.
|
||||
|
||||
One declares a FileAggregator in dynamic memory by using the smart
|
||||
pointer class (Ptr<T>). To create a FileAggregator in dynamic memory
|
||||
with smart pointers, one just needs to call the |ns3| method
|
||||
CreateObject. The following code from
|
||||
``src/stats/examples/file-aggregator-example.cc`` shows how
|
||||
to do this:
|
||||
|
||||
::
|
||||
|
||||
string fileName = "file-aggregator-formatted-values.txt";
|
||||
|
||||
// Create an aggregator that will have formatted values.
|
||||
Ptr<FileAggregator> aggregator =
|
||||
CreateObject<FileAggregator> (fileName, FileAggregator::FORMATTED);
|
||||
|
||||
The first argument for the constructor, filename, is the name of the
|
||||
file to write; the second argument, fileType, is type of file to
|
||||
write. This FileAggregator will create a file named
|
||||
"file-aggregator-formatted-values.txt" with its values printed as
|
||||
specified by fileType, i.e., formatted in this case.
|
||||
|
||||
The following file type enum values are allowed:
|
||||
|
||||
::
|
||||
|
||||
enum FileType {
|
||||
FORMATTED,
|
||||
SPACE_SEPARATED,
|
||||
COMMA_SEPARATED,
|
||||
TAB_SEPARATED
|
||||
};
|
||||
|
||||
Examples
|
||||
########
|
||||
|
||||
One example will be discussed in detail here:
|
||||
|
||||
- File Aggregator Example
|
||||
|
||||
File Aggregator Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An example that exercises the FileAggregator can be found in
|
||||
``src/stats/examples/file-aggregator-example.cc``.
|
||||
|
||||
The following text file with 2 columns of values separated by commas
|
||||
was created using the example.
|
||||
|
||||
::
|
||||
|
||||
-5,25
|
||||
-4,16
|
||||
-3,9
|
||||
-2,4
|
||||
-1,1
|
||||
0,0
|
||||
1,1
|
||||
2,4
|
||||
3,9
|
||||
4,16
|
||||
5,25
|
||||
|
||||
This code from the example shows how to construct the
|
||||
FileAggregator as was discussed above.
|
||||
|
||||
::
|
||||
|
||||
void CreateCommaSeparatedFile ()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
string fileName = "file-aggregator-comma-separated.txt";
|
||||
string datasetContext = "Dataset/Context/String";
|
||||
|
||||
// Create an aggregator.
|
||||
Ptr<FileAggregator> aggregator =
|
||||
CreateObject<FileAggregator> (fileName, FileAggregator::COMMA_SEPARATED);
|
||||
|
||||
FileAggregator attributes are set.
|
||||
|
||||
::
|
||||
|
||||
// aggregator must be turned on
|
||||
aggregator->Enable ();
|
||||
|
||||
Next, the 2-D values are calculated, and each one is individually
|
||||
written to the FileAggregator using the ``Write2d()`` function.
|
||||
|
||||
::
|
||||
|
||||
double time;
|
||||
double value;
|
||||
|
||||
// Create the 2-D dataset.
|
||||
for (time = -5.0; time <= +5.0; time += 1.0)
|
||||
{
|
||||
// Calculate the 2-D curve
|
||||
//
|
||||
// 2
|
||||
// value = time .
|
||||
//
|
||||
value = time * time;
|
||||
|
||||
// Add this point to the plot.
|
||||
aggregator->Write2d (datasetContext, time, value);
|
||||
}
|
||||
|
||||
// Disable logging of data for the aggregator.
|
||||
aggregator->Disable ();
|
||||
}
|
||||
|
||||
The following text file with 2 columns of formatted values was also
|
||||
created using the example.
|
||||
|
||||
::
|
||||
|
||||
Time = -5.000e+00 Value = 25
|
||||
Time = -4.000e+00 Value = 16
|
||||
Time = -3.000e+00 Value = 9
|
||||
Time = -2.000e+00 Value = 4
|
||||
Time = -1.000e+00 Value = 1
|
||||
Time = 0.000e+00 Value = 0
|
||||
Time = 1.000e+00 Value = 1
|
||||
Time = 2.000e+00 Value = 4
|
||||
Time = 3.000e+00 Value = 9
|
||||
Time = 4.000e+00 Value = 16
|
||||
Time = 5.000e+00 Value = 25
|
||||
|
||||
This code from the example shows how to construct the
|
||||
FileAggregator as was discussed above.
|
||||
|
||||
::
|
||||
|
||||
void CreateFormattedFile ()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
string fileName = "file-aggregator-formatted-values.txt";
|
||||
string datasetContext = "Dataset/Context/String";
|
||||
|
||||
// Create an aggregator that will have formatted values.
|
||||
Ptr<FileAggregator> aggregator =
|
||||
CreateObject<FileAggregator> (fileName, FileAggregator::FORMATTED);
|
||||
|
||||
FileAggregator attributes are set, including the C-style format string
|
||||
to use.
|
||||
|
||||
::
|
||||
|
||||
// Set the format for the values.
|
||||
aggregator->Set2dFormat ("Time = %.3e\tValue = %.0f");
|
||||
|
||||
// aggregator must be turned on
|
||||
aggregator->Enable ();
|
||||
|
||||
Next, the 2-D values are calculated, and each one is individually
|
||||
written to the FileAggregator using the ``Write2d()`` function.
|
||||
|
||||
::
|
||||
|
||||
double time;
|
||||
double value;
|
||||
|
||||
// Create the 2-D dataset.
|
||||
for (time = -5.0; time <= +5.0; time += 1.0)
|
||||
{
|
||||
// Calculate the 2-D curve
|
||||
//
|
||||
// 2
|
||||
// value = time .
|
||||
//
|
||||
value = time * time;
|
||||
|
||||
// Add this point to the plot.
|
||||
aggregator->Write2d (datasetContext, time, value);
|
||||
}
|
||||
|
||||
// Disable logging of data for the aggregator.
|
||||
aggregator->Disable ();
|
||||
}
|
||||
|
||||
18
src/stats/doc/collector.rst
Normal file
18
src/stats/doc/collector.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
.. heading hierarchy:
|
||||
************* Section (#.#)
|
||||
============= Subsection (#.#.#)
|
||||
############# Paragraph (no number)
|
||||
~~~~~~~~~~~~~ Sub-paragraph (no number)
|
||||
|
||||
Collectors
|
||||
**********
|
||||
|
||||
This section is a placeholder to detail the functionalities provided by
|
||||
the Collector
|
||||
class to an |ns3| simulation, and gives examples on how to code them
|
||||
in a program.
|
||||
|
||||
**Note:** As of ns-3.18, Collectors are still under development and
|
||||
not yet provided as part of the framework.
|
||||
630
src/stats/doc/data-collection-helpers.rst
Normal file
630
src/stats/doc/data-collection-helpers.rst
Normal file
@@ -0,0 +1,630 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
.. heading hierarchy:
|
||||
************* Section (#.#)
|
||||
============= Subsection (#.#.#)
|
||||
############# Paragraph (no number)
|
||||
~~~~~~~~~~~~~ Sub-paragraph (no number)
|
||||
|
||||
Data Collection Helpers
|
||||
***********************
|
||||
|
||||
The full flexibility of the data collection framework is provided by
|
||||
the interconnection of probes, collectors, and aggregators. Performing
|
||||
all of these interconnections leads to many configuration statements
|
||||
in user programs. For ease of use, some of the most common operations
|
||||
can be combined and encapsulated in helper functions. In addition,
|
||||
some statements involving |ns3| trace sources do not have Python
|
||||
bindings, due to limitations in the bindings.
|
||||
|
||||
Data Collection Helpers Overview
|
||||
================================
|
||||
|
||||
In this section, we provide an overview of some helper classes that
|
||||
have been created to ease the configuration of the data collection
|
||||
framework for some common use cases. The helpers allow users to form
|
||||
common operations with only a few statements in their C++ or Python
|
||||
programs. But, this ease of use comes at the cost of significantly
|
||||
less flexibility than low-level configuration can provide, and the
|
||||
need to explicitly code support for new Probe types into the helpers
|
||||
(to work around an issue described below).
|
||||
|
||||
The emphasis on the current helpers is to marshal data out of |ns3|
|
||||
trace sources into gnuplot plots or text files, without a high degree
|
||||
of output customization or statistical processing (initially). Also,
|
||||
the use is constrained to the available probe types in |ns3|. Later
|
||||
sections of this documentation will go into more detail about creating
|
||||
new Probe types, as well as details about hooking together Probes,
|
||||
Collectors, and Aggregators in custom arrangements.
|
||||
|
||||
To date, two Data Collection helpers have been implemented:
|
||||
|
||||
- GnuplotHelper
|
||||
- FileHelper
|
||||
|
||||
GnuplotHelper
|
||||
=============
|
||||
|
||||
The GnuplotHelper is a helper class for producing output files used to
|
||||
make gnuplots. The overall goal is to provide the ability for users
|
||||
to quickly make plots from data exported in |ns3| trace sources. By
|
||||
default, a minimal amount of data transformation is performed; the
|
||||
objective is to generate plots with as few (default) configuration
|
||||
statements as possible.
|
||||
|
||||
GnuplotHelper Overview
|
||||
######################
|
||||
|
||||
The GnuplotHelper will create 3 different files at the end of the
|
||||
simulation:
|
||||
|
||||
- A space separated gnuplot data file
|
||||
- A gnuplot control file
|
||||
- A shell script to generate the gnuplot
|
||||
|
||||
There are two configuration statements that are needed to produce plots.
|
||||
The first statement configures the plot (filename, title, legends, and
|
||||
output type, where the output type defaults to PNG if unspecified):
|
||||
|
||||
::
|
||||
|
||||
void ConfigurePlot (const std::string &outputFileNameWithoutExtension,
|
||||
const std::string &title,
|
||||
const std::string &xLegend,
|
||||
const std::string &yLegend,
|
||||
const std::string &terminalType = ".png");
|
||||
|
||||
The second statement hooks the ``Probe`` of interest:
|
||||
|
||||
::
|
||||
|
||||
void PlotProbe (const std::string &typeId,
|
||||
const std::string &path,
|
||||
const std::string &probeTraceSource,
|
||||
const std::string &title);
|
||||
|
||||
The arguments are as follows:
|
||||
|
||||
* typeId: The |ns3| TypeId of the Probe
|
||||
* path: The path in the |ns3| configuration namespace to one or more probes
|
||||
* probeTraceSource: Which output of the probe should be connected to
|
||||
* title: The title to associate with the dataset (in the gnuplot legend)
|
||||
|
||||
A variant on the PlotProbe above is to specify a fifth optional argument
|
||||
that controls where in the plot the key (legend) is placed.
|
||||
|
||||
A fully worked example (from ``seventh.cc``) is shown below:
|
||||
|
||||
::
|
||||
|
||||
// Create the gnuplot helper.
|
||||
GnuplotHelper plotHelper;
|
||||
|
||||
// Configure the plot.
|
||||
plotHelper.ConfigurePlot ("seventh-packet-byte-count",
|
||||
"Packet Byte Count vs. Time",
|
||||
"Time (Seconds)",
|
||||
"Packet Byte Count",
|
||||
"png");
|
||||
|
||||
// Plot the values generated by the probe.
|
||||
plotHelper.PlotProbe ("ns3::Ipv4PacketProbe",
|
||||
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
|
||||
"OutputBytes",
|
||||
"Packet Byte Count",
|
||||
GnuplotAggregator::KEY_BELOW);
|
||||
|
||||
Note that the path specified may contain wildcards. In this case, multiple
|
||||
datasets are plotted on one plot; one for each matched path.
|
||||
|
||||
The main output produced will be three files:
|
||||
|
||||
::
|
||||
|
||||
seventh-packet-byte-count.dat
|
||||
seventh-packet-byte-count.plt
|
||||
seventh-packet-byte-count.sh
|
||||
|
||||
At this point, users can either hand edit the .plt file for further
|
||||
customizations, or just run it through gnuplot. Running
|
||||
`sh seventh-packet-byte-count.sh` simply runs the plot through gnuplot,
|
||||
as shown below.
|
||||
|
||||
.. _seventh-packet-byte-count:
|
||||
|
||||
.. figure:: figures/seventh-packet-byte-count.png
|
||||
|
||||
2-D Gnuplot Created by seventh.cc Example.
|
||||
|
||||
It can be seen that the key elements (legend, title, legend placement,
|
||||
xlabel, ylabel, and path for the data) are all placed on the plot.
|
||||
Since there were two matches to the configuration path provided, the
|
||||
two data series are shown:
|
||||
|
||||
* Packet Byte Count-0 corresponds to /NodeList/0/$ns3::Ipv4L3Protocol/Tx
|
||||
* Packet Byte Count-1 corresponds to /NodeList/1/$ns3::Ipv4L3Protocol/Tx
|
||||
|
||||
GnuplotHelper ConfigurePlot
|
||||
###########################
|
||||
|
||||
The GnuplotHelper's ``ConfigurePlot()`` function can be used
|
||||
to configure plots.
|
||||
|
||||
It has the following prototype:
|
||||
|
||||
::
|
||||
|
||||
void ConfigurePlot (const std::string &outputFileNameWithoutExtension,
|
||||
const std::string &title,
|
||||
const std::string &xLegend,
|
||||
const std::string &yLegend,
|
||||
const std::string &terminalType = ".png");
|
||||
|
||||
It has the following arguments:
|
||||
|
||||
+--------------------------------+------------------------------+
|
||||
| Argument | Description |
|
||||
+================================+==============================+
|
||||
| outputFileNameWithoutExtension | Name of gnuplot related files|
|
||||
| | to write with no extension. |
|
||||
+--------------------------------+------------------------------+
|
||||
| title | Plot title string to use for |
|
||||
| | this plot. |
|
||||
+--------------------------------+------------------------------+
|
||||
| xLegend | The legend for the x |
|
||||
| | horizontal axis. |
|
||||
+--------------------------------+------------------------------+
|
||||
| yLegend | The legend for the y |
|
||||
| | vertical axis. |
|
||||
+--------------------------------+------------------------------+
|
||||
| terminalType | Terminal type setting string |
|
||||
| | for output. The default |
|
||||
| | terminal type is "png". |
|
||||
+--------------------------------+------------------------------+
|
||||
|
||||
The GnuplotHelper's ``ConfigurePlot()`` function configures plot
|
||||
related parameters for this gnuplot helper so
|
||||
that it will create a space separated gnuplot data file named
|
||||
outputFileNameWithoutExtension + ".dat", a gnuplot control file
|
||||
named outputFileNameWithoutExtension + ".plt", and a shell script
|
||||
to generate the gnuplot named outputFileNameWithoutExtension +
|
||||
".sh".
|
||||
|
||||
An example of how to use this function can be seen in the
|
||||
``seventh.cc`` code described above where it was used as follows:
|
||||
|
||||
::
|
||||
|
||||
plotHelper.ConfigurePlot ("seventh-packet-byte-count",
|
||||
"Packet Byte Count vs. Time",
|
||||
"Time (Seconds)",
|
||||
"Packet Byte Count",
|
||||
"png");
|
||||
|
||||
GnuplotHelper PlotProbe
|
||||
#######################
|
||||
|
||||
The GnuplotHelper's ``PlotProbe()`` function can be used
|
||||
to plot values generated by probes.
|
||||
|
||||
It has the following prototype:
|
||||
|
||||
::
|
||||
|
||||
void PlotProbe (const std::string &typeId,
|
||||
const std::string &path,
|
||||
const std::string &probeTraceSource,
|
||||
const std::string &title,
|
||||
enum GnuplotAggregator::KeyLocation keyLocation = GnuplotAggregator::KEY_INSIDE);
|
||||
|
||||
It has the following arguments:
|
||||
|
||||
+------------------+------------------------------+
|
||||
| Argument | Description |
|
||||
+==================+==============================+
|
||||
| typeId | The type ID for the probe |
|
||||
| | used when it is created. |
|
||||
+------------------+------------------------------+
|
||||
| path | Config path to access the |
|
||||
| | probe. |
|
||||
+------------------+------------------------------+
|
||||
| probeTraceSource | The probe trace source to |
|
||||
| | access. |
|
||||
+------------------+------------------------------+
|
||||
| title | The title to be associated |
|
||||
| | to this dataset |
|
||||
+------------------+------------------------------+
|
||||
| keyLocation | The location of the key in |
|
||||
| | the plot. The default |
|
||||
| | location is inside. |
|
||||
+------------------+------------------------------+
|
||||
|
||||
The GnuplotHelper's ``PlotProbe()`` function
|
||||
plots a dataset generated by hooking the |ns3| trace source with a
|
||||
probe, and then plotting the values from the probeTraceSource.
|
||||
The dataset will have the provided title, and will consist of
|
||||
the 'newValue' at each timestamp.
|
||||
|
||||
If the config path has more than one match in the system because
|
||||
there is a wildcard, then one dataset for each match will
|
||||
be plotted. The dataset titles will be suffixed with the matched
|
||||
characters for each of the wildcards in the config path,
|
||||
separated by spaces. For example, if the proposed dataset title
|
||||
is the string "bytes", and there are two wildcards in the path,
|
||||
then dataset titles like "bytes-0 0" or "bytes-12 9" will be
|
||||
possible as labels for the datasets that are plotted.
|
||||
|
||||
An example of how to use this function can be seen in the
|
||||
``seventh.cc`` code described above where it was used as follows:
|
||||
|
||||
::
|
||||
|
||||
plotHelper.PlotProbe ("ns3::Ipv4PacketProbe",
|
||||
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
|
||||
"OutputBytes",
|
||||
"Packet Byte Count",
|
||||
GnuplotAggregator::KEY_BELOW);
|
||||
|
||||
Other Examples
|
||||
##############
|
||||
|
||||
Gnuplot Helper Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A slightly simpler example than the ``seventh.cc`` example can be
|
||||
found in ``src/stats/examples/gnuplot-helper-example.cc``. It
|
||||
is more of a toy example than ``seventh.cc`` because it has
|
||||
a made-up trace source created for demonstration purposes.
|
||||
|
||||
The following 2-D gnuplot was created using the example.
|
||||
|
||||
.. _gnuplot-helper-example:
|
||||
|
||||
.. figure:: figures/gnuplot-helper-example.png
|
||||
|
||||
2-D Gnuplot Created by gnuplot-helper-example.cc Example.
|
||||
|
||||
In this example, there is an Emitter object that increments
|
||||
its counter at various random times and then emits the counter's
|
||||
value as a trace source.
|
||||
|
||||
::
|
||||
|
||||
Ptr<Emitter> emitter = CreateObject<Emitter> ();
|
||||
Names::Add ("/Names/Emitter", emitter);
|
||||
|
||||
The following code is probing the Counter exported by the
|
||||
emitter object. This DoubleProbe is using a path in the
|
||||
configuration namespace to make the connection. Note that
|
||||
the emitter registered itself in the configuration namespace
|
||||
after it was created; otherwise, the ConnectByPath would not work.
|
||||
|
||||
::
|
||||
|
||||
Ptr<DoubleProbe> probe = CreateObject<DoubleProbe> ();
|
||||
probe->SetName ("PathProbe");
|
||||
Names::Add ("/Names/Probe", probe);
|
||||
|
||||
// Note, no return value is checked here.
|
||||
probe->ConnectByPath ("/Names/Emitter/Counter");
|
||||
|
||||
Note that because there are no wildcards in the path
|
||||
used below, only 1 datastream was drawn in the plot.
|
||||
This single datastream in the plot is simply labeled
|
||||
"Emitter Count", with no extra suffixes like you would
|
||||
see if there were wildcards in the path.
|
||||
|
||||
::
|
||||
|
||||
// Create the gnuplot helper.
|
||||
GnuplotHelper plotHelper;
|
||||
|
||||
// Configure the plot.
|
||||
plotHelper.ConfigurePlot ("gnuplot-helper-example",
|
||||
"Emitter Counts vs. Time",
|
||||
"Time (Seconds)",
|
||||
"Emitter Count",
|
||||
"png");
|
||||
|
||||
// Plot the values generated by the probe. The path that we provide
|
||||
// helps to disambiguate the source of the trace.
|
||||
plotHelper.PlotProbe ("ns3::DoubleProbe",
|
||||
"/Names/Probe/Output",
|
||||
"Output",
|
||||
"Emitter Count",
|
||||
GnuplotAggregator::KEY_INSIDE);
|
||||
|
||||
FileHelper
|
||||
==========
|
||||
|
||||
The FileHelper is a helper class used to put data values into a file.
|
||||
The overall goal is to provide the ability for users
|
||||
to quickly make formatted text files from data exported in |ns3|
|
||||
trace sources. By default, a minimal amount of data transformation is
|
||||
performed; the objective is to generate files with as few (default)
|
||||
configuration statements as possible.
|
||||
|
||||
FileHelper Overview
|
||||
###################
|
||||
|
||||
The FileHelper will create 1 or more text files at the end of the
|
||||
simulation.
|
||||
|
||||
The FileHelper can create 4 different types of text files:
|
||||
|
||||
- Formatted
|
||||
- Space separated (the default)
|
||||
- Comma separated
|
||||
- Tab separated
|
||||
|
||||
Formatted files use C-style format strings and the sprintf() function
|
||||
to print their values in the file being written.
|
||||
|
||||
The following text file with 2 columns of formatted values named
|
||||
``seventh-packet-byte-count-0.txt`` was created using more new
|
||||
code that was added to the original |ns3| Tutorial example's code.
|
||||
Only the first 10 lines of this file are shown here for brevity.
|
||||
|
||||
::
|
||||
|
||||
Time (Seconds) = 1.000e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.004e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.004e+00 Packet Byte Count = 576
|
||||
Time (Seconds) = 1.009e+00 Packet Byte Count = 576
|
||||
Time (Seconds) = 1.009e+00 Packet Byte Count = 576
|
||||
Time (Seconds) = 1.015e+00 Packet Byte Count = 512
|
||||
Time (Seconds) = 1.017e+00 Packet Byte Count = 576
|
||||
Time (Seconds) = 1.017e+00 Packet Byte Count = 544
|
||||
Time (Seconds) = 1.025e+00 Packet Byte Count = 576
|
||||
Time (Seconds) = 1.025e+00 Packet Byte Count = 544
|
||||
|
||||
...
|
||||
|
||||
The following different text file with 2 columns of formatted
|
||||
values named ``seventh-packet-byte-count-1.txt`` was also
|
||||
created using the same new code that was added to the original
|
||||
|ns3| Tutorial example's code. Only the first 10 lines of this
|
||||
file are shown here for brevity.
|
||||
|
||||
::
|
||||
|
||||
Time (Seconds) = 1.002e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.007e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.013e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.020e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.028e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.036e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.045e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.053e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.061e+00 Packet Byte Count = 40
|
||||
Time (Seconds) = 1.069e+00 Packet Byte Count = 40
|
||||
|
||||
...
|
||||
|
||||
The new code that was added to produce the two text files is below.
|
||||
More details about this API will be covered in a later section.
|
||||
|
||||
Note that because there were 2 matches for the wildcard in the path,
|
||||
2 separate text files were created. The first text file, which is
|
||||
named "seventh-packet-byte-count-0.txt", corresponds to the
|
||||
wildcard match with the "*" replaced with "0". The second text file,
|
||||
which is named "seventh-packet-byte-count-1.txt", corresponds to
|
||||
the wildcard match with the "*" replaced with "1". Also, note that
|
||||
the function call to ``WriteProbe()`` will give an error message if
|
||||
there are no matches for a path that contains wildcards.
|
||||
|
||||
::
|
||||
|
||||
// Create the file helper.
|
||||
FileHelper fileHelper;
|
||||
|
||||
// Configure the file to be written.
|
||||
fileHelper.ConfigureFile ("seventh-packet-byte-count",
|
||||
FileAggregator::FORMATTED);
|
||||
|
||||
// Set the labels for this formatted output file.
|
||||
fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
|
||||
|
||||
// Write the values generated by the probe.
|
||||
fileHelper.WriteProbe ("ns3::Ipv4PacketProbe",
|
||||
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
|
||||
"OutputBytes");
|
||||
|
||||
FileHelper ConfigureFile
|
||||
########################
|
||||
|
||||
The FileHelper's ``ConfigureFile()`` function can be used
|
||||
to configure text files.
|
||||
|
||||
It has the following prototype:
|
||||
|
||||
::
|
||||
|
||||
void ConfigureFile (const std::string &outputFileNameWithoutExtension,
|
||||
enum FileAggregator::FileType fileType = FileAggregator::SPACE_SEPARATED);
|
||||
|
||||
It has the following arguments:
|
||||
|
||||
+--------------------------------+------------------------------+
|
||||
| Argument | Description |
|
||||
+================================+==============================+
|
||||
| outputFileNameWithoutExtension | Name of output file to write |
|
||||
| | with no extension. |
|
||||
+--------------------------------+------------------------------+
|
||||
| fileType | Type of file to write. The |
|
||||
| | default type of file is space|
|
||||
| | separated. |
|
||||
+--------------------------------+------------------------------+
|
||||
|
||||
The FileHelper's ``ConfigureFile()`` function configures text file
|
||||
related parameters for the file helper so that
|
||||
it will create a file named outputFileNameWithoutExtension plus
|
||||
possible extra information from wildcard matches plus ".txt" with
|
||||
values printed as specified by fileType. The default file type
|
||||
is space-separated.
|
||||
|
||||
An example of how to use this function can be seen in the
|
||||
``seventh.cc`` code described above where it was used as follows:
|
||||
|
||||
::
|
||||
|
||||
fileHelper.ConfigureFile ("seventh-packet-byte-count",
|
||||
FileAggregator::FORMATTED);
|
||||
|
||||
FileHelper WriteProbe
|
||||
#####################
|
||||
|
||||
The FileHelper's ``WriteProbe()`` function can be used
|
||||
to write values generated by probes to text files.
|
||||
|
||||
It has the following prototype:
|
||||
|
||||
::
|
||||
|
||||
void WriteProbe (const std::string &typeId,
|
||||
const std::string &path,
|
||||
const std::string &probeTraceSource);
|
||||
|
||||
It has the following arguments:
|
||||
|
||||
+------------------+------------------------------+
|
||||
| Argument | Description |
|
||||
+==================+==============================+
|
||||
| typeId | The type ID for the probe |
|
||||
| | used when it is created. |
|
||||
+------------------+------------------------------+
|
||||
| path | Config path to access the |
|
||||
| | probe. |
|
||||
+------------------+------------------------------+
|
||||
| probeTraceSource | The probe trace source to |
|
||||
| | access. |
|
||||
+------------------+------------------------------+
|
||||
|
||||
The FileHelper's ``WriteProbe()`` function
|
||||
creates output text files generated by hooking the ns-3 trace source
|
||||
with a probe, and then writing the values from the
|
||||
probeTraceSource. The output file names will have the text stored
|
||||
in the member variable m_outputFileNameWithoutExtension plus ".txt",
|
||||
and will consist of the 'newValue' at each timestamp.
|
||||
|
||||
If the config path has more than one match in the system because
|
||||
there is a wildcard, then one output file for each match
|
||||
will be created. The output file names will contain the text in
|
||||
m_outputFileNameWithoutExtension plus the matched characters for
|
||||
each of the wildcards in the config path, separated by dashes,
|
||||
plus ".txt". For example, if the value in
|
||||
m_outputFileNameWithoutExtension is the string
|
||||
"packet-byte-count", and there are two wildcards in the path,
|
||||
then output file names like "packet-byte-count-0-0.txt" or
|
||||
"packet-byte-count-12-9.txt" will be possible as names for the
|
||||
files that will be created.
|
||||
|
||||
An example of how to use this function can be seen in the
|
||||
``seventh.cc`` code described above where it was used as follows:
|
||||
|
||||
::
|
||||
|
||||
fileHelper.WriteProbe ("ns3::Ipv4PacketProbe",
|
||||
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
|
||||
"OutputBytes");
|
||||
|
||||
Other Examples
|
||||
##############
|
||||
|
||||
File Helper Example
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A slightly simpler example than the ``seventh.cc`` example can be
|
||||
found in ``src/stats/examples/file-helper-example.cc``.
|
||||
This example only uses the FileHelper, not the FileHelper. It
|
||||
is also more of a toy example than ``seventh.cc`` because it has
|
||||
a made-up trace source created for demonstration purposes.
|
||||
|
||||
The following text file with 2 columns of formatted values named
|
||||
``file-helper-example.txt`` was created using the example.
|
||||
Only the first 10 lines of this file are shown here for brevity.
|
||||
|
||||
::
|
||||
|
||||
Time (Seconds) = 4.995e-01 Count = 1
|
||||
Time (Seconds) = 1.463e+00 Count = 2
|
||||
Time (Seconds) = 1.678e+00 Count = 3
|
||||
Time (Seconds) = 3.972e+00 Count = 4
|
||||
Time (Seconds) = 4.150e+00 Count = 5
|
||||
Time (Seconds) = 8.066e+00 Count = 6
|
||||
Time (Seconds) = 8.731e+00 Count = 7
|
||||
Time (Seconds) = 9.807e+00 Count = 8
|
||||
Time (Seconds) = 1.078e+01 Count = 9
|
||||
Time (Seconds) = 1.083e+01 Count = 10
|
||||
|
||||
...
|
||||
|
||||
In this example, there is an Emitter object that increments
|
||||
its counter at various random times and then emits the counter's
|
||||
value as a trace source.
|
||||
|
||||
::
|
||||
|
||||
Ptr<Emitter> emitter = CreateObject<Emitter> ();
|
||||
Names::Add ("/Names/Emitter", emitter);
|
||||
|
||||
The following code is probing the Counter exported by the
|
||||
emitter object. This DoubleProbe is using a path in the
|
||||
configuration namespace to make the connection. Note that
|
||||
the emitter registered itself in the configuration namespace
|
||||
after it was created; otherwise, the ConnectByPath would not work.
|
||||
|
||||
::
|
||||
|
||||
Ptr<DoubleProbe> probe = CreateObject<DoubleProbe> ();
|
||||
probe->SetName ("PathProbe");
|
||||
Names::Add ("/Names/Probe", probe);
|
||||
|
||||
// Note, no return value is checked here.
|
||||
probe->ConnectByPath ("/Names/Emitter/Counter");
|
||||
|
||||
Note that because there are no wildcards in the path
|
||||
used below, only 1 text file was created.
|
||||
This single text file is simply named
|
||||
"file-helper-example.txt", with no extra suffixes like
|
||||
you would see if there were wildcards in the path.
|
||||
|
||||
::
|
||||
|
||||
// Create the file helper.
|
||||
FileHelper fileHelper;
|
||||
|
||||
// Configure the file to be written.
|
||||
fileHelper.ConfigureFile ("file-helper-example",
|
||||
FileAggregator::FORMATTED);
|
||||
|
||||
// Set the labels for this formatted output file.
|
||||
fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tCount = %.0f");
|
||||
|
||||
// Write the values generated by the probe. The path that we
|
||||
// provide helps to disambiguate the source of the trace.
|
||||
fileHelper.WriteProbe ("ns3::DoubleProbe",
|
||||
"/Names/Probe/Output",
|
||||
"Output");
|
||||
|
||||
Scope and Limitations
|
||||
=====================
|
||||
|
||||
Currently, only these Probes have been implemented and connected
|
||||
to the GnuplotHelper and to the FileHelper:
|
||||
|
||||
- BooleanProbe
|
||||
- DoubleProbe
|
||||
- Uinteger8Probe
|
||||
- Uinteger16Probe
|
||||
- Uinteger32Probe
|
||||
- PacketProbe
|
||||
- ApplicationPacketProbe
|
||||
- Ipv4PacketProbe
|
||||
|
||||
These Probes, therefore, are the only ones available to be used
|
||||
in ``PlotProbe()`` and ``WriteProbe()``.
|
||||
|
||||
In the next few sections, we cover each of the fundamental object
|
||||
types (Probe, Collector, and Aggregator) in more detail, and show
|
||||
how they can be connected together using lower-level API.
|
||||
65
src/stats/doc/data-collection-overview.rst
Normal file
65
src/stats/doc/data-collection-overview.rst
Normal file
@@ -0,0 +1,65 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
Design
|
||||
******
|
||||
|
||||
The DCF consists of three basic classes:
|
||||
|
||||
* *Probe* is a mechanism to instrument and control the output of
|
||||
simulation data that is used to monitor interesting events. It
|
||||
produces output in the form of one or more |ns3| trace sources.
|
||||
Probe objects are hooked up to one or more trace *sinks* (called
|
||||
*Collectors*), which process samples on-line and prepare them for
|
||||
output.
|
||||
|
||||
* *Collector* consumes the data generated by one or more Probe objects.
|
||||
It performs transformations on the data, such as normalization, reduction, and
|
||||
the computation of basic statistics. Collector objects do not produce
|
||||
data that is directly output by the ns-3 run; instead, they output data
|
||||
downstream to another type of object, called *Aggregator*, which performs
|
||||
that function. Typically, Collectors output their data in the form of
|
||||
trace sources as well, allowing collectors to be chained in series.
|
||||
|
||||
* *Aggregator* is the end point of the data collected by a network of Probes and Collectors.
|
||||
The main responsibility of the Aggregator is to marshal data and their
|
||||
corresponding metadata, into different output
|
||||
formats such as plain text files, spreadsheet files, or databases.
|
||||
|
||||
All three of these classes provide the capability to dynamically turn themselves on or off throughout a simulation.
|
||||
|
||||
Any standalone |ns3| simulation run that uses the DCF will typically create
|
||||
at least one instance of each of the three classes above.
|
||||
|
||||
.. _dcf-overview:
|
||||
|
||||
.. figure:: figures/dcf-overview.*
|
||||
|
||||
Data Collection Framework overview
|
||||
|
||||
The overall flow of data processing is depicted in :ref:`dcf-overview`. On
|
||||
the left side, a running |ns3| simulation is depicted. In the course
|
||||
of running the simulation, data is made available by models through
|
||||
trace sources, or via other means. The diagram depicts that probes
|
||||
can be connected to these trace sources to receive data asynchronously,
|
||||
or probes can poll for data. Data is then passed to a collector object
|
||||
that transforms the data. Finally, an aggregator can be connected
|
||||
to the outputs of the collector, to generate plots, files, or databases.
|
||||
|
||||
.. _dcf-overview-with-aggregation:
|
||||
|
||||
.. figure:: figures/dcf-overview-with-aggregation.*
|
||||
|
||||
Data Collection Framework aggregation
|
||||
|
||||
A variation on the above figure is provided
|
||||
in :ref:`dcf-overview-with-aggregation`.
|
||||
This second figure illustrates that the DCF objects may be chained
|
||||
together in a manner that downstream objects take inputs from multiple
|
||||
upstream objects. The figure conceptually shows that multiple probes
|
||||
may generate output that is fed into a single collector; as an example,
|
||||
a collector that outputs a ratio of two counters would typically acquire
|
||||
each counter data from separate probes. Multiple collectors can also
|
||||
feed into a single aggregator, which (as its name implies) may collect
|
||||
a number of data streams for inclusion into a single plot, file, or
|
||||
database.
|
||||
|
||||
36
src/stats/doc/data-collection.rst
Normal file
36
src/stats/doc/data-collection.rst
Normal file
@@ -0,0 +1,36 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
Data Collection
|
||||
---------------
|
||||
|
||||
This chapter describes the ns-3 Data Collection Framework (DCF), which
|
||||
provides capabilities to obtain data generated by models in the simulator,
|
||||
to perform on-line reduction and data processing, and to marshal raw
|
||||
or transformed data into various output formats.
|
||||
|
||||
The framework presently supports standalone ns-3 runs that don't rely on
|
||||
any external program execution control. The objects provided by the
|
||||
DCF may be hooked to |ns3| trace sources to enable data processing.
|
||||
|
||||
The source code for the classes lives in the directory ``src/stats``.
|
||||
|
||||
This chapter is organized as follows. First, an overview of the architecture
|
||||
is presented. Next, the helpers for these classes are presented; this
|
||||
initial treatment should allow basic use of the data collection framework
|
||||
for many use cases. Users who wish to produce output outside of the
|
||||
scope of the current helpers, or who wish to create their own data
|
||||
collection objects, should read the remainder of the chapter, which
|
||||
goes into detail about all of the basic DCF object types and provides
|
||||
low-level coding examples.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
data-collection-overview.rst
|
||||
data-collection-helpers.rst
|
||||
probe.rst
|
||||
collector.rst
|
||||
aggregator.rst
|
||||
adaptor.rst
|
||||
scope-and-limitations.rst
|
||||
|
||||
BIN
src/stats/doc/dcf-overview-with-aggregation.dia
Normal file
BIN
src/stats/doc/dcf-overview-with-aggregation.dia
Normal file
Binary file not shown.
BIN
src/stats/doc/dcf-overview.dia
Normal file
BIN
src/stats/doc/dcf-overview.dia
Normal file
Binary file not shown.
468
src/stats/doc/probe.rst
Normal file
468
src/stats/doc/probe.rst
Normal file
@@ -0,0 +1,468 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
.. heading hierarchy:
|
||||
************* Section (#.#)
|
||||
============= Subsection (#.#.#)
|
||||
############# Paragraph (no number)
|
||||
~~~~~~~~~~~~~ Sub-paragraph (no number)
|
||||
|
||||
Probes
|
||||
******
|
||||
|
||||
This section details the functionalities provided by the Probe class
|
||||
to an |ns3| simulation, and gives examples on how to code them in a
|
||||
program. This section is meant for users interested in developing
|
||||
simulations with the |ns3| tools and using the Data Collection
|
||||
Framework, of which the Probe class is a part, to generate data output
|
||||
with their simulation's results.
|
||||
|
||||
Probe Overview
|
||||
==============
|
||||
|
||||
A Probe object is supposed to be connected to a variable from the
|
||||
simulation whose values throughout the experiment are relevant to the user.
|
||||
The Probe will record what were values assumed by the variable throughout
|
||||
the simulation and pass such data to another member of the Data Collection
|
||||
Framework. While it is out of this section's scope to discuss what happens
|
||||
after the Probe produces its output, it is sufficient to say that, by the
|
||||
end of the simulation, the user will have detailed information about what
|
||||
values were stored inside the variable being probed during the simulation.
|
||||
|
||||
Typically, a Probe is connected to an |ns3| trace source. In this manner,
|
||||
whenever the trace source exports a new value, the Probe consumes the
|
||||
value (and exports it downstream to another object via its own trace source).
|
||||
|
||||
The Probe can be thought of as kind of a filter on trace sources. The
|
||||
main reasons for possibly hooking to a Probe rather than directly to a
|
||||
trace source are as follows:
|
||||
|
||||
* Probes may be dynamically turned on and off during the simulation
|
||||
with calls to ``Enable()`` and ``Disable()``. For example, the
|
||||
outputting of data may be turned off during the simulation warmup
|
||||
phase.
|
||||
* Probes may perform operations on the data to extract values from more
|
||||
complicated structures; for instance, outputting the packet size value
|
||||
from a received ns3::Packet.
|
||||
* Probes register a name in the ns3::Config namespace (using
|
||||
``Names::Add ()``) so that other objects may refer to them.
|
||||
* Probes provide a static method that allows one to manipulate a Probe
|
||||
by name, such as what is done in ns2measure [Cic06]_ ::
|
||||
|
||||
Stat::put ("my_metric", ID, sample);
|
||||
|
||||
The ns-3 equivalent of the above ns2measure code is, e.g.::
|
||||
|
||||
DoubleProbe::SetValueByPath ("/path/to/probe", sample);
|
||||
|
||||
Creation
|
||||
########
|
||||
|
||||
Note that a Probe base class object can not be created because it
|
||||
is an abstract base class, i.e. it has pure virtual functions that
|
||||
have not been implemented. An object of type DoubleProbe,
|
||||
which is a subclass of the Probe class, will be created here to
|
||||
show what needs to be done.
|
||||
|
||||
One declares a DoubleProbe in dynamic memory by using the smart pointer class
|
||||
(Ptr<T>). To create a DoubleProbe in dynamic memory with smart pointers, one
|
||||
just needs to call the |ns3| method ``CreateObject()``:
|
||||
|
||||
::
|
||||
|
||||
Ptr<DoubleProbe> myprobe = CreateObject<DoubleProbe> ();
|
||||
|
||||
The declaration above creates DoubleProbes using the default values for its
|
||||
attributes. There are four attributes in the DoubleProbe class; two in the
|
||||
base class object DataCollectionObject, and two in the Probe base class:
|
||||
|
||||
* "Name" (DataCollectionObject), a StringValue
|
||||
* "Enabled" (DataCollectionObject), a BooleanValue
|
||||
* "Start" (Probe), a TimeValue
|
||||
* "Stop" (Probe), a TimeValue
|
||||
|
||||
One can set such attributes at object creation by using the following
|
||||
method:
|
||||
|
||||
::
|
||||
|
||||
Ptr<DoubleProbe> myprobe = CreateObjectWithAttributes<DoubleProbe> (
|
||||
"Name", StringValue ("myprobe"),
|
||||
"Enabled", BooleanValue (false),
|
||||
"Start", TimeValue (Seconds (100.0)),
|
||||
"Stop", TimeValue (Seconds (1000.0)));
|
||||
|
||||
Start and Stop are Time variables which determine the interval of action
|
||||
of the Probe. The Probe will only output data if the current time of the
|
||||
Simulation is inside of that interval. The special time value of 0 seconds
|
||||
for Stop will disable this attribute (i.e. keep the Probe on for the whole
|
||||
simulation). Enabled is a flag that turns the
|
||||
Probe on or off, and must be set to true for the Probe to export data.
|
||||
The Name is the object's name in the DCF framework.
|
||||
|
||||
Importing and exporting data
|
||||
############################
|
||||
|
||||
|ns3| trace sources are strongly typed, so the mechanisms for hooking
|
||||
Probes to a trace source and for exporting data belong to its
|
||||
subclasses. For instance, the default distribution of |ns3| provides
|
||||
a class DoubleProbe that is designed to hook to a trace source
|
||||
exporting a double value. We'll next detail the operation of the
|
||||
DoubleProbe, and then discuss how other Probe classes may be defined
|
||||
by the user.
|
||||
|
||||
DoubleProbe Overview
|
||||
====================
|
||||
|
||||
The DoubleProbe connects to a double-valued |ns3| trace source, and itself
|
||||
exports a different double-valued |ns3| trace source.
|
||||
|
||||
The following code, drawn from
|
||||
``src/stats/examples/double-probe-example.cc``, shows the basic
|
||||
operations of plumbing the DoubleProbe into a simulation, where it is
|
||||
probing a Counter exported by an emitter object (class Emitter).
|
||||
|
||||
::
|
||||
|
||||
Ptr<Emitter> emitter = CreateObject<Emitter> ();
|
||||
Names::Add ("/Names/Emitter", emitter);
|
||||
...
|
||||
|
||||
Ptr<DoubleProbe> probe1 = CreateObject<DoubleProbe> ();
|
||||
|
||||
// Connect the probe to the emitter's Counter
|
||||
bool connected = probe1->ConnectByObject ("Counter", emitter);
|
||||
|
||||
The following code is probing the same Counter exported by the same
|
||||
emitter object. This DoubleProbe, however, is using a path in the
|
||||
configuration namespace to make the connection. Note that the emitter
|
||||
registered itself in the configuration namespace after it was created;
|
||||
otherwise, the ConnectByPath would not work.
|
||||
|
||||
::
|
||||
|
||||
Ptr<DoubleProbe> probe2 = CreateObject<DoubleProbe> ();
|
||||
|
||||
// Note, no return value is checked here
|
||||
probe2->ConnectByPath ("/Names/Emitter/Counter");
|
||||
|
||||
The next DoubleProbe shown that is shown below will have its value set using
|
||||
its path in the configuration namespace. Note that this time the
|
||||
DoubleProbe registered itself in the configuration namespace after it was
|
||||
created.
|
||||
|
||||
::
|
||||
|
||||
Ptr<DoubleProbe> probe3 = CreateObject<DoubleProbe> ();
|
||||
probe3->SetName ("StaticallyAccessedProbe");
|
||||
|
||||
// We must add it to the config database
|
||||
Names::Add ("/Names/Probes", probe3->GetName (), probe3);
|
||||
|
||||
The emitter's Count() function is now able to set the value for this DoubleProbe as follows:
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
Emitter::Count (void)
|
||||
{
|
||||
...
|
||||
m_counter += 1.0;
|
||||
DoubleProbe::SetValueByPath ("/Names/StaticallyAccessedProbe", m_counter);
|
||||
...
|
||||
}
|
||||
|
||||
The above example shows how the code calling the Probe does not have to
|
||||
have an explicit reference to the Probe, but can direct the value
|
||||
setting through the Config namespace. This is similar in functionality
|
||||
to the `Stat::Put` method introduced by ns2measure paper [Cic06]_, and allows
|
||||
users to temporarily insert Probe statements like `printf` statements within
|
||||
existing |ns3| models. Note that in order to be able to use the DoubleProbe in this example like this, 2 things were necessary:
|
||||
|
||||
1. the stats module header file was included in the example .cc file
|
||||
2. the example was made dependent on the stats module in its wscript file.
|
||||
|
||||
Analogous things need to be done in order to add other Probes in other places in the |ns3| code base.
|
||||
|
||||
The values for the DoubleProbe can also be set using the function
|
||||
DoubleProbe::SetValue(), while the values for the DoubleProbe can be gotten
|
||||
using the function DoubleProbe::GetValue().
|
||||
|
||||
The DoubleProbe exports double values in its "Output" trace source;
|
||||
a downstream object can hook a trace sink (NotifyViaProbe) to this as follows:
|
||||
|
||||
::
|
||||
|
||||
connected = probe1->TraceConnect ("Output", probe1->GetName (), MakeCallback (&NotifyViaProbe));
|
||||
|
||||
|
||||
Other probes
|
||||
============
|
||||
|
||||
Besides the DoubleProbe, the following Probes are also available:
|
||||
|
||||
- Uinteger8Probe connects to an |ns3| trace source exporting an uint8_t.
|
||||
- Uinteger16Probe connects to an |ns3| trace source exporting an uint16_t.
|
||||
- Uinteger32Probe connects to an |ns3| trace source exporting an uint32_t.
|
||||
- PacketProbe connects to an |ns3| trace source exporting a packet.
|
||||
- ApplicationPacketProbe connects to an |ns3| trace source exporting a packet and a socket address.
|
||||
- Ipv4PacketProbe connects to an |ns3| trace source exporting a packet, an IPv4 object, and an interface.
|
||||
|
||||
Creating new Probe types
|
||||
========================
|
||||
|
||||
To create a new Probe type, you need to perform the following steps:
|
||||
|
||||
- Be sure that your new Probe class is derived from the Probe base class.
|
||||
- Be sure that the pure virtual functions that your new Probe class
|
||||
inherits from the Probe base class are implemented.
|
||||
- Find an existing Probe class that uses a trace source that is
|
||||
closest in type to the type of trace source your Probe will be
|
||||
using.
|
||||
- Copy that existing Probe class's header file (.h) and implementation
|
||||
file (.cc) to two new files with names matching your new Probe.
|
||||
- Replace the types, arguments, and variables in the copied files with
|
||||
the appropriate type for your Probe.
|
||||
- Make necessary modifications to make the code compile and to make it
|
||||
behave as you would like.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Two examples will be discussed in detail here:
|
||||
|
||||
- Double Probe Example
|
||||
- IPv4 Packet Plot Example
|
||||
|
||||
Double Probe Example
|
||||
####################
|
||||
|
||||
The double probe example has been discussed previously. The example
|
||||
program can be found in
|
||||
``src/stats/examples/double-probe-example.cc``. To
|
||||
summarize what occurs in this program, there is an emitter that
|
||||
exports a counter that increments according to a Poisson process. In
|
||||
particular, two ways of emitting data are shown:
|
||||
|
||||
1. through a traced variable hooked to one Probe:
|
||||
|
||||
::
|
||||
|
||||
TracedValue<double> m_counter; // normally this would be integer type
|
||||
|
||||
2. through a counter whose value is posted to a second Probe, referenced by its name in the Config system:
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
Emitter::Count (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_DEBUG ("Counting at " << Simulator::Now ().GetSeconds ());
|
||||
m_counter += 1.0;
|
||||
DoubleProbe::SetValueByPath ("/Names/StaticallyAccessedProbe", m_counter);
|
||||
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
|
||||
}
|
||||
|
||||
Let's look at the Probe more carefully. Probes can receive their values
|
||||
in a multiple ways:
|
||||
|
||||
1. by the Probe accessing the trace source directly and connecting
|
||||
a trace sink to it
|
||||
2. by the Probe accessing the trace source through the config namespace
|
||||
and connecting a trace sink to it
|
||||
3. by the calling code explicitly calling the Probe's `SetValue()` method
|
||||
4. by the calling code explicitly calling `SetValueByPath ("/path/through/Config/namespace", ...)`
|
||||
|
||||
The first two techniques are expected to be the most common. Also in the
|
||||
example, the hooking of a normal callback function is shown,
|
||||
as is typically done in |ns3|. This callback function is not associated
|
||||
with a Probe object. We'll call this case 0) below.
|
||||
|
||||
::
|
||||
|
||||
// This is a function to test hooking a raw function to the trace source
|
||||
void
|
||||
NotifyViaTraceSource (std::string context, double oldVal, double newVal)
|
||||
{
|
||||
NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
|
||||
}
|
||||
|
||||
First, the emitter needs to be setup:
|
||||
|
||||
::
|
||||
|
||||
Ptr<Emitter> emitter = CreateObject<Emitter> ();
|
||||
Names::Add ("/Names/Emitter", emitter);
|
||||
|
||||
// The Emitter object is not associated with an ns-3 node, so
|
||||
// it won't get started automatically, so we need to do this ourselves
|
||||
Simulator::Schedule (Seconds (0.0), &Emitter::Start, emitter);
|
||||
|
||||
The various DoubleProbes interact with the emitter in the example as
|
||||
shown below.
|
||||
|
||||
Case 0):
|
||||
|
||||
::
|
||||
|
||||
// The below shows typical functionality without a probe
|
||||
// (connect a sink function to a trace source)
|
||||
//
|
||||
connected = emitter->TraceConnect ("Counter", "sample context", MakeCallback (&NotifyViaTraceSource));
|
||||
NS_ASSERT_MSG (connected, "Trace source not connected");
|
||||
|
||||
|
||||
case 1):
|
||||
|
||||
::
|
||||
|
||||
//
|
||||
// Probe1 will be hooked directly to the Emitter trace source object
|
||||
//
|
||||
|
||||
// probe1 will be hooked to the Emitter trace source
|
||||
Ptr<DoubleProbe> probe1 = CreateObject<DoubleProbe> ();
|
||||
// the probe's name can serve as its context in the tracing
|
||||
probe1->SetName ("ObjectProbe");
|
||||
|
||||
// Connect the probe to the emitter's Counter
|
||||
connected = probe1->ConnectByObject ("Counter", emitter);
|
||||
NS_ASSERT_MSG (connected, "Trace source not connected to probe1");
|
||||
|
||||
case 2):
|
||||
|
||||
::
|
||||
|
||||
//
|
||||
// Probe2 will be hooked to the Emitter trace source object by
|
||||
// accessing it by path name in the Config database
|
||||
//
|
||||
|
||||
// Create another similar probe; this will hook up via a Config path
|
||||
Ptr<DoubleProbe> probe2 = CreateObject<DoubleProbe> ();
|
||||
probe2->SetName ("PathProbe");
|
||||
|
||||
// Note, no return value is checked here
|
||||
probe2->ConnectByPath ("/Names/Emitter/Counter");
|
||||
|
||||
case 4) (case 3 is not shown in this example):
|
||||
|
||||
::
|
||||
|
||||
//
|
||||
// Probe3 will be called by the emitter directly through the
|
||||
// static method SetValueByPath().
|
||||
//
|
||||
Ptr<DoubleProbe> probe3 = CreateObject<DoubleProbe> ();
|
||||
probe3->SetName ("StaticallyAccessedProbe");
|
||||
// We must add it to the config database
|
||||
Names::Add ("/Names/Probes", probe3->GetName (), probe3);
|
||||
|
||||
And finally, the example shows how the probes can be hooked to
|
||||
generate output:
|
||||
|
||||
::
|
||||
|
||||
// The probe itself should generate output. The context that we provide
|
||||
// to this probe (in this case, the probe name) will help to disambiguate
|
||||
// the source of the trace
|
||||
connected = probe3->TraceConnect ("Output", "/Names/Probes/StaticallyAccessedProbe/Output", MakeCallback (&NotifyViaProbe));
|
||||
NS_ASSERT_MSG (connected, "Trace source not .. connected to probe3 Output");
|
||||
|
||||
The following callback is hooked to the Probe in this example for
|
||||
illustrative purposes; normally, the Probe would be hooked to a
|
||||
Collector object.
|
||||
|
||||
::
|
||||
|
||||
// This is a function to test hooking it to the probe output
|
||||
void
|
||||
NotifyViaProbe (std::string context, double oldVal, double newVal)
|
||||
{
|
||||
NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
|
||||
}
|
||||
|
||||
|
||||
IPv4 Packet Plot Example
|
||||
########################
|
||||
|
||||
The IPv4 packet plot example is based on the fifth.cc example from the |ns3|
|
||||
Tutorial. It can be found in
|
||||
``src/stats/examples/ipv4-packet-plot-example.cc``.
|
||||
|
||||
::
|
||||
|
||||
// ===========================================================================
|
||||
//
|
||||
// node 0 node 1
|
||||
// +----------------+ +----------------+
|
||||
// | ns-3 TCP | | ns-3 TCP |
|
||||
// +----------------+ +----------------+
|
||||
// | 10.1.1.1 | | 10.1.1.2 |
|
||||
// +----------------+ +----------------+
|
||||
// | point-to-point | | point-to-point |
|
||||
// +----------------+ +----------------+
|
||||
// | |
|
||||
// +---------------------+
|
||||
|
||||
|
||||
|
||||
We'll just look at the Probe, as it illustrates that Probes may also
|
||||
unpack values from structures (in this case, packets) and report
|
||||
those values as trace source outputs, rather than just passing through
|
||||
the same type of data.
|
||||
|
||||
There are other aspects of this example that will be explained later in
|
||||
the documentation. The two types of data that are exported are the packet
|
||||
itself (`Output`) and a count of the number of bytes in the packet
|
||||
(`OutputBytes`).
|
||||
|
||||
::
|
||||
|
||||
TypeId
|
||||
Ipv4PacketProbe::GetTypeId ()
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::Ipv4PacketProbe")
|
||||
.SetParent<Probe> ()
|
||||
.AddConstructor<Ipv4PacketProbe> ()
|
||||
.AddTraceSource ( "Output",
|
||||
"The packet plus its IPv4 object and interface that serve as the output for this probe",
|
||||
MakeTraceSourceAccessor (&Ipv4PacketProbe::m_output))
|
||||
.AddTraceSource ( "OutputBytes",
|
||||
"The number of bytes in the packet",
|
||||
MakeTraceSourceAccessor (&Ipv4PacketProbe::m_outputBytes))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
When the Probe's trace sink gets a packet, if the Probe is enabled, then
|
||||
it will output the packet on its `Output` trace source, but it will also
|
||||
output the number of bytes on the `OutputBytes` trace source.
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
Ipv4PacketProbe::TraceSink (Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << packet << ipv4 << interface);
|
||||
if (IsEnabled ())
|
||||
{
|
||||
m_packet = packet;
|
||||
m_ipv4 = ipv4;
|
||||
m_interface = interface;
|
||||
m_output (packet, ipv4, interface);
|
||||
|
||||
uint32_t packetSizeNew = packet->GetSize ();
|
||||
m_outputBytes (m_packetSizeOld, packetSizeNew);
|
||||
m_packetSizeOld = packetSizeNew;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [Cic06] Claudio Cicconetti, Enzo Mingozzi, Giovanni Stea, "An Integrated
|
||||
Framework for Enabling Effective Data Collection and Statistical
|
||||
Analysis with ns2, Workshop on ns-2 (WNS2), Pisa, Italy, October 2006.
|
||||
50
src/stats/doc/scope-and-limitations.rst
Normal file
50
src/stats/doc/scope-and-limitations.rst
Normal file
@@ -0,0 +1,50 @@
|
||||
.. include:: replace.txt
|
||||
|
||||
.. heading hierarchy:
|
||||
************* Section (#.#)
|
||||
============= Subsection (#.#.#)
|
||||
############# Paragraph (no number)
|
||||
|
||||
Scope/Limitations
|
||||
*****************
|
||||
|
||||
This section discusses the scope and limitations of the Data
|
||||
Collection Framework.
|
||||
|
||||
Currently, only these Probes have been implemented in DCF:
|
||||
|
||||
- BooleanProbe
|
||||
- DoubleProbe
|
||||
- Uinteger8Probe
|
||||
- Uinteger16Probe
|
||||
- Uinteger32Probe
|
||||
- PacketProbe
|
||||
- ApplicationPacketProbe
|
||||
- Ipv4PacketProbe
|
||||
|
||||
Currently, no Collectors are available in the DCF, although a
|
||||
BasicStatsCollector is under development.
|
||||
|
||||
Currently, only these Aggregators have been implemented in DCF:
|
||||
|
||||
- GnuplotAggregator
|
||||
- FileAggregator
|
||||
|
||||
Currently, only this Adaptor has been implemented in DCF:
|
||||
|
||||
Time-Series Adaptor.
|
||||
|
||||
Future Work
|
||||
###########
|
||||
|
||||
This section discusses the future work to be done on the Data
|
||||
Collection Framework.
|
||||
|
||||
Here are some things that still need to be done:
|
||||
|
||||
- Hook up more trace sources in |ns3| code to get more values out of the simulator.
|
||||
- Implement more types of Probes than there currently are.
|
||||
- Implement more than just the single current 2-D Collector, BasicStatsCollector.
|
||||
- Implement more Aggregators.
|
||||
- Implement more than just Adaptors.
|
||||
|
||||
Reference in New Issue
Block a user