NS3 seventh.cc为例说明Probe<二>

对NS3 seventh.cc为例说明Probe< 一>长篇分析总结如下:

一 结构

要使用Gnuplot helper对象画图需要用到关键函数PlotProbe,其格式:

PlotProbe(probetype, external trace source's path,probe trace source,legend of data line in the figure,the location of key in the figure)

probetype在NS3中一共存在如下几类:

     类型                                      路径                                  作用

• BooleanProbe                   src/stats/model               
• DoubleProbe                     src/stats/model
• Uinteger8Probe                 src/stats/model             connects to an ns-3 trace source exporting an uint8_t
• Uinteger16Probe               src/stats/model             connects to an ns-3 trace source exporting an uint16_t
• Uinteger32Probe               src/stats/model             connects to an ns-3 trace source exporting an uint32_t
• TimeProbe                        src/stats/model
• PacketProbe                     src/network/utils           connects to an ns-3 trace source exporting a packet
• ApplicationPacketProbe     src/applications/model   connects to an ns-3 trace source exporting a packet and a socket address
• Ipv4PacketProbe               src/internet/model         connects to an ns-3 trace source exporting a packet, an IPv4 object, and an interface

它们都继承虚基类Probe,通过实现代码文件中的trace source相关联,实现对应Probe类数据的导出。例如seventh.cc里为Ipv4PacketProbe。

该类存在两个TraceSource,我们称之为内部Source:

m_output-------------Output,回调标签是Ipv4L3Protocol::TxRxTracedCallback

m_outputBytes-------------OutputBytes,回调标签是Packet::SizeTracedCallback

external trace source's path,即在仿真程序中需要真正检测统计观察的变量或者对象,我们称之为外部Source,这里是/NodeList/*/$ns3::Ipv4L3Protocol/Tx,通过API查询可知Ipv4L3Protocol对应的Trace Source多个,Tx就是其中之一:

TypeId 
Ipv4L3Protocol::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::Ipv4L3Protocol")
    .SetParent<Ipv4> ()
    .SetGroupName ("Internet")
    .AddConstructor<Ipv4L3Protocol> ()
.AddTraceSource ("Tx",
                     "Send ipv4 packet to outgoing interface.",
                     MakeTraceSourceAccessor (&Ipv4L3Protocol::m_txTrace),
                     "ns3::Ipv4L3Protocol::TxRxTracedCallback")
    .AddTraceSource ("Rx",
                     "Receive ipv4 packet from incoming interface.",
                     MakeTraceSourceAccessor (&Ipv4L3Protocol::m_rxTrace),
                     "ns3::Ipv4L3Protocol::TxRxTracedCallback")
    .AddTraceSource ("Drop",
                     "Drop ipv4 packet",
                     MakeTraceSourceAccessor (&Ipv4L3Protocol::m_dropTrace),
                     "ns3::Ipv4L3Protocol::DropTracedCallback")
  ;
  return tid;
}
可见这个外部Source如下:

Ipv4L3Protocol::m_txTrace--------Tx,回调标签是Ipv4L3Protocol::TxRxTracedCallback

probe trace source是从Probe类选择一个Trace Source对于外部Source,如这里的OutputBytes

二 Probe

在了解完整的执行流程之前,先必须知道所用的probetype内容。其分类上述已经说明,这里先拿较为简单的DoubleProbe类进行举例说明,其常用属性有Name,Enabled等,例如必须要Enabled=1时该Probe才有效。

打开src/stats/examples/double-probe-example.cc

#include <string>

#include "ns3/core-module.h"
#include "ns3/double-probe.h"

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("DoubleProbeExample");

/*
 * This is our test object, an object that increments counters at
 * various times and emits one of them as a trace source.
 */
class Emitter : public Object
{
public:
  /**
   * Register this type.
   * \return The TypeId.
   */
  static TypeId GetTypeId (void);
  Emitter ();
private:
  void DoInitialize (void);
  void Emit (void);
  void Count (void);

  TracedValue<double> m_counter;  // normally this would be integer type
  Ptr<ExponentialRandomVariable> m_var;

};

NS_OBJECT_ENSURE_REGISTERED (Emitter);

