ns-3的跟踪与采集技术除了直接将执行过程显示在命令行中的Logging系统,还有一种更为常用的将采集到的数据直接存放在一个文件中以便后期处理与分析的Tracing系统。
ns-3的Tracing系统大体分为3个部分:Tracing Sources,Tracing Sinks,以及将Tracing Sources和Tracing Sinks关联起来的方法。
Tracing Sources是一个实体,它可以用来标记仿真中发生的时间,也可以提供一个访问底层数据的方法。例如,当一个网络设备或者网卡收到一个网络分组时,Tracing Sources可以指示并提供一个途经将分组的内容传递给对该分组感兴趣的Tracing Sinks。此外,Tracing Sources还可以在感兴趣的状态发生变化时给出相应的指示。例如,TCP 网络协议模块中的拥塞窗口发生改变时,Tracing Sources会给出指示。
Tracing Sources提供信息,而Tracing Sinks消费信息。Tracing Sources本身不起任何作用,只有当它和一段有实际功能的代码相关联时才有意义,这段代码就是使用Tracing Sources提供的信息来做相关事物的。使用(或消费)Tracing Sources提供信息的实体称为Tracing Sink。
一个Tracing Sources产生的信息可以没有Tracing Sink消费,也可以有一个或者多个Tracing Sink消费。它们之间是一对多的关系。
下面通过最简单的跟踪示例 fourth.cc 来说明Tracing Sources,Tracing Sinks,以及它们之间是如何关联起来的。代码如下:
#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"
#include
using namespace ns3;
首先要定义自己的类,该类的父类为Object,因此要引入头文件 #include “ns3/object.h”。
再引入ns-3自定义的无符号整形所声明的头文件 #include “ns3/uinteger.h”。
#include "ns3/traced-value.h"头文件中引入了要跟踪数据的类型,即TracedValue。
#include "ns3/trace-source-accessor.h"头文件中包含了本程序要使用的能把自定义数据转换为Trace Sources的函数。
#include是指包含后面所跟的内容,iostream 库的基础是两种命名为 istream 和 ostream 的类型,分别表示输入流和输出流。所以#include定义的就是你要输入和输出的内容。
class MyObject : public Object
{
public:
/**
* Register this type.
* \return The TypeId.
*/
static TypeId GetTypeId (void)
{
static TypeId tid = TypeId ("MyObject")
.SetParent
因为Tracing系统和属性系统有很大关联,而属性系统和对象相关联,所以,每一个要追踪的数据都必须属于一个特定的类,这里这个类定义为MyObject,要追踪的数据为m_myInt。
GetTypeId()函数定义了一个关于MyObject的元数据集,并返回标识类TypeId。
ns-3中所有由Object类派生的类都可以包含在一个叫TypeId的元数据类,该类用来记录关于类的元信息,以便在对象聚合以及构建管理中使用,TypeId 类中设计了用唯一的字符串来标识一个类、子类的基类以及子类中可以访问的构造函数。
SetParent()函数的作用是表明该类和父类的关系,避免在向上或向下类型转换时发生不必要的错误。
AddConstructor()函数的作用是在用户使用对象工厂机制时,不用考虑类的具体细节就可以创建对象。
AddTraceSource()函数的作用是提供一个“挂钩”,把自定义的名为“MyInterger”的Trace Source与系统外相关联。
MakeTraceSourceAccessor()函数的作用是使MyObject类的成员变量m_myInt成为一个可存取的Trace Sources。
void
IntTrace (int32_t oldValue, int32_t newValue)
{
std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
}
上述代码就是定义的回调函数,就是Tracing系统中的Trace Sink。
函数的行为就是输出Trace Source改变前后的值。
int
main (int argc, char *argv[])
{
Ptr myObject = CreateObject ();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback (&IntTrace));
myObject->m_myInt = 1234;
}
主函数中首先定义了一个类对象实例,这个实例中包含了一个TraceSource。
下面一个函数TraceConnectWithoutContext非常重要,它将Trace Sources和Trace Sink相关联。只要调用了这个函数,当Trace Sources数据m_myInt发生改变时,IntTrace函数才会被调用。
最后一行代码可以看作是把常量1234赋值给m_myInt,这四系统会识别这一行为,并将m_myInt赋值前和赋值后的两个值作为形参传递给Trace Sink的回调函数IntTrace。