The ONE使用笔记:main函数剖析

The ONE是基于代理离散事件(agent-based discrete event)仿真器。把节点间连接建立UP或DOWN,消息产生、发送、接收都视为事件,The ONE进行一些初始化工作后,反反复复处理这些动态事件,这就是The ONE运行原理,这点非常类似于Contiki(机制是相通的)。因此,理清The ONE的main函数和事件处理,就能对The ONE有个大局观,日后编程,思路也更加清晰。本文深入源码剖析The ONE的主函数。

1. main概述

The ONE有两种运行模式,即TEXT和GUI,以TEXT为例,命令行运行方式如下:

./one.sh –b 5 default_settings.txt

以批处理(batch mode)为例,main函数整个调用过程如下:

main(String[] args)    //DTNSim.java 
    initSettings(confFiles, firstConfIndex);  //初始化设置,读入default_settings.txt
    new DTNSimTextUI().start();
        initModel();         //创建仿真模型
        runSim();            //开始仿真
            world.update();  //在每个updateInterval,处理所有到期事件

首先,解析运行命令,将运行次数5保存在nrofRunsinitSettings()将配置文件default_settings.txt读到static Properties props。在这里,直观理解成将txt文件读到内存,方便后续读取。

其次,initModel()创建仿真模型。先基于配置文件创建场景(SimScenario.getInstance,创建DTNHost,设置World);增加reports,处理warmupTime (clockTime -= warmupTime, warmupTime在配置文件设置),对移动模型热身warmupMovementModel()

最后,rumSim()开始仿真。执行更新world.update(),努力(在updateInterval内)处理所有事件,更新节点移动moveHosts,更新节点连接情况updateHosts

2. 相关源代码

The ONE有两种运行模式,即TEXT和GUI,以TEXT为例,命令行运行方式如下:

./one.sh –b 5 default_settings.txt

-b指批处理模式(batch mode),5指运行次数(nrofRuns[2],实际上是一个范围),default_settings.txt是配置文件。

2.1 main函数

main函数首先解析命令行参数,读入初始设置文件default_settings.txt;接着创建仿真实例,创建仿真模型;最后开始仿真。去掉一些不相关的代码,main函数源代码(core/DTNSim.java)如下:

public static void main(String[] args) {
    nrofRuns = parseNrofRuns(args[1]);  //解析命令行参数,将运行次数保存在nrofRuns[2],配置文件名保存在confFiles[]
    initSettings(confFiles, firstConfIndex); //confFiles在这里是default_settings.txt

    for (int i=nrofRuns[0]; i<nrofRuns[1]; i++) {
        Settings.setRunIndex(i);
        resetForNextRun();
        new DTNSimTextUI().start();  //TextUI
    }
}

new DTNSimTextUI()得到一个场景实例,调用start(),该函数仅包含调用另两个函数:initModel()runSim()。源代码如下:

//DTNSim.java中new DTNSimTextUI().start(); 
//DTNSimTextUI.java
public void start() {
    initModel();   //增加reports,  设置仿真时间(减去warmupTime)
    runSim();      //抽象函数,定位到DTNSimTextUI.runSim()
}

2.2 初始化模型initModel

初始化模型initModel主要做了两件事:其一,增加报告reports;其二,处理热身时间warmup。相关源代码如下:

//DTNSimUI.java  初始化模型
protected SimScenario scen;
private void initModel() {
    settings = new Settings();
    this.scen = SimScenario.getInstance(); //创建场景,包括创建DTNHost
    
    /*** 增加报告, add reports ***/
    protected Vector<Report> reports; //
    String reportClass = settings.getSetting(REPORT_S + i); //REPORT_S="Report.report",想想配置文件
    addReport((Report)settings.createObject(REPORT_PAC + reportClass)); //REPORT_PAC="report.", 包名前缀
    
    /*** 处理热身,即不把热身这段时间的仿真统计信息计算在内 ***/
    SimClock c = SimClock.getInstance();
    c.setTime(-warmupTime);
    
    //移动模型热身 
    protected World world; //包含所有节点,更新节点的位置和连接状态
    this.world = this.scen.getWorld();
    world.warmupMovementModel(warmupTime);
}

2.3 开始仿真rumSim

rumSim最主要的是调用world.update(),其主要源代码如下:

//DTNSimTextUI.java
protected void runSim() {
    double simTime = SimClock.getTime();
    double endTime = scen.getEndTime();

    while (simTime < endTime && !simCancelled) {
        world.update();
        simTime = SimClock.getTime();
        this.update(false);  //如果下一个updateInterval还没到,就什么都不做
    }

    /*** 整个仿真结束 ***/
    simDone = true;
    done();     //所有Report r.close()
    this.update(true); //更新时间统计值
}

2.4 world.update

world.update()处理所有到期的事件。获取含有到期事件的事件队列,处理到期的事件。主要源代码如下:

//World.java
private List<EventQueue> eventQueues;  //事件队列链表,用链表将事件队列组织起来
public void update () {
    double runUntil = SimClock.getTime() + this.updateInterval;  //

    /* process all events that are due until next interval update */
    setNextEventQueue();  //找到一个事件队列,该事件队列含有本updateInterval可以处理的事件
    while (this.nextQueueEventTime <= runUntil) {
        simClock.setTime(this.nextQueueEventTime);
        ExternalEvent ee = this.nextEventQueue.nextEvent();  //取得事件
       ee.processEvent(this);  //处理事件
        updateHosts(); // update all hosts after every event
        setNextEventQueue();   
    }

    moveHosts(this.updateInterval);  //Moves all hosts in the world for a given amount of time
    simClock.setTime(runUntil);
    updateHosts();
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

8 thoughts on “The ONE使用笔记:main函数剖析