TypeId
Emitter::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::Emitter")
    .SetParent<Object> ()
    .SetGroupName ("Stats")
    .AddConstructor<Emitter> ()
    .AddTraceSource ("Counter",
                     "sample counter",
                     MakeTraceSourceAccessor (&Emitter::m_counter),
                     "ns3::TracedValueCallback::Double")
  ;
  return tid;
}

Emitter::Emitter (void)
{
  NS_LOG_FUNCTION (this);
  m_counter = 0;
  m_var = CreateObject<ExponentialRandomVariable> ();
}

void
Emitter::DoInitialize (void)
{
  NS_LOG_FUNCTION (this);
  Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
  Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}

void
Emitter::Emit (void)
{
  NS_LOG_FUNCTION (this);
  NS_LOG_DEBUG ("Emitting at " << Simulator::Now ().GetSeconds ());
  Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
}

void
Emitter::Count (void)
{
  NS_LOG_FUNCTION (this);
  NS_LOG_DEBUG ("Counting at " << Simulator::Now ().GetSeconds ());
  m_counter += 1.0;
  DoubleProbe::SetValueByPath ("/Names/StaticallyAccessedProbe", m_counter);
  Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}

// This is a function to test hooking a raw function to the trace source
void
NotifyViaTraceSource (std::string context, double oldVal, double newVal)
{
  NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
}

// This is a function to test hooking it to the probe output
void
NotifyViaProbe (std::string context, double oldVal, double newVal)
{
  NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
}
int main (int argc, char *argv[])
{
  CommandLine cmd;
  cmd.Parse (argc, argv);
  bool connected;

  Ptr<Emitter> emitter = CreateObject<Emitter> ();
  Names::Add ("/Names/Emitter", emitter);//自定义类路径加入到NS3 配置空间中

  //
  // The below shows typical functionality without a probe
  // (connect a sink function to a trace source)
  //
  connected = emitter->TraceConnect ("Counter", "sample context", MakeCallback (&NotifyViaTraceSource));
  NS_ASSERT_MSG (connected, "Trace source not connected");

  //
  // Next, we'll show several use cases of using a Probe to access and
  // filter the values of the underlying trace source
  //

  //
  // Probe1 will be hooked directly to the Emitter trace source object
  //
  // probe1 will be hooked to the Emitter trace source
  Ptr<DoubleProbe> probe1 = CreateObject<DoubleProbe> ();
  // the probe's name can serve as its context in the tracing
  probe1->SetName ("ObjectProbe");

  // Connect the probe to the emitter's Counter
  connected = probe1->ConnectByObject ("Counter", emitter);
  NS_ASSERT_MSG (connected, "Trace source not connected to probe1");

  // The probe itself should generate output.  The context that we provide
  // to this probe (in this case, the probe name) will help to disambiguate
  // the source of the trace
  connected = probe1->TraceConnect ("Output", probe1->GetName (), MakeCallback (&NotifyViaProbe));
  NS_ASSERT_MSG (connected, "Trace source not connected to probe1 Output");

  //
  // Probe2 will be hooked to the Emitter trace source object by
  // accessing it by path name in the Config database
  //
  // Create another similar probe; this will hook up via a Config path
  Ptr<DoubleProbe> probe2 = CreateObject<DoubleProbe> ();
  probe2->SetName ("PathProbe");

  // Note, no return value is checked here
  probe2->ConnectByPath ("/Names/Emitter/Counter");

  // The probe itself should generate output.  The context that we provide
  // to this probe (in this case, the probe name) will help to disambiguate
  // the source of the trace
  connected = probe2->TraceConnect ("Output", "/Names/Probes/PathProbe/Output", MakeCallback (&NotifyViaProbe));
  NS_ASSERT_MSG (connected, "Trace source not connected to probe2 Output");
  //
  // Probe3 will be called by the emitter directly through the
  // static method SetValueByPath().
  //
  Ptr<DoubleProbe> probe3 = CreateObject<DoubleProbe> ();
  probe3->SetName ("StaticallyAccessedProbe");
  // We must add it to the config database
  Names::Add ("/Names/Probes", probe3->GetName (), probe3);

  // The probe itself should generate output.  The context that we provide
  // to this probe (in this case, the probe name) will help to disambiguate
  // the source of the trace
  connected = probe3->TraceConnect ("Output", "/Names/Probes/StaticallyAccessedProbe/Output", MakeCallback (&NotifyViaProbe));
  NS_ASSERT_MSG (connected, "Trace source not connected to probe3 Output");
  // The Emitter object is not associated with an ns-3 node, so
  // it won't get started automatically, so we need to do this ourselves
  Simulator::Schedule (Seconds (0.0), &Emitter::Initialize, emitter);
  Simulator::Stop (Seconds (100.0));
  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}
