CloudSim3.0.3power编程examples及辅助类解析
power编程依赖的底层主要类(PowerDataCenter、PowerDCBroker、调度策略类等等)都是org.cloudbus.cloudsim.power包中,这些类在之前的文章中已经介绍:
Cloudsim 3.0.3中Power系列类的解析——PowerDataCenter和PowerDCBroker(2017-07-17 16:36)
Cloudsim 3.0.3中Power系列类的解析——PowerHost, PowerVM, PowerModel(2017-07-18 09:57)
Cloudsim 3.0.3中VM调度策略系列类解析(无迁移的策略)(2017-07-18 15:06)
Cloudsim 3.0.3中VM调度策略系列类解析(带迁移的策略)(2017-07-18 17:12)
等等
CloudSim3.0.3与power包相关的样例在org.cloudbus.cloudsim.examples.power.random/planetlab中,基本辅助类在org.cloudbus.cloudsim.examples.power中,样例特定的辅助类则与样例存放在一起。
1、基本辅助类
位置:org.cloudbus.cloudsim.examples.power,用于辅助power examples的编写,功能主要包括定义所有常量(如VM类型、host类型、任务类型、调度间隔schedulingInterval等)、创建数据中心、VM等各实验对象和初始化并启动模拟等等。
1.1 org.cloudbus.cloudsim.examples.power.Constants.java
定义了power仿真需要用到的各种常量,重要常量包括:
public final static double SCHEDULING_INTERVAL = 300; //调度间隔,在创建DC时会传入,数据中心在无事件可处理时,会发出delay=SCHEDULING_INTERVAL的事件以将clock向前推演一个间隔。另外,从example代码中看,300秒同时是planetlab.workload负载数据的间隔。
public final static double SIMULATION_LIMIT = 24 * 60 * 60; //仿真模拟时间上限=1天
// length: 2500 mips * 1 day
public final static int CLOUDLET_LENGTH= 2500 * (int) SIMULATION_LIMIT; //云任务的指令长度
public final static int CLOUDLET_PES= 1; //云任务的PE需求
//定义了4种虚拟机,均为单核
public final static int VM_TYPES= 4;
public final static int[] VM_MIPS= { 2500, 2000, 1000, 500 };
public final static int[] VM_PES= { 1, 1, 1, 1 };
public final static int[] VM_RAM= { 870, 1740, 1740, 613 };
public final static int VM_BW= 100000; // 100 Mbit/s
public final static int VM_SIZE= 2500; // 2.5 GB
// 定义了2种服务器
public final static int HOST_TYPES= 2;
public final static int[] HOST_MIPS= { 1860, 2660 };
public final static int[] HOST_PES= { 2, 2 };
public final static int[] HOST_RAM= { 4096, 4096 };
public final static int HOST_BW= 1000000; // 1 Gbit/s
public final static int HOST_STORAGE = 1000000; // 1 GB
//2种服务器对应的能耗模型
//每个能耗模型就是一个11元素(0%-100%)的数组
public final static PowerModel[] HOST_POWER = {
new PowerModelSpecPowerHpProLiantMl110G4Xeon3040(),
new PowerModelSpecPowerHpProLiantMl110G5Xeon3075()
};
1.2 org.cloudbus.cloudsim.examples.power.Helper.java
主要封装了创建Broker、DataCenter、主机、VM方法逻辑(Cloudlet不在此创建),用于创建数据中心的最基本组件和底层逻辑,主要方法如下:
public static List<PowerHost> createHostList(int hostsNumber) {
...
//创建主机集合,只需指定数量,其它信息由Constants内指定,其中主机类型是那2种类型循环创建,主机上的VM是timeShared
}
public static Datacenter createDatacenter(
String name,
Class<? extends Datacenter> datacenterClass,
List<PowerHost> hostList,
VmAllocationPolicy vmAllocationPolicy) {
...
//创建数据中心,需要指定datacenterClass(在power包中,用到的基本是PowerDataCenter类,譬如RunnerAbstract中调用createDataCenter就传入的它),
//还需要指定vmAllocationPolicy,即虚拟机调度策略类(在系列文章中介绍过),vmAllocationPolicy内部包含了vmSelectionPolicy。
}...
public static DatacenterBroker createBroker() {
...
//创建Broker
}
public static List<Vm> createVmList(int brokerId, int vmsNumber) {
...
}// 指定要创建的VM数量,根据Constants.java内指定的4种VM类型类创建VM。
public static void printResults( PowerDatacenter datacenter, List<Vm> vms, double lastClock, String experimentName, boolean outputInCsv, String outputFolder) {
...
// 这是打印函数,根据传入的PowerDC对象和主机列表,统计各种各样的数据(e.g., 总能耗DC.getPower()、MigrationCount、slaTimePerActiveHost等等)
// 同时会输出到参数指定的outputFolder中的文件(不存在则创建)
}
1.3 org.cloudbus.cloudsim.examples.power.RunnerAbstract.java
在更高一层封装了整个实验初始化代码,将power仿真程序中整个逻辑(从init、创建DC到提交云任务并开始仿真、最后到结束仿真)都封装在了构造函数里,其中构造函数里调用init()方法完成DCBroker、host集合、VM集合和Cloudlet集合的初始化,然后根据字符串解析出所指定的VmAllocationPolicy对象,再调用start()方法创建数据中心(用Helper提供的函数)。不过,基本辅助类RunnerAbstract是抽象类,start()方法是完整可用的(事实上辅助子类直接继承该方法),但init()方法为空,需要继承的子辅助类来实现,这是因为不同样例需要定义的Cloudlet集合不相同。
关键方法解析:
1.3 org.cloudbus.cloudsim.examples.power.RunnerAbstract.java
public RunnerAbstract( boolean enableOutput, boolean outputToFile, String inputFolder, String outputFolder, String workload, String vmAllocationPolicy, String vmSelectionPolicy, String parameter) {
// 构造函数,整个仿真逻辑都封装在了构造函数里,先调用initLogOutput()方法初始化输出目录和文件(其中文件命名与workload、policy等相关),再调用init()方法
// 初始化DCBroker、host集合、VM集合和Cloudlet集合,最后解析字符串获得vmAllocationPolicy对象和vmSelectionPolicy对象并传入start()方法开始仿真。
// 所以该构造函数(准确的说是其子类构造函数)的调用就代表初始化并开始仿真了。
...}
protected abstract void init(String inputFolder);
// init()在RunnerAbstract中是抽象函数,没有实现,因为Cloudlet的定义因样例而异。
protected void start(String experimentName, String outputFolder, VmAllocationPolicy vmAllocationPolicy) {
// 首先根据hostlist成员和vmAllocationPolicy创建出数据中心(指定为PowerDataCenter类),使能VM迁移(datacenter.setDisableMigrations(false)),
// 然后通过broker提交VM列表和Cloudlet列表,开始仿真,接收云任务执行返回列表后调用Helper的printResults()方法输出统计信息。
...}
2、样例相关的辅助类
与样例存放在一起,其中planetlab包包含使用planetlab负载数据(一大批数据文件)的样例,random包则是使用随机的负载数据。两个包里面的样例的逻辑基本是一样的,本节以random包中的辅助类和样例为例。
2.1 RandomConstants.java:
定义了3个常量:
public final static int NUMBER_OF_VMS = 50; public final static int NUMBER_OF_HOSTS = 50; public final static long CLOUDLET_UTILIZATION_SEED = 1;
// RandomConstants.java是power包中的Constants.java的补充,补充的内容就是VM数、HOST数
//是对power包中的Helper.java的补充,补充了创建Cloudlet集合的函数如下:2.2 RandomHelper.java:
public static List<Cloudlet> createCloudletList(int brokerId, int cloudletsNumber)
{
...
//该方法根据指定的cloudlet数量、power包Constants.java中定义的任务属性(指令长度、核数)来创建任务集合,另外任务的CPU负载模型采用
...//UtilizationModelStochastic类,内存和带宽用的utilizationModelNull。
}
继承:power包的RunnerAbstract2.3 RandomRunner.java
重要函数:
public RandomRunner(...){
...
//通过super()调用父类的构造函数,封装整个初始化和模拟程序逻辑。
}
@Override protected void init(String inputFolder) {
...
CloudSim.init(1, Calendar.getInstance(), false);//初始化
broker = Helper.createBroker();//调用Helper的方法创建Broker cloudletList = RandomHelper.createCloudletList(brokerId, RandomConstants.NUMBER_OF_VMS);//调用RandomHelper的方法创建Cloudlet集合
vmList = Helper.createVmList(brokerId, cloudletList.size());//调用Helper的方法创建VM集合
hostList = Helper.createHostList(RandomConstants.NUMBER_OF_HOSTS);//调用Helper的方法创建HOST集合
...
}
init()方法实现了父类抽象方法(父类RunnerAbstract)没有实现,完成DCBroker、cloudlet集合、VM集合和HOST集合的创建。
3、程序样例
有了上述的power包相关基本辅助类和特定样例辅助类,power仿真样例的代码就十分简洁了。
下面以org.cloudbus.cloudsim.examples.power.random包中的两个样例为例,一个是采用简单调度策略(PowerVmAllocationPolicySimple,系列文章中讲过,是无迁移的
First-Fit)的程序样例NonPowerAware.java,以及一个基于阈值选择迁出VM、基于负载相关性进行放置的程序样例ThrMc.java(Thr指基于阈值的vmSelectionPolicy,Mc指基
于Max correlation的放置策略,二者组合为一个总的vmAllocationPolicy来管理DC)。
3.1、NonPowerAware.java
该样例仿真一个采用简单FF调度策略的数据中心,它没有借助RunnerAbstract及其,而是直接调用power包的辅助类(Helper和Constants)的方法、Random包的样例辅助类完成的各类对象创建,所以代码比较长。public class NonPowerAware { /** * Creates main() to run this example. * * @param args the args * @throws IOException */ public static void main(String[] args) throws IOException { String experimentName = "random_npa"; String outputFolder = "output"; //允许VM调度 Log.setDisabled(!Constants.ENABLE_OUTPUT); Log.printLine("Starting " + experimentName); try { CloudSim.init(1, Calendar.getInstance(), false); //用Helper的方法创建Broker DatacenterBroker broker = Helper.createBroker(); int brokerId = broker.getId(); //用RandomHelper的方法创建任务列表 List<Cloudlet> cloudletList = RandomHelper.createCloudletList( brokerId, RandomConstants.NUMBER_OF_VMS);
//用Helper的方法创建VM集合 List<Vm> vmList = Helper.createVmList(brokerId, cloudletList.size());
List<PowerHost> hostList = Helper.createHostList(RandomConstants.NUMBER_OF_HOSTS);//用Helper的方法创建host集合
//用Helper的方法创建数据中心,并且该样例指定为PowerDatacenterNonPowerAware,VM调度策略使用PowerVmAllocationPolicySimple
PowerDatacenterNonPowerAware datacenter = (PowerDatacenterNonPowerAware) Helper.createDatacenter("Datacenter",PowerDatacenterNonPowerAware.class,hostList,new PowerVmAllocationPolicySimple(hostList));datacenter.setDisableMigrations(true);broker.submitVmList(vmList);broker.submitCloudletList(cloudletList);CloudSim.terminateSimulation(Constants.SIMULATION_LIMIT);double lastClock = CloudSim.startSimulation();List<Cloudlet> newList = broker.getCloudletReceivedList();Log.printLine("Received " + newList.size() + " cloudlets");CloudSim.stopSimulation();Helper.printResults(datacenter,vmList,lastClock,experimentName,Constants.OUTPUT_CSV,outputFolder);} catch (Exception e) {e.printStackTrace();Log.printLine("The simulation has been terminated due to an unexpected error");System.exit(0);}Log.printLine("Finished " + experimentName);}} 该样例调度策略选择的是PowerVmAllocationPolicySimple,是一种无迁移的简单FF;另外,它没有使用RunnerAbstract及其子类提供的方法来创建DC,是因为它创建的是PowerDatacenterNonPowerAware对象(而非PowerDatacenter)。//即First-Fit
查看代码,我发现PowerDatacenterNonPowerAware是继承PowerDatacenter的,并且唯一@override的方法是updateCloudletProcessing() ——一个负责输出主机、DC功耗/能耗等信息、调用各主机实例的updateVmsProcessing()方法并根据最快出现的状态变化时刻发出下一个DC事件。虽然实现不尽相同,PowerDatacenterNonPowerAware中updateCloudletProcessing()相比其父类PowerDatacenter逻辑上基本没什么不同,主要区别在于前者是先打印当前集群功耗/能耗信息,再进行状态更新,最后VM调度;而其父类则是先(调用updateCloudetProcessingWithoutSchedulingFutureEventsForce)完成状态更新和信息打印,最后VM调度。编写自定义VM掉策略的测试样例时,如果想减少封装使代码更直观,那么NonPowerAware.java是不错的参考。
3.2、ThrMc.java
该样例仿真一个采用复杂VM策略(基于阈值选择迁出VM、基于负载相关性进行放置)的PowerDC,使用了特定辅助类RandomRunner来实现全部创建和模拟启动工作,所以代码很简洁。
public class ThrMc { public static void main(String[] args) throws IOException { boolean enableOutput = true; boolean outputToFile = false; String inputFolder = ""; String outputFolder = ""; String workload = "random"; // Random workload,对于plannetlab的样例,这里就要指定负载文件名 String vmAllocationPolicy = "thr"; // Static Threshold (THR) VM allocation policy String vmSelectionPolicy = "mc"; // Maximum Correlation (MC) VM selection policy String parameter = "0.8"; // the static utilization threshold
// 辅助类RandomRunner的构造函数包含了所有逻辑,上面代码指定的各字符串会被解析并用于PowerDatacenter的配置和创建 new RandomRunner( enableOutput, outputToFile, inputFolder, outputFolder, workload, vmAllocationPolicy, vmSelectionPolicy, parameter); } }
在RandomRunner的构造函数中,vmSelectionPolicy = "mc"会被解析为PowerVmSelectionPolicyMaximumCorrelation(基于最大相关性的迁出VM选择),vmAllocationPolicy = "thr"会被解析成为PowerVmAllocationPolicyMigrationStaticThreshold(基于静态阈值的VM放置)。前者创建后作为参数传给后者的构造函数成为后者成员(毕竟VMSelection是整个Allocation或者说VMScheduling的一部分),因为带迁移的VM调度策略的抽象类PowerVmAllocationPolicyMigrationAbstract有成员:private PowerVmSelectionPolicy vmSelectionPolicy; (详见系列文章Cloudsim 3.0.3中VM调度策略系列类解析(带迁移的策略)(2017-07-18 17:12))。