add some words about tracing to the manual
This commit is contained in:
@@ -82,8 +82,9 @@ see @uref{http://www.nsnam.org/docs/manual.pdf}.
|
||||
@menu
|
||||
* Random variables::
|
||||
* Callbacks::
|
||||
* Attributes::
|
||||
* Object model::
|
||||
* Attributes::
|
||||
* Tracing::
|
||||
* RealTime::
|
||||
* Emulation::
|
||||
* Packets::
|
||||
@@ -100,8 +101,9 @@ see @uref{http://www.nsnam.org/docs/manual.pdf}.
|
||||
|
||||
@include random.texi
|
||||
@include callbacks.texi
|
||||
@include attributes.texi
|
||||
@include objects.texi
|
||||
@include attributes.texi
|
||||
@include tracing.texi
|
||||
@include realtime.texi
|
||||
@include emulation.texi
|
||||
@include packets.texi
|
||||
|
||||
325
doc/manual/tracing.texi
Normal file
325
doc/manual/tracing.texi
Normal file
@@ -0,0 +1,325 @@
|
||||
@node Tracing
|
||||
@chapter Tracing
|
||||
|
||||
The tracing subsystem is one of the most important mechansisms to understand in
|
||||
@command{ns-3}. In most cases, @command{ns-3} users will have a brilliant idea
|
||||
for some new and improved networking feature. In order to verify that this
|
||||
idea works, the researcher will make changes to an existing system and then run
|
||||
experiments to see how the new feature behaves by gathering some form of statistic
|
||||
that captures the behavior of the feature.
|
||||
|
||||
In other words, the whole point of running a simulation is to generate output for
|
||||
further study. In @command{ns-3}, the subsystem that enables a researcher to do
|
||||
this is the tracing subsystem.
|
||||
|
||||
@menu
|
||||
* Motivation::
|
||||
* Overview::
|
||||
* Using the Tracing API::
|
||||
* Implementation details::
|
||||
@end menu
|
||||
|
||||
@node Motivation
|
||||
@section Motivation
|
||||
|
||||
There are many ways to get information out of a program. The most straightforward
|
||||
way is to just directly print the information to the standard output, as in,
|
||||
|
||||
@verbatim
|
||||
#include <iostream>
|
||||
...
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
std::cout << ``The value of x is `` << x << std::endl;
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This is workable in small environments, but as your simulations get more and more
|
||||
compliated, you end up with more and more prints and the task of parsing and
|
||||
performing computations on the output begins to get harder and harder.
|
||||
|
||||
Another thing to consider is that every time a new tidbit is needed, the software
|
||||
core must be edited and another print introduced. There is no standardized way
|
||||
to control all of this output, so the amount of output tends to grow without
|
||||
bounds. Eventually, the bandwidth required for simply outputting this information
|
||||
begins to limit the running time of the simulation. The output files grow to
|
||||
enormous sizes and parsing them becomes a problem.
|
||||
|
||||
@command{ns-3} provides a simple mechanism for logging and providing some control
|
||||
over output via @emph{Log Components}, but the level of control is not very fine
|
||||
grained at all. The logging module is a relatively blunt instrument.
|
||||
|
||||
It is desirable to have a facility that allows one to reach into the core system
|
||||
and only get the information required without having to change and recompile the
|
||||
core system. Even better would be a system that notified the user when an item
|
||||
of interest changed or an interesting event happened.
|
||||
|
||||
The @command{ns-3} tracing system is designed to work along those lines and is
|
||||
well-integrated with the Attribute and Config substems allowing for relatively
|
||||
simple use scenarios.
|
||||
|
||||
@node Overview
|
||||
@section Overview
|
||||
|
||||
The tracing subsystem relies heavily on the @code{ns-3} Callback and Attribute
|
||||
mechanisms. You should read and understand the corresponding sections of the
|
||||
manual before attempting to understand the tracing system.
|
||||
|
||||
The ns-3 tracing system is built on the concepts of independent tracing sources
|
||||
and tracing sinks; along with a uniform mechanism for connecting sources to sinks.
|
||||
|
||||
Trace sources are entities that can signal events that happen in a simulation and
|
||||
provide access to interesting underlying data. For example, a trace source could
|
||||
indicate when a packet is received by a net device and provide access to the
|
||||
packet contents for interested trace sinks. A trace source might also indicate
|
||||
when an iteresting state change happens in a model. For example, the congestion
|
||||
window of a TCP model is a prime candidate for a trace source.
|
||||
|
||||
Trace sources are not useful by themselves; they must be connected to other pieces
|
||||
of code that actually do something useful with the information provided by the source.
|
||||
The entities that consume trace information are called trace sinks. Trace sources
|
||||
are generators of events and trace sinks are consumers.
|
||||
|
||||
This explicit division allows for large numbers of trace sources to be scattered
|
||||
around the system in places which model authors believe might be useful. Unless
|
||||
a user connects a trace sink to one of these sources, nothing is output. This
|
||||
arrangement allows relatively unsophisticated users to attach new types of sinks
|
||||
to existing tracing sources, without requiring editing and recompiling the core
|
||||
or models of the simulator.
|
||||
|
||||
There can be zero or more consumers of trace events generated by a trace source.
|
||||
One can think of a trace source as a kind of point-to-multipoint information link.
|
||||
|
||||
The ``transport protocol'' for this conceptual point-to-multipoint link as an
|
||||
@code{ns-3} @code{Callback}.
|
||||
|
||||
Recall from the Callback Section that callback facility is a way to allow two
|
||||
modules in the system to communicate via function calls while at the same time
|
||||
decoupling the calling function from the called class completely. This is the
|
||||
same requirement as outlined above for the tracing system.
|
||||
|
||||
Basically, a trace source @emph{is} a callback. When a trace sink expresses
|
||||
interest in receiving trace events, it adds a callback to a list of callbacks
|
||||
held by the trace source. When an interesting event happens, the trace source
|
||||
invokes its @code{operator()} providing zero or more parameters. This tells
|
||||
the source to go through its list of callbacks invoking each one in turn. In
|
||||
this way, the parameter(s) are communicated to the trace sinks, which are just
|
||||
functions.
|
||||
|
||||
@subsection The Simplest Example
|
||||
|
||||
It will be useful to go walk a quick example just to reinforce what we've said.
|
||||
|
||||
@verbose
|
||||
#include ``ns3/object.h''
|
||||
#include ``ns3/uinteger.h''
|
||||
#include ``ns3/traced-value.h''
|
||||
#include ``ns3/trace-source-accessor.h''
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
@end verbose
|
||||
|
||||
The first thing to do is include the required files. As mentioned above, the
|
||||
trace system makes heavy use of the Object and Attribute systems. The first
|
||||
two includes bring in the declarations for those systems. The file,
|
||||
@code{traced-value.h} brings in the required declarations for tracing data
|
||||
that obeys value semantics.
|
||||
|
||||
In general, value semantics just means that you can pass the object around,
|
||||
not an address. In order to use value semantics at all you have to have an
|
||||
object with an associated copy constructor and assignment operator
|
||||
available. We extend the requirements to talk about the set of operators
|
||||
that are pre-defined for plain-old-data (POD) types. Operator=, operator++,
|
||||
operator--, operator+, operator==, etc.
|
||||
|
||||
What this all means is that you will be able to trace changes to an object
|
||||
made using those operators.
|
||||
|
||||
@verbatim
|
||||
class MyObject : public Object
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("MyObject")
|
||||
.SetParent (Object::GetTypeId ())
|
||||
.AddConstructor<MyObject> ()
|
||||
.AddTraceSource ("MyInteger",
|
||||
"An integer value to trace.",
|
||||
MakeTraceSourceAccessor (&MyObject::m_myInt))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
MyObject () {}
|
||||
TracedValue<uint32_t> m_myInt;
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
Since the tracing system is integrated with Attributes, and Attributes work
|
||||
with Objects, there must be an @command{ns-3} @code{Object} for the trace source
|
||||
to live in. The two important lines of code are the @code{.AddTraceSource} and
|
||||
the @code{TracedValue} declaration.
|
||||
|
||||
The @code{.AddTraceSource} provides the ``hooks'' used for connecting the trace
|
||||
source to the outside world. The @code{TracedValue} declaration provides the
|
||||
infrastructure that overloads the operators above and drives the callback
|
||||
process.
|
||||
|
||||
@verbatim
|
||||
void
|
||||
IntTrace (Int oldValue, Int newValue)
|
||||
{
|
||||
std::cout << ``Traced `` << oldValue << `` to `` << newValue << std::endl;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This is the definition of the trace sink. It corresponds directly to a callback
|
||||
function. This function will be called whenever one of the operators of the
|
||||
@code{TracedValue} is executed.
|
||||
|
||||
@verbatim
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
Ptr<MyObject> myObject = CreateObject<MyObject> ();
|
||||
|
||||
myObject->TraceConnectWithoutContext ("MyInt", MakeCallback(&IntTrace));
|
||||
|
||||
myObject->m_myInt = 1234;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
In this snippet, the first thing that needs to be done is to create the object
|
||||
in which the trace source lives.
|
||||
|
||||
The next step, the @code{TraceConnectWithoutContext}, forms the connection
|
||||
between the trace source and the trace sink. Notice the @code{MakeCallback}
|
||||
template function. Recall from the Callback section that this creates the
|
||||
specialized functor responsible for providing the overloaded @code{operator()}
|
||||
used to ``fire'' the callback. The @code{TraceConnectWithoutContext}, takes
|
||||
a string parameter that provides the name of the Attribute assigned to the
|
||||
trace source. Let's ignore the bit about context for now.
|
||||
|
||||
Finally, the line,
|
||||
|
||||
@verbatim
|
||||
myObject->m_myInt = 1234;
|
||||
@end verbatim
|
||||
|
||||
should be interpreted as an invocation of @code{operator=} on the member
|
||||
variable @code{m_myInt} with the integer @code{1234} passed as a parameter.
|
||||
It turns out that this operator is defined (by @code{TracedValue}) to execute
|
||||
a callback that returns void and takes two integer values as parameters --
|
||||
an old value and a new value for the integer in question. That is exactly
|
||||
the function signature for the callback function we provided -- @code{IntTrace}.
|
||||
|
||||
To summarize, a trace source is, in essence, a variable that holds a list of
|
||||
callbacks. A trace sink is a function used as the target of a callback. The
|
||||
Attribute and object type information systems are used to provide a way to
|
||||
connect trace sources to trace sinks. The act of ``hitting'' a trace source
|
||||
is executing an operator on the trace source which fires callbacks. This
|
||||
results in the trace sink callbacks registering interest in the source being
|
||||
called with the parameters provided by the source.
|
||||
|
||||
@subsection Using the Config Subsystem to Connect to Trace Sources
|
||||
|
||||
The @code{TraceConnectWithoutContext} call shown above in the simple example is
|
||||
actually very rarely used in the system. More typically, the @code{Config}
|
||||
subsystem is used to allow selecting a trace source in the system using what is
|
||||
called a @emph{config path}.
|
||||
|
||||
For example, one might find something that looks like the following in the system
|
||||
(taken from @code{examples/tcp-large-transfer.cc})
|
||||
|
||||
@verbatim
|
||||
void CwndTracer (uint32_t oldval, uint32_t newval) {}
|
||||
|
||||
...
|
||||
|
||||
Config::ConnectWithoutContext (
|
||||
"/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
|
||||
MakeCallback (&CwndTracer));
|
||||
@end verbatim
|
||||
|
||||
This should look very familiar. It is the same thing as the previous example,
|
||||
except that a static member function of @code{Config} is being called instead of
|
||||
a method on @code{Object}, and instead of an @code{Attribute} name, a path is
|
||||
being provided.
|
||||
|
||||
The first thing to do is to read the path backward. The last segment of the path
|
||||
must be an @code{Attribute} of an @code{Object}. In fact, if you had a pointer to
|
||||
the @code{Object} that has the @code{Attribute} handy, you could write this just like
|
||||
the previous example:
|
||||
|
||||
@verbatim
|
||||
void CwndTracer (uint32_t oldval, uint32_t newval) {}
|
||||
|
||||
...
|
||||
|
||||
object->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
|
||||
@end verbatim
|
||||
|
||||
And it turns out that @code{Config::ConnectWithoutContext} does exactly that. This
|
||||
function takes a path that represents a chain of @code{Object} pointers and follows
|
||||
them until it gets to the end of the path and interprets the last segment as an
|
||||
@code{Attribute} on the last object.
|
||||
|
||||
The leading ``/'' character in the path refers to a so-called namespace. One of the
|
||||
predefined namespaces in the config system is ``NodeList'' which is a list of all of
|
||||
the nodes in the simulation. Items in the list are referred to by indices into the
|
||||
list, so ``/NodeList/0'' refers to the zeroth node in the list of nodes created by
|
||||
the simulation. This node is actually a @code{Ptr<Node>} and so is a subclass of
|
||||
an @code{ns3::Object}.
|
||||
|
||||
As described in the Object Model section, @code{ns-3} supports an object aggregation
|
||||
model. The next path segment begins with the ``$'' character which indicates a
|
||||
@code{GetObject} call should be made looking for the type that follows. When a
|
||||
node is initialized by an @code{InternetStackHelper} a number of interfaces are
|
||||
aggregated to the node. One of these is the TCP level four protocol. The runtime
|
||||
type of this protocol object is ``ns3::TcpL4Protocol''. When the @code{GetObject}
|
||||
is executed, it returns a pointer to the object of this type.
|
||||
|
||||
The @code{TcpL4Protocol} class defines an Attribute called ``SocketList'' which is
|
||||
a list of sockets. Each socket is actually an @code{ns3::Object} with its own
|
||||
@code{Attributes}. The items in the list of sockets are referred to by index just
|
||||
as in the NodeList, so ``SocketList/0'' refers to the zeroth socket in the list
|
||||
of sockets on the zeroth node in the NodeList -- the first node constructed in the
|
||||
simulation.
|
||||
|
||||
This socket, the type of which turns out to be an @code{ns3::TcpSocketImpl} defines
|
||||
an attribute called ``CongestionWindow'' which is a @code{TracedValue<uint32_t>}.
|
||||
The @code{Config::ConnectWithoutContext} now does a,
|
||||
|
||||
@verbatim
|
||||
object->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
|
||||
@end verbatim
|
||||
|
||||
using the object pointer from ``SocketList/0'' which makes the connection between
|
||||
the trace source defined in the socket to the callback -- @code{CwndTracer}.
|
||||
|
||||
Now, whenever a change is made to the @code{TracedValue<uint32_t>} representing the
|
||||
congestion window in the TCP socket, the registered callback will be executed and
|
||||
the function @code{Cwndtracer} will be called printing out the old and new values
|
||||
of the TCP congestion window.
|
||||
|
||||
@node Using the Tracing API
|
||||
@section Using the Tracing API
|
||||
|
||||
There
|
||||
are three levels of interaction with the tracing system:
|
||||
|
||||
@itemize @bullet
|
||||
@item Beginning user can easily control which objects are participating in tracing;
|
||||
@item Intermediate users can extend the tracing system to modify the output format
|
||||
generated or use existing trace sources in different ways, without modifying the
|
||||
core of the simulator;
|
||||
@item Advanced users can modify the simulator core to add new tracing sources and
|
||||
sinks.
|
||||
|
||||
@node Implementation details
|
||||
@section Implementation details
|
||||
Reference in New Issue
Block a user