Java tutorial
/** * Copyright (C) 2010-2013 Barcelona Supercomputing Center * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. This library is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy of * the GNU Lesser General Public License along with this library; if not, write * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package eu.optimis.ecoefficiencytool.core; import eu.optimis.cloudoptimizer.rest.client.CloudOptimizerRESTClient; import eu.optimis.ecoefficiencytool.core.tools.*; import eu.optimis.ecoefficiencytool.rest.client.EcoEfficiencyToolValidatorRESTClient; import eu.optimis.manifest.api.ip.Manifest; import eu.optimis.manifest.api.ip.VirtualMachineComponent; import eu.optimis.mi.monitoring_resources.MonitoringResourceDataset; import eu.optimis.mi.monitoring_resources.MonitoringResourceDatasets; import eu.optimis.mi.rest.client.getClient; import java.text.DecimalFormat; import java.util.*; import net.emotivecloud.utils.ovf.OVFWrapper; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.log4j.Logger; /** * * @author jsubirat */ public class EcoEffForecasterIP { protected static Logger log = Logger.getLogger(EcoEffForecasterIP.class); private CloudOptimizerRESTClient co; private getClient mi_client; private InfrastructureMetrics metrics; private EnergyEstimator energyEstimator; private CertificateTools certificates; private double PUE; private double initialCPUUtilization; private HashMap<String, VariableEstimator> vmCPUPredictors; //private HashMap<String, HashMap<Long, Double>> vmUtilizations; private List<String> deploymentMessages; private EcoEfficiencyToolValidatorRESTClient cpuValidator; public EcoEffForecasterIP(HashMap<String, VariableEstimator> vmCPUPredictors, EnergyEstimator energyEstimator, InfrastructureMetrics metrics) { //log = Log.getLog(getClass()); log.debug("Starting EcoEfficiency Forecaster (**IP**)"); PropertiesConfiguration configOptimis = ConfigManager .getPropertiesConfiguration(ConfigManager.OPTIMIS_CONFIG_FILE); PropertiesConfiguration configEco = ConfigManager.getPropertiesConfiguration(ConfigManager.ECO_CONFIG_FILE); co = new CloudOptimizerRESTClient(configOptimis.getString("optimis-ipvm")); mi_client = new getClient(configOptimis.getString("optimis-ipvm"), Integer.parseInt(configOptimis.getString("monitoringport")), configOptimis.getString("monitoringpath")); deploymentMessages = new LinkedList<String>(); PUE = Double.parseDouble(configEco.getString("PUE")); initialCPUUtilization = Double.parseDouble(configEco.getString("initialCPUUtilization")); this.vmCPUPredictors = vmCPUPredictors; //this.vmUtilizations = vmUtilizations; this.certificates = new CertificateTools(); this.metrics = metrics; this.energyEstimator = energyEstimator; cpuValidator = new EcoEfficiencyToolValidatorRESTClient(configOptimis.getString("optimis-ipvm")); } public synchronized String forecastVMEcoEfficiency(String vmId, String type, Long timeSpan) { double[] ecoefficiencyForecast = forecastVMEcoEfficiency(vmId, timeSpan); //Return desired ecoefficiency forecast type. if (type.equalsIgnoreCase("energy")) { return Double.toString(ecoefficiencyForecast[0]); } else { return Double.toString(ecoefficiencyForecast[1]); } } /** * Forecasts the ecoefficiency of a VM. * * @param vmId VM identifier. * @param timeSpan Time in the future in which the prediction will be made. * @return */ public synchronized double[] forecastVMEcoEfficiency(String vmId, Long timeSpan) { double futPerfPower[]; double ret[] = { -1.0, -1.0 }; //Check of parameters if (vmId == null) { log.error("VM identifier can't be null."); return ret; } if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } //Performance (perfPower[0]) and Real Power consumed (perfPower[1]) calculation. try { futPerfPower = getVMFuturePerformanceAndPower(vmId, timeSpan); } catch (Exception ex) { log.error(ex.getMessage()); return ret; } //Ecoefficiency calculation and update. double energyEfficiencyForecast = (futPerfPower[0]) / (futPerfPower[1] * PUE); double ecologicalEfficiencyForecast = (futPerfPower[0]) / (CO2Converter.getCO2FromPower(futPerfPower[1] * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); log.info("VM: " + vmId + " EnEffForec: " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); ret[0] = energyEfficiencyForecast; ret[1] = ecologicalEfficiencyForecast; return ret; } public synchronized String forecastNodeEcoEfficiency(String nodeId, List<String> ovfs, String type, Long timeSpan) { double[] ecoefficiencyForecast = forecastNodeEcoEfficiency(nodeId, ovfs, timeSpan); //Return desired ecoefficiency forecast type. if (type.equalsIgnoreCase("energy")) { return Double.toString(ecoefficiencyForecast[0]); } else { return Double.toString(ecoefficiencyForecast[1]); } } /** * Forecasts the ecoefficiency of a node. VMs in the "ovfs" parameter which * exist in the system will be considered as undeployments, while * non-present VMs specified in the "ovfs" parameter will be treated as new * deployments. * * @param nodeId Physical node identifier. * @param ovfs List of OVF descriptors of the VMs to deploy (if not existing * in the node) or undeploy (if existing in the node), generated using * EMOTIVEs OVFWrapper (see Installation Guide). * @param timeSpan Time in the future in which the prediction will be made. * @return */ public synchronized double[] forecastNodeEcoEfficiency(String nodeId, List<String> ovfs, Long timeSpan) { double ret[] = { -1.0, -1.0 }; if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } //Obtain lists of VMs under deployment or undeployment. List<OVFWrapper> deployments = new LinkedList<OVFWrapper>(); List<String> undeployments = new LinkedList<String>(); if (ovfs != null) { for (String ovf : ovfs) { try { OVFWrapper tempOVF = new OVFWrapper(ovf); if (co.getVMsId(nodeId).contains(tempOVF.getId())) { log.debug("Undeployment evaluation. VM " + tempOVF.getId()); undeployments.add(co.getVMName(tempOVF.getId())); } else { log.debug("Deployment evaluation. VM " + tempOVF.getId()); deployments.add(tempOVF); } } catch (Exception ex) { log.error("Error while parsing received OVF."); log.error(ex.getMessage()); } } } //Obtain node future performance and power consumption, considering deployments and undeployments. double futPerfPower[] = null; try { futPerfPower = getNodeFuturePerformanceAndPower(nodeId, deployments, undeployments, null, timeSpan); } catch (Exception ex) { log.error(ex.getMessage()); return ret; } //Ecoefficiency calculation and update. double energyEfficiencyForecast = (futPerfPower[0]) / (futPerfPower[1] * PUE); double ecologicalEfficiencyForecast = (futPerfPower[0]) / (CO2Converter.getCO2FromPower(futPerfPower[1] * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); log.info("Node: " + nodeId + " EnEffForec: " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); ret[0] = energyEfficiencyForecast; ret[1] = ecologicalEfficiencyForecast; return ret; } /** * Forecasts the ecoefficiency of a given list of nodes, using the default * timeSpan value. * * @param nodeList List of nodes to forecast its ecoefficiency. * @return The predicted ecoefficiency of each node following the same order * as in the input. (Each position of the returned List is a Double into a * String). */ public synchronized List<String> forecastMultipleNodesEfficiency(List<String> nodeList, String type) { return forecastMultipleNodesEfficiency(nodeList, type, new Long(Constants.DEFAULT_TIMESPAN)); } /** * Forecasts the ecoefficiency of a given list of nodes, at timeSpan * milliseconds in the future. * * @param nodeList List of nodes to forecast its ecoefficiency. * @param timeSpan Milliseconds in the future at which the prediction will * be made. * @return The predicted ecoefficiency of each node following the same order * as in the input. (Each position of the returned List is a Double into a * String). */ public synchronized List<String> forecastMultipleNodesEfficiency(List<String> nodeList, String type, Long timeSpan) { return forecastMultipleNodesEfficiency(nodeList, null, type, timeSpan); } public synchronized List<String> forecastMultipleNodesEfficiency(List<String> nodeList, List<String> ovfs, String type, Long timeSpan) { List<String> ret = new LinkedList<String>(); for (String nodeId : nodeList) { nodeId = nodeId.trim(); ret.add(forecastNodeEcoEfficiency(nodeId, ovfs, type, timeSpan)); } return ret; } public synchronized String forecastIPEcoEfficiency(String type, Long timeSpan) { log.debug("Forecasting infrastructure ecoefficiency."); return this.forecastIPEcoEfficiencyServiceDeployment(null, type, timeSpan); } public synchronized double[] forecastIPEcoEfficiency(Long timeSpan) { log.debug("Forecasting infrastructure ecoefficiency."); return forecastIPEcoEfficiencyServiceDeployment(null, timeSpan); } public synchronized String forecastIPEcoEfficiencyServiceDeployment(String manifest, String type, Long timeSpan) { double[] ecoefficiencyForecast = forecastIPEcoEfficiencyServiceDeployment(manifest, timeSpan); //Return desired ecoefficiency forecast type. if (type.equalsIgnoreCase("energy")) { return Double.toString(ecoefficiencyForecast[0]); } else { return Double.toString(ecoefficiencyForecast[1]); } } /** * Forecasts the EcoEfficiency of the IP provider when deploying a new * service. * * @param manifest Manifest describing the VMs to be deployed in the * infrastructure. * @param timeSpan Time in the future in which the prediction will be made. * @return The IP EcoEfficiency prediction. */ public synchronized double[] forecastIPEcoEfficiencyServiceDeployment(String manifest, Long timeSpan) { double ret[] = { -1.0, -1.0 }; if (timeSpan == null) { //TODO This shouldn't condition the timespan. Even if manifest is present, we can estimate the non-variant part of the IP eco. if (manifest == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } else { timeSpan = new Long(0); } } //Estimating infrastructure performance and forecast (without any deployment) double totalPerformanceForecast = 0.0, totalPowerForecast = 0.0; for (String nodeId : co.getNodesId()) { try { double temp[] = getNodeFuturePerformanceAndPower(nodeId, null, null, null, timeSpan); totalPerformanceForecast += temp[0]; totalPowerForecast += temp[1]; } catch (Exception ex) { log.error("Couldn't get node " + nodeId + " performance and power forecasts."); log.error(ex.getMessage()); return ret; } } //Adding performance and power required by manifest. Manifest parsedManifest = null; String serviceId = null; if (manifest != null) { log.debug("Forecasting infrastructure ecoefficiency upon service deployment."); //Parse Service Manifest log.debug("Parsing manifest..."); try { parsedManifest = Manifest.Factory.newInstance(manifest); serviceId = parsedManifest.getVirtualMachineDescriptionSection().getServiceId(); } catch (Exception ex) { log.error("Couldn't parse Service Manifest."); log.error(ex.getMessage()); return ret; } addDeploymentMessage("Infrastructure-level service " + serviceId + " deployment eco-forecast."); //Checking of certificates if (certificates.checkCertificates(manifest) == false) { log.info("One or more certificate requirements wasn't fulfilled. Service can't be accepted."); addDeploymentMessage("Certificate requirements weren't fulfilled for service " + serviceId + ".\nNo additional performance or power considered at infrastructure-level.\n"); ret[0] = 0.0; ret[1] = 0.0; return ret; } else { //Adding the addicional performance and power required to run the service. double perfPowServiceForecast[] = getNewServiceFuturePerformanceAndPower(parsedManifest); totalPerformanceForecast += perfPowServiceForecast[0]; totalPowerForecast += perfPowServiceForecast[1]; } } //Ecoefficiency forecast calculation. double energyEfficiencyForecast = (totalPerformanceForecast) / (totalPowerForecast * PUE); double ecologicalEfficiencyForecast = (totalPerformanceForecast) / (CO2Converter.getCO2FromPower(totalPowerForecast * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); if (manifest == null) { log.info("IP EnEffForec: " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); } else { log.info("IP EnEffForec (Service " + parsedManifest.getVirtualMachineDescriptionSection().getServiceId() + " deployment): " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); DecimalFormat df = new DecimalFormat("####.##"); addDeploymentMessage("Energy Efficiency Forecast: " + df.format(new Double(energyEfficiencyForecast)) + "MWIPS/W. Ecological Efficiency Forecast: " + df.format(new Double(ecologicalEfficiencyForecast)) + "MWIPS/(grCO2/s).\n"); } ret[0] = energyEfficiencyForecast; ret[1] = ecologicalEfficiencyForecast; return ret; } public synchronized String forecastIPEcoEfficiencyVMCancellation(String vmId, String type, Long timeSpan) { log.debug("Forecasting infrastructure ecoefficiency upon VM cancellation."); if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } //Determining in which node VM is placed. String vmNode = co.getNodeId(vmId); List<String> vmRemoveList = new LinkedList<String>(); vmRemoveList.add(vmId); //Estimating infrastructure performance and forecast (without any deployment) double totalPerformanceForecast = 0.0, totalPowerForecast = 0.0; for (String nodeId : co.getNodesId()) { try { double temp[] = null; if (vmNode.equalsIgnoreCase(nodeId)) { temp = getNodeFuturePerformanceAndPower(nodeId, null, vmRemoveList, null, timeSpan); } else { temp = getNodeFuturePerformanceAndPower(nodeId, null, null, null, timeSpan); } totalPerformanceForecast += temp[0]; totalPowerForecast += temp[1]; } catch (Exception ex) { log.error("Couldn't get node " + nodeId + " performance and power forecasts."); log.error(ex.getMessage()); return "-1.0"; } } //Ecoefficiency forecast calculation. double energyEfficiencyForecast = (totalPerformanceForecast) / (totalPowerForecast * PUE); double ecologicalEfficiencyForecast = (totalPerformanceForecast) / (CO2Converter.getCO2FromPower(totalPowerForecast * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); log.info("IP EnEffForec (Cancelling VM " + vmId + " in host " + vmNode + "): " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); //Return desired ecoefficiency forecasted type. if (type.equalsIgnoreCase("energy")) { return Double.toString(energyEfficiencyForecast); } else { return Double.toString(ecologicalEfficiencyForecast); } } public synchronized String forecastIPEcoEfficiencyVMDeploymentKnownPlacement(OVFWrapper ovfDom, String destNode, List<String> activeNodes, String type, Long timeSpan) { log.debug("Forecasting infrastructure ecoefficiency upon VM deployment on node " + destNode + " ."); if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } if (activeNodes == null) { activeNodes = co.getNodesId(); } List<OVFWrapper> deployments = new LinkedList<OVFWrapper>(); deployments.add(ovfDom); //Estimating infrastructure performance and forecast (without any deployment) double totalPerformanceForecast = 0.0, totalPowerForecast = 0.0; for (String nodeId : co.getNodesId()) { if (activeNodes.contains(nodeId)) { try { double temp[] = null; if (destNode.equalsIgnoreCase(nodeId)) { temp = getNodeFuturePerformanceAndPower(nodeId, deployments, null, null, timeSpan); } else { temp = getNodeFuturePerformanceAndPower(nodeId, null, null, null, timeSpan); } totalPerformanceForecast += temp[0]; totalPowerForecast += temp[1]; } catch (Exception ex) { log.debug("Couldn't get node " + nodeId + " performance and power forecasts."); log.error(ex.getMessage()); return "-1.0"; } } } //Ecoefficiency forecast calculation. double energyEfficiencyForecast = (totalPerformanceForecast) / (totalPowerForecast * PUE); double ecologicalEfficiencyForecast = (totalPerformanceForecast) / (CO2Converter.getCO2FromPower(totalPowerForecast * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); log.info("IP EnEffForec (Deploying VM " + ovfDom.getId() + " in host " + destNode + "): " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); //Return desired ecoefficiency forecasted type. if (type.equalsIgnoreCase("energy")) { return Double.toString(energyEfficiencyForecast); } else { return Double.toString(ecologicalEfficiencyForecast); } } public synchronized String forecastIPEcoEfficiencyVMMigrationKnownPlacement(String vmId, String destNode, List<String> activeNodes, String type, Long timeSpan) { log.debug("Forecasting infrastructure ecoefficiency upon VM migration."); if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } if (activeNodes == null) { activeNodes = co.getNodesId(); } //Determining from which node VM is to be migrated. String vmMigrateOutNode = co.getNodeId(vmId); List<String> vmMigrateList = new LinkedList<String>(); vmMigrateList.add(vmId); //Estimating infrastructure performance and forecast (without any deployment) double totalPerformanceForecast = 0.0, totalPowerForecast = 0.0; for (String nodeId : activeNodes) { try { double temp[] = null; if (vmMigrateOutNode.equalsIgnoreCase(nodeId)) { temp = getNodeFuturePerformanceAndPower(nodeId, null, vmMigrateList, null, timeSpan); } else if (destNode.equalsIgnoreCase(nodeId)) { temp = getNodeFuturePerformanceAndPower(nodeId, null, null, vmMigrateList, timeSpan); } else { temp = getNodeFuturePerformanceAndPower(nodeId, null, null, null, timeSpan); } totalPerformanceForecast += temp[0]; totalPowerForecast += temp[1]; } catch (Exception ex) { log.error("Couldn't get node " + nodeId + " performance and power forecasts."); log.error(ex.getMessage()); return "-1.0"; } } //Ecoefficiency forecast calculation. double energyEfficiencyForecast = (totalPerformanceForecast) / (totalPowerForecast * PUE); double ecologicalEfficiencyForecast = (totalPerformanceForecast) / (CO2Converter.getCO2FromPower(totalPowerForecast * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); log.info("IP EnEffForec (Migrating VM " + vmId + " from host " + vmMigrateOutNode + " to host " + destNode + "): " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); //Return desired ecoefficiency forecasted type. if (type.equalsIgnoreCase("energy")) { return Double.toString(energyEfficiencyForecast); } else { return Double.toString(ecologicalEfficiencyForecast); } } public synchronized String forecastIPEcoEfficiencyVMDeploymentUnknownPlacement(OVFWrapper ovfDom, String type, Long timeSpan) { log.debug("Forecasting infrastructure ecoefficiency upon service deployment."); if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } //Estimating infrastructure performance and forecast (without any deployment) double totalPerformanceForecast = 0.0, totalPowerForecast = 0.0; for (String nodeId : co.getNodesId()) { try { double temp[] = getNodeFuturePerformanceAndPower(nodeId, null, null, null, timeSpan); totalPerformanceForecast += temp[0]; totalPowerForecast += temp[1]; } catch (Exception ex) { log.error("Couldn't get node " + nodeId + " performance and power forecasts."); log.error(ex.getMessage()); return "-1.0"; } } //Adding performance and power required to run the new VM if (ovfDom != null) { double perfPowVMForecast[] = getNewVMFuturePerformanceAndPowerUnknownPlacement(ovfDom, null); totalPerformanceForecast += perfPowVMForecast[0]; totalPowerForecast += perfPowVMForecast[1]; } //Ecoefficiency forecast calculation. double energyEfficiencyForecast = (totalPerformanceForecast) / (totalPowerForecast * PUE); double ecologicalEfficiencyForecast = (totalPerformanceForecast) / (CO2Converter.getCO2FromPower(totalPowerForecast * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); log.info("IP EnEffForec (Deployment of VM " + ovfDom.getId() + ", unknown placement): " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); //Return desired ecoefficiency forecasted type. if (type.equalsIgnoreCase("energy")) { return Double.toString(energyEfficiencyForecast); } else { return Double.toString(ecologicalEfficiencyForecast); } } public synchronized String forecastIPEcoEfficiencyVMMigrationUnknownPlacement(String vmId, String type, Long timeSpan) { log.debug("Forecasting infrastructure ecoefficiency upon VM migration (unknown destination yet)."); if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } //Determining in which node VM is placed. String vmNode = co.getNodeId(vmId); List<String> vmRemoveList = new LinkedList<String>(); vmRemoveList.add(vmId); //Estimating infrastructure performance and forecast (taking out the VM to be migrated) double totalPerformanceForecast = 0.0, totalPowerForecast = 0.0; for (String nodeId : co.getNodesId()) { try { double temp[] = null; if (vmNode.equalsIgnoreCase(nodeId)) { temp = getNodeFuturePerformanceAndPower(nodeId, null, vmRemoveList, null, timeSpan); } else { temp = getNodeFuturePerformanceAndPower(nodeId, null, null, null, timeSpan); } totalPerformanceForecast += temp[0]; totalPowerForecast += temp[1]; } catch (Exception ex) { log.error("Couldn't get node " + nodeId + " performance and power forecasts."); log.error(ex.getMessage()); return "-1.0"; } } try { //Adding performance (same as if it wasn't migrated) double futureVMPerformance = getVMFuturePerformanceAndPower(vmId, timeSpan)[0]; double futureCPUMeanPower = energyEstimator.getFutureCPUMeanPower(0, null, true); //0 because no extra CPUs will be used, as the VM is already present and being migrated. double futureVMPower = ((double) metrics.getCPUNumber(vmId)) * futureCPUMeanPower; totalPerformanceForecast += futureVMPerformance; totalPowerForecast += futureVMPower; } catch (Exception ex) { log.error("Error while obtaining VM future performance and forecast upon migration."); log.error(ex.getMessage()); } //Ecoefficiency forecast calculation. double energyEfficiencyForecast = (totalPerformanceForecast) / (totalPowerForecast * PUE); double ecologicalEfficiencyForecast = (totalPerformanceForecast) / (CO2Converter.getCO2FromPower(totalPowerForecast * PUE)); Date date = new Date(); long futureTimeStamp = date.getTime() + timeSpan.longValue(); log.info("IP EnEffForec (Migrating VM " + vmId + ", unknown placement): " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast + " FutTS: " + futureTimeStamp); //Return desired ecoefficiency forecasted type. if (type.equalsIgnoreCase("energy")) { return Double.toString(energyEfficiencyForecast); } else { return Double.toString(ecologicalEfficiencyForecast); } } public synchronized String forecastServiceEcoEfficiency(String manifest, String type, Long timeSpan) { double[] ecoefficiencyForecast = forecastServiceEcoEfficiency(null, timeSpan, manifest); //Return desired ecoefficiency forecast type. if (type.equalsIgnoreCase("energy")) { return Double.toString(ecoefficiencyForecast[0]); } else { return Double.toString(ecoefficiencyForecast[1]); } } /** * Predicts the expected eco-efficiency of a given service. If the service * is already deployed it will be calculated based on the current number of * VMs (components) of the service. If the service is not deployed (new * deployment situation) and typeIdReplicas is null, it will be assumed that * it will require one replica of each component when performing the * prediction. Otherwise, it will take into account the amount of replicas * to be deployed of each component type when performing the prediction. * * @param manifest Service Manifest. * @param typeIdReplicas Number of VM replicas of each type to be deployed. * @param timeSpan Time in the future in which the prediction will be made. * @return Predicted ecoefficiency in timeSpan milliseconds (Double into a * String). */ public synchronized double[] forecastServiceEcoEfficiency(String serviceId, Long timeSpan, String manifest) { double ret[] = { -1.0, -1.0 }; double energyEfficiencyForecast, ecologicalEfficiencyForecast; log.debug("Forecasting service ecoefficiency."); if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } //Parse Service Manifest //log.info("Parsing manifest..."); Manifest parsedManifest = null; if (serviceId == null && manifest != null) { try { parsedManifest = Manifest.Factory.newInstance(manifest); serviceId = parsedManifest.getVirtualMachineDescriptionSection().getServiceId(); addDeploymentMessage("Service-level service " + serviceId + " deployment eco-forecast."); } catch (Exception ex) { log.error("Couldn't parse Service Manifest. Error: \n", ex); return ret; } //Checking of certificates if (certificates.checkCertificates(manifest) == false) { log.info("One or more certificate requirements wasn't fulfilled. Service can't be accepted."); addDeploymentMessage( "Certificate requirements weren't fulfilled for service " + serviceId + ". Returned 0.\n"); ret[0] = 0.0; ret[1] = 0.0; return ret; } } List<String> vmsId = co.getVMsIdsOfService(serviceId); vmsId = co.getVMsIdsOfService(serviceId); if (vmsId != null) { if (vmsId.size() > 0) { double totalPerformanceForecast = 0.0, totalPowerForecast = 0.0; for (String vmId : vmsId) { try { double perfPowerForecast[] = getVMFuturePerformanceAndPower(vmId, timeSpan); totalPerformanceForecast += perfPowerForecast[0]; totalPowerForecast += perfPowerForecast[1]; } catch (Exception ex) { log.error("Couldn't obtain VM " + vmId + " predicted performance and power."); log.error(ex.getMessage()); return ret; } } //Ecoefficiency Forecast calculation. energyEfficiencyForecast = (totalPerformanceForecast) / (totalPowerForecast * PUE); ecologicalEfficiencyForecast = (totalPerformanceForecast) / (CO2Converter.getCO2FromPower(totalPowerForecast * PUE)); ret[0] = energyEfficiencyForecast; ret[1] = ecologicalEfficiencyForecast; log.info("Service " + serviceId + " EnEffForec: " + energyEfficiencyForecast + " EcoEffForec: " + ecologicalEfficiencyForecast); } else { if (parsedManifest != null) { log.debug("New deployment evaluation."); double perfPowPrediction[] = getNewServiceFuturePerformanceAndPower(parsedManifest); //Ecoefficiency Forecast calculation. energyEfficiencyForecast = (perfPowPrediction[0]) / (perfPowPrediction[1] * PUE); ecologicalEfficiencyForecast = (perfPowPrediction[0]) / (CO2Converter.getCO2FromPower(perfPowPrediction[1] * PUE)); DecimalFormat df = new DecimalFormat("####.##"); addDeploymentMessage( "Energy Efficiency Forecast: " + df.format(new Double(energyEfficiencyForecast)) + "MWIPS/W. Ecological Efficiency Forecast: " + df.format(new Double(ecologicalEfficiencyForecast)) + "MWIPS/(grCO2/s).\n"); ret[0] = energyEfficiencyForecast; ret[1] = ecologicalEfficiencyForecast; log.info("Service " + serviceId + " deployment EnEff: " + energyEfficiencyForecast + " EcoEff: " + ecologicalEfficiencyForecast); } else { log.error("Parsed manifest was null, new deployment can't be evaluated."); } } } else { log.error("Obtained a null list of VMs from CO."); return ret; } return ret; } /** * **********************Internal Methods******************************* */ private double[] getNodeFuturePerformanceAndPower(String nodeId, List<OVFWrapper> deployments, List<String> undeploymentNames, List<String> migrationVmIds, Long timeSpan) throws Exception { double perfPowerPrediction[] = new double[2]; //Checking of parameters if (undeploymentNames == null) { undeploymentNames = new LinkedList<String>(); } if (deployments == null) { deployments = new LinkedList<OVFWrapper>(); } if (migrationVmIds == null) { migrationVmIds = new LinkedList<String>(); } //Obtain xentop_cpu report from Monitoring Infrastructure. String xenTopReport = null; MonitoringResourceDatasets nodeReportForEnergy = null; try { nodeReportForEnergy = mi_client.getLatestReportForEnergy(nodeId); } catch (Exception ex) { log.error("Error while obtaining energy values from the Energy Collector."); log.error(ex.getMessage()); throw new Exception("Error while obtaining energy values from the Energy Collector."); } List<MonitoringResourceDataset> nodeEnergyMetrics = nodeReportForEnergy.getMonitoring_resource(); for (MonitoringResourceDataset metric : nodeEnergyMetrics) { if (metric.getMetric_name().equalsIgnoreCase("xentop_cpu")) { xenTopReport = metric.getMetric_value(); } } if (xenTopReport == null) { log.error("Obtained null xen_top values from the Monitoring"); throw new Exception("Obtained null xen_top values from the Monitoring"); } //Obtain which VMs are present in the node (including Domain-0) and forecast its CPU utilization. Discard undeployment utilizations. double vmsCpuUtilization = 0.0; double dom0CpuUtilization = 0.0; String tmp[] = xenTopReport.split(";"); for (int i = 0; i < tmp.length; i++) { String domNameVsCpu[] = tmp[i].split(" "); if (domNameVsCpu.length == 2) { if (!undeploymentNames.contains(domNameVsCpu[0])) { if (!domNameVsCpu[0].equalsIgnoreCase("Domain-0")) { double tmpCPU = forecastVMCpuUtilization(domNameVsCpu[0], timeSpan); if (tmpCPU > 0.0) { vmsCpuUtilization += tmpCPU; } } else { dom0CpuUtilization = forecastVMCpuUtilization("Domain-0".concat(nodeId), timeSpan); } } else { log.debug("VM " + domNameVsCpu[0] + " is not considered in the calculation (VM cancellation)."); } } else { log.debug("Invalid Domain CPU lecture."); } } //Calculate additional CPU utilization and power incurred by the new VMs under deployment. double additionalCPURequired = 0.0; for (OVFWrapper ovfDom : deployments) { additionalCPURequired += ((double) ovfDom.getCPUsNumber()) * (initialCPUUtilization / ((double) metrics.getCPUNumber(nodeId))); } //Calculate additional CPU utilization incurred by the new VMs being migrated to the node. for (String vmId : migrationVmIds) { double vmFuturePerformance = this.getVMFuturePerformanceAndPower(vmId, timeSpan)[0]; log.debug("VM " + vmId + " will require " + vmFuturePerformance + " MWIPS. Will result in " + vmFuturePerformance / metrics.getNodeBenchmarkResult(nodeId) + " additional CPU required."); additionalCPURequired += vmFuturePerformance / metrics.getNodeBenchmarkResult(nodeId); } //Add the forecasted additional CPU utilization to the VMs. If it's greater than 100.0, correct. vmsCpuUtilization += additionalCPURequired; if (vmsCpuUtilization + dom0CpuUtilization > 100.0) { vmsCpuUtilization = 100.0 - dom0CpuUtilization; } else if (vmsCpuUtilization < 0.0) { vmsCpuUtilization = 0.0; } //Obtain the future performance taking into account the forecasted CPU utilizations. double futurePerformance = (vmsCpuUtilization / 100.0) * metrics.getNodeBenchmarkResult(nodeId); double futurePower = energyEstimator.estimatePowerConsumption(nodeId, vmsCpuUtilization + dom0CpuUtilization); perfPowerPrediction[0] = futurePerformance; perfPowerPrediction[1] = futurePower; return perfPowerPrediction; } /** * Forecasts the performance which delivered to this VMs, as well as the * real power consumed by it, after timeSpan milliseconds. * * @param vmId VM identifier * @return A vector containing the predicted performance delivered to the VM * in the first position and the predicted real power consumed by it on the * second position. * @throws Exception */ private double[] getVMFuturePerformanceAndPower(String vmId, Long timeSpan) throws Exception { double futPerfPow[] = new double[2]; String nodeId = null; String vmName = null; int numVmsNode = 0; nodeId = co.getNodeId(vmId); if (nodeId == null) { log.error("VM " + vmId + " was not present in the system."); throw new Exception("VM " + vmId + " was not present in the system."); } List<String> temp = co.getVMsId(nodeId); if (temp == null) { log.error("Error while retreiving number of VMs in node."); throw new Exception("Error while retreiving number of VMs in node."); } vmName = co.getVMName(vmId); if (vmName == null) { log.error("Could not retreive VM name."); throw new Exception("Could not retreive VM name."); } double vmsCpuUtilization = 0.0; double vmCpuUtilization = 0.0; double dom0CpuUtilization = 0.0; String xenTopReport = null; MonitoringResourceDatasets nodeReportForEnergy = null; try { nodeReportForEnergy = mi_client.getLatestReportForEnergy(nodeId); } catch (Exception ex) { log.error("Error while obtaining energy values from the Energy Collector."); log.error(ex.getMessage()); throw new Exception("Error while obtaining energy values from the Energy Collector."); } List<MonitoringResourceDataset> nodeEnergyMetrics = nodeReportForEnergy.getMonitoring_resource(); for (MonitoringResourceDataset metric : nodeEnergyMetrics) { if (metric.getMetric_name().equalsIgnoreCase("xentop_cpu")) { xenTopReport = metric.getMetric_value(); } } if (xenTopReport == null) { log.error("Obtained null xen_top values from the Monitoring"); throw new Exception("Obtained null xen_top values from the Monitoring."); } String tmp[] = xenTopReport.split(";"); for (int i = 0; i < tmp.length; i++) { String domNameVsCpu[] = tmp[i].split(" "); if (domNameVsCpu.length == 2) { if (!domNameVsCpu[0].equalsIgnoreCase("Domain-0")) { numVmsNode++; double tmpCPU = forecastVMCpuUtilization(domNameVsCpu[0], timeSpan); if (tmpCPU > 0.0) { vmsCpuUtilization += tmpCPU; if (domNameVsCpu[0].equalsIgnoreCase(vmName)) { vmCpuUtilization = tmpCPU; } } } else { dom0CpuUtilization = forecastVMCpuUtilization("Domain-0".concat(nodeId), timeSpan); } } else { log.debug("Invalid Domain CPU lecture."); } } if (vmsCpuUtilization + dom0CpuUtilization > 100.0) { vmsCpuUtilization = 100.0 - dom0CpuUtilization; } else if (vmsCpuUtilization < 0.0) { vmsCpuUtilization = 0.0; } double totalcpuforecast = vmsCpuUtilization + dom0CpuUtilization; double futurePerformance = (vmCpuUtilization / 100.0) * metrics.getNodeBenchmarkResult(nodeId); double futurePower = energyEstimator.estimatePowerConsumption(nodeId, totalcpuforecast) * ((vmCpuUtilization + dom0CpuUtilization / ((double) numVmsNode)) / (totalcpuforecast)); futPerfPow[0] = futurePerformance; futPerfPow[1] = futurePower; return futPerfPow; } private double[] getNewVMFuturePerformanceAndPowerUnknownPlacement(OVFWrapper ovfDom, List<String> activeNodes) { double futPerfPow[] = new double[2]; double totalPerformance = ((double) ovfDom.getCPUsNumber()) * metrics.getCPUMeanPerformance(activeNodes) * (initialCPUUtilization / 100.0); double futureCPUMeanPower = 0.0; futureCPUMeanPower = energyEstimator.getFutureCPUMeanPower(0, activeNodes, true); double totalPower = ((double) ovfDom.getCPUsNumber()) * futureCPUMeanPower; futPerfPow[0] = totalPerformance; futPerfPow[1] = totalPower; return futPerfPow; } private double[] getNewServiceFuturePerformanceAndPower(Manifest parsedManifest) { double futPerfPow[] = new double[2]; //TODO take into consideration replicas in SM. int numCpus = 0; for (VirtualMachineComponent vmOvf : parsedManifest.getVirtualMachineDescriptionSection() .getVirtualMachineComponentArray()) { numCpus += vmOvf.getAllocationConstraints().getInitial() * vmOvf.getOVFDefinition().getVirtualSystem() .getVirtualHardwareSection().getNumberOfVirtualCPUs(); } double totalPerformance = ((double) numCpus) * metrics.getCPUMeanPerformance(null) * (initialCPUUtilization / 100.0); double futureCPUMeanPower = energyEstimator.getFutureCPUMeanPower(numCpus, null, true); double totalPower = ((double) numCpus) * futureCPUMeanPower; DecimalFormat df = new DecimalFormat("#.##"); addDeploymentMessage("Num CPUs: " + numCpus + "Initial CPU Utilization: " + initialCPUUtilization + "% Performance delivered: " + df.format(new Double(totalPerformance)) + "MWIPS Power delivered: " + df.format(new Double(totalPower)) + "W"); futPerfPow[0] = totalPerformance; futPerfPow[1] = totalPower; return futPerfPow; } /** * Forecasts the CPU utilization of the VM identified by vmId at the time * specified in timeSpan based on previous CPU utilization values and using * Linear Regression. * * @param vmId Virtual Machine's Identifier. * @param timeSpan Future time specified in milliseconds since 1/1/1970. * @return Forecasted CPU utilization. */ private synchronized double forecastVMCpuUtilization(String vmId, Long timeSpan) { if (timeSpan == null) { timeSpan = new Long(Constants.DEFAULT_TIMESPAN); } VariableEstimator vmCPUPredictor = vmCPUPredictors.get(vmId); if (vmCPUPredictor != null) { Date currentDate = new Date(); //TimeSpan is in minutes, converting it to milliseconds. long futurePredictionTimeStamp = currentDate.getTime() + timeSpan.longValue(); double predictedUtilization = vmCPUPredictor.obtainBestForecast(futurePredictionTimeStamp); if (predictedUtilization < 0.0) { predictedUtilization = 0.0; } else if (predictedUtilization > 100.0) { predictedUtilization = 100.0; } cpuValidator.performForecasts(vmId, futurePredictionTimeStamp); return predictedUtilization; } else { log.error("No previous information was found of VM " + vmId + " to forecast its CPU usage."); return -1.0; } } /* * private synchronized double forecastVMCpuUtilization(String vmId, Long * timeSpan) { * * //TODO CHECK FOR NULL PARAMETERS. if (timeSpan == null) { timeSpan = new * Long(Constants.DEFAULT_TIMESPAN); } * * HashMap<Long, Double> vmUtilization = vmUtilizations.get(vmId); double * predictedUtilization = -1.0; if (vmUtilization != null) { * * if (vmUtilizations.size() <= 2) { log.error("Trying to interpolate with * only 1 previous utilization sample."); return -1.0; } * * //TODO Change this by timestamps. double xValues[] = new * double[vmUtilization.size()]; double yValues[] = new * double[vmUtilization.size()]; * * Iterator it = vmUtilization.keySet().iterator(); int i = 0; while * (it.hasNext()) { Long tmpTimeStamp = (Long) it.next(); xValues[i] = * Double.parseDouble(tmpTimeStamp.toString()); yValues[i] = * vmUtilization.get(tmpTimeStamp); //System.out.println("**ECO-REMOVE: * Forecasting. Iteration: " + i + " Timestamp: " + tmpTimeStamp + " Value: * " + vmUtilization.get(tmpTimeStamp)); i++; } * * Date currentDate = new Date(); //TimeSpan is in minutes, converting it to * milliseconds. double futurePredictionTimeStamp = (double) * currentDate.getTime() + timeSpan.doubleValue(); * * LinearRegression lr = new LinearRegression(xValues, yValues); * predictedUtilization = lr.calculateY(futurePredictionTimeStamp); if * (predictedUtilization < 0.0) { predictedUtilization = 0.0; } else if * (predictedUtilization > 100.0) { predictedUtilization = 100.0; } //Date * date = new Date(); //System.out.println("**ECO-REMOVE: Predicted * utilization: " + predictedUtilization + " Date: " + date.toString() + " * Timestamp: " + date.getTime()); } else { log.error("No previous * information was found of VM " + vmId + " to forecast its CPU usage."); * return -1.0; } * * //System.out.println("*******ECO-REMOVE: Forecast of VM " + vmId + ": " * + predictedUtilization); * * return predictedUtilization; } */ private void addDeploymentMessage(String message) { if (deploymentMessages.size() == Constants.MAX_DEPLOYMENT_MESSAGES) { deploymentMessages.remove(0); } deploymentMessages.add(message); } public String getAllDeploymentMessages() { String ret = ""; for (String message : deploymentMessages) { ret = ret.concat(message).concat("\n"); } return ret; } }