This is an automated email from the ASF dual-hosted git repository.
shwstppr pushed a commit to branch 4.17
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.17 by this push:
new b831f23f5f kvm: add libvirt host capabilities method for cpu speed
retrieval (#6696)
b831f23f5f is described below
commit b831f23f5fe9850a8984634b687e865119bfccda
Author: Abhishek Kumar <[email protected]>
AuthorDate: Tue Sep 6 16:45:05 2022 +0530
kvm: add libvirt host capabilities method for cpu speed retrieval (#6696)
Fixes #6680
While finding CPU speed for KVM host following methods will be used in the
same order:
1. lscpu
2. value in /sys/devices/system/cpu/cpu0/cpufreq/base_frequency
3. virsh capabilities
4. libvirt nodeinfo
This will allow correct value for AMD based hosts when first two methods
doesn't give a value
Signed-off-by: Abhishek Kumar <[email protected]>
---
.../apache/cloudstack/utils/linux/KVMHostInfo.java | 68 ++++++++++++++++++----
.../cloudstack/utils/linux/KVMHostInfoTest.java | 27 ++++++---
2 files changed, 77 insertions(+), 18 deletions(-)
diff --git
a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java
b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java
index e34f39fde3..807b2541fd 100644
---
a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java
+++
b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java
@@ -16,21 +16,33 @@
// under the License.
package org.apache.cloudstack.utils.linux;
-import com.cloud.hypervisor.kvm.resource.LibvirtCapXMLParser;
-import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
-import com.cloud.utils.script.Script;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.cloudstack.utils.security.ParserUtils;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.libvirt.Connect;
import org.libvirt.LibvirtException;
import org.libvirt.NodeInfo;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
+import com.cloud.hypervisor.kvm.resource.LibvirtCapXMLParser;
+import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
+import com.cloud.utils.script.Script;
public class KVMHostInfo {
@@ -82,7 +94,7 @@ public class KVMHostInfo {
return this.capabilities;
}
- protected static long getCpuSpeed(final NodeInfo nodeInfo) {
+ protected static long getCpuSpeed(final String cpabilities, final NodeInfo
nodeInfo) {
long speed = 0L;
speed = getCpuSpeedFromCommandLscpu();
if(speed > 0L) {
@@ -94,6 +106,11 @@ public class KVMHostInfo {
return speed;
}
+ speed = getCpuSpeedFromHostCapabilities(cpabilities);
+ if(speed > 0L) {
+ return speed;
+ }
+
LOGGER.info(String.format("Using the value [%s] provided by Libvirt.",
nodeInfo.mhz));
speed = nodeInfo.mhz;
return speed;
@@ -125,12 +142,41 @@ public class KVMHostInfo {
}
}
+ protected static long getCpuSpeedFromHostCapabilities(final String
capabilities) {
+ LOGGER.info("Fetching CPU speed from \"host capabilities\"");
+ long speed = 0L;
+ try {
+ DocumentBuilderFactory docFactory =
ParserUtils.getSaferDocumentBuilderFactory();
+ DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+ Document doc = docBuilder.parse(new InputSource(new
StringReader(capabilities)));
+ Element rootElement = doc.getDocumentElement();
+ NodeList nodes = rootElement.getElementsByTagName("cpu");
+ Node node = nodes.item(0);
+ nodes = ((Element)node).getElementsByTagName("counter");
+ for (int i = 0; i < nodes.getLength(); i++) {
+ node = nodes.item(i);
+ NamedNodeMap attributes = node.getAttributes();
+ Node nameNode = attributes.getNamedItem("name");
+ Node freqNode = attributes.getNamedItem("frequency");
+ if (nameNode != null && "tsc".equals(nameNode.getNodeValue())
&& freqNode != null && StringUtils.isNotEmpty(freqNode.getNodeValue())) {
+ speed = Long.parseLong(freqNode.getNodeValue()) / 1000000;
+ LOGGER.info(String.format("Retrieved value [%s] from
\"host capabilities\". This corresponds to a CPU speed of [%s] MHz.",
freqNode.getNodeValue(), speed));
+ }
+ }
+ } catch (Exception ex) {
+ LOGGER.error("Unable to fetch CPU speed from \"host
capabilities\"", ex);
+ speed = 0L;
+ }
+ return speed;
+ }
+
private void getHostInfoFromLibvirt() {
try {
final Connect conn = LibvirtConnection.getConnection();
final NodeInfo hosts = conn.nodeInfo();
+ final String capabilities = conn.getCapabilities();
if (this.cpuSpeed == 0) {
- this.cpuSpeed = getCpuSpeed(hosts);
+ this.cpuSpeed = getCpuSpeed(capabilities, hosts);
} else {
LOGGER.debug(String.format("Using existing configured CPU
frequency %s", this.cpuSpeed));
}
@@ -146,7 +192,7 @@ public class KVMHostInfo {
this.cpus = hosts.cpus;
final LibvirtCapXMLParser parser = new LibvirtCapXMLParser();
- parser.parseCapabilitiesXML(conn.getCapabilities());
+ parser.parseCapabilitiesXML(capabilities);
final ArrayList<String> oss = parser.getGuestOsType();
for (final String s : oss) {
/*
diff --git
a/plugins/hypervisors/kvm/src/test/java/org/apache/cloudstack/utils/linux/KVMHostInfoTest.java
b/plugins/hypervisors/kvm/src/test/java/org/apache/cloudstack/utils/linux/KVMHostInfoTest.java
index 360f72579a..67d3e011f8 100644
---
a/plugins/hypervisors/kvm/src/test/java/org/apache/cloudstack/utils/linux/KVMHostInfoTest.java
+++
b/plugins/hypervisors/kvm/src/test/java/org/apache/cloudstack/utils/linux/KVMHostInfoTest.java
@@ -16,23 +16,22 @@
// 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.Assume;
+import org.junit.Test;
import org.junit.runner.RunWith;
import org.libvirt.Connect;
-import org.mockito.Mockito;
-
import org.libvirt.NodeInfo;
+import org.mockito.Mockito;
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;
+import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
+
@RunWith(PowerMockRunner.class)
@PrepareForTest(value = {LibvirtConnection.class})
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*",
"org.xml.*"})
@@ -45,7 +44,21 @@ public class KVMHostInfoTest {
Assume.assumeTrue(SystemUtils.IS_OS_LINUX);
NodeInfo nodeInfo = Mockito.mock(NodeInfo.class);
nodeInfo.mhz = 1000;
- Assert.assertThat(KVMHostInfo.getCpuSpeed(nodeInfo),
Matchers.greaterThan(0l));
+ Assert.assertThat(KVMHostInfo.getCpuSpeed(null, nodeInfo),
Matchers.greaterThan(0l));
+ }
+
+ @Test
+ public void getCpuSpeedFromHostCapabilities() {
+ String capabilities = "<host>\n" +
+ "<uuid>8a330742-345f-b0df-7954-c9960b88116c</uuid>\n" +
+ " <cpu>\n" +
+ " <arch>x86_64</arch>\n" +
+ " <model>Opteron_G2</model>\n" +
+ " <vendor>AMD</vendor>\n" +
+ " <counter name='tsc' frequency='2350000000'
scaling='no'/>\n" +
+ " </cpu>\n" +
+ "</host>\n";;
+ Assert.assertEquals(2350L,
KVMHostInfo.getCpuSpeedFromHostCapabilities(capabilities));
}
@Test