[PATCH V2 3/7] config-tools: extract CPU frequency info in board_inspector


Zhou, Wu
 

This patch adds CPU frequency info extraction for board_inspector.

It is supposed to be used by ACRN CPU performance management.

Including those:
- Capabilities for HWP base regs, and turbo boost, by reading cpuids.
- Max none turbo ratio and max turbo ratio, by reading MSRs.
- HWP capabilities, by reading IA32_HWP_CAPABILITIES. Reading this
register requires HWP enabled in IA32_PM_ENABLE.
- ACPI _PSD info, by reading sys nodes of Linux acpi-pstate driver.
This table describes frequency domains in which CPUs shares the same
frequency.

Signed-off-by: Wu Zhou <wu.zhou@...>
---
.../board_inspector/board_inspector.py | 2 +-
.../board_inspector/cpuparser/cpuids.py | 6 +++
.../board_inspector/cpuparser/msr.py | 31 ++++++++++++-
.../board_inspector/cpuparser/platformbase.py | 13 ++++++
.../extractors/10-processors.py | 45 ++++++++++++++++++-
5 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/misc/config_tools/board_inspector/board_inspector.py b/misc/config_tools/board_inspector/board_inspector.py
index 1b8737c8a..3cdf7fbdc 100755
--- a/misc/config_tools/board_inspector/board_inspector.py
+++ b/misc/config_tools/board_inspector/board_inspector.py
@@ -38,7 +38,7 @@ class AddLLCCATAction(argparse.Action):

def check_deps():
# Check that the required tools are installed on the system
- BIN_LIST = ['cpuid', 'rdmsr', 'lspci', ' dmidecode', 'blkid', 'stty']
+ BIN_LIST = ['cpuid', 'rdmsr', 'wrmsr', 'lspci', ' dmidecode', 'blkid', 'stty']
cpuid_min_ver = 20170122
had_error = False
for execute in BIN_LIST:
diff --git a/misc/config_tools/board_inspector/cpuparser/cpuids.py b/misc/config_tools/board_inspector/cpuparser/cpuids.py
index 6013ffeb9..50cc473dd 100644
--- a/misc/config_tools/board_inspector/cpuparser/cpuids.py
+++ b/misc/config_tools/board_inspector/cpuparser/cpuids.py
@@ -285,6 +285,7 @@ class LEAF_6(CPUID):
arat_supported = cpuidfield(EAX, 2, 2, doc = "APIC-Timer-always-running feature is supported if set")
pln_supported = cpuidfield(EAX, 4, 4, doc = "Power limit notification controls are supported if set")
ecmd_supported = cpuidfield(EAX, 5, 5, doc = "Clock modulation duty cycle extension is supported if set")
+ hwp_supported = cpuidfield(EAX, 7, 7, doc = "HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set")
package_thermal_management_supported = cpuidfield(EAX, 6, 6, doc = "Package thermal management is supported if set")

num_interrupt_thresholds = cpuidfield(EBX, 3, 0, doc="Number of interrupt thresholds in digital thermal sensor")
@@ -292,6 +293,11 @@ class LEAF_6(CPUID):
hardware_coordination_feedback_capability = cpuidfield(ECX, 0, 0, doc="Hardware coordination feedback capability")
performance_energy_bias = cpuidfield(ECX, 3, 3, doc="Performance-energy bias preference support")

