基于CloudSim Plus的计算卸载仿真设计

基于CloudSim Plus的计算卸载仿真设计

1. 前提介绍

仿真框架的实现,主要依托于仿真实体、以及仿真事件,简单介绍如下

1.1 仿真实体

  • 继承CloudSimEntity类(推荐)或者实现SimEntity接口(不建议)

    public class ExampleEntity extends CloudSimEntity {
    
        public ExampleEntity(Simulation simulation) {
            super(simulation);
        }
    
        @Override
        protected void startInternal() {
    	// 实体开始启动
        }
    
        @Override
        public void processEvent(SimEvent evt) {
    	// 接收仿真事件
        }
    }
    
  • 该实体将交由CloudSim进行管理

  • 各个实体之间因此也可以通信(通过仿真事件)

1.2 仿真事件

  • 发送仿真事件

    可以使用schedule()scheduleNow()来发送仿真事件

    schedule(final SimEntity dest, final double delay, final CloudSimTag tag, final Object data)
    scheduleNow(final SimEntity dest, final CloudSimTag tag, final Object data) 
    

    例如:实体启动时给自身发送事件

    @Override
    protected void startInternal() {
        schedule(this, 1, CloudSimTag.ENTITY_UPDATE);
    }
    

    主要包括:事件的接收实体,事件的到达时间,事件的标签

    例如:this表示事件发送给该实体自身,1表示事件一秒钟后到达,ENTITY_UPDATE表示事件的标签

  • 接收仿真事件

    @Override
    public void processEvent(SimEvent evt) {
        CloudSimTag tag = evt.getTag();
        if (tag == CloudSimTag.ENTITY_UPDATE){
            // Do Something(在这里可以执行更新状态的逻辑)
            // 继续发送仿真事件,从而使得仿真实体每秒钟更新自身状态
             schedule(this, 1, CloudSimTag.ENTITY_UPDATE);
        }
    }
    

2. 基础设施层

2.1 边缘设备

  • 实现方式:继承仿真实体类,然后给自身发送仿真事件,实现自身状态的更新(如:位置,能耗,利用率等)

    public class DeviceEntity extends CloudSimEntity {
    
        public DeviceEntity(Simulation simulation) {
            super(simulation);
        }
    
        @Override
        protected void startInternal() {
            schedule(this, 1, CloudSimTag.ENTITY_UPDATE);
        }
    
        @Override
        public void processEvent(SimEvent evt) {
            CloudSimTag tag = evt.getTag();
            if (tag == CloudSimTag.ENTITY_UPDATE){
                updateStatus();
                schedule(this, 1, CloudSimTag.ENTITY_UPDATE);
            }
        }
    
        private void updateStatus() {
    		// 更新能耗、利用率、节点位置、无线接入点切换等(根据需求自定义)
        }
    }
    
  • 自定义的其他组件同理

3. 其他组件

3.1 任务调度算法接口

  • 为任务执行计算卸载决策
  • 计算节点内进行任务与虚拟机匹配调度
  • 任务结果返回事件(便于扩展强化学习算法)
    public abstract class AbstractAlgorithm extends DatacenterBrokerSimple {
    
        protected SimManager simulationManager;
    
        public SimManager getSimulationManager() {
            return simulationManager;
        }
    
        public AbstractAlgorithm(SimManager simulation) {
            super(simulation.getSimulation());
            this.simulationManager = simulation;
        }
    
        /**
         * 选择任务处理方式:本地处理、边缘处理、云端处理
         * @param cloudlet 待处理的任务
         * @return 为任务选择的计算节点
         */
        public abstract AbstractNode makeDecision(Cloudlet cloudlet);
    
        /**
         * 任务在计算节点内的调度策略
         *
         * @param cloudlet 待调度的任务
         * @return Vm 为任务选择的虚拟机
         */
        public abstract Vm scheduleTask(Cloudlet cloudlet);
    
        /**
         * 任务返回: 例如使用强化学习算法计算奖励值
         *
         * @param cloudlet 执行完成的任务
         */
        public abstract void resultReturn(Cloudlet cloudlet);
    
        @Override
        protected Vm defaultVmMapper(Cloudlet cloudlet) {
            if (cloudlet.isBoundToVm()) {
                return cloudlet.getVm();
            }
    
            Vm mappedVm = Vm.NULL;
            if (!getVmCreatedList().isEmpty()){
                mappedVm = scheduleTask(cloudlet);
            }
    
            if (mappedVm == Vm.NULL) {
                LOGGER.warn("{}: {}: {} (PEs: {}) couldn't be mapped to any suitable VM.",
                    getSimulation().clockStr(), getName(), cloudlet, cloudlet.getNumberOfPes());
            } else {
                LOGGER.trace("{}: {}: {} (PEs: {}) mapped to {} (available PEs: {}, tot PEs: {})",
                    getSimulation().clockStr(), getName(), cloudlet, cloudlet.getNumberOfPes(), mappedVm,
                    mappedVm.getExpectedFreePesNumber(), mappedVm.getFreePesNumber());
            }
            return mappedVm;
        }
    
        @Override
        public void processEvent(final SimEvent ev) {
            super.processEvent(ev);
            if (ev.getTag() == CloudSimTag.CLOUDLET_RETURN) {
                Cloudlet cloudlet = (Cloudlet) ev.getData();
                resultReturn(cloudlet);
            }
        }
    }
    

