From: Masayoshi Mizuma <m.mizuma@xxxxxxxxxxxxxx> lscpu may show the wrong number of sockets if the machine is aarch64 and doesn't have ACPI PPTT. That's because lscpu shows the number of sockets by using a sysfs entry (cpu/cpuX/topology/core_siblings). The sysfs entry is set by MPIDR_EL1 register if the machine doesn't have ACPI PPTT. MPIDR_EL1 doesn't show the physical socket information directly. It shows the affinity level. According to linux/arch/arm64/kernel/topology.c:store_cpu_topology(), the top level of affinity is called as 'Cluster'. Use Cluster instead of Socket on the machine which doesn't have ACPI PPTT. This patch is useful for aarch64 machine which is based on ARM SBBR v1.0 and v1.1, the specs don't require ACPI PPTT. ARM SBBR v1.2 requires ACPI PPTT. Signed-off-by: Masayoshi Mizuma <m.mizuma@xxxxxxxxxxxxxx> --- include/c.h | 1 + sys-utils/lscpu-arm.c | 23 +++++++++++++++++++++++ sys-utils/lscpu.1 | 3 +++ sys-utils/lscpu.c | 42 +++++++++++++++++++++++++++++++++++------- sys-utils/lscpu.h | 3 +++ 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/include/c.h b/include/c.h index ae0813109..e92636177 100644 --- a/include/c.h +++ b/include/c.h @@ -16,6 +16,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <sys/utsname.h> #include <assert.h> diff --git a/sys-utils/lscpu-arm.c b/sys-utils/lscpu-arm.c index 1cbc9775f..7ef05e8e7 100644 --- a/sys-utils/lscpu-arm.c +++ b/sys-utils/lscpu-arm.c @@ -362,10 +362,33 @@ static void arm_decode(struct lscpu_cxt *cxt, struct lscpu_cputype *ct) arm_rXpY_decode(ct); } +int lscpu_is_cluster_arm(struct lscpu_cxt *cxt) +{ + char *arch; + struct stat st; + struct utsname utsbuf; + + if (cxt) + arch = cxt->arch->name; + else { + if (uname(&utsbuf) == -1) + err(EXIT_FAILURE, _("error: uname failed")); + arch = utsbuf.machine; + } + + if (!(strcmp(arch, "aarch64")) && (stat(_PATH_ACPI_PPTT, &st) < 0) + && (cxt->ncputypes == 1)) + return 1; + else + return 0; +} + void lscpu_decode_arm(struct lscpu_cxt *cxt) { size_t i; + cxt->is_cluster = lscpu_is_cluster_arm(cxt); + for (i = 0; i < cxt->ncputypes; i++) arm_decode(cxt, cxt->cputypes[i]); } diff --git a/sys-utils/lscpu.1 b/sys-utils/lscpu.1 index ed14dc663..a41125395 100644 --- a/sys-utils/lscpu.1 +++ b/sys-utils/lscpu.1 @@ -55,6 +55,9 @@ The logical core number. A core can contain several CPUs. .B SOCKET The logical socket number. A socket can contain several cores. .TP +.B CLUSTER +The logical cluster number. A cluster can contain several cores. +.TP .B BOOK The logical book number. A book can contain several sockets. .TP diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c index 6e501b044..c5a4cc984 100644 --- a/sys-utils/lscpu.c +++ b/sys-utils/lscpu.c @@ -95,6 +95,7 @@ enum { COL_CPU_CPU, COL_CPU_CORE, COL_CPU_SOCKET, + COL_CPU_CLUSTER, COL_CPU_NODE, COL_CPU_BOOK, COL_CPU_DRAWER, @@ -138,6 +139,7 @@ static struct lscpu_coldesc coldescs_cpu[] = [COL_CPU_BOGOMIPS] = { "BOGOMIPS", N_("crude measurement of CPU speed"), SCOLS_FL_RIGHT, 1 }, [COL_CPU_CPU] = { "CPU", N_("logical CPU number"), SCOLS_FL_RIGHT, 1 }, [COL_CPU_CORE] = { "CORE", N_("logical core number"), SCOLS_FL_RIGHT }, + [COL_CPU_CLUSTER] = { "CLUSTER", N_("logical cluster number"), SCOLS_FL_RIGHT }, [COL_CPU_SOCKET] = { "SOCKET", N_("logical socket number"), SCOLS_FL_RIGHT }, [COL_CPU_NODE] = { "NODE", N_("logical NUMA node number"), SCOLS_FL_RIGHT }, [COL_CPU_BOOK] = { "BOOK", N_("logical book number"), SCOLS_FL_RIGHT }, @@ -181,12 +183,21 @@ static int cpu_column_name_to_id(const char *name, size_t namesz) { size_t i; + int is_cluster = lscpu_is_cluster_arm(NULL); for (i = 0; i < ARRAY_SIZE(coldescs_cpu); i++) { const char *cn = coldescs_cpu[i].name; - if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) + if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) { + if ((!strncasecmp(cn, "cluster", namesz)) && (!is_cluster)) { + warnx(_("%s doesn't work on this machine. Use socket."), name); + return -1; + } else if ((!strncasecmp(cn, "socket", namesz)) && (is_cluster)) { + warnx(_("%s doesn't work on this machine. Use cluster."), name); + return -1; + } return i; + } } warnx(_("unknown column: %s"), name); return -1; @@ -337,6 +348,7 @@ static char *get_cell_data( fill_id(cxt, cpu, core, buf, bufsz); break; case COL_CPU_SOCKET: + case COL_CPU_CLUSTER: fill_id(cxt, cpu, socket, buf, bufsz); break; case COL_CPU_DRAWER: @@ -843,7 +855,10 @@ print_summary_cputype(struct lscpu_cxt *cxt, add_summary_s(tb, sec, _("Model:"), ct->revision ? ct->revision : ct->model); add_summary_n(tb, sec, _("Thread(s) per core:"), ct->nthreads_per_core); - add_summary_n(tb, sec, _("Core(s) per socket:"), ct->ncores_per_socket); + if (cxt->is_cluster) + add_summary_n(tb, sec, _("Core(s) per cluster:"), ct->ncores_per_socket); + else + add_summary_n(tb, sec, _("Core(s) per socket:"), ct->ncores_per_socket); if (ct->nbooks) { add_summary_n(tb, sec, _("Socket(s) per book:"), ct->nsockets_per_book); @@ -852,8 +867,14 @@ print_summary_cputype(struct lscpu_cxt *cxt, add_summary_n(tb, sec, _("Drawer(s):"), ct->ndrawers_per_system ?: ct->ndrawers); } else add_summary_n(tb, sec, _("Book(s):"), ct->nbooks_per_drawer ?: ct->nbooks); - } else - add_summary_n(tb, sec, _("Socket(s):"), ct->nsockets_per_book ?: ct->nsockets); + } else { + if (cxt->is_cluster) + add_summary_n(tb, sec, _("Cluster(s):"), + ct->nsockets_per_book ?: ct->nsockets); + else + add_summary_n(tb, sec, _("Socket(s):"), + ct->nsockets_per_book ?: ct->nsockets); + } if (ct->stepping) add_summary_s(tb, sec, _("Stepping:"), ct->stepping); @@ -1325,8 +1346,12 @@ int main(int argc, char *argv[]) columns[ncolumns++] = COL_CPU_DRAWER; if (ct && ct->nbooks) columns[ncolumns++] = COL_CPU_BOOK; - if (ct && ct->nsockets) - columns[ncolumns++] = COL_CPU_SOCKET; + if (ct && ct->nsockets) { + if (cxt->is_cluster) + columns[ncolumns++] = COL_CPU_CLUSTER; + else + columns[ncolumns++] = COL_CPU_SOCKET; + } if (ct && ct->ncores) columns[ncolumns++] = COL_CPU_CORE; if (cxt->ncaches) @@ -1350,7 +1375,10 @@ int main(int argc, char *argv[]) if (!ncolumns) { columns[ncolumns++] = COL_CPU_CPU; columns[ncolumns++] = COL_CPU_CORE; - columns[ncolumns++] = COL_CPU_SOCKET; + if (cxt->is_cluster) + columns[ncolumns++] = COL_CPU_CLUSTER; + else + columns[ncolumns++] = COL_CPU_SOCKET; columns[ncolumns++] = COL_CPU_NODE; columns[ncolumns++] = COL_CPU_CACHE; cxt->show_compatible = 1; diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h index 465bd3fe2..227e7f391 100644 --- a/sys-utils/lscpu.h +++ b/sys-utils/lscpu.h @@ -33,6 +33,7 @@ UL_DEBUG_DECLARE_MASK(lscpu); #define _PATH_SYS_NODE _PATH_SYS_SYSTEM "/node" #define _PATH_SYS_DMI "/sys/firmware/dmi/tables/DMI" #define _PATH_SYS_DMI_TYPE4 "/sys/firmware/dmi/entries/4-0/raw" +#define _PATH_ACPI_PPTT "/sys/firmware/acpi/tables/PPTT" struct lscpu_cache { int id; /* unique identifier */ @@ -242,6 +243,7 @@ struct lscpu_cxt { json : 1, bytes : 1; + int is_cluster; /* For aarch64 if the machine doesn't have ACPI PPTT */ }; #define is_cpu_online(_cxt, _cpu) \ @@ -291,6 +293,7 @@ int lscpu_cpu_set_type(struct lscpu_cpu *cpu, struct lscpu_cputype *type); int lscpu_create_cpus(struct lscpu_cxt *cxt, cpu_set_t *cpuset, size_t setsize); struct lscpu_cpu *lscpu_cpus_loopup_by_type(struct lscpu_cxt *cxt, struct lscpu_cputype *ct); +int lscpu_is_cluster_arm(struct lscpu_cxt *cxt); void lscpu_decode_arm(struct lscpu_cxt *cxt); int lookup(char *line, char *pattern, char **value); -- 2.27.0