[PATCH] cpu_map: Add libcpuinfo as optional data source

Tim Wiederhake posted 1 patch 3 months, 4 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20240621132400.190223-1-twiederh@redhat.com
src/cpu_map/libcpuinfo_aliases.xml     | 75 +++++++++++++++++++++++++
src/cpu_map/sync_qemu_features_i386.py | 77 +++++++++++++++++++++++---
2 files changed, 145 insertions(+), 7 deletions(-)
create mode 100644 src/cpu_map/libcpuinfo_aliases.xml
[PATCH] cpu_map: Add libcpuinfo as optional data source
Posted by Tim Wiederhake 3 months, 4 weeks ago
This adds an option to use libcpuinfo [1] as data source for
libvirt's list of x86 cpu features. This is purely optional and
does not change the script's behavior if libcpuinfo is not
installed.

libcpuinfo is a cross-vendor, cross-architecture source for CPU
related information that has the capability to replace libvirt's
dependence on qemu's cpu feature list.

[1] https://gitlab.com/twiederh/libcpuinfo

Signed-off-by: Tim Wiederhake <twiederh@redhat.com>
---
 src/cpu_map/libcpuinfo_aliases.xml     | 75 +++++++++++++++++++++++++
 src/cpu_map/sync_qemu_features_i386.py | 77 +++++++++++++++++++++++---
 2 files changed, 145 insertions(+), 7 deletions(-)
 create mode 100644 src/cpu_map/libcpuinfo_aliases.xml

diff --git a/src/cpu_map/libcpuinfo_aliases.xml b/src/cpu_map/libcpuinfo_aliases.xml
new file mode 100644
index 0000000000..75d243fead
--- /dev/null
+++ b/src/cpu_map/libcpuinfo_aliases.xml
@@ -0,0 +1,75 @@
+<!--
+    libvirt uses slightly different names for some cpu features than other
+    software does. Install this file into libcpuinfo's alias directory
+    (e.g. /usr/share/libcpuinfo/aliases/libvirt.xml) to have libcpuinfo
+    automatically translate feature names into the names libvirt uses.
+-->
+
+<external_aliases>
+    <external_alias>
+        <type>feature</type>
+        <canonical>pclmulqdq</canonical>
+        <name>pclmuldq</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>ds-cpl</canonical>
+        <name>ds_cpl</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>sse4-1</canonical>
+        <name>sse4.1</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>sse4-2</canonical>
+        <name>sse4.2</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>tsc-adjust</canonical>
+        <name>tsc_adjust</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>lahf-lm</canonical>
+        <name>lahf_lm</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>cmp-legacy</canonical>
+        <name>cmp_legacy</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>nodeid-msr</canonical>
+        <name>nodeid_msr</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>perfctr-core</canonical>
+        <name>perfctr_core</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>perfctr-nb</canonical>
+        <name>perfctr_nb</name>
+        <domain>libvirt</domain>
+    </external_alias>
+    <external_alias>
+        <type>feature</type>
+        <canonical>fxsr-opt</canonical>
+        <name>fxsr_opt</name>
+        <domain>libvirt</domain>
+    </external_alias>
+</external_aliases>
diff --git a/src/cpu_map/sync_qemu_features_i386.py b/src/cpu_map/sync_qemu_features_i386.py
index e4b1f7275a..3b3ad5a643 100755
--- a/src/cpu_map/sync_qemu_features_i386.py
+++ b/src/cpu_map/sync_qemu_features_i386.py
@@ -4,6 +4,11 @@ import argparse
 import os
 import re
 
