CloudSim源码分析之startSimulation()
在CloudSim源码中的example都是通过startSimulation()启动仿真过程,实际上startSimulation()方法内部做了非常多的工作,此次博客将详细分析startSimulation()方法的工作流程。
startSimulation()是CloudSim类的静态方法,该方法在所有的实体被创建和加载之后调用,开始执行CloudSim仿真,直到所有的实体完全执行(所有的实体线程到达non-RUNNABLE状态或者在future队列中没有事件)才结束。
startSimulation()方法完成的核心工作:
1、启动所有在startSimulation()方法之前定义好的实体(CloudSimShutdown、CloudInformationService、Datacenter、DatacenterBroker)。核心是根据不同实体间的逻辑关系创建相关事件,并将事件添加到等待队列(future)。比如:datacenter实体首先需要向CIS注册,因此datacenter会创建一个向CIS请求注册的事件,并将该事件添加到等待队列;datacenterBroker实体需要知道数据中心特征,因此datacenterBroker会创建一个向datacenter实体请求数据中心特征的事件,并将该事件添加到等待队列。在下面的源码中会按照方法调用的深度详细分析。
(1)startSimulation()源码分析:
-
// CloudSim类的静态方法,该方法在所有的实体被创建和加载之后调用,开始执行CloudSim仿真,直到所有的实体完全执行
-
-
// (所有的实体线程到达non-RUNNABLE状态或者在future队列中没有事件)才结束。
-
-
public static double startSimulation() throws NullPointerException {
-
Log.printLine("Starting CloudSim version " + CLOUDSIM_VERSION_STRING);
-
try {
-
// 开始仿真至结束
-
-
double clock = run();
-
-
// reset all static variables
-
-
// 仿真结束,重设所有的静态变量
-
-
cisId = -1;
-
shutdownId = -1;
-
cis = null;
-
calendar = null;
-
traceFlag = false;
-
-
return clock;
-
} catch (IllegalArgumentException e) {
-
e.printStackTrace();
-
throw new NullPointerException("CloudSim.startCloudSimulation() :"
-
+ " Error - you haven't initialized CloudSim.");
-
}
-
}
(2)run()开始仿真:
-
// 开始仿真直到结束仿真
-
-
public static double run() {
-
if (!running) {
-
runStart(); // 开始仿真,start所有实体
-
}
-
.......
-
}
(3)runStart()启动所有仿真实体:
-
// 启动仿真实体
-
-
public static void runStart() {
-
running = true;
-
// Start all the entities
-
-
for (SimEntity ent : entities) {
-
Log.printLine("实体名称:"+ent.getName());
-
// 每个实体都继承了SimEntity类的startEntity()方法,实际工作是向其他实体发送一个请求事件,
-
-
// 并将该事件添加到future队列中。
-
-
ent.startEntity();
-
}
-
-
printMessage("Entities started.");
-
}
(4)启动云实体datacenterBroker
-
// 启动云实体
-
@Override
-
public void startEntity() {
-
Log.printLine(getName() + " is starting...");
-
// 通过id和数据向另一个实体发送事件,请求数据中心特征
-
schedule(getId(), 0, CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST);
-
}
(5)向另外实体发送事件
-
// 向另外一个实体发送关联事件
-
-
public void schedule(int dest, double delay, int tag, Object data) {
-
if (!CloudSim.running()) {
-
return;
-
}
-
CloudSim.send(id, dest, delay, tag, data);
-
}
(6)创建仿真事件,并添加到等待队列
-
// 一个实体向另一个实体发送事件
-
-
public static void send(int src, int dest, double delay, int tag, Object data) {
-
// 事件发生的延时不能为负值
-
-
if (delay < 0) {
-
throw new IllegalArgumentException("Send delay can't be negative.");
-
}
-
-
// 创建一个仿真事件对象
-
-
SimEvent e = new SimEvent(SimEvent.SEND, clock + delay, src, dest, tag, data);
-
Log.printLine("````````````````````"+e.getTag());
-
// 将创建的事件添加到等待队列中
-
-
future.addEvent(e);
-
}
2、处理具体的仿真任务,实际是处理延时队列以及等待队列中的各种事件。CloudSim允许仿真突然中止、在特定时刻中止仿真、在某一时刻暂停仿真,最主要也最一般的情况是在一个时钟心跳期间处理事件队列中的事件。在下面的源码中会按照方法调用的深度详细分析。
(1)处理仿真事件
-
// 开始仿真直到结束仿真
-
-
public static double run() {
-
if (!running) {
-
runStart(); // 开始仿真,start所有实体
-
}
-
while (true) {
-
// 运行一个时钟心跳如果future中没有事件了,则runClockTick()返回true,或者突然中断,while循环终止,仿真结束。
-
if (runClockTick() || abruptTerminate) {
-
break;
-
}
-
-
// this block allows termination of simulation at a specific time
-
// 允许在特定的时间点终止仿真。
-
if (terminateAt > 0.0 && clock >= terminateAt) {
-
terminateSimulation(); // 终止仿真
-
-
clock = terminateAt;
-
break;
-
}
-
// 在某一时刻(pauseAt)暂停仿真
-
if (pauseAt != -1
-
&& ((future.size() > 0 && clock <= pauseAt && pauseAt <= future.iterator().next()
-
.eventTime()) || future.size() == 0 && pauseAt <= clock)) {
-
pauseSimulation(); // 设置paused为true
-
-
clock = pauseAt;
-
}
-
-
// 如果paused为true,则线程休眠100毫秒,但是何时会重新设置paused为false,终止暂定仿真呢?
-
while (paused) {
-
try {
-
Thread.sleep(100);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
........
-
}
(2)处理延时队列和等待队列中的事件,分析runClockTick()方法
3、获取仿真运行时间,仿真完成,运行结束。
-
// 开始仿真直到结束仿真
-
-
public static double run() {
-
if (!running) {
-
runStart(); // 开始仿真,start所有实体
-
-
}
-
while (true) {
-
// 运行一个时钟心跳如果future中没有事件了,则runClockTick()返回true,或者突然中断,while循环终止,仿真结束。
-
if (runClockTick() || abruptTerminate) {
-
break;
-
}
-
-
// this block allows termination of simulation at a specific time
-
// 允许在特定的时间点终止仿真。
-
if (terminateAt > 0.0 && clock >= terminateAt) {
-
terminateSimulation(); // 终止仿真
-
-
clock = terminateAt;
-
break;
-
}
-
-
// 在某一时刻(pauseAt)暂停仿真
-
if (pauseAt != -1
-
&& (