Chinaunix首页 | 论坛 | 博客
  • 博客访问: 189437
  • 博文数量: 19
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1062
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-10 15:52
个人简介

经历过才能真的感受,做一个靠谱的人!

文章分类

全部博文(19)

文章存档

2015年(1)

2013年(18)

我的朋友

分类: 云计算

2013-09-23 09:38:19

                                                                 CloudSim源码分析之startSimulation()

CloudSim源码中的example都是通过startSimulation()启动仿真过程,实际上startSimulation()方法内部做了非常多的工作,此次博客将详细分析startSimulation()方法的工作流程。

startSimulation()CloudSim类的静态方法,该方法在所有的实体被创建和加载之后调用,开始执行CloudSim仿真,直到所有的实体完全执行(所有的实体线程到达non-RUNNABLE状态或者在future队列中没有事件)才结束。

startSimulation()方法完成的核心工作:

1启动所有在startSimulation()方法之前定义好的实体CloudSimShutdownCloudInformationServiceDatacenterDatacenterBroker)。核心是根据不同实体间的逻辑关系创建相关事件,并将事件添加到等待队列(future比如:datacenter实体首先需要向CIS注册,因此datacenter会创建一个向CIS请求注册的事件,并将该事件添加到等待队列;datacenterBroker实体需要知道数据中心特征,因此datacenterBroker会创建一个向datacenter实体请求数据中心特征的事件,并将该事件添加到等待队列。在下面的源码中会按照方法调用的深度详细分析。
    (1)startSimulation()源码分析:    

点击(此处)折叠或打开

  1. // CloudSim类的静态方法,该方法在所有的实体被创建和加载之后调用,开始执行CloudSim仿真,直到所有的实体完全执行

  2.     // (所有的实体线程到达non-RUNNABLE状态或者在future队列中没有事件)才结束。

  3.     public static double startSimulation() throws NullPointerException {
  4.         Log.printLine("Starting CloudSim version " + CLOUDSIM_VERSION_STRING);
  5.         try {
  6.             // 开始仿真至结束

  7.             double clock = run();

  8.             // reset all static variables

  9.             // 仿真结束,重设所有的静态变量

  10.             cisId = -1;
  11.             shutdownId = -1;
  12.             cis = null;
  13.             calendar = null;
  14.             traceFlag = false;

  15.             return clock;
  16.         } catch (IllegalArgumentException e) {
  17.             e.printStackTrace();
  18.             throw new NullPointerException("CloudSim.startCloudSimulation() :"
  19.                     + " Error - you haven't initialized CloudSim.");
  20.         }
  21.     }
   (2)run()开始仿真:

点击(此处)折叠或打开

  1. // 开始仿真直到结束仿真

  2.     public static double run() {
  3.         if (!running) {
  4.             runStart(); // 开始仿真,start所有实体    
  5.         }
  6.     .......
  7.     }
   (3)runStart()启动所有仿真实体:

点击(此处)折叠或打开

  1. // 启动仿真实体

  2.     public static void runStart() {
  3.         running = true;
  4.         // Start all the entities

  5.         for (SimEntity ent : entities) {
  6.             Log.printLine("实体名称:"+ent.getName());
  7.             // 每个实体都继承了SimEntity类的startEntity()方法,实际工作是向其他实体发送一个请求事件,

  8.             // 并将该事件添加到future队列中。

  9.             ent.startEntity();
  10.         }

  11.         printMessage("Entities started.");
  12.     }
   (4)启动云实体datacenterBroker

点击(此处)折叠或打开

  1. // 启动云实体
  2.     @Override
  3.     public void startEntity() {
  4.         Log.printLine(getName() + " is starting...");
  5.         // 通过id和数据向另一个实体发送事件,请求数据中心特征
  6.         schedule(getId(), 0, CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST);
  7.     }
   (5)向另外实体发送事件

点击(此处)折叠或打开

  1. // 向另外一个实体发送关联事件

  2.     public void schedule(int dest, double delay, int tag, Object data) {
  3.         if (!CloudSim.running()) {
  4.             return;
  5.         }
  6.         CloudSim.send(id, dest, delay, tag, data);
  7.     }
   (6)创建仿真事件,并添加到等待队列

点击(此处)折叠或打开

  1. // 一个实体向另一个实体发送事件

  2.     public static void send(int src, int dest, double delay, int tag, Object data) {
  3.         // 事件发生的延时不能为负值

  4.         if (delay < 0) {
  5.             throw new IllegalArgumentException("Send delay can't be negative.");
  6.         }

  7.         // 创建一个仿真事件对象

  8.         SimEvent e = new SimEvent(SimEvent.SEND, clock + delay, src, dest, tag, data);
  9.         Log.printLine("````````````````````"+e.getTag());
  10.         // 将创建的事件添加到等待队列中

  11.         future.addEvent(e);
  12.     }


2处理具体的仿真任务,实际是处理延时队列以及等待队列中的各种事件。CloudSim允许仿真突然中止、在特定时刻中止仿真、在某一时刻暂停仿真,最主要也最一般的情况是在一个时钟心跳期间处理事件队列中的事件。在下面的源码中会按照方法调用的深度详细分析。
    (1)处理仿真事件

点击(此处)折叠或打开

  1. // 开始仿真直到结束仿真

  2.     public static double run() {
  3.         if (!running) {
  4.             runStart(); // 开始仿真,start所有实体
  5.         }
  6.         while (true) {
  7.             // 运行一个时钟心跳如果future中没有事件了,则runClockTick()返回true,或者突然中断,while循环终止,仿真结束。
  8.             if (runClockTick() || abruptTerminate) {
  9.                 break;
  10.             }

  11.             // this block allows termination of simulation at a specific time
  12.             // 允许在特定的时间点终止仿真。
  13.             if (terminateAt > 0.0 && clock >= terminateAt) {
  14.                 terminateSimulation(); // 终止仿真

  15.                 clock = terminateAt;
  16.                 break;
  17.             }
  18.             // 在某一时刻(pauseAt)暂停仿真
  19.             if (pauseAt != -1
  20.                     && ((future.size() > 0 && clock <= pauseAt && pauseAt <= future.iterator().next()
  21.                             .eventTime()) || future.size() == 0 && pauseAt <= clock)) {
  22.                 pauseSimulation(); // 设置paused为true

  23.                 clock = pauseAt;
  24.             }

  25.             // 如果paused为true,则线程休眠100毫秒,但是何时会重新设置paused为false,终止暂定仿真呢?
  26.             while (paused) {
  27.                 try {
  28.                     Thread.sleep(100);
  29.                 } catch (InterruptedException e) {
  30.                     e.printStackTrace();
  31.                 }
  32.             }
  33.         }
  34.         ........
  35.     }
   (2)处理延时队列和等待队列中的事件,分析runClockTick()方法

点击(此处)折叠或打开

  1.     // 运行一个时钟滴答,首先处理延时队列(deferred)中跟各个实体相关的事件。当延时队列为空时,
  2.     // 处理等待队列(future)中的事件,问题是deferred中的事件是何时从future中添加过来的?
  3.     public static boolean runClockTick() {
  4.         SimEntity ent;
  5.         boolean queue_empty;
  6.         int entities_size = entities.size(); // 实体的个数

  7.         for (int i = 0; i < entities_size; i++) { // 逐个获取实体

  8.             ent = entities.get(i);
  9.             if (ent.getState() == SimEntity.RUNNABLE) { // 设置实体状态为RUNNABLE
  10.                 // run()是各实体类继承了SimEntity类的方法,作用是处理与各个实体相关的事件。
  11.                 ent.run();
  12.             }
  13.         }

  14.         // If there are more future events then deal with them
  15.         // 等待队列中还有未处理的事件
  16.         if (future.size() > 0) {
  17.             List<SimEvent> toRemove = new ArrayList<SimEvent>();
  18.             Iterator<SimEvent> it = future.iterator();
  19.             queue_empty = false;
  20.             SimEvent first = it.next();
  21.             processEvent(first);// 直接处理了!事件何时添加到future队列中呢?

  22.             future.remove(first);

  23.             it = future.iterator();

  24.             // Check if next events are at same time...
  25.             boolean trymore = it.hasNext();
  26.             while (trymore) {
  27.                 SimEvent next = it.next();
  28.                 // 检查下一个事件的时间是否相同,相同则处理下一个事件,因为必须在同一个时钟心跳。
  29.                 if (next.eventTime() == first.eventTime()) {
  30.                     processEvent(next);
  31.                     toRemove.add(next);
  32.                     trymore = it.hasNext();
  33.                 } else {
  34.                     trymore = false;
  35.                 }
  36.             }

  37.             future.removeAll(toRemove);

  38.         } else {
  39.             queue_empty = true;
  40.             running = false;
  41.             printMessage("Simulation: No more future events");
  42.         }

  43.         return queue_empty;
  44.     }
    (3)分析SimEntity类的run()方法

点击(此处)折叠或打开

  1.     //所有的实体都直接继承了run()方法,并没有重写。
  2.     public void run() {

  3.         // evbuf如果为null,则ev=getNextEvent(),否则ev=evbuf.
  4.         // getNextEvent():获取延时队列(deferred)中第一个事件(可算找到你了)
  5.         SimEvent ev = evbuf != null ? evbuf : getNextEvent();
  6.         
  7.         while (ev != null) {

  8.             // 每个实体类都有自己的processEvent()方法,哪个实体调用了run()方法,就会调用其processEvent()方法。
  9.             processEvent(ev);
  10.             if (state != RUNNABLE) {
  11.                 break;
  12.             }

  13.             ev = getNextEvent();
  14.         }

  15.         evbuf = null;
  16.     }
    (4)每个实体类都重载了processEvent()方法,负责处理与自己相关的事件

点击(此处)折叠或打开

  1. // DatacenterBroker重载的processEvent()方法
  2. public void processEvent(SimEvent ev) {
  3.         switch (ev.getTag()) {
  4.         // Resource characteristics request

  5.             case CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST:
  6.                 processResourceCharacteristicsRequest(ev);
  7.                 break;
  8.             // Resource characteristics answer

  9.             case CloudSimTags.RESOURCE_CHARACTERISTICS:
  10.                 processResourceCharacteristics(ev);
  11.                 break;
  12.             // VM Creation answer

  13.             case CloudSimTags.VM_CREATE_ACK:
  14.                 processVmCreate(ev);
  15.                 break;
  16.             // A finished cloudlet returned

  17.             case CloudSimTags.CLOUDLET_RETURN:
  18.                 processCloudletReturn(ev);
  19.                 break;
  20.             // if the simulation finishes

  21.             case CloudSimTags.END_OF_SIMULATION:
  22.                 shutdownEntity();
  23.                 break;
  24.             // other unknown tags are processed by this method

  25.             default:
  26.                 processOtherEvent(ev);
  27.                 break;
  28.         }
  29.     }

3、获取仿真运行时间,仿真完成,运行结束。

点击(此处)折叠或打开

  1. // 开始仿真直到结束仿真

  2.     public static double run() {
  3.         if (!running) {
  4.             runStart(); // 开始仿真,start所有实体

  5.         }
  6.         while (true) {
  7.             // 运行一个时钟心跳如果future中没有事件了,则runClockTick()返回true,或者突然中断,while循环终止,仿真结束。
  8.             if (runClockTick() || abruptTerminate) {
  9.                 break;
  10.             }

  11.             // this block allows termination of simulation at a specific time
  12.             // 允许在特定的时间点终止仿真。
  13.             if (terminateAt > 0.0 && clock >= terminateAt) {
  14.                 terminateSimulation(); // 终止仿真

  15.                 clock = terminateAt;
  16.                 break;
  17.             }

  18.             // 在某一时刻(pauseAt)暂停仿真
  19.             if (pauseAt != -1
  20.                     && (
阅读(4978) | 评论(4) | 转发(3) |
给主人留下些什么吧!~~

xiaoyao38572014-03-21 16:24:25

xiaoyao3857:学习笔记,结构清晰,解说落到实处,并有实际问题留待探讨,很有帮助,我这里受益不少,另外,我也抛个问题:各事件是如何设置与相应的处理程序对应的,比如对于CloudSim.VM_DATA_ADD是由什么事件设置的

另外,任务队列中什么时候从Deffered加入到Future队列中,可能是在CloudletScheduler的派生类中实现的

回复 | 举报

xiaoyao38572014-03-21 15:05:16

学习笔记,结构清晰,解说落到实处,并有实际问题留待探讨,很有帮助,我这里受益不少,另外,我也抛个问题:各事件是如何设置与相应的处理程序对应的,比如对于CloudSim.VM_DATA_ADD是由什么事件设置的

xuru19902014-02-21 14:47:16

这篇文章,解决了我不少的困惑,非常感谢!楼主对cloudsim研究的很透彻,思路清晰,层层深入。32个赞!刚加你为好友,希望还有些问题能和你讨论下!

CU博客助理2013-10-10 11:17:55

嘉宾点评: 这种文章更像是学习笔记,结构清晰,步骤分明,还解说的非常清楚 ,是很好的博文,简单实用,请作者多产吧!!(感谢您参与“原创博文评选”获奖结果即将公布)