ndnSIM仿真平台中获取仿真数据有两种方式:
- 打印输出运行日志,并在其中配置需要查看的数据,具体方式可以查看教程:ndnSIM 如何打印 运行日志 获取日志 调试 获取实验数据_ndnsim运行日志-CSDN博客
- 通过平台内建输出程序获取,即使用trace helpers来对仿真结果进行跟踪,生成数据文件txt
其中,第一种方式比较灵活,可以输出的数据种类比较多,便于分析,并且可以在需要的地方去修改源码打印任何变量到日志中。第二种方式则比较简单,需要完成的代码比较少,风险低代码容易运行成功,ndnSIM已经提供了常用指标的输出与处理,比较稳定成熟。
对于常用指标,ndnSIM提供了相应的平台内建输出程序可以获取实验结果,具体可以参考 NFD’s Content Store 和 Obtaining metrics(比较重要)。平台内建输出程序的使用方式如下:
为了获得模拟结果,您需要连接到ndnSIM类提供的一个或多个跟踪源。
也可以使用现有的跟踪助手,该助手在文本文件中收集和汇总请求的统计信息。
Packet-level trace helpers
1、L3RateTracer
用于获取节点吞吐量指标(官网示例文件:ndn-tree-tracers.cpp),可以 跟踪NDN节点转发的兴趣/数据包的字节数和速率
以下示例启用了对所有模拟节点的跟踪:
// the following should be put just before calling Simulator::Run in the scenario
L3RateTracer::InstallAll("rate-trace.txt", Seconds(1.0));
Simulator::Run();
...
生成结果文件rate-trace.txt,包含以下内容:
Time Node FaceId FaceDescr Type Packets Kilobytes PacketRaw KilobytesRaw
0.5 leaf-1 1 internal:// InInterests 0 0 0 0
0.5 leaf-1 1 internal:// OutInterests 0 0 0 0
0.5 leaf-1 1 internal:// InData 0 0 0 0
0.5 leaf-1 1 internal:// OutData 0 0 0 0
0.5 leaf-1 1 internal:// InNacks 0 0 0 0
0.5 leaf-1 1 internal:// OutNacks 0 0 0 0
0.5 leaf-1 1 internal:// InSatisfiedInterests 0 0 0 0
0.5 leaf-1 1 internal:// InTimedOutInterests 0 0 0 0
0.5 leaf-1 1 internal:// OutSatisfiedInterests 1.6 0 1 0
0.5 leaf-1 1 internal:// OutTimedOutInterests 0 0 0 0
输出文件格式是以制表符分隔的值,第一行指定列的名称。有关列的说明,请参阅下表:
字段名称 | 描述 |
---|---|
Time | 模拟时间 |
Node | 节点ID,全局唯一 |
FaceId | 接口ID(-1为组合指标) |
Type | 测量类型:
|
Packets | 最后平均周期内的数据包的估计速率(EWMA平均)(数据包数/秒)。 |
Kilobytes | 上一个平均周期内的估计速率(EWMA平均值)(千字节/秒) |
PacketsRaw | 最后平均周期内的绝对数据包数(数据包数)。 |
KilobytesRaw | 在最后一个平均周期内传输的绝对千字节数(数据包数)。 |
使用示例:
使用ndn::L3RateTracer
可以输出每个节点的流量信息,其中常用的为进/出兴趣包/数据包数量,在Simulator::Run();
前添加如下代码:
ndn::L3RateTracer::InstallAll("rate-trace.txt", Seconds(1.0));
以ndn-simple.cpp(在原示例中增加一个节点)文件为例,加入上述代码后运行,在ns-3的主目录下,可以发现程序输出文件rate-trace.txt,内容为:
节点1 | ![]() |
节点2 | ![]() |
节点3 | ![]() |
节点4 | ![]() |
由上可以清楚看到每个节点的InInterests、OutInterests、InData和OutData等信息,统计指标包括数量与字节。这里要额外说明第四列FaceDescr的选择,注意到每个节点包括四种FaceDescr:internal、netDeviceFace、ndnFace和appFace。我们需要用到的是netDeviceFace和appFace。
为了介绍这两种FaceDescr的区别,我们再次说明实验中用到的ndn-simple.cpp的拓扑结构:节点0、1、2、3串联,节点0上安装用户(Consumer),节点3上安装服务器(Provider)。
在上图中,节点1和节点2的netDeviceFace有两个端口号,而节点0和节点3的netDeviceFace只有一个端口号,因此netDeviceFace表示该节点与其他路由节点相连的端口。节点1和节点2没有appFace,而节点0和节点3分别有一个appFace,因此appFace表示该节点与用户或服务器相连的端口。
因此在这个示例中,统计服务器的负载时使用的是节点3的appFace端口的OutInterests和InData的信息。
全部代码为:
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/ndnSIM-module.h"
namespace ns3 {
int
main(int argc, char* argv[])
{
// setting default parameters for PointToPoint links and channels
Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps"));
Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("20p"));
// Read optional command-line parameters (e.g., enable visualizer with ./waf --run=<> --visualize
CommandLine cmd;
cmd.Parse(argc, argv);
// Creating nodes
NodeContainer nodes;
nodes.Create(4);
// Connecting nodes using two links
PointToPointHelper p2p;
p2p.Install(nodes.Get(0), nodes.Get(1));
p2p.Install(nodes.Get(1), nodes.Get(2));
p2p.Install(nodes.Get(2), nodes.Get(3));
// Install NDN stack on all nodes
ndn::StackHelper ndnHelper;
ndnHelper.SetDefaultRoutes(true);
ndnHelper.InstallAll();
// Choosing forwarding strategy
ndn::StrategyChoiceHelper::InstallAll("/prefix", "/localhost/nfd/strategy/multicast");
// Installing applications
// Consumer
ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
// Consumer will request /prefix/0, /prefix/1, ...
consumerHelper.SetPrefix("/prefix");
consumerHelper.SetAttribute("Frequency", StringValue("10")); // 10 interests a second
auto apps = consumerHelper.Install(nodes.Get(0)); // first node
apps.Stop(Seconds(10.0)); // stop the consumer app at 10 seconds mark
// Producer
ndn::AppHelper producerHelper("ns3::ndn::Producer");
// Producer will reply to all requests starting with /prefix
producerHelper.SetPrefix("/prefix");
producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
producerHelper.Install(nodes.Get(3)); // last node
Simulator::Stop(Seconds(20.0));
ndn::L3RateTracer::InstallAll("rate-trace.txt", Seconds(1.0));
Simulator::Run();
Simulator::Destroy();
return 0;
}
} // namespace ns3
int
main(int argc, char* argv[])
{
return ns3::main(argc, argv);
}
2、L2RateTracer
用于获取丢包率指标(官网示例文件:ndn-simple-withl2tracer.cpp)
该跟踪器在本质上与ndn :: L3RateTracer相似,但是它目前仅跟踪第2层上的数据包丢失(例如,由于传输队列溢出)。
以下示例启用了对所有模拟节点的跟踪:
// the following should be put just before calling Simulator::Run in the scenario
L2RateTracer::InstallAll("drop-trace.txt", Seconds(0.5));
Simulator::Run();
...
结果文件包含以下内容:
Time Node Interface Type Packets Kilobytes PacketsRaw KilobytesRaw
1 Rtr1 combined Drop 0 0 0 0
输出文件格式是制表符分隔的值,第一行指定列的名称。 有关各列的说明,请参考下表:
字段名称 | 描述 |
---|---|
Time | 模拟时间 |
Node | 节点ID,全局唯一 |
Interface | 接口名称(当前仅“组合”) |
Type | 测量类型:
|
Packets | 最后平均周期内的数据包的估计速率(EWMA平均)(数据包数/秒)。 |
Kilobytes | 上一个平均周期内的估计速率(EWMA平均值)(千字节/秒) |
PacketsRaw | 最后平均周期内的绝对数据包数(数据包数)。 |
KilobytesRaw | 在最后一个平均周期内传输的绝对千字节数(数据包数)。 |
使用示例:
以ndn-simple.cpp(在原示例中增加一个节点)文件为例,加入以下代码后运行,在ns-3的主目录下,可以发现程序输出文件rate-trace.txt,内容如下。
ns3::L2RateTracer::InstallAll("rate-trace.txt", Seconds(1.0));
Note:
plugins/tracers-broken
文件夹中还有许多其他跟踪器,但它们尚不适用于当前代码。最终,我们会将它们中的大多数移植到当前代码中,但这不是我们目前的主要优先事项,并且非常感谢在编写新的跟踪程序和移植旧的跟踪程序方面所提供的帮助。
Content store trace helper
可以用于获取缓存命中率指标(官网示例文件:ndn-tree-cs-tracers.cpp)
通过使用ndn :: CsTracer,可以获得仿真节点上缓存命中/缓存未命中的统计信息。
以下代码启用内容存储库跟踪:
// the following should be put just before calling Simulator::Run in the scenario
CsTracer::InstallAll("cs-trace.txt", Seconds(1));
Simulator::Run();
...
结果文件包含:
Time Node Type Packets
1 leaf-1 CacheHits 0
1 leaf-1 CacheMisses 11
1 leaf-2 CacheHits 0
1 leaf-2 CacheMisses 1
输出文件格式是制表符分隔的值,第一行指定列的名称。 有关各列的说明,请参考下表:
字段名称 | 描述 |
---|---|
Time | 模拟时间 |
Node | 节点ID,全局唯一 |
Type | 时间段内的计数器类型。可能的值为:
|
Packets | 该时间段内的数据包数,其含义取决于 Type 列 |
注意
仅当使用OldContentStore结构时,此跟踪器才起作用!
ndnSIM2.1中支持两种版本的Content Store实现,新版本的CS中只有FIFO缓存替换策略,旧版本的CS中缓存替换策略更加丰富(此处官网有更详细的介绍NFD’s Content Store — ndnSIM documentation),且只有使用旧版本的实现才可使用平台内建的命中数与丢失数统计程序。如果研究目的不涉及到新的缓存策略,推荐使用旧版本的CS。以ndn-simple.cpp(在原示例中增加一个节点)文件为例,使用旧版CS且缓存替换策略为LRU,即:
// Install NDN stack on all nodes
ndn::StackHelper ndnHelper;
ndnHelper.SetDefaultRoutes(true);
ndnHelper.SetOldContentStore("ns3::ndn::cs::Lru", "MaxSize", "100");
ndnHelper.InstallAll();
然后在Simulator::Run();
前添加缓存命中信息输出代码:
ndn::CsTracer::InstallAll("cs-trace.txt", Seconds(1.0));
Simulator::Run();
Simulator::Destroy();
其中Seconds(1.0)
表示1秒统计1次。然后运行ndn-simple.cpp,在ns-3的主目录下,可以发现程序输出cs-trace.txt文件,内容为:
可以看出程序每隔1秒输出一次每个节点的命中包数与丢失包数,稍加计算即可得到单个缓存节点的命中率与全网平均命中率。
全部代码:
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/ndnSIM-module.h"
namespace ns3 {
int
main(int argc, char* argv[])
{
// setting default parameters for PointToPoint links and channels
Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps"));
Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("20p"));
// Read optional command-line parameters (e.g., enable visualizer with ./waf --run=<> --visualize
CommandLine cmd;
cmd.Parse(argc, argv);
// Creating nodes
NodeContainer nodes;
nodes.Create(4);
// Connecting nodes using two links
PointToPointHelper p2p;
p2p.Install(nodes.Get(0), nodes.Get(1));
p2p.Install(nodes.Get(1), nodes.Get(2));
p2p.Install(nodes.Get(2), nodes.Get(3));
// Install NDN stack on all nodes
ndn::StackHelper ndnHelper;
ndnHelper.SetDefaultRoutes(true);
ndnHelper.SetOldContentStore("ns3::ndn::cs::Lru", "MaxSize", "100");
ndnHelper.InstallAll();
// Choosing forwarding strategy
ndn::StrategyChoiceHelper::InstallAll("/prefix", "/localhost/nfd/strategy/multicast");
// Installing applications
// Consumer
ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
// Consumer will request /prefix/0, /prefix/1, ...
consumerHelper.SetPrefix("/prefix");
consumerHelper.SetAttribute("Frequency", StringValue("10")); // 10 interests a second
auto apps = consumerHelper.Install(nodes.Get(0)); // first node
apps.Stop(Seconds(10.0)); // stop the consumer app at 10 seconds mark
// Producer
ndn::AppHelper producerHelper("ns3::ndn::Producer");
// Producer will reply to all requests starting with /prefix
producerHelper.SetPrefix("/prefix");
producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
producerHelper.Install(nodes.Get(3)); // last node
Simulator::Stop(Seconds(20.0));
ndn::CsTracer::InstallAll("cs-trace.txt", Seconds(1.0));
Simulator::Run();
Simulator::Destroy();
return 0;
}
} // namespace ns3
int
main(int argc, char* argv[])
{
return ns3::main(argc, argv);
}
Application-level trace helper
可用于获取时延指标(官网示例文件:ndn-tree-app-delay-tracer.cpp)
通过使用ndn :: AppDelayTracer,可以获取有关发出兴趣和接收相应数据包之间的延迟的数据。
以下代码启用应用程序级别的兴趣数据延迟跟踪:
// the following should be put just before calling Simulator::Run in the scenario
AppDelayTracer::InstallAll("app-delays-trace.txt");
Simulator::Run();
...
结果文件中包含:
Time Node AppId SeqNo Type DelayS DelayUS RetxCount HopCount
10.0058 leaf-1 0 0 LastDelay 0.0057904 5790.4 1 2
10.0058 leaf-1 0 0 FullDelay 9.00579 9.00579e+06 3 2
输出文件格式是制表符分隔的值,第一行指定列的名称。 有关各列的说明,请参考下表:
字段名称 | 描述 |
---|---|
Time | 接收到SeqNo时的模拟时间 |
Node | 节点ID,全局唯一 |
AppId | 应用程序ID,在节点上是本地唯一的,不是全局的 |
SeqNo | 兴趣数据的序列号 |
Type | 延迟类型:
|
DelayS | 延迟值,以秒为单位 |
DelayUS | 延迟值,以微秒为单位(10 ^ -6) |
RetxCount | 兴趣重传次数(对于LastDelay始终等于1) |
HopCount | 检索到的数据包在从生产者应用程序或缓存返回的途中经过的网络跃点数。 请注意, |
使用示例:
以ndn-simple.cpp(在原示例中增加一个节点)文件为例,加入以下代码后运行,在ns-3的主目录下,可以发现程序输出文件app-delays-trace.txt,内容如下。
ndn::AppDelayTracer::InstallAll("app-delays-trace.txt");
至此,使用平台内建输出程序 trace helpers 获取仿真结果结束,剩下的工作就是将结果数据文件处理后可视化,可以参考教程(ndnSIM 仿真数据处理 仿真结果 生成实验结果图_ndnsim中吞吐量如何计算-CSDN博客)。官方使用的R语言,使用python等其他语言进行数据处理也可以。
NDN科研工作者,长期研究,欢迎讨论交流与合作!