--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/tracing.h Wed Aug 29 14:43:31 2007 +0200
@@ -0,0 +1,297 @@
+/**
+ * \defgroup tracing Tracing
+ *
+ * The flexibility of the ns-3 tracing system comes at the cost of quite
+ * a bit of complexity so, before trying to use the low-level aspects
+ * of the tracing API, it is important to focus on some basic definitions:
+ *
+ * - A trace source is an object instance which can report trace events
+ * to a set of listening trace sinks.
+ *
+ * - A trace sink is a user-provided callback (a function) which can
+ * be connected to a set of trace sources to receive the events generated
+ * by each trace source.
+ *
+ * - Trace context: each trace source instance is associated with a single
+ * trace context which can be used by each connected trace sink to
+ * identify the instance of the source of the event.
+ *
+ * - A trace resolver is an object which allows users to establish
+ * connections between a set of trace sources and a set of trace sinks.
+ * The trace contexts are configured during connection by the trace
+ * resolvers.
+ *
+ * So, what does it look like in practice ? First, let's look at trace
+ * sources. We have two types of trace sources: numeric, and, normal
+ * trace sources. Numeric trace sources behave as normal c++ integers
+ * or c++ floating point numbers except that they report as trace events
+ * each change of their value. For example:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * void DoSomething (void)
+ * {
+ * // use the "int" trace source just
+ * // like any other "int" variable.
+ * m_cwnd *= 2;
+ * m_cwnd += 4;
+ * if (m_cwnd > 100)
+ * {
+ * // do something.
+ * }
+ * }
+ * private:
+ * // declare an instance of a "int" trace source
+ * SVTraceSource<int> m_cwnd;
+ * };
+ * \endcode
+ * Normal trace sources, on the other hand, allow you to trace the
+ * call of arbitrary functions and methods, as shown below. They are
+ * typically used to track "rx", "tx", or "drop" events but could
+ * also be used to track route change events, or position change
+ * events:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * void DoSomething (Packet packet, double value)
+ * {
+ * m_doSomething (packet, value);
+ * // do something
+ * }
+ * private:
+ * // report every "something" function call.
+ * CallbackTraceSource<Packet,double> m_doSomething;
+ * };
+ * \endcode
+ * Every type of trace source derives from the ns3::TraceSource base class.
+ * As of today, the set of concrete subclasses is relatively short:
+ * ns3::CallbackTraceSource, ns3::SvTraceSource, ns3::UvTraceSource, and,
+ * ns3::FvTraceSource.
+ *
+ * To receive these trace events, a user should specify a set of trace sinks.
+ * For example, to receive the "int" and the "something events outlined
+ * above, a user would declare the following functions which receive
+ * as an extra first argument the context of the trace source which
+ * generated the specific event.
+ * \code
+ * // oldValue and newValue contain the previous and new values of
+ * // the connected SVTraceSource<int> trace source.
+ * void
+ * CwndTraceSink (const TraceContext &context, int64_t oldValue, int64_t newValue)
+ * {
+ * // for example, print the new value:
+ * std::cout << "cwnd=" << newValue << std::endl;
+ * }
+ * void
+ * DoSomethingTraceSink (const TraceContext &context, Packet packet, double value)
+ * {
+ * // for example, print the arguments
+ * std::cout << "value=" << value << ", packet " << packet << std::endl;
+ * }
+ * \endcode
+ *
+ * The hard part of this tracing framework is the "connection" step: there is a point
+ * in the simulation scenario where the user is expected to specify which trace sources
+ * should be connected to which trace sinks. There are many ways to do this: the
+ * users who want to could implement the "quick and dirty" way, that is, they could
+ * write adhoc code to connect their trace sinks to the trace sources using the
+ * TraceSource::AddCallback method. For example, they could patch their models to
+ * the following:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * void DoSomething (void)
+ * {
+ * // ...
+ * }
+ * SVTraceSource<int> *GetCwndTraceSource (void) const
+ * {
+ * return &m_cwnd;
+ * }
+ * private:
+ * // declare an instance of a "int" trace source
+ * SVTraceSource<int> m_cwnd;
+ * };
+ * \endcode
+ * And, then, call directly the GetCwndTraceSource method:
+ * \code
+ * CwndTraceSink (const TraceContext &context, int64_t oldValue, int64_t newValue)
+ * {
+ * // for example, print the new value:
+ * std::cout << "cwnd=" << newValue << std::endl;
+ * }
+ * // create a model instance
+ * MyModel *model = ...;
+ * SVTraceSource<int> *cwnd = model->GetCwndTraceSource ();
+ * // connect the trace sink to the cwnd trace source of
+ * // this model instance.
+ * cwnd->AddCallback (MakeCallback (&CwndTraceSink),
+ * TraceContext ());
+ * \endcode
+ *
+ * The solution described above is simple to implement for a model
+ * author but it is hard to extend and becomes quickly cumbersome
+ * to use with complex models made of composite objects. TraceResolvers
+ * deal with these problems and offer a simple API to connect large
+ * sets of trace sources to a single sink (as is typical for simulations
+ * where users want to receive the "ipv4 rx" events from all nodes).
+ *
+ * The user-visible API to connect and disconnect trace sources to
+ * and from trace sinks is quite small: ns3::Object::Connect
+ * and ns3::Object::Disconnect both take a "namespace" regexp string
+ * and a callback. The input callback is connected to each trace source
+ * which matches the namespace regexp string. The format of the namespace
+ * string depends on the set of models implemented by the simulator.
+ * The following diagram shows a small part of the namespace exported
+ * by the current version of the simulator:
+ *
+ * \image html namespace-2.png ns-3 namespace
+ *
+ * In this namespace, the "rx" trace source of the PointToPointNetdevice
+ * index 0 within node index 3 is uniquely identified by the namespace
+ * string "/nodes/3/devices/0/rx". It is also possible to match all
+ * such "rx" trace sources with a single namespace string using
+ * a limited form of regular expressions: "/nodes/3/devices/* /rx"
+ * identifies the "rx" trace source within all NetDevices within node
+ * index 3. Similarly, "/nodes/* /devices/* /rx" identifies the "rx"
+ * trace source within all NetDevices within all nodes. It is thus
+ * possible to connect a single trace sink to a set of matching trace
+ * sources in a single operation:
+ * \code
+ * void DeviceRxSink (const TraceContext &context, const Packet &packet)
+ * {
+ * // context contains enough information to uniquely identify
+ * // the trace source instance.
+ * std::cout << "context: \"" << context << "\"";
+ * // packet is the per-event information conveyed from the
+ * // trace source to the trace sink.
+ * std:: cout << " packet: " << packet << std::endl;
+ * }
+ * NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback (&DeviceRxSink));
+ * \endcode
+ * Which, at runtime, is going to generate output looking like this:
+ * \code
+ * context: "nodeid=2 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
+ * context: "nodeid=1 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
+ * ...
+ * \endcode
+ * In the example above, we see that the ns3::TraceContext contains three
+ * ns3::TraceContextElement which were printed using a space separator:
+ * - nodeid=i
+ * - device=j
+ * - dev-rx
+ *
+ * Of course, the user could also extract each of these elements from
+ * the context to generate a different output:
+ * \code
+ * void DeviceRxSink (const TraceContext &context, const Packet &packet)
+ * {
+ * NodeListIndex nodeIndex;
+ * NodeNetDeviceIndex deviceIndex;
+ * context.Get (nodeIndex);
+ * context.Get (deviceIndex);
+ * std::cout << "node-index=" << nodeIndex.Get ();
+ * std::cout << ", device-index=" << deviceIndex.Get ();
+ * std::cout << ", packet: " << packet;
+ * std::cout << std::endl;
+ * }
+ * NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback (&DeviceRxSink));
+ * \endcode
+ * Extracting TraceContextElement objects from a TraceContext in this manner
+ * raises a few obvious questions:
+ * - how do I know which trace context elements are present in a given
+ * TraceContext ?
+ * - how are these elements added to the TraceContext ?
+ *
+ *
+ *
+ *
+ * Connecting trace sinks to a set of existing trace sources is nice but
+ * model developers also often need to be able to create new trace sources
+ * and hook them into the namespace resolution system. Creating new trace
+ * sources is pretty easy: it is a matter of instantiating a proper
+ * subclass of the ns3::TraceSource base class. However, hooking each
+ * new trace source in the overall namespace resolution system requires
+ * some new effort. The core requirement is that the user needs to
+ * subclass from the ns3::Object base class which provides the most
+ * basic ns3::Object::Connect, and, ns3::Object::Disconnect methods.
+ * These two methods are simple forwarding methods to the virtual
+ * ns3::Object::GetTraceResolver method which does the bulk of the work
+ * required to setup properly trace sources.
+ *
+ * Every subclass of the ns3::Object base class which wishes to export
+ * a set of trace sources and make them available through the Connect/Disconnect
+ * functions needs to override the ns3::Object::GetTraceResolver method.
+ * This method needs to return a subclass of the ns3::TraceResolver
+ * base class which implements the ns3::TraceResolver::Connect and
+ * ns3::TraceResolver::Disconnect methods. Providing an implementation
+ * of these two methods is a bit complicated so, a default implementation
+ * named CompositeTraceResolver is provided:
+ * \code
+ * class MyModel : public Object
+ * {
+ * public:
+ * void DoSomething (void)
+ * {
+ * // change value of m_cwnd
+ * }
+ * protected:
+ * virtual Ptr<TraceResolver> GetTraceResolver (void)
+ * {
+ * // create the composite resolver
+ * Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ * resolver->AddSource ("cwnd", m_cwnd);
+ * resolver->AddSource ("rx", m_rx);
+ * return resolver;
+ * }
+ * private:
+ * SVTraceSource<int> m_cwnd;
+ * CallbackTraceSource<Packet> m_rx;
+ * };
+ * void MyTraceSink (const TraceContext &context, Packet packet)
+ * {
+ * std::cout << context << " packet: " << packet << std::endl;
+ * }
+ * object->Connect ("/.../rx", MakeCallback (&MyTraceSink));
+ * \endcode
+ *
+ * The above example is enough to export a trace source as a member of the
+ * tracing namespace so, it would be enough to allow a user to perform a
+ * pair of Connect/Disconnect operations but it would not be enough to allow
+ * a TraceContext to contain information about these trace sources. Specifically,
+ * printing the content of the TraceContext as shown above would give no
+ * information whatsoever about the type of trace source which was connected.
+ *
+ * but it is not enough to allow the TraceContext
+ * stored in each TraceSource to store information about these trace sources.
+ *
+ * - A trace source: a trace source is an object instance which is a
+ * subclass of the ns3::TraceSource base class. Each instance
+ * of a trace source should be used to report a single type of
+ * event. For example, if you want to report ipv4 rx and tx events,
+ * you should use two different trace source instances.
+ *
+ * - Trace sinks: a trace sink is a callback, that is, a function,
+ * which is provided by the user of a model to receive the events
+ * reported by a set of trace sources within that model. A trace
+ * sink is said to be "connected" once it has been associated
+ * to a set of trace sources.
+ *
+ * - Trace context: each trace source instance is associated with a single
+ * instance of an immutable trace context. Each ns3::TraceContext stores
+ * a set of trace context element instances, each of which is a subclass
+ * of the ns3::TraceContextElement base class. Whenever a trace sink
+ * provided by a user is called because a trace event was reported on
+ * a connected trace source, the trace context associated to the
+ * relevant trace source is passed as an extra argument to the user's
+ * trace sink.
+ *
+ * - instrumentation of models is done through a set of trace source
+ * instances, each of which is a subclass of the ns3::TraceSource
+ * base class.
+ *
+ *
+ */