3.2 能耗模型

  • 1.主机功耗数据来源:SPEC官网

  • 例如型号为AcerR380F2 的主机功耗数据,其中11个数据分别对于主机利用率从0, 0.1, 0.2, ..., 1的功耗

    double[] AcerR380F2 = { 63.7, 78.0, 87.0, 96.5, 106, 116, 135, 158, 188, 221, 252};
    
  • 2.为了计算功耗,可以基于主机功耗数据,拟合利用率-功耗函数,从而根据利用率来计算能耗

    new PowerModelHostFunc(x -> 100.7 + 103.6 * x - 8.7 * x * x);
    

    在这里插入图片描述

    PowerModelHostFunc介绍如下:

    public class PowerModelHostFunc extends PowerModelHost {
    
        /**
         * 功率计算函数
         */
        Function<Double,Double> function;
    
        public PowerModelHostFunc(Function<Double, Double> function) {
            this.function = function;
        }
    
        @Override
        public double getPower(double utilization) throws IllegalArgumentException {
            if (utilization < 0 || utilization > 1) {
                throw new IllegalArgumentException("utilizationFraction has to be between [0 and 1]");
            }
            return function.apply(utilization);
        }
    
        @Override
        public PowerMeasurement getPowerMeasurement() {
            final double utilization = getHost().getCpuMipsUtilization() / getHost().getTotalMipsCapacity();
            Double dynamicPower = function.apply(utilization);
            return new PowerMeasurement(0, dynamicPower);
        }
    }
    
  • 2.或者,直接基于主机利用率功耗数据,来计算能耗

    new PowerModelHostSpec(Arrays.stream(AcerR380F2).boxed().collect(Collectors.toList()));
    

    PowerModelHostSpec介绍如下:

    /**
     * 原作者代码存在问题: 一般 SPEC 官网提供的功率数据为11个,即为 0,10,20,...,100%的利用率功耗数据;
     * 而原作者考虑不周到,假设有10个数据,从而造成数组越界.
     * 更正:
     * 修改获得当前功率的代码从 powerSpec.size() 改成 (powerSpec.size()-1)
     * 例如:当前功率为 98%, 则 Math.round(0.98 * 10) = 10, 即取功率为 100% 的利用率数据
     */
    public class PowerModelHostSpec extends PowerModelHost {
        public static final int MIN_POWER_CONSUMPTION_DATA_SIZE = 2;
    
        private final List<Double> powerSpec;
    
        public PowerModelHostSpec(final List<Double> powerSpec) {
            super();
            Objects.requireNonNull(powerSpec, "powerSpec cannot be null");
            if (powerSpec.size() >= MIN_POWER_CONSUMPTION_DATA_SIZE) {
                this.powerSpec = powerSpec;
                return;
            }
    
            final String msg = String.format("powerSpec has to contain at least %d elements (representing utilization at 0%% and 100%% load, respectively)", MIN_POWER_CONSUMPTION_DATA_SIZE);
            throw new IllegalArgumentException(msg);
        }
    
        @Override
        public PowerMeasurement getPowerMeasurement() {
            final double utilizationFraction = getHost().getCpuMipsUtilization() / getHost().getTotalMipsCapacity();
            final int utilizationIndex = (int) Math.round(utilizationFraction * (powerSpec.size()-1));
            final double powerUsage = powerSpec.get(utilizationIndex);
            return new PowerMeasurement(powerSpec.get(0), powerUsage - powerSpec.get(0));
        }
    
        @Override
        public double getPower(final double utilizationFraction) throws IllegalArgumentException {
            final int utilizationIndex = (int) Math.round(utilizationFraction * (powerSpec.size()-1));
            return powerSpec.get(utilizationIndex);
        }
    }
    

