这是Andras发表的一篇在OMNeT++中如何使用EV来有效的输出日志信息的文章。原网址在http://www.omnetpp.org/article.php?story=20040804203301352
。
译者注:现在的
OMNeT++4.0
已经将这里的结果集成了进去,推荐使用
EV
来输出日志信息。具体的定义见
include/cenvir.h
文件。这篇文章详细的讨论了如何设置
EV
,具有普遍的借鉴作用。
ev<<
语句可以用来打印信息从而了解到仿真模型正在做什么。这在进行调试和理解模型运行的时候是很有用的。现在的问题是,当模型需要运行很长时间的时候,
ev<<
语句将会消耗大量的
CPU
周期。这个时候该怎么办呢?
本文将介绍如何高效率的进行记录,并且同时介绍如何创建
log channels
或者调试
channels
。
在
Cmdevn
环境下,当设置
express-mode=true
的时候,输出将会被丢弃而不会被打印,从而使得执行可以更快。但是实际上,
ev<<
语句还是会带来一些开销。这种速度的减小可能不会被注意到,但是影响却是很大的。这里的问题是,
OMNeT++
将只会丢弃也就是不打印已经转换为文本格式的字符串。举个例子,如下面的语句:
ev << "Average bit/sec is: " << totalBits/simTime() << "n";
即使是在极速模式下,
simTime()
将会被调用,浮点数除法也会被执行。结果将会被转换为字符串并存储在缓冲区中,而这里的缓冲区则会被丢弃。很遗憾的是,
OMNeT++
核心没有办法阻止这种事情发生,因为这是
C++
的工作方式。
这时候该怎么办呢?一种常见的方式是采用
#ifdef
。
#ifdef DEBUGGING
ev << "Average bit/sec is: " << totalBits/simTime() << endl;
#endif
这并不坏,但是却有一个很严重的问题:在切换打印输出的时候必须重新编译所有的文件。根据墨菲定律(有可能出错的事情,就会出错,Anything
that can go wrong will go wrong),当人们需要输出的时候往往看不到有输出。另外,代码中满含有
#ifdef
也不是一个好办法。随后想到的就是如何在编译的时候就将是否输出考虑到,下面是一个示例代码。
if (debugging)
ev << "Average bit/sec is: " << totalBits/simTime() << endl;
这比前面要好一些。
if
语句的开销是比较小的。这样,就可以在初始化的时候通过
debugging
变量来决定是否输出信息。
debugging = par("debugging").boolValue();
这种做法还不是很方便,因为我们需要手工维护输出的状态。有些人会发现此值可以在调试中进行动态设置,但是这还不能令人满意。为什么不能让代码知道我们是否需要记录呢?
实际上,我们可以回答这个问题。一般的,
OMNeT++
知道我们何时需要进行记录:不在极速模式下的时候。幸运的是,
ev
对象可以知道这点,所以现在最新的代码如下。
if (!ev.disabled())
ev << "Average bit/sec is: " << totalBits/simTime() << endl;
几乎就是这样了。现在的问题是需要为每个
ev
输出增加一个
if
语句。有经验的
C/C++
程序员将会马上想到采用宏来产生精炼的代码。第一次尝试:
#define EV if (!ev.disabled()) ev // *** DANGEROUS!***
...
EV << "Average bit/sec is: " << totalBits/simTime() << endl;
注意,这里的宏将会产生很严重的问题。考虑一下下面的代码:
if (totalBits>1000)
EV << "Average bit/sec is: " << totalBits/simTime() << "n";
else
EV << "Not enough data yet" << endl;
这段代码并不会按照设想的那样工作。当我们宏替换完成并重新缩进代码后,将得到下面的代码:
if (totalBits>1000)
if (!ev.disabled())
ev << "Average bit/sec is: " << totalBits/simTime() << endl;
else if (!ev.disabled())
ev << "Not enough data yet" << endl;
所以这里的代码将永远不会打印出“
Not
enough data
”。
最好是忘记上面的
EV
定义,因为这很容易会使得你栽在上面。即使是在这个宏定义中加上一对括号也不能解决问题,因为打印参数将会在括号之外。看起来这个问题没法修复。
尽管如此,让我们来看看下面这个版本:
#define EV ev.disabled() ? ev : ev
...
EV << "Average bit/sec is: " << totalBits/simTime() << endl;
这看起来有点奇怪。这里的宏定义看起来没有区别(无论是为
true
或者是
false
),而且这和所有
C
语言教科书中所倡导的(宏如果需要扩展成表达式需要加上圆括号)相违背。但是确实这个宏是可以工作的。现在
EV<<
将会变成一个简单的表达式。
ev.disabled() ? ev : ev << "Average bit/sec is: " << totalBits/simTime() << endl;
这和下面的相同(注意符号的优先级)
:
ev.disabled() ? ev : (ev << "Average bit/sec is: " << totalBits/simTime() << endl);
这时候,当
ev
被禁止的时候(条件为
true
),这只是简单的一个
ev
对象的引用(这最终将会被编译器所优化,而不会产生任何的
CPU
指令);当
ev
启用的时候(条件为
false
),将会被还原成原始的
ev<<
语句。这正是我们所需要的。证明这里的
EV
定义在任何使用场景中都是可行的,这可以作为练习。无论是否有
if
语句,或者是还有一个
?:
操作符,或者是其他的场景,这都是适用的。
实际上,上面
EV
的
?:
版本并不能在
VC++ 7.0
中通过编译(因为在
VC++ 7.0
中需要?:三元操作符的第二个和第三个参数的类型是一样的,而不会做默认的转换)。所以在
VC7
中的版本是这样的:
#define EV ev.disabled() ? (std::ostream&)ev : ev
(译者注:实际上,由于现在最新的
OMNeT++
4.0
并不支持使用
VC
编译器进行编译,所以也没有采用这样的方式)。
如果你没有用过
log4j
或者是
C++
中类似的工具(
log4Cpp
,
libCWD
等),那你有可能错过调试管道或者说是日志管道。简单地说,
channels
是针对快速滚动日志问题的答案(因为你几乎不可能在日志的海洋中找到有用的信息)。你的代码日志将会记录到多个管道中,而在调试的时候可以只关注自己感兴趣的管道。有两个标准可以用来区分管道日志:
topic
和调试级别(如
detail,
info, warnings
)。其中第三个标准是位置(模块位置),这已经被
OMNeT++
内置了。可以通过查看模块的输出来得到你想要的信息。
一个比较好的消息是通过上面的
EV
定义,可以用来简单的模拟日志管道。当书写一个
IP
模块的时候,检查下面的定义:
#define fwdingEV (ev.disabled()||!fwdingChannel) ? (std::ostream&)ev : ev
#define localEV (ev.disabled()||!localChannel) ? (std::ostream&)ev : ev
#define mcastEV (ev.disabled()||!mcastChannel) ? (std::ostream&)ev : ev
#define dropEV (ev.disabled()||!dropChannel) ? (std::ostream&)ev : ev
上面的定义提供了四个日志信道(
wdingEV, localEV, mcastEV, dropEV
),可以通过单独设置
fwdingChannel,
localChannel, mcastChannel, dropChannel
布尔变量的值来进行开关。可以像下面这样使用日志管道。
...
EV << "packet received" << endl;
...
if (destAddress.isMulticast())
{
mcastEV << "multicast packet, addr=" << destAddress << endl;
...
}
...
if (!routeFound)
{
dropEV << "unroutable packet, dropping" << endl;
delete datagram;
}
...
分享到:
相关推荐
OMNeT++中文使用手册 第[1],[2]章包括介绍性的资料 第二组章节,[3],[4],和[6]是编程向导.他们提出了NED语言,仿真的概念和他们在OMNet++ 中的执行,解释了如何写一个简单的模块并描述了类库. 第[9],[11]进一步阐述了...
OMNET++结合MiXiM ,更方便做无线移动网络的仿真,MiXiM结合和扩展了一些现有的模拟框架来发展基于OMNeT++的无线移动仿真。它提供了详细的无线通道模型(褪色等),无线连接,移动模型,障碍模型和许多通信协议尤其...
版权为原作者所有,仅供参考,下载后24小时内请自觉删除
主用用于通信中的MAC层协议的仿真,模拟节点发包、丢包过程
omnet++5.2软件的安装包以及安装的指南,以及用户的使用手册
适合没接触过omnet++又要使用它的初学者,详细介绍了omnet++5.6的安装和IDE的使用,每一个步骤都有截图,供大家参考。
一部非常详细和基础的OMnet++教程,相信大家会学清OMnet++的原理,是做仿真的必备资料
omnet++中文使用手册,很全的,希望没有传重复,大家下下来慢慢看吧,希望有帮助
OMNET++4.1中文手册。全部翻译英文手册,借助该手册可以帮助你快速学会OMNet++。
基于omnet++的leach协议的仿真研究,适合新手
Leach协议在omnet++ 5.1平台下的仿真代码,主要由BS和Node两类节点组成,BS通过收集信息,对网络内节点进行分簇,节点发送消息到簇头,簇头周期性向BS报告自己的状态,以便进行下一轮的分簇........
OMNeT++经典教程实例;OMNeT++_4.0_IDE(集成开发环境)教程;OMNeT++_4.0中文手册
2.3.2.1 OMNET++中离散事件 17 2.3.2.2 包传输模型 17 2.3.2.3定义简单模块 18 2.3.2.4 简单模块中的主要成员函数 20 2.3.3 消息 20 2.3.3.1 cMessage类 20 2.3.3.2 消息定义 21 2.3.3.3 消息的收发 22 2.3.4 模块...
The OMNeT++ discrete event simulation environment has been publicly available since 1997. It has been created with the simulation of communication networks, multiprocessors and other distributed ...
omnet++4.1_中文手册
用OMNET++4.0 对MD5加密算法的实现。(注:只能在OMNET++4.0中打开)
omnet++的基本入门介绍,介绍的很详细,是基于手册进行修改制作的
omnet++方面在国内用的比较少,最近得到一个资料供大家分享