Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VM RAM usage keeps high after cloudlet finishes #429

Open
manoelcampos opened this issue Mar 22, 2023 · 1 comment
Open

VM RAM usage keeps high after cloudlet finishes #429

manoelcampos opened this issue Mar 22, 2023 · 1 comment
Labels
bug cloudlet help wanted resource-utilization Features related to the utilization of resources by a Host, VM or Cloudlet Vm

Comments

@manoelcampos
Copy link
Collaborator

From @ulfaric:

The RAM issue always happens whenever you use a random function to generate RAM usage. The RAM usage of that VM will simply keeps as the last randomly generated value and doesn't change back to 0. If this is the last cloudlet to be scheduled on the VM.

My fix is simply add a never ending Cloudlet(using the on finish listener to put a new same Cloudlet back on to the VM) for each VM. Because I am simulating containers which must have a process that is always running. So this "deamon" cloudlet fixes the issue because it overwrites the incorrect RAM usage at the end.

@manoelcampos manoelcampos added bug resource-utilization Features related to the utilization of resources by a Host, VM or Cloudlet Vm cloudlet labels Mar 22, 2023
@AndrewLawrence80
Copy link

AndrewLawrence80 commented Aug 13, 2023

Yes, and another bug is the VM RAM usage is 100% after a new VM is created

To reproduce the problem

