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

Reply via email to