仿真实验测试

1. 本地处理算法

1.1 实验设定

  • 任务只在本地处理,不进行卸载处理
  • 假设任务执行时,计算节点的功耗保持不变。因此,任务消耗的能源=处理时间*当前功耗
  • 任务处理延迟包括:排队延迟 + 执行延迟

1.2 仿真实验结果

  • 计算节点利用率
    在这里插入图片描述

  • 计算节点能源消耗
    在这里插入图片描述

  • 仿真结果数据

    {
      "algorithmName" : "LocalAlgorithm",
      "taskSuccessRate" : 0.770289898928766,
      "avgTaskTotalDelay" : 1.732609574535639,
      "avgTaskTotalEnergy" : 26.7213677578472,
      "avgCloudUtilization" : 0.0,
      "avgEdgeUtilization" : 0.0,
      "avgDeviceUtilization" : 29.972115384615385,
      "avgCloudEnergyConsume" : 22776.0,
      "avgEdgeEnergyConsume" : 35692.8,
      "avgTaskNetworkDelay" : 0.0,
      "cloudTaskExecuted" : 0.0,
      "cloudTaskSuccessExecuted" : 0.0,
      "edgeTaskExecuted" : 0.0,
      "edgeTaskSuccessExecuted" : 0.0,
      "deviceTaskExecuted" : 66092.0,
      "deviceTaskSuccessExecuted" : 50910.0
    }
    

1.2 随机算法

  • 计算节点平均利用率
    在这里插入图片描述

  • 计算节点能源消耗
    在这里插入图片描述

  • 仿真结果数据

    {
      "algorithmName" : "RandomAlgorithm",
      "taskSuccessRate" : 0.920377786173026,
      "avgTaskTotalDelay" : 1.2247280541003729,
      "avgTaskTotalEnergy" : 18.352311136392565,
      "avgCloudUtilization" : 38.35336538461539,
      "avgEdgeUtilization" : 35.13461538461538,
      "avgDeviceUtilization" : 9.517307692307694,
      "avgCloudEnergyConsume" : 95546.2,
      "avgEdgeEnergyConsume" : 67100.36,
      "avgDeviceEnergyConsume" : 12109.257999999996,
      "cloudTaskExecuted" : 22044.0,
      "cloudTaskSuccessExecuted" : 21781.0,
      "edgeTaskExecuted" : 21924.0,
      "edgeTaskSuccessExecuted" : 20995.0,
      "deviceTaskExecuted" : 22207.0,
      "deviceTaskSuccessExecuted" : 18130.0
    }
    

1.3 贪心算法

  • 计算节点平均利用率
    在这里插入图片描述

  • 计算节点能源消耗
    在这里插入图片描述

  • 仿真结果数据

    {
      "algorithmName" : "GreedyAlgorithm",
      "taskSuccessRate" : 0.9416770318235598,
      "avgTaskTotalDelay" : 1.2437790398350788,
      "avgTaskTotalEnergy" : 17.790207236463743,
      "avgCloudUtilization" : 28.44951923076923,
      "avgEdgeUtilization" : 30.355769230769226,
      "avgDeviceUtilization" : 16.62211538461539,
      "avgCloudEnergyConsume" : 72169.3,
      "avgEdgeEnergyConsume" : 63736.02,
      "avgDeviceEnergyConsume" : 15318.622999999994,
      "cloudTaskExecuted" : 2874.0,
      "cloudTaskSuccessExecuted" : 2397.0,
      "edgeTaskExecuted" : 6510.0,
      "edgeTaskSuccessExecuted" : 5667.0,
      "deviceTaskExecuted" : 56542.0,
      "deviceTaskSuccessExecuted" : 54017.0
    }
    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值