package com.example;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.cloudsimplus.brokers.DatacenterBroker;
import org.cloudsimplus.brokers.DatacenterBrokerSimple;
import org.cloudsimplus.builders.tables.CloudletsTableBuilder;
import org.cloudsimplus.cloudlets.Cloudlet;
import org.cloudsimplus.cloudlets.CloudletExecution;
import org.cloudsimplus.cloudlets.CloudletSimple;
import org.cloudsimplus.core.CloudSimPlus;
import org.cloudsimplus.datacenters.Datacenter;
import org.cloudsimplus.datacenters.DatacenterSimple;
import org.cloudsimplus.hosts.Host;
import org.cloudsimplus.hosts.HostSimple;
import org.cloudsimplus.listeners.EventInfo;
import org.cloudsimplus.listeners.EventListener;
import org.cloudsimplus.resources.Pe;
import org.cloudsimplus.resources.PeSimple;
import org.cloudsimplus.schedulers.cloudlet.CloudletSchedulerTimeShared;
import org.cloudsimplus.utilizationmodels.UtilizationModelDynamic;
import org.cloudsimplus.vms.Vm;
import org.cloudsimplus.vms.VmSimple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BasicExample {
    private static final class Config {
        // Host config
        public static final class Host {
            public static final int NUM = 1; // Big enough to hold all created Vm
            public static final int PES = 64; // 64 CPU cores
            public static final long MIPS = (long) (2 * 1e3); // 2GHz CPU
            public static final long RAM = Long.MAX_VALUE; // Infinite RAM (MB)
            public static final long BW = Long.MAX_VALUE; // Infinite band width (Mb)
            public static final long STORAGE = Long.MAX_VALUE; // Infinite storage (MB)
        }

        // Vm config
        public static final class Vm {
            public static final int NUM = 2; // Create 1 vm initially
            public static final int PES = 1; // 1 Pe by default
            public static final long MIPS = Host.MIPS; // Keep the same as host
            public static final long RAM = 1024; // 1G by default
            public static final long BW = 100; // 100 Mbps by default
            public static final long STORAGE = (long) (10 * 1e3); // 10GB by default
            public static final long STARTUP_DELAY = 5;
            public static final long SHUTDOWN_DELAY = 2;
        }

        // Cloudlet config
        public static final class Cloudlet {
            public static final int NUM = 1; // Create 1 cloudlet once
            public static final int PES = 1; // 1 Pe by default
            public static final long MAXLEN = (long) (3600 * 1e3); // 3600*1M instructions, take 1h for a 1Ghz CPU
            public static final long MINLEN = (long) (1e3); // 1M instructions, take 1s for a 1GHz CPU
            public static final double MAX_CPU_USAGE_FACTOR = 1; // 100% CPU usage
            public static final double MIN_CPU_USAGE_FACTOR = 1e-2; // 1% CPU usage
            public static final double MAX_RAM_USAGE_FACTOR = 1; // 1G, fill the whole memory
            public static final double MIN_RAM_USAGE_FACTOR = 1e-3; // 1M
            public static final double MAX_BW_USAGE_FACTOR = 1e-1; // 4 Mbps
            public static final double MIN_BW_USAGE_FACTOR = 1e-2; // 1Mbps
            public static final long MIN_INFILE_SIZE = (long) 1e3; // read 1KB file
            public static final long MAX_INFILE_SIZE = (long) 1e8; // read 100MB file
            public static final long MIN_OUTFILE_SIZE = (long) 1e3; // write 1KB file
            public static final long MAX_OUTFILE_SIZE = (long) 1e8;// write 100MB file
        }
    }

    private Datacenter datacenter;
    private DatacenterBroker broker;
    private int numVmCreated;
    private int numCloudletCreated;
    private Random random = new Random();

    private List<Host> createHostList() {
        List<Host> hostList = new ArrayList<>();
        for (int i = 0; i < Config.Host.NUM; ++i) {
            List<Pe> peList = new ArrayList<>();
            for (int j = 0; j < Config.Host.PES; ++j) {
                peList.add(new PeSimple(Config.Host.MIPS));
            }
            Host newHost = new HostSimple(Config.Host.RAM, Config.Host.BW, Config.Host.STORAGE, peList);
            hostList.add(newHost);
        }
        return hostList;
    }

    private List<Vm> createVmList() {
        List<Vm> vmList = new ArrayList<>();
        for (int i = 0; i < Config.Vm.NUM; ++i) {
            Vm newVm = new VmSimple(numVmCreated, Config.Vm.MIPS, Config.Vm.PES);
            newVm.setRam(Config.Vm.RAM);
            newVm.setBw(Config.Vm.BW);
            newVm.setStartupDelay(Config.Vm.STARTUP_DELAY);
            newVm.setShutDownDelay(Config.Vm.SHUTDOWN_DELAY);
            newVm.setCloudletScheduler(new CloudletSchedulerTimeShared()); // by default;
            vmList.add(newVm);
            ++numVmCreated;
        }
        return vmList;
    }

    private List<Cloudlet> createCloudLetList() {
        List<Cloudlet> cloudletList = new ArrayList<>();
        for (int i = 0; i < Config.Cloudlet.NUM; ++i) {
            double length = random.nextDouble() * (Config.Cloudlet.MAXLEN - Config.Cloudlet.MINLEN)
                    + Config.Cloudlet.MINLEN;
            Cloudlet newCloudlet = new CloudletSimple(numCloudletCreated, (long) length, Config.Cloudlet.PES);
            double ramUtilizationFactor = random.nextDouble()
                    * (Config.Cloudlet.MAX_RAM_USAGE_FACTOR - Config.Cloudlet.MIN_RAM_USAGE_FACTOR)
                    + Config.Cloudlet.MIN_RAM_USAGE_FACTOR;
            newCloudlet.setUtilizationModelRam(new UtilizationModelDynamic(ramUtilizationFactor));
            double bwUtilizationFactor = random.nextDouble()
                    * (Config.Cloudlet.MAX_BW_USAGE_FACTOR - Config.Cloudlet.MIN_BW_USAGE_FACTOR)
                    + Config.Cloudlet.MIN_BW_USAGE_FACTOR;
            newCloudlet.setUtilizationModelBw(new UtilizationModelDynamic(bwUtilizationFactor));
            double cpuUtilizationFactor = random.nextDouble()
                    * (Config.Cloudlet.MAX_CPU_USAGE_FACTOR - Config.Cloudlet.MIN_CPU_USAGE_FACTOR)
                    + Config.Cloudlet.MIN_CPU_USAGE_FACTOR;
            newCloudlet.setUtilizationModelCpu(new UtilizationModelDynamic(cpuUtilizationFactor));
            double inFileSize = random.nextDouble()
                    * (Config.Cloudlet.MAX_INFILE_SIZE - Config.Cloudlet.MIN_INFILE_SIZE)
                    + Config.Cloudlet.MIN_INFILE_SIZE;
            newCloudlet.setFileSize((long) inFileSize);
            double outFileSize = random.nextDouble()
                    * (Config.Cloudlet.MAX_OUTFILE_SIZE - Config.Cloudlet.MIN_OUTFILE_SIZE)
                    + Config.Cloudlet.MIN_OUTFILE_SIZE;
            newCloudlet.setOutputSize((long) outFileSize);
            ++numCloudletCreated;
            cloudletList.add(newCloudlet);
        }
        return cloudletList;
    }

    private Datacenter createDatacenter(CloudSimPlus simulation) {
        List<Host> hostList = createHostList();
        Datacenter datacenter = new DatacenterSimple(simulation, hostList);
        datacenter.setSchedulingInterval(1);
        return datacenter;
    }

    private void createAndSubmitNewCloudlets(EventInfo info) {
        final long CREATE_INTERVAL = 5;
        long time = (long) info.getTime();
        if (time % CREATE_INTERVAL == 0 && time <= 10) {
            List<Cloudlet> cloudletList = createCloudLetList();
            broker.submitCloudletList(cloudletList);
        }
    }

    private void logVmStatus(EventInfo info) {
        final long LOG_INTERVAL = 100;
        long time = (long) info.getTime();
        if (time % LOG_INTERVAL == 0) {
            List<Vm> vmList = broker.getVmExecList();
            Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
            for (Vm vm : vmList) {
                logger.info(String.format(
                        "%.2f:\t VM %d, CPU usage %.2f%% (%d vCPUs), RAM usage %.2f%% (%dMB/%dMB) %dMb available, BW usage %.2f%% (%dMbps/%dMbps) %dMbps available",
                        info.getTime(), vm.getId(),
                        vm.getCpuPercentUtilization() * 100, vm.getPesNumber(),
                        vm.getRam().getPercentUtilization() * 100, vm.getRam().getAllocatedResource(),
                        vm.getRam().getCapacity(), vm.getRam().getAvailableResource(),
                        vm.getBw().getPercentUtilization() * 100, vm.getBw().getAllocatedResource(),
                        vm.getBw().getCapacity(), vm.getBw().getAvailableResource()));
                List<CloudletExecution> cloudletExecutionList = vm.getCloudletScheduler().getCloudletExecList();
                for (CloudletExecution cloudletExecution : cloudletExecutionList) {
                    logger.info(String.format(
                            "|------\t Cloudlet %d, CPU utilization %.2f%%, RAM utilization %.2f%%, BW utiliztion %.2f%%",
                            cloudletExecution.getCloudlet().getId(),
                            cloudletExecution.getCloudlet().getUtilizationOfCpu() * 100,
                            cloudletExecution.getCloudlet().getUtilizationOfRam() * 100,
                            cloudletExecution.getCloudlet().getUtilizationOfBw() * 100));
                }
            }
        }
    }

    private BasicExample() {
        CloudSimPlus simulation = new CloudSimPlus();
        simulation.addOnClockTickListener(new EventListener<EventInfo>() {

            @Override
            public void update(EventInfo info) {
                // createAndSubmitNewCloudlets(info);
                logVmStatus(info);
            }

        });
        datacenter = createDatacenter(simulation);
        broker = new DatacenterBrokerSimple(simulation);
        List<Vm> vmList = createVmList();
        List<Cloudlet> cloudletList = createCloudLetList();
        broker.submitVmList(vmList);
        broker.submitCloudletList(cloudletList);
        simulation.start();
        List<Cloudlet> finishedCloudletList = broker.getCloudletFinishedList();
        new CloudletsTableBuilder(finishedCloudletList).build();
    }

    public static void main(String[] args) {
        // try {
        //     PrintStream oStream = new PrintStream(new File("cloudsim.log"));
        //     System.setOut(oStream);
        // } catch (FileNotFoundException e) {
        //     // TODO Auto-generated catch block
        //     e.printStackTrace();
        // }
        new BasicExample();
    }
}