首先自定义了一个类Emitter,类似上面的Ipv4L3Protocol其主要信息:

typeid是“ns3::Emitter”,                                                         VS                                               ns3::Ipv4L3Protocol                                          

Trace Source:m_counter-----Counter,标签ns3::TracedValueCallback::Double         VS                   m_txTrace----Tx, 回调标签ns3::Ipv4L3Protocol::TxRxTracedCallback

然后定义了两个回调函数:

// This is a function to test hooking a raw function to the trace source
void
NotifyViaTraceSource (std::string context, double oldVal, double newVal)
{
  NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
}

// This is a function to test hooking it to the probe output
void
NotifyViaProbe (std::string context, double oldVal, double newVal)
{
  NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
}

在仿真程序主函数里定义了四种针对Trace source处理的方法:

a 无probe,常有的source-sink形式

connected = emitter->TraceConnect ("Counter", "sample context", MakeCallback (&NotifyViaTraceSource));
b 有probe,采用对象

// probe1 will be hooked to the Emitter trace source
  Ptr<DoubleProbe> probe1 = CreateObject<DoubleProbe> ();
  // the probe's name can serve as its context in the tracing
  probe1->SetName ("ObjectProbe");
  // Connect the probe to the emitter's Counter
  connected = probe1->ConnectByObject ("Counter", emitter);
c 有probe,采用路径
// Create another similar probe; this will hook up via a Config path
  Ptr<DoubleProbe> probe2 = CreateObject<DoubleProbe> ();
  probe2->SetName ("PathProbe");
  // Note, no return value is checked here
  probe2->ConnectByPath ("/Names/Emitter/Counter");
  // The probe itself should generate output.  The context that we provide
  // to this probe (in this case, the probe name) will help to disambiguate
  // the source of the trace
  connected = probe2->TraceConnect ("Output", "/Names/Probes/PathProbe/Output", MakeCallback (&NotifyViaProbe));
d 有probe,该probe也写进NS3配置空间

Ptr<DoubleProbe> probe3 = CreateObject<DoubleProbe> ();
  probe3->SetName ("StaticallyAccessedProbe");
  // We must add it to the config database
  Names::Add ("/Names/Probes", probe3->GetName (), probe3);
  // The probe itself should generate output.  The context that we provide
  // to this probe (in this case, the probe name) will help to disambiguate
  // the source of the trace
  connected = probe3->TraceConnect ("Output", "/Names/Probes/StaticallyAccessedProbe/Output", MakeCallback (&NotifyViaProbe));
由此可知, probe不是简单的就是trace source,而是对trace source进行处理滤波。于此同时,可以知道,probe类最重要的两个成员函数是:ConnectByObject/ConnectByPath和最终的TraceConnect。有必要了解DoubleProbe,故gedit src/stats/model/double-probe.cc,可类比上面的Ipv4-Packet-Probe

                                      DoubleProbe                                                                Ipv4-Packet-Probe

typeid                      DoubleProbe                                                                         Ipv4PacketProbe

内部source             Output------m_output                                                  m_output-------------Output,m_outputBytes-------------OutputBytes

内部source签名   ns3::TracedValueCallback::Double                                 Ipv4L3Protocol::TxRxTracedCallback,Packet::SizeTracedCallback

ConnectByObject/ConnectByPath函数如下:

bool
DoubleProbe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
  NS_LOG_FUNCTION (this << traceSource << obj);
  NS_LOG_DEBUG ("Name of trace source (if any) in names database: " << Names::FindPath (obj));
  bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::DoubleProbe::TraceSink, this));
  return connected;
}

