diff mbox series

[RFC,45/52] hw/machine: Add hybrid cpu topology validation

Message ID 20230213095035.158240-46-zhao1.liu@linux.intel.com
State New
Headers show
Series Introduce hybrid CPU topology | expand

Commit Message

Zhao Liu Feb. 13, 2023, 9:50 a.m. UTC
From: Zhao Liu <zhao1.liu@intel.com>

Because of the "-hybrid" format, in the process of parsing the command
line, we cannot know exactly the complete topology details until all the
hybrid commands have been parsed, so we cannot verify the hybrid
topology during the parsing process.

Thus validate the hybrid topology before machine running. At this moment,
the hybrid topology must have been parsed.

Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
 hw/core/machine-topo.c | 126 +++++++++++++++++++++++++++++++++++++++++
 hw/core/machine.c      |   4 ++
 include/hw/boards.h    |   1 +
 3 files changed, 131 insertions(+)
diff mbox series

Patch

diff --git a/hw/core/machine-topo.c b/hw/core/machine-topo.c
index 6e4a9ec1495d..2cf71cc466aa 100644
--- a/hw/core/machine-topo.c
+++ b/hw/core/machine-topo.c
@@ -625,3 +625,129 @@  void machine_free_hybrid_topology(MachineState *ms)
         g_free(ms->topo.hybrid.cluster_list);
     }
 }
+
+/*
+ * Report information of a machine's supported CPU hybrid topology
+ * hierarchy. Topology members will be ordered in the string as:
+ * sockets (%u) * dies (%u) * ( cluster0:[ core0:[ cores (type: %s, %u) *
+ * threads (%u) ] + ... + core_n:[ cores (type: %s, %u) * threads (%u) ] ] +
+ * ... + cluster_m:[ core0:[ cores (type: %s, %u) * threads (%u) ] + ... +
+ * core_m:[ cores (type: %s, %u) * threads (%u)) ] ].
+ */
+static char *hybrid_cpu_hierarchy_to_string(MachineState *ms)
+{
+    HybridCluster *cluster;
+    HybridCorePack *core_pack;
+    MachineClass *mc = MACHINE_GET_CLASS(ms);
+    GString *s = g_string_new(NULL);
+
+    g_string_append_printf(s, "sockets (%u)", ms->topo.hybrid.sockets);
+
+    if (mc->topo_props.dies_supported) {
+        g_string_append_printf(s, " * dies (%u)", ms->topo.hybrid.dies);
+    }
+
+    if (ms->topo.hybrid.cluster_list != NULL) {
+        g_string_append_printf(s, " * ( ");
+        for (int i = 0; i < ms->topo.hybrid.clusters; i++) {
+            if (i) {
+                g_string_append_printf(s, " + ");
+            }
+            if (mc->topo_props.clusters_supported) {
+                g_string_append_printf(s, "cluster%u ", i);
+            }
+            if (ms->topo.hybrid.cluster_list[i].cores) {
+                int core_idx = 0;
+                cluster = &ms->topo.hybrid.cluster_list[i];
+
+                QSLIST_FOREACH(core_pack, &cluster->core_pack_list, node) {
+                    if (!core_idx) {
+                        g_string_append_printf(
+                            s, "%s ",
+                            mc->topo_props.clusters_supported ?
+                            ":[" : "[");
+                    } else {
+                        g_string_append_printf(s, " + ");
+                    }
+                    g_string_append_printf(
+                        s, "core%u:[ cores (type: %u, "
+                        "num: %u) * threads (%u) ]",
+                        core_idx++, core_pack->core.core_type,
+                        core_pack->core_num, core_pack->core.threads);
+                }
+                if (mc->topo_props.clusters_supported) {
+                    g_string_append_printf(s, " ] ");
+                }
+            }
+        }
+        g_string_append_printf(s, " )");
+    }
+
+    return g_string_free(s, false);
+}
+
+void machine_validate_hybrid_topology(MachineState *ms, Error **errp)
+{
+    MachineClass *mc = MACHINE_GET_CLASS(ms);
+    HybridCluster *cluster;
+
+    if (ms->topo.max_cpus == 0) {
+        /*
+         * Cores are not set, and maybe clusters are also not set.
+         * At present, since the coretype cannot be omitted, the core
+         * level must be specified.
+         *
+         * TODO: Support coretype and core level can be omitted.
+         */
+        g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+        error_setg(errp, "Invalid hybrid CPU topology: Lack "
+                   "of core configuration, unable to generate "
+                   "valid topology: %s", topo_msg);
+        exit(1);
+    } else {
+        /*
+         * Though currently max_cpus equals to cpus, still check cpus here
+         * as the complete code logic.
+         *
+         * TODO: Consider adding more complete online cpus configuration
+         * support in the future.
+         *
+         * Since cpus = 0 is deprecated CPU topology for smp, now -hybrid
+         * returns error directly.
+         */
+        if (ms->topo.cpus == 0) {
+            error_setg(errp, "Must set at least one cpu online");
+            exit(1);
+        }
+    }
+
+    /* Each cluster need at least one core. */
+    for (int i = 0; i < ms->topo.hybrid.clusters; i++) {
+        cluster = &ms->topo.hybrid.cluster_list[i];
+
+        if (!cluster->cores) {
+            g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+            error_setg(errp, "Invalid hybrid CPU topology: no core is "
+                       "specified for cluster (id: %d), unable to "
+                       "generate valid topology: %s",
+                       i, topo_msg);
+            exit(1);
+        }
+    }
+
+    if (ms->topo.cpus < mc->min_cpus) {
+        g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+        error_setg(errp, "Invalid Hybrid CPUs %d. The min CPUs "
+                   "supported by machine '%s' is %d. Topology: %s",
+                   ms->topo.cpus, mc->name, mc->min_cpus, topo_msg);
+        exit(1);
+    }
+
+    if (ms->topo.max_cpus > mc->max_cpus) {
+        g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+        error_setg(errp, "Invalid Hybrid CPUs %d. The max CPUs "
+                   "supported by machine '%s' is %d. Topology: %s",
+                   ms->topo.max_cpus, mc->name, mc->max_cpus, topo_msg);
+        exit(1);
+    }
+}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index f2c6aac4ef94..630934317e3c 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1327,6 +1327,10 @@  void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
         }
     }
 
+    if (!machine_topo_is_smp(machine)) {
+        machine_validate_hybrid_topology(machine, errp);
+    }
+
     if (machine->memdev) {
         ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev),
                                                            "size",  &error_abort);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 09b93c17a245..9156982e4de6 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -41,6 +41,7 @@  void set_hybrid_options(MachineState *ms,
                         const HybridOptions *config,
                         Error **errp);
 void machine_free_hybrid_topology(MachineState *ms);
+void machine_validate_hybrid_topology(MachineState *ms, Error **errp);
 
 /**
  * machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices