CloudSim源碼分析之-startSimulation()

 在CloudSim源碼中的example都是通過startSimulation()啓動仿真過程,實際上startSimulation()方法內部做了非常多的工作,此次博客將詳細分析startSimulation()方法的工作流程。

     startSimulation()CloudSim類的靜態方法,該方法在所有的實體被創建和加載之後調用,開始執行CloudSim仿真,直到所有的實體完全執行(所有的實體線程到達non-RUNNABLE狀態或者在future隊列中沒有事件)才結束。

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

1.開始實體

startSimulation()----->

                       run()----->

                                startEntity()----->

                                            sendNow()-->send()-->schedule()-->send(){.....

                                                                                        simEvent.e

                                                                                        future.addEvent(e)

                                                                                     }

2.執行事件

startSimulation()----->

                       run()----->

                             runClockTick()----->

                                             defferredQueue----->1)執行事件   2)發送事件並加入futureQueue

                                             futureQueue----->把事件加入deferredQueue中

1啓動所有在startSimulation()方法之前定義好的實體CloudSimShutdownCloudInformationServiceDatacenterDatacenterBroker)。核心是根據不同實體間的邏輯關係創建相關事件,並將事件添加到等待隊列(future比如:datacenter實體首先需要向CIS註冊,因此datacenter會創建一個向CIS請求註冊的事件,並將該事件添加到等待隊列;datacenterBroker實體需要知道數據中心特徵,因此datacenterBroker會創建一個向datacenter實體請求數據中心特徵的事件,並將該事件添加到等待隊列。在下面的源碼中會按照方法調用的深度詳細分析。
    (1)startSimulation()源碼分析:    

點擊(此處)摺疊或打開

  1. // CloudSim類的靜態方法,該方法在所有的實體被創建和加載之後調用,開始執行CloudSim仿真,直到所有的實體完全執行

  2.     // (所有的實體線程到達non-RUNNABLE狀態或者在future隊列中沒有事件)才結束。

  3.     publicstaticdoublestartSimulation()throwsNullPointerException{
  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.             thrownewNullPointerException("CloudSim.startCloudSimulation() :"
  19.                     +" Error - you haven't initialized CloudSim.");
  20.         }
  21.     }
   (2)run()開始仿真:

點擊(此處)摺疊或打開

  1. // 開始仿真直到結束仿真

  2.     publicstaticdoublerun(){
  3.         if(!running){
  4.             runStart();// 開始仿真,start所有實體    
  5.         }
  6.     .......
  7.     }
   (3)runStart()啓動所有仿真實體:

點擊(此處)摺疊或打開

  1. // 啓動仿真實體

  2.     publicstaticvoid 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.     publicvoidstartEntity(){
  4.         Log.printLine(getName()+" is starting...");
  5.         // 通過id和數據向另一個實體發送事件,請求數據中心特徵
  6.         schedule(getId(), 0, CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST);
  7.     }
   (5)向另外實體發送事件

點擊(此處)摺疊或打開

  1. // 向另外一個實體發送關聯事件

  2.     publicvoid schedule(int dest,doubledelay,int tag,Object data){
  3.         if(!CloudSim.running()){
  4.             return;
  5.         }
  6.         CloudSim.send(id, dest,delay, tag, data);
  7.     }
   (6)創建仿真事件,並添加到等待隊列

點擊(此處)摺疊或打開

  1. // 一個實體向另一個實體發送事件

  2.     publicstaticvoidsend(int src,int dest,doubledelay,int tag,Object data){
  3.         // 事件發生的延時不能爲負值

  4.         if(delay< 0){
  5.             thrownewIllegalArgumentException("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.     publicstaticdoublerun(){
  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.     publicstaticboolean 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 =newArrayList<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.     publicvoidrun(){

  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. publicvoidprocessEvent(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.     publicstaticdoublerun(){
  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.                     &&(
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章