从零开始的ns3笔记(五):ns3队列和追踪fourth.cc

一、队列

1.1队列基础介绍

以下参考官方文档ns3学习记录(六):ns3队列

ns-3 中队列规则的选择会对性能产生很大影响,因此用户有必要了解默认安装了什么,以及如何更改默认值并观察其性能。

从架构上讲,ns-3 将设备层与互联网主机的 IP 层或流量控制层分开。自 ns-3 最新版本发布以来,传出数据包在到达通道对象之前要经过两个队列层。遇到的第一个队列层在 ns-3 中被称为 "流量控制层";在这里,主动队列管理(RFC7567)和服务质量(QoS)优先级是通过使用队列规则以独立于设备的方式进行的。第二个队列层通常存在于 NetDevice 对象中。不同的设备(如 LTE、Wi-Fi)对这些队列有不同的实现方式。这种双层方法反映了实际情况(提供优先级的软件队列和特定于链路类型的硬件队列)。实际上,情况可能比这还要复杂。例如,ARP协议有一个小队列。Linux 中的 Wi-Fi 有四层队列 (https://lwn.net/Articles/705884/)。

只有当设备队列满时,NetDevice 通知流量控制层,流量控制层才能停止向 NetDevice 发送数据包。否则,队列纪律的backlog(累计未完成的待处理事件,即接收队列的大小)总是空的,它们就不起作用。目前,以下使用队列对象(或队列子类对象)存储数据包的 NetDevice 支持流量控制,即通知流量控制层的功能:

  • Point-To-Point
  • Csma
  • Wi-Fi
  • SimpleNetDevice

队列规则的性能受 NetDevice 所用队列大小的影响很大。目前,ns-3 中的队列默认情况下不会根据配置的链路属性(带宽、延迟)进行自动调整,而且通常是最简单的变体(例如,具有Drop Tail行为的 FIFO 调度,Drop Tail:当路由器队列长度达到最大值时,通过丢包来指示拥塞,先到达路由器的分组首先被传输。一旦发生丢包,发送端立即被告知网络拥塞,从而调整发送速率)。不过,队列的大小可以通过启用 BQL(字节队列限制)来动态调整,BQL 是 Linux 内核中实现的一种算法,用于调整设备队列的大小,以对抗缓冲区膨胀,同时避免饥饿。目前,支持流量控制的 NetDevice 都支持 BQL。

1.2 ns-3 中可用的队列模型

  • PFifoFastQueueDisc: The default maximum size is 1000 packets
  • FifoQueueDisc: The default maximum size is 1000 packets
  • RedQueueDisc: The default maximum size is 25 packets
  • CoDelQueueDisc: The default maximum size is 1500 kilobytes
  • FqCoDelQueueDisc: The default maximum size is 10240 packets
  • PieQueueDisc: The default maximum size is 25 packets
  • MqQueueDisc: This queue disc has no limits on its capacity
  • TbfQueueDisc: The default maximum size is 1000 packets

默认情况下,当 IPv4 或 IPv6 地址分配给与 NetDevice 相关联的接口时,会在 NetDevice 上安装 pfifo_fast 队列规范,除非 NetDevice 上已经安装了队列规范。

在设备层,有设备特定队列:

  • PointToPointNetDevice: The default configuration (as set by the helper) is to install a DropTail queue of default size (100 packets) 默认配置时安装一个大小为100个包的去尾队列
  • CsmaNetDevice: The default configuration (as set by the helper) is to install a DropTail queue of default size (100 packets) 默认配置时安装一个大小为100个包的去尾队列
  • WiFiNetDevice: The default configuration is to install a DropTail queue of default size (100 packets) for non-QoS stations and four DropTail queues of default size (100 packets) for QoS stations 默认配置时没有QoS的站点安装一个大小为100个包的去尾队列,有QoS的站点安装四个大小为100个包的去尾队列
  • SimpleNetDevice: The default configuration is to install a DropTail queue of default size (100 packets) 默认配置时安装一个大小为100个包的去尾队列
  • LteNetDevice: Queueing occurs at the RLC layer (RLC UM default buffer is 10 * 1024 bytes, RLC AM does not have a buffer limit). 排队发生在RLC层(RLC UM的默认缓冲区是10 × 1024字节,RLC AM没有缓冲区限制)
  • UanNetDevice: There is a default 10 packet queue at the MAC layer 在MAC层上有一个默认的10个数据包队列

1.3 修改队列的默认值

1.NetDevice 使用的队列类型通常可以通过设备辅助程序修改:(设置网络模式之后)

NodeContainer nodes;
nodes.Create(2);

PointToPointHelper p2p;
p2p.SetQueue("ns3::DropTailQueue", "MaxSize", StringValue("50p")); //这里改

NetDeviceContainer devices = p2p.Install(nodes);

2.可以通过流量控制助手修改 NetDevice 上安装的队列盘类型: (安装协议栈之后)

InternetStackHelper stack;
stack.Install(nodes);

TrafficControlHelper tch;
tch.SetRootQueueDisc("ns3::CoDelQueueDisc", "MaxSize", StringValue("1000p")); //这里改
tch.Install(devices);

3.可通过流量控制助手在支持 BQL 的设备上启用 BQL: 

InternetStackHelper stack;
stack.Install(nodes);

TrafficControlHelper tch;
tch.SetRootQueueDisc("ns3::CoDelQueueDisc", "MaxSize", StringValue("1000p"));
tch.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("4ms")); //BQL多这一行
tch.Install(devices);

