package org.ovirt.engine.core.bll.scheduling.policyunits;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.math.NumberUtils;
import org.ovirt.engine.core.bll.scheduling.PolicyUnitImpl;
import org.ovirt.engine.core.bll.scheduling.PolicyUnitParameter;
import org.ovirt.engine.core.bll.scheduling.SchedulingUnit;
import org.ovirt.engine.core.bll.scheduling.SlaValidator;
import org.ovirt.engine.core.bll.scheduling.pending.PendingResourceManager;
import org.ovirt.engine.core.common.businessentities.Cluster;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.scheduling.PerHostMessages;
import org.ovirt.engine.core.common.scheduling.PolicyUnit;
import org.ovirt.engine.core.common.scheduling.PolicyUnitType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SchedulingUnit(
guid = "98842bc5-4094-4b83-8224-7b50f86a94c9",
name = "CPUOverloaded",
type = PolicyUnitType.FILTER,
description = "Filters out CPU overloaded hosts.",
parameters = {
PolicyUnitParameter.HIGH_UTILIZATION,
PolicyUnitParameter.CPU_OVERCOMMIT_DURATION_MINUTES
}
)
public class CpuOverloadPolicyUnit extends PolicyUnitImpl {
private static final Logger log = LoggerFactory.getLogger(CpuOverloadPolicyUnit.class);
public CpuOverloadPolicyUnit(PolicyUnit policyUnit,
PendingResourceManager pendingResourceManager) {
super(policyUnit, pendingResourceManager);
}
@Override
public List<VDS> filter(Cluster cluster, List<VDS> hosts, VM vm, Map<String, String> parameters, PerHostMessages messages) {
List<VDS> list = new ArrayList<>();
final int highUtilization = NumberUtils.toInt(parameters.get(PolicyUnitParameter.HIGH_UTILIZATION.getDbName()),
getHighUtilizationDefaultValue());
final int cpuOverCommitDurationMinutes =
NumberUtils.toInt(parameters.get(PolicyUnitParameter.CPU_OVERCOMMIT_DURATION_MINUTES.getDbName()),
Config.<Integer>getValue(ConfigValues.CpuOverCommitDurationMinutes));
for (VDS vds : hosts) {
// Check the core count
Integer cores = SlaValidator.getEffectiveCpuCores(vds,
cluster != null && cluster.getCountThreadsAsCores());
if (cores == null) {
log.warn("Unknown number of cores for host {}.", vds.getName());
continue;
}
// Check the CPU load. A Host is considered overloaded when all cores are loaded
// more than the defined percentage
int highUtilizationTotal = getHighUtilizationForAllCores(highUtilization, cores);
if ((vds.getUsageCpuPercent()
// This has to use greater than (without 'or equals') as we only have percents without
// fractional part and 100% means we still have some power on machines with more
// than 100 cpus
+ CpuAndMemoryBalancingPolicyUnit.calcSpmCpuConsumption(vds)) > highUtilizationTotal
&& vds.getCpuOverCommitTimestamp() != null
&& (getTime().getTime() - vds.getCpuOverCommitTimestamp().getTime())
>= TimeUnit.MINUTES.toMillis(cpuOverCommitDurationMinutes)) {
messages.addMessage(vds.getId(), EngineMessage.VAR__DETAIL__CPU_OVERLOADED.toString());
log.debug("Host '{}' is too loaded ({}%) and has been overloaded since {}.",
vds.getName(), vds.getUsageCpuPercent(),
vds.getCpuOverCommitTimestamp().toString());
continue;
}
list.add(vds);
}
return list;
}
/**
* Compute a minimal global utilization percentage that is equivalent to
* a situation where there is no core that would be loaded to less than
* highUtilization percents.
*
* @param highUtilization all cores are loaded more than this value
* @param cores number of cores
* @return the global utilization
*/
protected int getHighUtilizationForAllCores(int highUtilization, int cores) {
// Convert the numbers from utilization to free resources
int freeCpu = 100 - highUtilization;
// Substract it from the full load
float load = 100f * cores - freeCpu;
// Scale to percents
return Math.round(load / cores);
}
protected Date getTime() {
return new Date();
}
protected static int getHighUtilizationDefaultValue() {
return Config.<Integer> getValue(ConfigValues.HighUtilizationForScheduling);
}
}