@Override
  public void execute() {

    double util = 0;
    double power = 0;
    double prevSlavWork;
    double prevWork;

    // store current work and SLA violated work values
    prevSlavWork = totalSlavWork;
    prevWork = totalWork;

    // reset total work values
    totalSlavWork = 0;
    totalWork = 0;

    totalPower = 0;

    for (Host host : dc.getHosts()) {

      // store host CPU utilization
      if (!hostUtil.containsKey(host)) {
        hostUtil.put(host, new DescriptiveStatistics());
      }

      hostUtil.get(host).addValue(host.getCpuManager().getCpuInUse());

      util += host.getCpuManager().getCpuInUse();

      // get VM SLA values
      for (VMAllocation vmAlloc : host.getVMAllocations()) {
        totalSlavWork += vmAlloc.getVm().getApplication().getTotalSLAViolatedWork();
        totalWork +=
            vmAlloc
                .getVm()
                .getApplication()
                .getTotalIncomingWork(); // NOTE: This ONLY works with SINGLE TIERED applications.
        // For multi-tiered applications, this will count incoming
        // work multiple times!!
      }

      // get power consumption
      power += host.getCurrentPowerConsumption();
      totalPower += host.getPowerConsumed();
    }

    dcUtil.addValue(util);

    dcPower.addValue(power);
    dcPowerEfficiency.addValue(util / power);
    double optimalPowerConsumption = calculateOptimalPowerConsumption(util);
    dcOptimalPower.addValue(optimalPowerConsumption);
    dcOptimalPowerEfficiency.addValue(util / optimalPowerConsumption);

    dcOptimalPowerRatio.addValue((util / optimalPowerConsumption) / (util / power));

    // records the total fraction of SLA violated incoming work since the last time interval
    dcSla.addValue((totalSlavWork - prevSlavWork) / (totalWork - prevWork));
  }
  @Override
  public void schedulePrivDomain(VMAllocation privDomainAllocation) {
    // schedule privileged domain as much CPU as it requires (takes priority over all other VMs)
    double cpuConsumed = privDomainAllocation.getVm().execute(getAvailableCpu());

    consumeAvailableCpu(cpuConsumed);
  }
  @Override
  public boolean processVM(VMAllocation vmAllocation) {

    double cpuAvail =
        Math.min(
            roundCpuShare,
            getAvailableCpu()); // overcome rounding errors that allow sightly more CPU to be used
                                // than available

    double cpuConsumed = vmAllocation.getVm().execute(cpuAvail);

    if (cpuConsumed == 0) {
      --nVms; // once a VM does not execute any work, it will no longer have any work for this
              // interval, due to the order in which dependent VMs are scheduled by the master
              // scheduler
      return false;
    }

    consumeAvailableCpu(cpuConsumed);

    return true;
  }
  /**
   * Execute the VMs in the simulation
   *
   * @param hosts
   */
  public void execute(ArrayList<Host> hosts) {

    // retrieve ordered list of vm allocations
    ArrayList<VMAllocation> vmList = buildVmList(hosts);

    // calculate the resources each VM has available
    for (VMAllocation vmAllocation : vmList) {
      if (vmAllocation.getVm() != null) vmAllocation.getVm().prepareExecution();
    }

    // prepare hosts for VM execution
    for (Host host : hosts) {
      // if the Host is ON
      if (host.getState() == Host.HostState.ON) {
        // allow the Host's CPU Scheduler to prepare for scheduling
        host.getCpuScheduler().prepareScheduler();
        host.getCpuScheduler().beginScheduling();

        // prepare the privileged domain VM for execution
        host.getPrivDomainAllocation().getVm().prepareExecution();

        // instruct the Host's CPU Scheduler to run the priviledged domain VM
        host.getCpuScheduler().schedulePrivDomain(host.getPrivDomainAllocation());
      }
    }

    HashSet<VMAllocation> completedVms =
        new HashSet<VMAllocation>(); // set of VMs that have completed execution
    boolean notDone = true; // true while execution is not complete

    // execute VMs in rounds until complete. In each round, every VM has a chance to execute
    do {
      notDone = false; // start by assuming done

      // instruct Host CPU Schedulers to begin a round of scheduling
      for (Host host : hosts) {
        if (host.getState() == Host.HostState.ON) host.getCpuScheduler().beginRound();
      }

      // execute VMs
      for (VMAllocation vmAllocation : vmList) {
        // if the VM has not be executed, the VM Allocation actually contains a VM, and the host is
        // ON
        if (!completedVms.contains(vmAllocation)
            && vmAllocation.getVm() != null
            && vmAllocation.getHost().getState()
                == Host.HostState.ON) { // ensure that a VM is instantiated within the allocation
          // if the CPU scheduler has not indicated that is is COMPLETE (i.e. out of resources)
          if (vmAllocation.getHost().getCpuScheduler().getState()
              != CpuScheduler.CpuSchedulerState.COMPLETE) {
            // run the VM
            if (vmAllocation.getHost().getCpuScheduler().processVM(vmAllocation)) {
              // returned true = VM is not finished executing (still has work to complete)
              notDone = true; // not done yet
            } else {
              // returned false = VM is done (no more work to complete)
              completedVms.add(vmAllocation);
            }
          }
        }
      }

      // instruct Host CPU Schedulers that the round has completed
      for (Host host : hosts) {
        if (host.getState() == Host.HostState.ON) host.getCpuScheduler().endRound();
      }

    } while (notDone); // if not done, execute another round

    // instruct Host CPU Schedulers that scheduling is complete
    for (Host host : hosts) {
      if (host.getState() == Host.HostState.ON) {
        host.getCpuScheduler().endScheduling();

        host.getPrivDomainAllocation().getVm().completeExecution();
      }
    }

    // update the resourcesInUse for each VM
    for (VMAllocation vmAllocation : vmList) {
      if (vmAllocation.getVm() != null) {
        vmAllocation.getVm().completeExecution();
      }
    }
  }