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

news/2024/5/19 14:03:45 标签: java, cloudsim plus, 仿真, 边缘计算

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

1. 前提介绍

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

1.1 仿真实体

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

    java">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()来发送仿真事件

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

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

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

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

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

  • 接收仿真事件

    java">@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 边缘设备

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

    java">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 任务调度算法接口

  • 为任务执行计算卸载决策
  • 计算节点内进行任务与虚拟机匹配调度
  • 任务结果返回事件(便于扩展强化学习算法)
    java">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的功耗

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

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

    在这里插入图片描述

    PowerModelHostFunc介绍如下:

    java">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.或者,直接基于主机利用率功耗数据,来计算能耗

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

    PowerModelHostSpec介绍如下:

    java">/**
     * 原作者代码存在问题: 一般 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
    }
    

http://www.niftyadmin.cn/n/193868.html

相关文章

C#项目实战——【实例】企业人事管理系统(二):4、数据库与数据表设计;5、创建项目;

本样例为学习《C#从入门到精通》的过程,边学边练记录,便于后期回顾查阅。 本篇为第企业人事管理系统的第2篇,第1篇的连接及目录如下: C#项目实战——【实例】企业人事管理系统(一) 1、系统分析; 2、系统设计; 3、系统运行环境; 以下为本篇主要内容: 4、数据库与数…

零基础学习Java 06

目录 String String构造方法 字符串查找 字符串截取 字符串替换 字符串拆分 字符串修改 String String类在java.lang包下&#xff0c;所以使用的时候不需要导包。 String构造方法 字符串查找 char charAt(int index)&#xff0c;输入位置index&#xff0c;找单个字符 …

程序员如何能提高自己的编程水平?

这些实用的小建议&#xff0c;能帮你迅速地提高编程水平&#xff1a; 不要做无意义的奋斗 拒绝喊口号和无意义的奋斗&#xff0c;包括但不限于&#xff1a; ①做了计划表却从未有执行的一天&#xff1b; ②每天都是最早来、最晚走&#xff0c;但是工作进度趋近于0&#xff1b…

【概念梳理】激活函数

一、引言 常用的激活函数如下&#xff1a; 1、Sigmoid函数 2、Tanh函数 3、ReLU函数 4、ELU函数 5、PReLU函数 6、Leaky ReLU函数 7、Maxout函数 8、Mish函数 二、激活函数的定义 多层神经网络中&#xff0c;上层节点的输出和下层节点的输入之间具有一个函数关系&#xff0c;…

Python 自动化指南(繁琐工作自动化)第二版:十一、调试

原文&#xff1a;https://automatetheboringstuff.com/2e/chapter11/ 既然你已经知道了足够多的知识来编写更复杂的程序&#xff0c;你可能会开始发现其中不那么简单的错误。这一章介绍了一些工具和技术&#xff0c;用于查找程序中错误的根本原因&#xff0c;帮助您更快、更省力…

华为OD机试题【查找树中的元素 or 查找二叉树节点】用 C++ 编码,速通

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:查找树中的元素 or 查找二叉树…

【智能算法】蚁群算法及Matlab实现 —— TSP问题

目录 蚁群算法及Matlab实现 —— TSP问题 蚁群算法及Matlab实现 —— TSP问题 %% 数据准备 % 清空环境变量 clear all clc% 程序运行计时开始 t0 = clock;%导入数据 citys=xlsread(Chap9_citys_data.xlsx, B2:C53); %-------------------------------------------------------…

如何安装固态继电器以获得最佳性能

您是否正在考虑在机器制造中使用固态继电器&#xff0c;但不知道如何操作&#xff1f;您对固态继电器最佳实践有疑问吗&#xff1f;本文将告诉您。 什么是固态继电器&#xff1f; 固态继电器是电子开关设备&#xff0c;当在其输入端子上施加外部电压时&#xff0c;它们会打开和…