package org.ovirt.engine.core.bll.utils;
import javax.inject.Singleton;
import org.ovirt.engine.core.common.FeatureSupported;
import org.ovirt.engine.core.common.businessentities.ArchitectureType;
import org.ovirt.engine.core.common.businessentities.VM;
@Singleton
public class VmOverheadCalculatorImpl implements VmOverheadCalculator {
/**
* Return total required RAM for running the given VM.
* It includes VM size, expected QEMU overhead and other memory taken from
* the system by running the VM (such as page tables).
*
* Please note the return value is just estimation of the memory
* requirements and the real required RAM may differ in both directions.
*
* @param vm the relevant VM
* @return required amount of memory in MiB
* @throws RuntimeException
* thrown in case the cluster architecture cannot be identified
*/
@Override
public int getTotalRequiredMemoryInMb(VM vm) {
int vmRam = vm.getVmMemSizeMb();
return vmRam + getOverheadInMb(vm);
}
/**
* Get total expected memory overhead
*
* It includes VM size, expected QEMU overhead and other memory taken from
* the system by running the VM (such as page tables).
*
* Please note the return value is just estimation of the memory
* requirements and the real required RAM may differ in both directions.
*
* @param vm the relevant VM
* @return required amount of memory in MiB
* @throws RuntimeException
* thrown in case the cluster architecture cannot be identified
*/
@Override
public int getOverheadInMb(VM vm) {
return getStaticOverheadInMb(vm) + getPossibleOverheadInMb(vm);
}
/**
* Get the size of possible memory overhead. This represents memory
* that might be allocated by QEMU, but the memory is then not used
* immediately.
*
* @param vm the relevant VM
* @return required amount of memory in MiB
*/
@Override
public int getPossibleOverheadInMb(VM vm) {
int videoRam = VideoDeviceSettings.totalVideoRAMSizeMb(vm);
int cpuOverhead = 8 * vm.getNumOfCpus(true);
int iothreadsOverhead = 8 * vm.getNumOfIoThreads();
return videoRam + cpuOverhead + iothreadsOverhead;
}
/**
* Get the memory overhead QEMU imposes on the VM immediately.
* The value contains the needed memory size for page tables and
* memory hotplug structures + expected fixed overhead (shared libraries
* and internal QEMU structures).
*
* @param vm the relevant VM
* @return required amount of memory in MiB
* @throws RuntimeException
* thrown in case the cluster architecture cannot be identified
*/
@Override
public int getStaticOverheadInMb(VM vm) {
int vmRam = vm.getVmMemSizeMb();
ArchitectureType architecture = vm.getClusterArch().getFamily();
boolean onPpc = architecture == ArchitectureType.ppc;
int fixedOverhead = onPpc ? 100 : 64;
int pageTable;
if (onPpc) {
int maxRam = vmRam;
if (FeatureSupported.hotPlugMemory(vm.getCompatibilityVersion(), vm.getClusterArch())) {
maxRam = vm.getMaxMemorySizeMb();
}
int powerOf2 = Integer.highestOneBit(maxRam);
pageTable = (maxRam > powerOf2 ? powerOf2 * 2 : powerOf2) / 64;
} else {
pageTable = vmRam / 512;
}
return pageTable + fixedOverhead;
}
/**
* Returns the required size for saving all the memory used by this VM.
* It is useful for determining the size to be allocated in the storage when hibernating
* VM or taking a snapshot with memory.
*
* @param vm The VM to compute the memory size for.
* @return - Memory size for allocation in bytes.
*/
@Override
public long getSnapshotMemorySizeInBytes(VM vm) {
long videoRam = (long)VideoDeviceSettings.totalVideoRAMSizeMb(vm);
return (vm.getVmMemSizeMb() + 200 + videoRam) * 1024 * 1024;
}
}