+ capability_bits = [
+ "turbo_boost_available",
+ "hwp_supported",
+ ]
+
class LEAF_7(CPUID):
"""Structured Extended Feature Flags Enumeration Leaf

diff --git a/misc/config_tools/board_inspector/cpuparser/msr.py b/misc/config_tools/board_inspector/cpuparser/msr.py
index 0d482f877..cdc7cc3fb 100644
--- a/misc/config_tools/board_inspector/cpuparser/msr.py
+++ b/misc/config_tools/board_inspector/cpuparser/msr.py
@@ -3,7 +3,8 @@
# SPDX-License-Identifier: BSD-3-Clause
#

-from cpuparser.platformbase import MSR, msrfield
+from cgitb import enable
+from cpuparser.platformbase import MSR, msrfield, msrfields

class MSR_IA32_MISC_ENABLE(MSR):
addr = 0x1a0
@@ -270,3 +271,31 @@ def MSR_IA32_L3_MASK_n(n):
bit_mask = msrfield(32, 0, doc="Capacity bit mask")

return IA32_L3_MASK_n
+
+class MSR_IA32_HWP_CAPABILITIES(MSR):
+ addr = 0x00000771
+ highest_performance_lvl = msrfields(7, 0, doc=None)
+ guaranteed_performance_lvl = msrfields(15, 8, doc=None)
+ lowest_performance_lvl = msrfields(31, 24, doc=None)
+
+ attribute_bits = [
+ "highest_performance_lvl",
+ "guaranteed_performance_lvl",
+ "lowest_performance_lvl",
+ ]
+
+class MSR_TURBO_RATIO_LIMIT(MSR):
+ addr = 0x000001ad
+ max_ratio_1core = msrfields(7, 0, doc=None)
+
+ attribute_bits = [
+ "max_ratio_1core",
+ ]
+
+class MSR_TURBO_ACTIVATION_RATIO(MSR):
+ addr = 0x0000064c
+ max_none_turbo_ratio = msrfields(7, 0, doc=None)
+
+ attribute_bits = [
+ "max_none_turbo_ratio",
+ ]
diff --git a/misc/config_tools/board_inspector/cpuparser/platformbase.py b/misc/config_tools/board_inspector/cpuparser/platformbase.py
index 7acaa0661..1deba562f 100644
--- a/misc/config_tools/board_inspector/cpuparser/platformbase.py
+++ b/misc/config_tools/board_inspector/cpuparser/platformbase.py
@@ -228,3 +228,16 @@ class msrfield(property):
self.value = (self.value & ~field_mask) | (value << lsb)

super(msrfield, self).__init__(getter, setter, doc=doc)
+
+class msrfields(property):
+ def __init__(self, msb, lsb, doc="Bogus"):
+ self.msb = msb
+ self.lsb = lsb
+
+ max_value = (1 << (msb - lsb + 1)) - 1
+ field_mask = max_value << lsb
+
+ def getter(self):
+ return (self.value & field_mask) >> lsb
+ super(msrfields, self).__init__(getter, doc=doc)
+
diff --git a/misc/config_tools/board_inspector/extractors/10-processors.py b/misc/config_tools/board_inspector/extractors/10-processors.py
index 11c3dcd76..205227f27 100644
--- a/misc/config_tools/board_inspector/extractors/10-processors.py
+++ b/misc/config_tools/board_inspector/extractors/10-processors.py
@@ -4,6 +4,7 @@
#

import logging
+import subprocess
import lxml.etree
import re

@@ -47,7 +48,7 @@ def extract_model(processors_node, cpu_id, family_id, model_id, core_type, nativ
brandstring += leaf_data.brandstring
n.set("description", re.sub('[^!-~]+', ' ', brandstring.decode()).strip())

- leaves = [(1, 0), (7, 0), (0x80000001, 0), (0x80000007, 0)]
+ leaves = [(1, 0), (6, 0), (7, 0), (0x80000001, 0), (0x80000007, 0)]
for leaf in leaves:
leaf_data = parse_cpuid(leaf[0], leaf[1], cpu_id)
for cap in leaf_data.capability_bits:
@@ -70,6 +71,12 @@ def extract_model(processors_node, cpu_id, family_id, model_id, core_type, nativ
for cap in leaf_data.attribute_bits:
add_child(n, "attribute", str(getattr(leaf_data, cap)), id=cap)

+ msr_regs = [MSR_TURBO_RATIO_LIMIT, MSR_TURBO_ACTIVATION_RATIO]
+ for msr_reg in msr_regs:
+ msr_data = msr_reg.rdmsr(cpu_id)
+ for attr in msr_data.attribute_bits:
+ add_child(n, "attribute", str(getattr(msr_data, attr)), id=attr)
+
def extract_topology(processors_node):
cpu_ids = get_online_cpu_ids()
for cpu_id in cpu_ids:
@@ -130,6 +137,42 @@ def extract_topology(processors_node):
last_shift = leaf_topo.num_bit_shift
subleaf += 1

+def extract_hwp_info(processors_node):
+ if processors_node.xpath("//capability[@id = 'hwp_supported']") is None:
+ return
+
+ try:
+ subprocess.check_call('/usr/sbin/wrmsr 0x770 1', shell=True, stdout=subprocess.PIPE)
+ except subprocess.CalledProcessError:
+ logging.debug("MSR 0x770 write failed!")
+ return
+
+ threads = processors_node.xpath("//thread")
+ for thread in threads:
+ cpu_id = get_node(thread, "cpu_id/text()")
+ msr_regs = [MSR_IA32_HWP_CAPABILITIES,]
+ for msr_reg in msr_regs:
+ msr_data = msr_reg.rdmsr(cpu_id)
+ for attr in msr_data.attribute_bits:
+ add_child(thread, attr, str(getattr(msr_data, attr)))
+
+def extract_psd_info(processors_node):
+ sysnode = '/sys/devices/system/cpu/'
+ threads = processors_node.xpath("//thread")
+ for thread in threads:
+ cpu_id = get_node(thread, "cpu_id/text()")
+ try:
+ with open(sysnode + "cpu{cpu_id}/cpufreq/freqdomain_cpus", 'r') as f_node:
+ freqdomain_cpus = f_node.read()
+ except IOError:
+ logging.info("No _PSD info for cpu {cpu_id}")
+ freqdomain_cpus = cpu_id
+
+ freqdomain_cpus.replace('\n','')
+ add_child(thread, "freqdomain_cpus", freqdomain_cpus)
+
def extract(args, board_etree):
processors_node = get_node(board_etree, "//processors")
extract_topology(processors_node)
+ extract_hwp_info(processors_node)
+ extract_psd_info(processors_node)
--
2.25.1