CloudSim源码分析之startSimulation()

1050阅读 0评论2014-03-21 xiaoyao3857
分类:云计算

                                                                 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.                     && (
上一篇:Ceph:一个可扩展,高性能的分布式文件系统
下一篇:没有了