source
- ns3 manual of Callbacks
- tutorial of tracing 能回答包括但不限于如下的几个问题:
- Trace/Connect & Trace/ConnectWithoutContext 的关系
- how to find available traces
- how to find config path
- how to find signature of traces (有的在当前类,有的是ns3名字空间的,后者我反正一开始是没找到
- how to solve frequentlt seen error messages (是不是就是把context打出来然后grep去查看…有点不太记得了…哈哈回头再看看吧
callback
// 回调函数 int myCallback(...){...} // 注册回调的函数 Callback<int,...> callbackHook = MakeCallback<int,...>(myCallback);
这里要区分的是:myCallback是我们自己实现的回调函数,MakeCallback是用于注册的,返回的是一个Callback<int,…>对象(这里底层是基于C++的模版实现的)
- C语言回调函数的原理(functor之类的… tl;dr,但感觉很有用,回头补上… )
- MakeCallback 和 MakeBoundCallback之间的联系与区别
基于C++的回调机制实现的
- MakeBoundCallback是在这样的场景下使用:回调函数的参数不希望提供给MakeBoundCallback的函数 (maunal里面举了例子),所以这两个不能随便乱用哈哈…
- 举了一个main-callback.cc里面的例子
我自己代码的例子:
这里DevicePacketsInQueueTrace相对于PacketsInQueue对应的回调函数,还额外多了两个固定的绑定参数 device_idx和ivoid DevicePacketsInQueueTrace(uint32_t device, uint32_t node, uint32_t oldValue, uint32_t newValue) { NS_LOG_DEBUG("DevicePacketsInQueue " << oldValue << " to " << newValue << " at " << device << "@" << node); nodeStatus[node].UpdateDeviceQueue(device, newValue); } for (auto iter = devicesInfo.begin(); iter != devicesInfo.end(); iter++) { uint32_t device_idx = distance(devicesInfo.begin(), iter); Ptr<PointToPointNetDevice> ptpnd = ns3::DynamicCast<PointToPointNetDevice> (iter-> first); Ptr<Queue<Packet> > queue = ptpnd-> GetQueue(); assert(queue); queue-> TraceConnectWithoutContext( "PacketsInQueue", MakeBoundCallback(&DevicePacketsInQueueTrace, device_idx, i)); //排队情况
- 举了一个main-callback.cc里面的例子
- MakeBoundCallback是在这样的场景下使用:回调函数的参数不希望提供给MakeBoundCallback的函数 (maunal里面举了例子),所以这两个不能随便乱用哈哈…
trace
- 实际上利用了callback机制去实现的
- 比较典型的参考文件是examples/tcp/tcp-variants-comparison.cc
- trace sink的定义:使用 .addTrace(…) , 实际上是联系了三方面的事情,trace源、callback函数、config系统,这样算是实现了一个trace
class MyObject : public Object { public: static TypeId GetTypeId (void) { static TypeId tid = TypeId ("MyObject") .SetParent (Object::GetTypeId ()) .SetGroupName ("MyGroup") .AddConstructor<MyObject> () .AddTraceSource ("MyInteger", "An integer value to trace.", MakeTraceSourceAccessor (&MyObject::m_myInt), "ns3::TracedValueCallback::Int32"); .AddTraceSource ("hesyCallBack", "callback function get from packet.h", MakeTraceSourceAccessor (&MyObject::m_myCBFunction), "ns3::MyObject::TracedCallback"); return tid; } MyObject () {} TracedValue<int32_t> m_myInt; typedef void (* TracedCallback) (Ptr<const Packet> packet); ns3::TracedCallback< Ptr<const Packet> > m_myCBFunction; }; void IntTrace (int32_t oldValue, int32_t newValue) { std::cout << "Traced " << oldValue << " to " << newValue << std::endl; } int main (int argc, char *argv[]) { Ptr<MyObject> myObject = CreateObject<MyObject> (); myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback (&IntTrace)); myObject->m_myInt = 1234; }
- 第一个参数给了trace source一个名字,使得可以在config path里main找到这个trace;
- 第二个参数是帮助文档
- 第三个参数(最重要的) &MyObject::m_myInt 是添加到类中的 TracedValue类型的数据,同时也是当前类的类数据成员。【我觉得他这个数据结构和泛型的参数也是暗示了 提供给回调函数的参数形式 】
- 第四个参数,是一个string,指向一个签名形式,是一个typedef定义的回调函数的形式
The final argument is the name of a typedef for the TracedValue type, as a string. This is used to generate documentation for the correct Callback function signature, which is useful especially for more general types of Callbacks.
- TracedValue<int32_t> m_myInt; 实际上就是在这个类里面定义了这个属性,以便config去access
- 所以就是三个元素: .addTrace, 然后定义trace source, 然后就是给出参数签名
如果是TraceCallBack,由于一般都是每个类里面的参数类型(packet类啊,tag类啊)往往是不一样的,所以在每个类里面会重新typedef一个(头文件中
typedef TraceCallBack\<curClass inst, XXX xxx \>
),所以一般第四个参数给的签名都是ns3::ClassName::TraceCallBack
; 而TraceValue一般都是传入一个int的参数,不用重新定义,所以一般第四个参数给的签名都是ns3::TraceValueInteger
(也会有float对应的啦 >w< )
config path的定义
tutorial - tracing: config-paths 里面描述得很详细了。
basis
- 形式一般是:
“/NodeList/7/$ns3::MobilityModel/CourseChange”
一个配置路径的最后一段必须是某个Object的Attribute
从nodelist中找出第七个object的指针,然后找到他聚合的MobilityModel对象,然后从这个对象里面找到其CourseChange属性。 - 两种access方式
- [namespace-based access]使用config
Config::Connect (oss.str (), MakeCallback (&CourseChange));
- [object-based access]使用Ptr<Node>来将callback Connect 到 trace
Ptr<Object> theObject = wifiStaNodes.Get (nWifi - 1); theObject->TraceConnectWithoutContext ("CourseChange", MakeCallback (&CourseChange));
- 如果想要额外给callback传递一个 context参数的话,就用TraceConnect() , 不需要的话就是 TraceWithoutContext
- 对于内部代码 Config::ConnectWithoutContext和Config::Connect实际找到对应的Ptr<Object>并调用相应的TraceConnect 底层方法。
- [namespace-based access]使用config
- TraceValue的使用和operator重载 (加减乘除赋值,>> , <<) 也在这页的底部有说明
系列递进问题
- 如何知道有哪些trace sources 以及 如何找到trace source的config path (实际上都在doxygen documents里面~)
- 新版本doxygen关于trace和config讲的不是很清楚,可以看这个3.29版本的
- 原来,新版本doxygen里面关于traces的在core module里面
- 有了如上两个,如何知道我的回调函数的返回类型和形式参数需要是什么?
看头文件里面的参数签名就可以了, 一般都用TraceWithoutContext,如果用了Trace,callback函数还得留第一个参数的位置用于接受不了trace source提供的字符串形式的context参数
坑点注意
- 动态 实时 hook , ref here
记得这个问题还蛮经典的…但是没有仔细看…下次再补充起来吧…
misc
config.h 本身也就那么多功能啊哈哈,常用的就是如下的,基本都掌握了…