原文链接:/zhoumhan_0351/blog/static/399542272009826105222389/(本文图片需用鼠标点击方可看到,其他转帖图片根本无法看到)整理:袁嘉璐10、OpNET的ODB调试1)基本概念日志文件:仿真日志(DESlog,DiscreteEventSimulationlog)和错误日志(Errorlog)。
它的内容是在仿真过程中由进程调用OPNET函数op_prg_log_handle_create()op_prg_log_entry_write()写入的。
在Help菜单下可以打开错误日志文件。
错误日志文件以文本方式保存为<home>/op_admin/err_log,除了在菜单中打开也可以在OPNET控制台(console)窗口输入op_vuerr命令查看。
它包含了函数调用堆栈信息,我们可以从函数阶层性的调用关系中精确定位出错位置。
在编写函数时必须使用FIN(functionbegin)、FOUT(functionout)、FRET (functionreturn)等界定函数范围的标识符,而且必须使它们配对。
编写程序时切记使FIN和FOUT/FRET配对。
要产生ODB调试信息,必须将仿真核心类型设定为development,优化的仿真核心(optimized)为了加快仿真速度不产生ODB调试信息。
之后我们还需要在仿真属性中包含debug环境变量。
ODB为控制和管理仿真行为提供一个交互式环境。
ODB支持断点(Breakpoint)定义,跟踪并显示仿真诊断信息。
ODB功能的实现有赖于进程模型中编写相应的程序支持,作为ODB指令激活调试状态(breakpoint、trace和action)的依据,可以在ODB窗口中输入help<参数:all,basic,action,event,memeory,misc,object,packet,process,scripting,stop,trace>查看感兴趣的指令。
ODB常用的指令分为basic,event,object,packet,stop,trace,process几类。
Basic类指令主要包含了一些基本的操作;Event类指令主要针对事件进行操作;Object 类指令主要针对各类对象(如节点,信道等)进行操作。
Packet类指令处理所有与包相关的操作。
proldiag带的参数有2个,分别是进程ID和标签(label)。
它的效果等同于3条指令的叠加,首先ltrace激活标签;然后prodiag执行进程诊断块中的程序,并且打印标签被激活程序段的信息;最后,在执行完程序后deltrace取消对标签的跟踪。
deltrace取消对某个标签的跟踪,与激活标签不同的是,它带的参数为trace_id,而不是标签本身,但是trace_id是系统分配的,不为我们所知,需要通过输入status指令查看。
2)针对结构错误(StructuralError)的ODB调试实例我们得知是第13个事件出错我们让仿真停止在第13个事件执行之前,如下所示,在事件栏中我们看到当前中断类型为流中断,另外还有两个ID号,其中executionID为当前事件ID,scheduleID标明当前事件处在仿真核心事件列表中的位置,这两个值可能不相同,因为随着事件的增加和消减,仿真核心列表是不断变化的。
Source指明了当前中断源,例如这里表明中断是由全球网top下的pksw1子网下的node_0节点下的src进程模块在执行事件9时发出来的。
Data指明了与当前中断相关的信息,这里表明封包是从1号流端口接收来的,封包的ID为0。
Module指明当前中断的接收方,top.pksw1.node_0.proc(processor)指明了物件的阶层关系和类型,OPNET中最高层物件永远为top,代表全球网。
接着将执行第13个事件,为了观察间中执行的代码,我们启动完全跟踪(fulltrace),之后输入status命令就可以查看已设定的中断和跟踪有哪些。
接下来输入next命令,让仿真执行下一个事件。
从进程信息栏中我们可以看出当前进程(Invokingprocess)的ID号为1,进程模型的名称为pksw_nd_proc。
进程收到中断后将执行红色idle状态的窗口执行代码(exitexecutives),首先判断中断的类型为流中断,接着获取流中断索引号,其值为1。
执行完之后满足条件SRC_ARRVL,从idle状态再次转移到idle状态,同时执行条件子程序xmt(),间中试图从0号流索引的包流中获取封包,这时我们已经看出一些端倪,应该是从1号流索引收包才对,果然指示包流中并没有数据包(strm.isempty),接着出现封包指针为空的错误提示,因此op_pk_nfd_set_int32代码肯定不能正常运行。
到这里我们找到了错误所在,只要把op_pk_get(0)改为op_pk_get(1)就行了。
注意到最后两行的提示Press(ENTER)tocontinue。
这是在edit->preference中,console_exit_pause设定为TRUE带来的结果。
2)针对逻辑错误的ODB调试实例例如某个端口正常情况下应该收到数据包,吞吐量却为零。
我们通过pktrace命令启动对PacketID为1的封包的跟踪,pktrace跟踪有关包的所有执行语句,直至包被销毁。
在新版的OPNET中支持对包设置断点,任何涉及到处理封包的事件到达时仿真都会停下来,如下图所示,要推进事件必须再次输入继续仿真的命令(cont或者next),这样让我们清晰查看包在每个事件中的行为。
下面我们再次输入cont命令,包被top.pksw1.node_1.src进程模块创建,接着被top.pksw1.node_1.proc进程接收并将其dest_address域设定为1,如下图方框所示,之后被传输到底层。
接着我们再连续输入cont命令,直到包被交换机节点进程(top.pksw1.hub.hub)接收,发现包的dest_address被修改为0,如图所示。
我们仔细想一下交换机应该取出包的目的地址,根据目的地址再选择正确的路由,而不是去重新设置,这时我们已经找到了这个逻辑上的错误,只要将op_pk_nfd_set_int32改为op_pk_nfd_get_int32问题就解决了。
3)针对进程模块的ODB调试由于进程是实现整个仿真的基础,因此针对进程的调试是ODB调试的主要内容,主要包括四个部分,分别是定位进程、控制进程、跟踪进程及显示进程状态。
(1)定位进程(11)promap<Objid>显示指定进程模块包含的所有进程的ProcessID。
(12)promapall显示所有仿真中存在的进程ProcessID,如图所示。
进程标记,用来更直观地区别同种类型进程(父进程产生多个进程,这些进程是由同一个进程模型派生而来的),使用这种方法必须在进程模块中通过op_pro_tag_set(pro_handle,tag_string)来设置进程标记。
(2)控制进程ODB调试时输入指令prostop<proc_id>为进程调用设置断点。
无论什么中断,只要调用该进程,仿真都会暂时中断。
首先在进程模型中通过op_prg_odb_bkpt(label)为指定位置设置断点,这个断点以标签(label)标识,ODB调试过程中如果通过prolstop<proc_id><label>激活了该断点标签,则仿真会在被设置标签的位置中断。
(3)跟踪进程(31)protrace<proc_id>跟踪并显示调用指定进程的信息。
(32)ltrace<label>是最实用的调试指令,例如如果想找到程序中的逻辑错误,可以在可疑的程序段中加入这样一个语句。
if(op_prg_odb_ltrace_active("label")==OPC_TRUE){printf(...)},printf打印需要观察的变量,在ODB中激活标签就可以看到仿真中这些变化的情况。
(33)proltrace<proc_id><label>显示指定进程中设置过某个标签的位置所对应的信息。
(4)显示进程状态(41)在进程的诊断块(Diagnosticblock)中编写与调试相关的程序后,ODB 调试时就能通过prodiag<proc_id>执行诊断块对应的程序,从而显示调试信息。
(42)proldiag<proc_id><label>指令相当于prodiag<proc_id>与ltrace<label>的叠加。
ODB>objmapprocdp查看进程对象的信息,dp为进程的名字。
ODB>promap2查看进程模块当前被激活的进程信息,其中2为Objid。
ODB>prostop0为进程设置断点,其中0为processidODB>protrace0激活进程跟踪信息显示,其中0为processidODB>status显示指令状态。
ODB>cont,继续执行事件直至仿真运行到断点位置。
ODB>next,执行下一个事件。
子进程dp_child中的有设置进程标记的语句:sprinf(tag_string,"DynProcChild(stream%d)",op_intrpt_strm());根据包流的输入端口索引号制定进程标记tag_stringop_pro_tag_set(op_pro_self(),tag_string);为进程自身设置标签。
ODB>delstopallODB>deltraceallODB>status,再次显示指令状态,发现断点已经被取消ODB>prolstop6"dynproc_50"这时激活进程6的断点标签,当执行到进程中的op_prg_odb_bkpt("dynproc_50")语句时程序中止运行。
ODB>prodiag6,运行进程诊断块的代码。