Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions agent/conf/agent.properties
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,6 @@ iscsi.session.cleanup.enabled=false

# Enable manually setting CPU's topology on KVM's VM.
# enable.manually.setting.cpu.topology.on.kvm.vm=true

# Manually set the host CPU MHz, in cases where CPU scaling support detected value is wrong
# host.cpu.manual.speed.mhz=0
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
protected String _rngPath = "/dev/random";
protected int _rngRatePeriod = 1000;
protected int _rngRateBytes = 2048;
protected int _manualCpuSpeed = 0;
protected String _agentHooksBasedir = "/etc/cloudstack/agent/hooks";

protected String _agentHooksLibvirtXmlScript = "libvirt-vm-xml-transformer.groovy";
Expand Down Expand Up @@ -1034,6 +1035,9 @@ public boolean configure(final String name, final Map<String, Object> params) th
_noMemBalloon = true;
}

value = (String)params.get("host.cpu.manual.speed.mhz");
_manualCpuSpeed = NumbersUtil.parseInt(value, 0);

_videoHw = (String) params.get("vm.video.hardware");
value = (String) params.get("vm.video.ram");
_videoRam = NumbersUtil.parseInt(value, 0);
Expand Down Expand Up @@ -3294,7 +3298,7 @@ private Map<String, String> getVersionStrings() {
@Override
public StartupCommand[] initialize() {

final KVMHostInfo info = new KVMHostInfo(_dom0MinMem, _dom0OvercommitMem);
final KVMHostInfo info = new KVMHostInfo(_dom0MinMem, _dom0OvercommitMem, _manualCpuSpeed);

String capabilities = String.join(",", info.getCapabilities());
if (dpdkSupport) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ public class KVMHostInfo {
private long overCommitMemory;
private List<String> capabilities = new ArrayList<>();

private static String cpuInfoMaxFreqFileName = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
private static String cpuInfoFreqFileName = "/sys/devices/system/cpu/cpu0/cpufreq/base_frequency";

public KVMHostInfo(long reservedMemory, long overCommitMemory) {
public KVMHostInfo(long reservedMemory, long overCommitMemory, long manualSpeed) {
this.cpuSpeed = manualSpeed;
this.reservedMemory = reservedMemory;
this.overCommitMemory = overCommitMemory;
this.getHostInfoFromLibvirt();
Expand Down Expand Up @@ -113,13 +114,13 @@ private static long getCpuSpeedFromCommandLscpu() {
}

private static long getCpuSpeedFromFile() {
LOGGER.info(String.format("Fetching CPU speed from file [%s].", cpuInfoMaxFreqFileName));
try (Reader reader = new FileReader(cpuInfoMaxFreqFileName)) {
Long cpuInfoMaxFreq = Long.parseLong(IOUtils.toString(reader).trim());
LOGGER.info(String.format("Retrieved value [%s] from file [%s]. This corresponds to a CPU speed of [%s] MHz.", cpuInfoMaxFreq, cpuInfoMaxFreqFileName, cpuInfoMaxFreq / 1000));
return cpuInfoMaxFreq / 1000;
LOGGER.info(String.format("Fetching CPU speed from file [%s].", cpuInfoFreqFileName));
try (Reader reader = new FileReader(cpuInfoFreqFileName)) {
Long cpuInfoFreq = Long.parseLong(IOUtils.toString(reader).trim());
LOGGER.info(String.format("Retrieved value [%s] from file [%s]. This corresponds to a CPU speed of [%s] MHz.", cpuInfoFreq, cpuInfoFreqFileName, cpuInfoFreq / 1000));
return cpuInfoFreq / 1000;
} catch (IOException | NumberFormatException e) {
LOGGER.error(String.format("Unable to retrieve the CPU speed from file [%s]", cpuInfoMaxFreqFileName), e);
LOGGER.error(String.format("Unable to retrieve the CPU speed from file [%s]", cpuInfoFreqFileName), e);
return 0L;
}
}
Expand All @@ -128,7 +129,11 @@ private void getHostInfoFromLibvirt() {
try {
final Connect conn = LibvirtConnection.getConnection();
final NodeInfo hosts = conn.nodeInfo();
this.cpuSpeed = getCpuSpeed(hosts);
if (this.cpuSpeed == 0) {
this.cpuSpeed = getCpuSpeed(hosts);
} else {
LOGGER.debug(String.format("Using existing configured CPU frequency %s", this.cpuSpeed));
}

/*
* Some CPUs report a single socket and multiple NUMA cells.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,26 @@
// under the License.
package org.apache.cloudstack.utils.linux;

import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
import org.apache.commons.lang.SystemUtils;

import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.Assume;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.libvirt.Connect;
import org.mockito.Mockito;

import org.libvirt.NodeInfo;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(value = {LibvirtConnection.class})
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
public class KVMHostInfoTest {
@Test
public void getCpuSpeed() {
Expand All @@ -34,4 +44,22 @@ public void getCpuSpeed() {
nodeInfo.mhz = 1000;
Assert.assertThat(KVMHostInfo.getCpuSpeed(nodeInfo), Matchers.greaterThan(0l));
}

@Test
public void manualCpuSpeedTest() throws Exception {
PowerMockito.mockStatic(LibvirtConnection.class);
Connect conn = Mockito.mock(Connect.class);
NodeInfo nodeInfo = Mockito.mock(NodeInfo.class);
nodeInfo.mhz = 1000;
String capabilitiesXml = "<capabilities></capabilities>";

PowerMockito.doReturn(conn).when(LibvirtConnection.class, "getConnection");
PowerMockito.when(conn.nodeInfo()).thenReturn(nodeInfo);
PowerMockito.when(conn.getCapabilities()).thenReturn(capabilitiesXml);
PowerMockito.when(conn.close()).thenReturn(0);
int manualSpeed = 500;

KVMHostInfo kvmHostInfo = new KVMHostInfo(10, 10, manualSpeed);
Assert.assertEquals(kvmHostInfo.getCpuSpeed(), manualSpeed);
}
}