void
DoubleProbe::ConnectByPath (std::string path)
{
  NS_LOG_FUNCTION (this << path);
  NS_LOG_DEBUG ("Name of trace source to search for in config database: " << path);
  Config::ConnectWithoutContext (path, MakeCallback (&ns3::DoubleProbe::TraceSink, this));
}
可以发现这种函数主要是将外部属于对象obj属性的trace source与本probe建立关系,具体而言是将外部source作为probe内部一source,将内部TraceSink函数作为该外部source的sink函数。

void
DoubleProbe::TraceSink (double oldData, double newData)
{
  NS_LOG_FUNCTION (this << oldData << newData);
  if (IsEnabled ())
    {
      m_output = newData;
    }
}

当外部source变化-->内部TraceSink函数回调-->sink对probe内部变量m_output赋值
故src/stats/examples/double-probe-example.cc 对应probe部分运行流程分析如下:

主程序中emitter对象的source Counter值变化->通过ConnectByObject函数,调用了probe内部函数TraceSink-->TraceSink完成对probe内部变量如m_output赋值--->m_output正好是probe内部source,通过调用TraceConnect完成与对应sink函数的关联-->调用对应sink函数NotifyViaProbe -->输出结果

三 执行流程

有了上面的分析,对于sevem.cc的probe分析就很简单了。

vim scratch/myseven.cc
分析函数PlotProbe(WriteProbe类似分析),打开对应的定义:

其主要实现是由函数ConnectProbeToAggregator实现:主要函数:

1 AddProbe 将外部source 路径path作为参数,内部通过ConnectByPath将这个外部source与Probe类内部sink相关联,Probe类是Ipv4PacketProbe类,其ConnectByPath定义可见src/internet/model/ipv4-packet-probe.cc,它将外部source与内部sink函数ns3::Ipv4PacketProbe::TraceSInk关联,TraceSInk是对类内数据成员赋值也包括内部source的赋值。故完成了以下功能:

外部source--->Ipv4PacketProbe内部sink函数---->内部source赋值

2 多条条件选择,选择对应自己的Probe,如这里是Ipv4PacketProbe,可以看到由TraceConnectWithoutContext实现,内部source即probeTraceSource,这里是OutputBytes,与最终的sink关联,这里sink函数选择的是TimeSeriesAdaptor::TraceSInkUinteger32完成对应时间下新数据的输出。故这里完成:

内部source赋值-->最终sink函数关联-->输出有外部source触发导致的内部source新值。

3 Adaptor(主要是TimeSeriesAdaptor)完成Probe与Aggregator直接相关,Aggregator是最终处理仿真数据并输出画图所需的文件如.txt  .dat  .plt  .sh

可以看到sink函数选择的是TimeSeriesAdaptor::TraceSInkUinteger32,而该函数右主要是调用sink函数选择的是TimeSeriesAdaptor::TraceSInkDouble完成功能:

m_output (Simulator::Now ().GetSeconds (), newData);
查看time-series-adaptor可知m_output是TimeSeriesAdaptorl类成员函数,是一个函数签名:

TracedCallback<double,double> m_output
并且并规定为TimeSeriesAdaptorl一个Trace Source:

.AddTraceSource ( "Output",
                      "The current simulation time versus "
                      "the current value converted to a double",
                      MakeTraceSourceAccessor (&TimeSeriesAdaptor::m_output),
                      "ns3::TimeSeriesAdaptor::OutputTracedCallback")
最后通过TimeSeriesAdaptorl类成员m_timeSeriesAdaptorMap调用TraceConnect(adaptosource,MakeCallback(&GnuplotAggregator::Write2d,aggregator));

总结:

seventh.cc-->外部Source/NodeList/*/$ns3::Ipv4L3Protocol/Tx---->

1通过PlotProbe的ConnectProbeToAggregator的AddProbe完成该外部sourec与Probe内部sink函数f1关联

--->Probe内部sink函数f1调用导致Probe内部成员变量赋值,内部source也被赋值

2在通过TraceConnectWithoutContext完成Proeb内部source 与Adaptor内sink函数f2的关联-->Adaptor内的f2被调用导致Adaptor的source发生变化

3最终通过adptor的TraceConnect将Adaptor的source与Aggregator函数(sink函数f3)关联

外部source1-->probe::sink f1--->probe::source2-->adaptor::sink f2--->adaptor::source3--->aggregator::sink f3


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值