to ease the problem by adding "no-op"-instruction-like cloudlet

package com.example;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.cloudsimplus.brokers.DatacenterBroker;
import org.cloudsimplus.brokers.DatacenterBrokerSimple;
import org.cloudsimplus.builders.tables.CloudletsTableBuilder;
import org.cloudsimplus.cloudlets.Cloudlet;
import org.cloudsimplus.cloudlets.CloudletExecution;
import org.cloudsimplus.cloudlets.CloudletSimple;
import org.cloudsimplus.core.CloudSimPlus;
import org.cloudsimplus.datacenters.Datacenter;
import org.cloudsimplus.datacenters.DatacenterSimple;
import org.cloudsimplus.hosts.Host;
import org.cloudsimplus.hosts.HostSimple;
import org.cloudsimplus.listeners.CloudletVmEventInfo;
import org.cloudsimplus.listeners.EventInfo;
import org.cloudsimplus.listeners.EventListener;
import org.cloudsimplus.listeners.VmHostEventInfo;
import org.cloudsimplus.resources.Pe;
import org.cloudsimplus.resources.PeSimple;
import org.cloudsimplus.schedulers.cloudlet.CloudletSchedulerTimeShared;
import org.cloudsimplus.utilizationmodels.UtilizationModelDynamic;
import org.cloudsimplus.utilizationmodels.UtilizationModelFull;
import org.cloudsimplus.vms.Vm;
import org.cloudsimplus.vms.VmSimple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BasicExample {
    private static final class Config {
        // Host config
        public static final class Host {
            public static final int NUM = 1; // Big enough to hold all created Vm
            public static final int PES = 64; // 64 CPU cores
            public static final long MIPS = (long) (2 * 1e3); // 2GHz CPU
            public static final long RAM = Long.MAX_VALUE; // Infinite RAM (MB)
            public static final long BW = Long.MAX_VALUE; // Infinite band width (Mb)
            public static final long STORAGE = Long.MAX_VALUE; // Infinite storage (MB)
        }

        // Vm config
        public static final class Vm {
            public static final int NUM = 2; // Create 1 vm initially
            public static final int PES = 1; // 1 Pe by default
            public static final long MIPS = Host.MIPS; // Keep the same as host
            public static final long RAM = 1024; // 1G by default
            public static final long BW = 100; // 100 Mbps by default
            public static final long STORAGE = (long) (10 * 1e3); // 10GB by default
            public static final long STARTUP_DELAY = 5;
            public static final long SHUTDOWN_DELAY = 2;
        }

        // Cloudlet config
        public static final class Cloudlet {
            public static final int NUM = 1; // Create 1 cloudlet once
            public static final int PES = 1; // 1 Pe by default
            public static final long MAXLEN = (long) (3600 * 1e3); // 3600*1M instructions, take 1h for a 1Ghz CPU
            public static final long MINLEN = (long) (1e3); // 1M instructions, take 1s for a 1GHz CPU
            public static final double MAX_CPU_USAGE_FACTOR = 1; // 100% CPU usage
            public static final double MIN_CPU_USAGE_FACTOR = 1e-2; // 1% CPU usage
            public static final double MAX_RAM_USAGE_FACTOR = 1; // 1G, fill the whole memory
            public static final double MIN_RAM_USAGE_FACTOR = 1e-3; // 1M
            public static final double MAX_BW_USAGE_FACTOR = 1e-1; // 4 Mbps
            public static final double MIN_BW_USAGE_FACTOR = 1e-2; // 1Mbps
            public static final long MIN_INFILE_SIZE = (long) 1e3; // read 1KB file
            public static final long MAX_INFILE_SIZE = (long) 1e8; // read 100MB file
            public static final long MIN_OUTFILE_SIZE = (long) 1e3; // write 1KB file
            public static final long MAX_OUTFILE_SIZE = (long) 1e8;// write 100MB file
        }
    }

    private Datacenter datacenter;
    private DatacenterBroker broker;
    private int numVmCreated;
    private int numCloudletCreated;
    private Random random = new Random();

    private List<Host> createHostList() {
        List<Host> hostList = new ArrayList<>();
        for (int i = 0; i < Config.Host.NUM; ++i) {
            List<Pe> peList = new ArrayList<>();
            for (int j = 0; j < Config.Host.PES; ++j) {
                peList.add(new PeSimple(Config.Host.MIPS));
            }
            Host newHost = new HostSimple(Config.Host.RAM, Config.Host.BW, Config.Host.STORAGE, peList);
            hostList.add(newHost);
        }
        return hostList;
    }

    private List<Vm> createVmList() {
        List<Vm> vmList = new ArrayList<>();
        for (int i = 0; i < Config.Vm.NUM; ++i) {
            Vm newVm = new VmSimple(numVmCreated, Config.Vm.MIPS, Config.Vm.PES);
            newVm.setRam(Config.Vm.RAM);
            newVm.setBw(Config.Vm.BW);
            newVm.setStartupDelay(Config.Vm.STARTUP_DELAY);
            newVm.setShutDownDelay(Config.Vm.SHUTDOWN_DELAY);
            newVm.setCloudletScheduler(new CloudletSchedulerTimeShared()); // by default;
            vmList.add(newVm);
            ++numVmCreated;
            newVm.addOnHostAllocationListener(new EventListener<VmHostEventInfo>() {

                // to avoid the bug that the allocated resource is 100%
                @Override
                public void update(VmHostEventInfo info) {
                    Cloudlet emptyCloudlet = createEmptyCloudlet();
                    broker.submitCloudlet(emptyCloudlet);
                    broker.bindCloudletToVm(emptyCloudlet, info.getVm());
                }

            });
        }
        return vmList;
    }

    private Datacenter createDatacenter(CloudSimPlus simulation) {
        List<Host> hostList = createHostList();
        Datacenter datacenter = new DatacenterSimple(simulation, hostList);
        datacenter.setSchedulingInterval(1);
        return datacenter;
    }

    private List<Cloudlet> createCloudLetList() {
        List<Cloudlet> cloudletList = new ArrayList<>();
        for (int i = 0; i < Config.Cloudlet.NUM; ++i) {
            double length = random.nextDouble() * (Config.Cloudlet.MAXLEN - Config.Cloudlet.MINLEN)
                    + Config.Cloudlet.MINLEN;
            Cloudlet newCloudlet = new CloudletSimple(numCloudletCreated, (long) length, Config.Cloudlet.PES);
            double ramUtilizationFactor = random.nextDouble()
                    * (Config.Cloudlet.MAX_RAM_USAGE_FACTOR - Config.Cloudlet.MIN_RAM_USAGE_FACTOR)
                    + Config.Cloudlet.MIN_RAM_USAGE_FACTOR;
            newCloudlet.setUtilizationModelRam(new UtilizationModelDynamic(ramUtilizationFactor));
            double bwUtilizationFactor = random.nextDouble()
                    * (Config.Cloudlet.MAX_BW_USAGE_FACTOR - Config.Cloudlet.MIN_BW_USAGE_FACTOR)
                    + Config.Cloudlet.MIN_BW_USAGE_FACTOR;
            newCloudlet.setUtilizationModelBw(new UtilizationModelDynamic(bwUtilizationFactor));
            double cpuUtilizationFactor = random.nextDouble()
                    * (Config.Cloudlet.MAX_CPU_USAGE_FACTOR - Config.Cloudlet.MIN_CPU_USAGE_FACTOR)
                    + Config.Cloudlet.MIN_CPU_USAGE_FACTOR;
            newCloudlet.setUtilizationModelCpu(new UtilizationModelDynamic(cpuUtilizationFactor));
            double inFileSize = random.nextDouble()
                    * (Config.Cloudlet.MAX_INFILE_SIZE - Config.Cloudlet.MIN_INFILE_SIZE)
                    + Config.Cloudlet.MIN_INFILE_SIZE;
            newCloudlet.setFileSize((long) inFileSize);
            double outFileSize = random.nextDouble()
                    * (Config.Cloudlet.MAX_OUTFILE_SIZE - Config.Cloudlet.MIN_OUTFILE_SIZE)
                    + Config.Cloudlet.MIN_OUTFILE_SIZE;
            newCloudlet.setOutputSize((long) outFileSize);
            newCloudlet.addOnFinishListener(new EventListener<CloudletVmEventInfo>() {

                // to avoid the bug that the allocated resource won't release

                @Override
                public void update(CloudletVmEventInfo info) {
                    Cloudlet emptyCloudlet = createEmptyCloudlet();
                    broker.submitCloudlet(emptyCloudlet);
                    broker.bindCloudletToVm(emptyCloudlet, info.getVm());
                }

            });
            ++numCloudletCreated;
            cloudletList.add(newCloudlet);
        }
        return cloudletList;
    }

    private Cloudlet createEmptyCloudlet() {
        Cloudlet newCloudlet = new CloudletSimple(1, 1)
                .setUtilizationModelCpu(new UtilizationModelDynamic(0.01))
                .setUtilizationModelRam(new UtilizationModelDynamic(0))
                .setUtilizationModelBw(new UtilizationModelDynamic(0));
        return newCloudlet;
    }

    private void createAndSubmitNewCloudlets(EventInfo info) {
        final long CREATE_INTERVAL = 5;
        long time = (long) info.getTime();
        if (time % CREATE_INTERVAL == 0 && time <= 2) {
            List<Cloudlet> cloudletList = createCloudLetList();
            broker.submitCloudletList(cloudletList);
        }
    }

    private void logVmStatus(EventInfo info) {
        final long LOG_INTERVAL = 1;
        long time = (long) info.getTime();
        if (time % LOG_INTERVAL == 0) {
            List<Vm> vmList = broker.getVmExecList();
            Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
            for (Vm vm : vmList) {
                logger.info(String.format(
                        "%.2f:\t VM %d, CPU usage %.2f%% (%d vCPUs), RAM usage %.2f%% (%dMB/%dMB) %dMb available, BW usage %.2f%% (%dMbps/%dMbps) %dMbps available",
                        info.getTime(), vm.getId(),
                        vm.getCpuPercentUtilization() * 100, vm.getPesNumber(),
                        vm.getRam().getPercentUtilization() * 100, vm.getRam().getAllocatedResource(),
                        vm.getRam().getCapacity(), vm.getRam().getAvailableResource(),
                        vm.getBw().getPercentUtilization() * 100, vm.getBw().getAllocatedResource(),
                        vm.getBw().getCapacity(), vm.getBw().getAvailableResource()));
                List<CloudletExecution> cloudletExecutionList = vm.getCloudletScheduler().getCloudletExecList();
                for (CloudletExecution cloudletExecution : cloudletExecutionList) {
                    logger.info(String.format(
                            "|------\t Cloudlet %d, length %d, CPU utilization %.2f%%, RAM utilization %.2f%%, BW utiliztion %.2f%%",
                            cloudletExecution.getCloudlet().getId(),
                            cloudletExecution.getCloudlet().getLength(),
                            cloudletExecution.getCloudlet().getUtilizationOfCpu() * 100,
                            cloudletExecution.getCloudlet().getUtilizationOfRam() * 100,
                            cloudletExecution.getCloudlet().getUtilizationOfBw() * 100));
                }
            }
        }
    }

    private BasicExample() {
        CloudSimPlus simulation = new CloudSimPlus();
        simulation.addOnClockTickListener(new EventListener<EventInfo>() {

            @Override
            public void update(EventInfo info) {
                // createAndSubmitNewCloudlets(info);
                logVmStatus(info);
            }

        });
        datacenter = createDatacenter(simulation);
        broker = new DatacenterBrokerSimple(simulation);
        List<Vm> vmList = createVmList();
        List<Cloudlet> cloudletList = createCloudLetList();
        broker.submitVmList(vmList);
        broker.submitCloudletList(cloudletList);
        simulation.start();
        List<Cloudlet> finishedCloudletList = broker.getCloudletFinishedList();
        new CloudletsTableBuilder(finishedCloudletList).build();
    }

    public static void main(String[] args) {
        try {
            PrintStream oStream = new PrintStream(new File("cloudsim.log"));
            System.setOut(oStream);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        new BasicExample();
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug cloudlet help wanted resource-utilization Features related to the utilization of resources by a Host, VM or Cloudlet Vm
Projects
None yet
Development

No branches or pull requests

2 participants