这是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++_omnet++mac_omnet_omnet++_deathioo_.doc"文件很可能包含了关于如何配置和运行WSN MAC层协议仿真的详细步骤、模型描述和结果分析。阅读这份文档将有助于深入理解...
通过深入学习和实践这份“Omnet++ 中文使用手册”,用户能够熟练地运用Omnet++进行各种复杂的系统仿真,无论是学术研究还是工业应用,都能得心应手。同时,持续关注社区动态和更新,能保持对Omnet++最新特性和技术的...
通过以上步骤,用户可以顺利完成OMNeT++的安装,并掌握如何使用OMNeT++ IDE来进行网络仿真的基本操作。这些教程不仅适用于初学者,也适合那些希望深入探索OMNeT++功能的进阶用户。随着实践的深入,用户还可以进一步...
- 在学术和非盈利性活动中免费使用OMNeT++。 - 进行商业性研究时需要从Global公司获得OMNeST许可证。 通过以上内容的详细介绍,我们可以了解到OMNeT++不仅是一款强大的网络模拟工具,而且具备高度的灵活性和扩展性,...
总之,“omnet++中文手册”是一个全面的学习资源,涵盖了Omnet++从基础到高级的所有重要概念,对于想要深入学习和使用Omnet++的人来说是宝贵的参考资料。通过仔细阅读和实践,用户可以掌握Omnet++的核心技术和方法,...
Omnet++是一款强大的开源模拟器,特别适用于网络和分布式系统的研究与开发。这份"Omnet++中文使用手册"是为那些想要深入理解和高效利用Omnet++的用户...在学习过程中,不断实践和总结,是提高Omnet++使用技巧的关键。
在实际应用中,OMNeT++可以用于模拟各种网络协议,评估网络设计的性能,以及研究网络技术的创新。它可以模拟从局域网到广域网、从有线到无线、从固定到移动的多种网络环境。 总而言之,OMNeT++是一个功能强大且灵活...
总的来说,这个AODV的Omnet++实现是一个宝贵的教育资源,有助于学术研究者和工程师理解AODV的工作原理,并对其在实际无线网络中的表现进行评估和优化。通过使用这个工具,我们可以深入探讨路由协议对网络性能的影响...
OMNET++是一种面向对象、模块化和可扩展的离散事件仿真框架,广泛应用于通信网络、多处理器系统、分布式系统等领域的...对于那些致力于无线传感器网络、网络仿真及OMNET++的使用者来说,这份资料是极具价值的参考资料。
作者通过结合多帧通信策略,优化LEACH算法,并在omnet++仿真环境中验证了这些改进措施的有效性。 #### omnet++平台介绍 omnet++是一个高性能、开源的离散事件仿真框架,特别适用于通信网络的研究与教学。它提供了...
本书主要针对使用OMNeT++进行无人机蜂群网络仿真的开发者,作者在学习和实践中积累了丰富的经验,并从官方手册中提炼出常用接口的详细说明,旨在为初学者提供一份实用的入门指南。作者强调,由于个人理解的局限性,...
总结来说,"Omnet++教程PDF版"是一份全面的学习资源,无论你是对无线传感器网络感兴趣,还是希望深入理解Omnet++的模拟技术,都能从中受益。通过这份中文教程,你将能够掌握Omnet++的核心功能,提升你的网络建模和...
- **第3、4、6章**:编程指南,介绍NED语言、模拟概念及其在OMNet++中的实现,指导如何编写简单的模块并描述类库。 - **第9、11章**:深入探讨如何定制网络图、编写NED源代码注释等高级主题。 - **第7、8、10章**:...
- **第3章、第4章和第6章**:编程指南,讲解NED语言、模拟原理及其在OMNeT++中的应用,以及如何编写简单的模块。 - **第9章和第11章**:深入探讨网络图的定制方法,以及如何编写NED源代码注释。 - **第7章、第8章和...
**MiXiM**(Mixed Mobility and Interference Model)作为一款专门针对无线移动网络仿真的扩展框架,它极大地丰富了OMNET++的能力。MiXiM不仅提供了细致的无线通道模型,还涵盖了移动性模型、障碍物模型及多种通信...
在本文中,我们将深入探讨如何使用OMNeT++进行无线传感器网络(WSN)的仿真,特别是关于100个节点间的路由协议。OMNeT++是一个强大的开源C++建模和仿真框架,广泛用于通信网络、分布式系统、嵌入式系统和其他复杂...
语法方面,OMnet++使用NED(Network Description)语言来定义网络结构和组件行为,结合C++用于编写更复杂的模块逻辑。 #### 1.2 物理层仿真(信道) 物理层仿真关注的是数据传输的物理媒介,如无线电波或光缆。在...
- 成功安装后,可以通过在`mingwenv.cmd`中输入`OMNETPP`命令来启动OMNET++4.0 IDE。 3. **启动OMNeT++4.0**: - 打开OMNeT++安装目录下的`mingwenv.cmd`,并在弹出的命令行界面中输入`omnetpp`以启动软件。 - ...