二、Tracing系统

以下参考ns-3中的数据跟踪与采集——Tracing系统综述及fourth脚本

从 ns-3 中获取输出结果有两种基本策略:使用通用的预定义批量输出机制(logging系统);或将采集到的数据直接存放在一个文件中以便后期处理与分析Tracing系统

ns-3 追踪系统分为三个部分:Tracing SourcesTracing Sinks,以及将Tracing Sources和Tracing Sinks关联起来的方法
Tracing Sources是一个实体,它可以用来标记仿真中发生的时间,也可以提供一个访问底层数据的方法。例如,Tracing Sources可指示网络设备何时接收到数据包,并为感兴趣的Tracing Sinks提供对数据包内容的访问。当模型中发生状态变化时,跟踪源也会发出指示。例如,TCP 模型的拥塞窗口发生变化时,连接的Tracing Sinks都会收到新旧值的通知。

Tracing Sources提供信息,而Tracing Sinks消费信息。Tracing Sources本身不起任何作用,只有当它和一段有实际功能的代码相关联时才有意义,这段代码就是使用Tracing Sources提供的信息来做相关事物的。使用(或消费)Tracing Sources提供信息的实体称为Tracing Sink。
一个Tracing Sources产生的信息可以没有Tracing Sink消费,也可以有一个或者多个Tracing Sink消费。它们之间是一对多的关系。相同的信息根据不同的代码可以做完全不同的事情。

三、fourth.cc介绍

fourth.cc是一个最简单的跟踪示例,打印要跟踪数据的值的变化。

3.1 类的引入

#include "ns3/object.h"
#include "ns3/simulator.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/traced-value.h"
#include "ns3/uinteger.h"

#include <iostream>

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的函数

3.2 构建一个自己的类(MyObject)

class MyObject : public Object  //定义类名并声明父类
{
  public:
    /**
     * Register this type.
     * \return The TypeId.
     */
    static TypeId GetTypeId() //定义函数名称
    {
        static TypeId tid = TypeId("MyObject")
                                .SetParent<Object>()
                                .SetGroupName("Tutorial")
                                .AddConstructor<MyObject>()
                                .AddTraceSource("MyInteger",
                                                "An integer value to trace.",
                                                MakeTraceSourceAccessor(&MyObject::m_myInt),
                                                "ns3::TracedValueCallback::Int32");
        return tid;
    }

    MyObject()
    {
    }

    TracedValue<int32_t> m_myInt; //!< The traced value.
};

因为Tracing系统和属性系统有很大关联,而属性系统和对象相关联,所以,每一个要追踪的数据都必须属于一个特定的类,这里这个类定义为MyObject,要追踪的数据为m_myInt

GetTypeId()函数定义了一个关于MyObject的元数据集,并返回标识类TypeId。
ns-3中所有由Object类派生的类都可以包含在一个叫TypeId的元数据类,该类用来记录关于类的元信息,以便在对象聚合以及构建管理中使用,TypeId 类中设计了用唯一的字符串来标识一个类、子类的基类以及子类中可以访问的构造函数。

SetParent()函数的作用是表明该类和父类的关系,避免在向上或向下类型转换时发生不必要的错误。

AddConstructor()函数的作用是在用户使用对象工厂机制时,不用考虑类的具体细节就可以创建对象。

AddTraceSource()函数的作用是提供一个“挂钩”,把自定义的名为“MyInterger”的Trace Source与系统外相关联。第二个参数是附加输出的字符串。第三个参数的参数:&MyObject::m_myInt,这是添加到类中的 TracedValue。最后一个参数是 TracedValue 类型的类型定义名称,以字符串形式表示。它用于为正确的回调函数签名生成文档,这对更多的回调类型非常有用。

MakeTraceSourceAccessor()函数的作用是使MyObject类的成员变量m_myInt成为一个可存取的Trace Sources。

TracedValue<> 声明提供了驱动回调过程的基础结构。当底层值发生变化时,TracedValue 机制将提供该变量的新旧值,在本例中是一个 int32_t 值。

3.3 定义回调函数Trace Sink

void
IntTrace (int32_t oldValue, int32_t newValue)
{
  std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
}

上述代码就是定义的回调函数,就是Tracing系统中的Trace Sink。
函数的行为就是输出Trace Source改变前后的值。

3.4 主函数

int
main (int argc, char *argv[])
{
  Ptr<MyObject> myObject = CreateObject<MyObject> ();
  myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback (&IntTrace));

  myObject->m_myInt = 1234;
}

主函数中定义了一个类对象实例myObject,这个实例中包含了一个TraceSource(也就是MyInteger)。

下面一个函数TraceConnectWithoutContext将Trace Sources和Trace Sink相关联。只要调用了这个函数,当Trace Sources数据m_myInt发生改变时,IntTrace函数才会被调用。

最后一行代码可以看作是把常量1234赋值给m_myInt,这时系统会识别这一行为,并将m_myInt赋值前和赋值后的两个值作为形参传递给Trace Sink的回调函数IntTrace。

运行结果

old值为0,新值为1234。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值