Use base clock when detecting host CPU speed from file, to match lscpu (#131)

* Use base clock when detecting host CPU speed from file, to match lscpu

Allow for manually setting the CPU speed via agent.properties if all else fails

Signed-off-by: Marcus Sorensen <mls@apple.com>

* Update agent/conf/agent.properties

Co-authored-by: dahn <daan.hoogland@gmail.com>

Co-authored-by: Marcus Sorensen <mls@apple.com>
Co-authored-by: Nicolas Vazquez <nicovazquez90@gmail.com>
Co-authored-by: dahn <daan.hoogland@gmail.com>
This commit is contained in:
Marcus Sorensen 2022-04-01 09:19:43 -06:00 committed by GitHub
parent dfc1f26762
commit 58ed95376c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 10 deletions

View File

@ -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

View File

@ -370,6 +370,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";
@ -1037,6 +1038,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
_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);
@ -3260,7 +3264,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
@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) {

View File

@ -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();
@ -113,13 +114,13 @@ public class KVMHostInfo {
}
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;
}
}
@ -128,7 +129,11 @@ public class KVMHostInfo {
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.

View File

@ -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() {
@ -34,4 +44,22 @@ public class KVMHostInfoTest {
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);
}
}