board_inspector/extractors: extract CPU topology and models

This patch extracts information on CPU topology and capability and put them
under the `/acrn-config/processors` node in the board XML.

The added information can be divided into two categories.

1. The topology of CPUs like the following. Each thread (which is a leaf
   node in the topology) contains its addresses (i.e. CPU ID, APIC ID,
   x2APIC ID) and model identifiers (i.e. family, model, stepping IDs, core
   types and native model ID).

    <die id="0">
      <core id="0x0">
        <thread id="0x0">
          <cpu_id>0</cpu_id>
          <apic_id>0x0</apic_id>
          <x2apic_id>0x0</x2apic_id>
          <family_id>0x6</family_id>
          <model_id>0x9e</model_id>
          <stepping_id>0x9</stepping_id>
          <core_type></core_type>
          <native_model_id></native_model_id>
	</thread>
        <thread id="0x1"> ... </thread>
      </core>
      <core id="0x1">
        <thread id="0x2"> ... </thread>
        <thread id="0x3"> ... </thread>
      </core>
      <core id="0x2">
        <thread id="0x4"> ... </thread>
        <thread id="0x5"> ... </thread>
      </core>
      <core id="0x3">
        <thread id="0x6"> ... </thread>
        <thread id="0x7"> ... </thread>
      </core>
    </die>

2. The CPU models identified by the quadruple (family_id, model_id,
   core_type, native_model_id). Each model is described by its brandstring
   and capabilities, both of which are fetched from CPUID leaves.

    <model description="Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz">
      <family_id>0x6</family_id>
      <model_id>0x9e</model_id>
      <core_type></core_type>
      <native_model_id></native_model_id>
      <capability id="sse3"/>
      <capability id="pclmulqdq"/>
      <capability id="dtes64"/>
      <capability id="monitor"/>
      ...
    </model>

Tracked-On: #5922
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Junjie Mao 2021-05-03 10:27:04 +08:00 committed by wenlingz
parent 4d3a765708
commit 3e3120d342

View File

@ -0,0 +1,128 @@
# Copyright (C) 2021 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import logging
import lxml.etree
from cpuparser import parse_cpuid
from extractors.helpers import add_child, get_node
level_types = {
1: "thread",
2: "core",
3: "module",
4: "tile",
5: "die",
}
def get_online_cpu_ids():
acc = list()
with open("/sys/devices/system/cpu/online", "r") as f:
line = f.read().strip()
for r in line.split(","):
if r.find("-") > 0:
first, last = tuple(map(int, r.split("-")))
acc.extend(range(first, last + 1))
else:
acc.append(int(r))
return acc
def get_parent(processors_node, topo_level, topo_id):
n = get_node(processors_node, f"//{topo_level}[@id='{topo_id}']")
return n
def get_or_create_parent(processors_node, topo_level, topo_id):
n = get_parent(processors_node, topo_level, topo_id)
if n is None:
n = lxml.etree.Element(topo_level)
n.set("id", topo_id)
return (n, True)
return (n, False)
def extract_model(processors_node, cpu_id, family_id, model_id, core_type, native_model_id):
n = get_node(processors_node, f"//model[family_id='{family_id}' and model_id='{model_id}' and core_type='{core_type}' and native_model_id='{native_model_id}']")
if n is None:
n = add_child(processors_node, "model")
add_child(n, "family_id", family_id)
add_child(n, "model_id", model_id)
add_child(n, "core_type", core_type)
add_child(n, "native_model_id", native_model_id)
brandstring = b""
for leaf in [0x80000002, 0x80000003, 0x80000004]:
leaf_data = parse_cpuid(leaf, 0, cpu_id)
brandstring += leaf_data.brandstring
n.set("description", brandstring.decode())
leaves = [(1, 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:
if getattr(leaf_data, cap) == 1:
add_child(n, "capability", id=cap)
def extract_topology(processors_node):
cpu_ids = get_online_cpu_ids()
for cpu_id in cpu_ids:
subleaf = 0
last_shift = 0
last_node = None
leaf_0 = parse_cpuid(0, 0, cpu_id)
if leaf_0.max_leaf >= 0x1f:
topo_leaf = 0x1f
else:
topo_leaf = 0xb
while True:
leaf_topo = parse_cpuid(topo_leaf, subleaf, cpu_id)
if leaf_topo.level_type == 0:
if last_node.tag != "package":
n, _ = get_or_create_parent(processors_node, "die", "0")
n.append(last_node)
last_node = n
processors_node.append(last_node)
break
topo_level = level_types[leaf_topo.level_type]
topo_id = hex(leaf_topo.x2apic_id >> last_shift)
n, created = get_or_create_parent(processors_node, topo_level, topo_id)
if last_node is None:
leaf_1 = parse_cpuid(1, 0, cpu_id)
family_id = hex(leaf_1.display_family)
model_id = hex(leaf_1.display_model)
if leaf_0.max_leaf >= 0x1a:
leaf_1a = parse_cpuid(0x1a, 0, cpu_id)
core_type = leaf_1a.core_type
native_model_id = hex(leaf_1a.native_model_id)
else:
core_type = ""
native_model_id = ""
add_child(n, "cpu_id", text=str(cpu_id))
add_child(n, "apic_id", text=hex(leaf_1.initial_apic_id))
add_child(n, "x2apic_id", text=hex(leaf_topo.x2apic_id))
add_child(n, "family_id", text=family_id)
add_child(n, "model_id", text=model_id)
add_child(n, "stepping_id", text=hex(leaf_1.stepping))
add_child(n, "core_type", text=core_type)
add_child(n, "native_model_id", text=native_model_id)
extract_model(processors_node, cpu_id, family_id, model_id, core_type, native_model_id)
else:
n.append(last_node)
if not created:
break
last_node = n
last_shift = leaf_topo.num_bit_shift
subleaf += 1
def extract(board_etree):
processors_node = get_node(board_etree, "//processors")
extract_topology(processors_node)