+try:
+    import pycpuinfo
+except ImportError:
+    pycpuinfo = None
+
 
 # features in qemu that we do not want in libvirt
 FEATURES_IGNORE = (
@@ -22,6 +27,7 @@ FEATURES_IGNORE = (
     "kvm-steal-time",
     "kvmclock",
     "kvmclock-stable-bit",
+    "kvmclock2",
 
     "xstore",
     "xstore-en",
@@ -295,6 +301,53 @@ def add_feature_qemu(query, data):
             add_feature_cpuid(eax, ecx, reg, bit, name)
 
 
+def add_features_cpuinfo():
+    def decode_bit(value):
+        for i in range(0, 64):
+            if value == (1 << i):
+                return i
+
+    def decode_cpuid(v):
+        if v[0] != 0 and v[1] == 0 and v[2] == 0 and v[3] == 0:
+            reg, val = "eax", v[0]
+        if v[0] == 0 and v[1] != 0 and v[2] == 0 and v[3] == 0:
+            reg, val = "ebx", v[1]
+        if v[0] == 0 and v[1] == 0 and v[2] != 0 and v[3] == 0:
+            reg, val = "ecx", v[2]
+        if v[0] == 0 and v[1] == 0 and v[2] == 0 and v[3] != 0:
+            reg, val = "edx", v[3]
+
+        return reg, decode_bit(val)
+
+    x86 = pycpuinfo.Family.find("x86", "")
+
+    for feature in pycpuinfo.features():
+        if feature.family() != x86:
+            continue
+
+        if list(feature.features()):
+            continue
+
+        name = feature.name("libvirt")
+        if name in FEATURES_IGNORE:
+            continue
+
+        cpuid = feature.extra_x86_cpuid()
+        if cpuid:
+            eax = cpuid[0]
+            ecx = cpuid[1]
+            if ecx == pycpuinfo.x86.CPUINFO_X86_CPUID_ECX_NONE:
+                ecx = None
+            reg, bit = decode_cpuid(cpuid[2:])
+            add_feature_cpuid(eax, ecx, reg, bit, name)
+
+        msr = feature.extra_x86_msr()
+        if msr:
+            index = msr[0]
+            bit = decode_bit(msr[1] | (msr[2] << 32))
+            add_feature_msr(index, bit, name)
+
+
 # read the `feature_word_info` struct from qemu's cpu.c into a list of strings
 def read_cpu_c(path):
     pattern_comment = re.compile("/\\*.*?\\*/")
@@ -450,6 +503,12 @@ def main():
         nargs="?",
         type=os.path.realpath,
     )
+    if pycpuinfo:
+        parser.add_argument(
+            "--libcpuinfo",
+            help="Use libcpuinfo as data source instead",
+            action="store_true",
+        )
     parser.add_argument(
         "--output",
         "-o",
@@ -459,14 +518,18 @@ def main():
     )
     args = parser.parse_args()
 
-    if not os.path.isdir(args.qemu):
-        parser.print_help()
-        exit("qemu source directory not found")
+    if pycpuinfo and args.libcpuinfo:
+        add_features_cpuinfo()
+    else:
+        if not os.path.isdir(args.qemu):
+            parser.print_help()
+            exit("qemu source directory not found")
+
+        read_headers(args.qemu)
+        lines = read_cpu_c(args.qemu)
+        parse_feature_words(lines)
+        add_extra_features()
 
-    read_headers(args.qemu)
-    lines = read_cpu_c(args.qemu)
-    parse_feature_words(lines)
-    add_extra_features()
     write_output(args.output)
 
     print(
-- 
2.43.0
Re: [PATCH] cpu_map: Add libcpuinfo as optional data source
Posted by Michal Prívozník 2 months, 3 weeks ago
On 6/21/24 15:24, Tim Wiederhake wrote:
> This adds an option to use libcpuinfo [1] as data source for
> libvirt's list of x86 cpu features. This is purely optional and
> does not change the script's behavior if libcpuinfo is not
> installed.
> 
> libcpuinfo is a cross-vendor, cross-architecture source for CPU
> related information that has the capability to replace libvirt's
> dependence on qemu's cpu feature list.
> 
> [1] https://gitlab.com/twiederh/libcpuinfo
> 
> Signed-off-by: Tim Wiederhake <twiederh@redhat.com>
> ---
>  src/cpu_map/libcpuinfo_aliases.xml     | 75 +++++++++++++++++++++++++
>  src/cpu_map/sync_qemu_features_i386.py | 77 +++++++++++++++++++++++---
>  2 files changed, 145 insertions(+), 7 deletions(-)
>  create mode 100644 src/cpu_map/libcpuinfo_aliases.xml

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>

Michal
Re: [PATCH] cpu_map: Add libcpuinfo as optional data source
Posted by Tim Wiederhake 3 months ago
ping

On Fri, 2024-06-21 at 15:24 +0200, Tim Wiederhake wrote:
> This adds an option to use libcpuinfo [1] as data source for
> libvirt's list of x86 cpu features. This is purely optional and
> does not change the script's behavior if libcpuinfo is not
> installed.
> 
> libcpuinfo is a cross-vendor, cross-architecture source for CPU
> related information that has the capability to replace libvirt's
> dependence on qemu's cpu feature list.
> 
> [1] https://gitlab.com/twiederh/libcpuinfo
> 
> Signed-off-by: Tim Wiederhake <twiederh@redhat.com>
> ---
>  src/cpu_map/libcpuinfo_aliases.xml     | 75
> +++++++++++++++++++++++++
>  src/cpu_map/sync_qemu_features_i386.py | 77 +++++++++++++++++++++++-
> --
>  2 files changed, 145 insertions(+), 7 deletions(-)
>  create mode 100644 src/cpu_map/libcpuinfo_aliases.xml
> 
> diff --git a/src/cpu_map/libcpuinfo_aliases.xml
> b/src/cpu_map/libcpuinfo_aliases.xml
> new file mode 100644
> index 0000000000..75d243fead
> --- /dev/null
> +++ b/src/cpu_map/libcpuinfo_aliases.xml
> @@ -0,0 +1,75 @@
> +<!--
> +    libvirt uses slightly different names for some cpu features than
> other
> +    software does. Install this file into libcpuinfo's alias
> directory
> +    (e.g. /usr/share/libcpuinfo/aliases/libvirt.xml) to have
> libcpuinfo
> +    automatically translate feature names into the names libvirt
> uses.
> +-->
> +
> +<external_aliases>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>pclmulqdq</canonical>
> +        <name>pclmuldq</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>ds-cpl</canonical>
> +        <name>ds_cpl</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>sse4-1</canonical>
> +        <name>sse4.1</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>sse4-2</canonical>
> +        <name>sse4.2</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>tsc-adjust</canonical>
> +        <name>tsc_adjust</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>lahf-lm</canonical>
> +        <name>lahf_lm</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>cmp-legacy</canonical>
> +        <name>cmp_legacy</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>nodeid-msr</canonical>
> +        <name>nodeid_msr</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>perfctr-core</canonical>
> +        <name>perfctr_core</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>perfctr-nb</canonical>
> +        <name>perfctr_nb</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +    <external_alias>
> +        <type>feature</type>
> +        <canonical>fxsr-opt</canonical>
> +        <name>fxsr_opt</name>
> +        <domain>libvirt</domain>
> +    </external_alias>
> +</external_aliases>
> diff --git a/src/cpu_map/sync_qemu_features_i386.py
> b/src/cpu_map/sync_qemu_features_i386.py
> index e4b1f7275a..3b3ad5a643 100755
> --- a/src/cpu_map/sync_qemu_features_i386.py
> +++ b/src/cpu_map/sync_qemu_features_i386.py
> @@ -4,6 +4,11 @@ import argparse
>  import os
>  import re
>  
> +try:
> +    import pycpuinfo
> +except ImportError:
> +    pycpuinfo = None
> +
>  
>  # features in qemu that we do not want in libvirt
>  FEATURES_IGNORE = (
> @@ -22,6 +27,7 @@ FEATURES_IGNORE = (
>      "kvm-steal-time",
>      "kvmclock",
>      "kvmclock-stable-bit",
> +    "kvmclock2",
>  
>      "xstore",
>      "xstore-en",
> @@ -295,6 +301,53 @@ def add_feature_qemu(query, data):
>              add_feature_cpuid(eax, ecx, reg, bit, name)
>  
>  
> +def add_features_cpuinfo():
> +    def decode_bit(value):
> +        for i in range(0, 64):
> +            if value == (1 << i):
> +                return i
> +
> +    def decode_cpuid(v):
> +        if v[0] != 0 and v[1] == 0 and v[2] == 0 and v[3] == 0:
> +            reg, val = "eax", v[0]
> +        if v[0] == 0 and v[1] != 0 and v[2] == 0 and v[3] == 0:
> +            reg, val = "ebx", v[1]
> +        if v[0] == 0 and v[1] == 0 and v[2] != 0 and v[3] == 0:
> +            reg, val = "ecx", v[2]
> +        if v[0] == 0 and v[1] == 0 and v[2] == 0 and v[3] != 0:
> +            reg, val = "edx", v[3]
> +
> +        return reg, decode_bit(val)
> +
> +    x86 = pycpuinfo.Family.find("x86", "")
> +
> +    for feature in pycpuinfo.features():
> +        if feature.family() != x86:
> +            continue
> +
> +        if list(feature.features()):
> +            continue
> +
> +        name = feature.name("libvirt")
> +        if name in FEATURES_IGNORE:
> +            continue
> +
> +        cpuid = feature.extra_x86_cpuid()
> +        if cpuid:
> +            eax = cpuid[0]
> +            ecx = cpuid[1]
> +            if ecx == pycpuinfo.x86.CPUINFO_X86_CPUID_ECX_NONE:
> +                ecx = None
> +            reg, bit = decode_cpuid(cpuid[2:])
> +            add_feature_cpuid(eax, ecx, reg, bit, name)
> +
> +        msr = feature.extra_x86_msr()
> +        if msr:
> +            index = msr[0]
> +            bit = decode_bit(msr[1] | (msr[2] << 32))
> +            add_feature_msr(index, bit, name)
> +
> +
>  # read the `feature_word_info` struct from qemu's cpu.c into a list
> of strings
>  def read_cpu_c(path):
>      pattern_comment = re.compile("/\\*.*?\\*/")
> @@ -450,6 +503,12 @@ def main():
>          nargs="?",
>          type=os.path.realpath,
>      )
> +    if pycpuinfo:
> +        parser.add_argument(
> +            "--libcpuinfo",
> +            help="Use libcpuinfo as data source instead",
> +            action="store_true",
> +        )
>      parser.add_argument(
>          "--output",
>          "-o",
> @@ -459,14 +518,18 @@ def main():
>      )
>      args = parser.parse_args()
>  
> -    if not os.path.isdir(args.qemu):
> -        parser.print_help()
> -        exit("qemu source directory not found")
> +    if pycpuinfo and args.libcpuinfo:
> +        add_features_cpuinfo()
> +    else:
> +        if not os.path.isdir(args.qemu):
> +            parser.print_help()
> +            exit("qemu source directory not found")
> +
> +        read_headers(args.qemu)
> +        lines = read_cpu_c(args.qemu)
> +        parse_feature_words(lines)
> +        add_extra_features()
>  
> -    read_headers(args.qemu)
> -    lines = read_cpu_c(args.qemu)
> -    parse_feature_words(lines)
> -    add_extra_features()
>      write_output(args.output)
>  
>      print(