]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lscpu: add lscpu_read_topology()
authorKarel Zak <kzak@redhat.com>
Wed, 15 Jul 2020 14:21:26 +0000 (16:21 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 13 Nov 2020 08:19:02 +0000 (09:19 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/lscpu-api.h
sys-utils/lscpu-cputype.c

index 0b35bc5a3f5010f791d5d5e4fc5944fa6652fb01..a7883e03f6eee9c4d356c5a482ab384c0398c80e 100644 (file)
@@ -56,11 +56,17 @@ struct lscpu_cputype {
        int     physchips;      /* Physical chips */
        int     physcoresperchip;       /* Physical cores per chip */
 
-       int     ncores;
-       int     nbooks;
-       int     threads;
-       int     ndrawers;
-
+       int     ncpus;          /* how many CPUs references this type */
+       int     nthreads;       /* calculated (probably same as ncpus) */
+
+       int             ncores;
+       cpu_set_t       **coremaps;
+       int             nsockets;
+       cpu_set_t       **socketmaps;
+       int             nbooks;
+       cpu_set_t       **bookmaps;
+       int             ndrawers;
+       cpu_set_t       **drawermaps;
 };
 
 struct lscpu_cpu {
@@ -72,6 +78,11 @@ struct lscpu_cpu {
 
        char    *dynamic_mhz;
        char    *static_mhz;
+
+       int     coreid;
+       int     socketid;
+       int     bookid;
+       int     drawerid;
 };
 
 struct lscpu_arch {
@@ -132,6 +143,7 @@ struct lscpu_cxt {
        size_t ncputypes;
        struct lscpu_cputype **cputypes;
 
+       /* CPUs as read from /proc/cpuinfo, it means online CPUs only */
        size_t ncpus;
        struct lscpu_cpu **cpus;
 
@@ -142,6 +154,8 @@ struct lscpu_cxt {
         *
         * For example, the possible system CPUs are: 1,3,5, it means that
         * ncpuspos=3, so all arrays are in range 0..3.
+        *
+        * TODO: Do we really need it if we have lscpu_cpu->logical_id?
         */
        size_t ncpuspos;        /* maximal possible CPUs */
        int *idx2cpunum;        /* mapping index to CPU num */
@@ -176,6 +190,7 @@ int lscpu_read_cpulists(struct lscpu_cxt *cxt);
 int lscpu_read_archext(struct lscpu_cxt *cxt);
 int lscpu_read_vulnerabilities(struct lscpu_cxt *cxt);
 int lscpu_read_numas(struct lscpu_cxt *cxt);
+int lscpu_read_topology(struct lscpu_cxt *cxt);
 
 struct lscpu_arch *lscpu_read_architecture(struct lscpu_cxt *cxt);
 void lscpu_free_architecture(struct lscpu_arch *ar);
index a9313215450b1d921536aaa07dc799f71f54036f..cca7fb89819a5c541a488385cbe545bee0841600 100644 (file)
@@ -71,6 +71,27 @@ int lookup(char *line, char *pattern, char **value)
        return 1;
 }
 
+/* add @set to the @ary, unnecessary set is deallocated. */
+static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set, size_t setsize)
+{
+       int i;
+
+       if (!ary)
+               return -1;
+
+       for (i = 0; i < *items; i++) {
+               if (CPU_EQUAL_S(setsize, set, ary[i]))
+                       break;
+       }
+       if (i == *items) {
+               ary[*items] = set;
+               ++*items;
+               return 0;
+       }
+       CPU_FREE(set);
+       return 1;
+}
+
 struct lscpu_cputype *lscpu_new_cputype(void)
 {
        struct lscpu_cputype *ct;
@@ -106,6 +127,10 @@ void lscpu_unref_cputype(struct lscpu_cputype *ct)
                free(ct->flags);
                free(ct->mtid);         /* maximum thread id (s390) */
                free(ct->addrsz);       /* address sizes */
+               free(ct->coremaps);
+               free(ct->socketmaps);
+               free(ct->bookmaps);
+               free(ct->drawermaps);
                free(ct);
        }
 }
@@ -176,6 +201,117 @@ static void lscpu_merge_cputype(struct lscpu_cputype *a, struct lscpu_cputype *b
                a->addrsz = xstrdup(b->addrsz);
 }
 
+/* Read topology for specified type */
+static int cputype_read_topology(struct lscpu_cxt *cxt, struct lscpu_cputype *ct)
+{
+       size_t i, setsize, npos;
+       struct path_cxt *sys;
+
+       sys = cxt->syscpu;                              /* /sys/devices/system/cpu/ */
+       setsize = CPU_ALLOC_SIZE(cxt->maxcpus);         /* CPU set size */
+       npos = cxt->ncpuspos;                           /* possible CPUs */
+
+       for (i = 0; i < cxt->ncpus; i++) {
+               struct lscpu_cpu *cpu = cxt->cpus[i++];
+               cpu_set_t *thread_siblings, *core_siblings;
+               cpu_set_t *book_siblings, *drawer_siblings;
+               int num;
+
+               if (cpu->type != ct)
+                       continue;
+
+               num = cpu->logical_id;
+               if (ul_path_accessf(sys, F_OK, "cpu%d/topology/thread_siblings", num) != 0)
+                       continue;
+
+               /* read topology maps */
+               ul_path_readf_cpuset(sys, &thread_siblings, cxt->maxcpus,
+                                       "cpu%d/topology/thread_siblings", num);
+               ul_path_readf_cpuset(sys, &core_siblings, cxt->maxcpus,
+                                       "cpu%d/topology/core_siblings", num);
+               ul_path_readf_cpuset(sys, &book_siblings, cxt->maxcpus,
+                                       "cpu%d/topology/book_siblings", num);
+               ul_path_readf_cpuset(sys, &drawer_siblings, cxt->maxcpus,
+                                       "cpu%d/topology/drawer_siblings", num);
+
+
+               /* Allocate arrays for topology maps.
+                *
+                * For each map we make sure that it can have up to ncpuspos
+                * entries. This is because we cannot reliably calculate the
+                * number of cores, sockets and books on all architectures.
+                * E.g. completely virtualized architectures like s390 may
+                * have multiple sockets of different sizes.
+                */
+               if (!ct->coremaps)
+                       ct->coremaps = xcalloc(npos, sizeof(cpu_set_t *));
+               if (!ct->socketmaps)
+                       ct->socketmaps = xcalloc(npos, sizeof(cpu_set_t *));
+               if (!ct->bookmaps && book_siblings)
+                       ct->bookmaps = xcalloc(npos, sizeof(cpu_set_t *));
+               if (!ct->drawermaps && drawer_siblings)
+                       ct->drawermaps = xcalloc(npos, sizeof(cpu_set_t *));
+
+               /* add to topology maps */
+               add_cpuset_to_array(ct->socketmaps, &ct->nsockets, core_siblings, setsize);
+               add_cpuset_to_array(ct->coremaps, &ct->ncores, thread_siblings, setsize);
+
+               if (book_siblings)
+                       add_cpuset_to_array(ct->bookmaps, &ct->nbooks, book_siblings, setsize);
+               if (drawer_siblings)
+                       add_cpuset_to_array(ct->drawermaps, &ct->ndrawers, drawer_siblings, setsize);
+
+               /* calculate threads */
+               if (!ct->nthreads) {
+                       int ndrawers, nbooks, nsockets, ncores, nthreads;
+
+                       /* threads within one core */
+                       nthreads = CPU_COUNT_S(setsize, thread_siblings);
+                       if (!nthreads)
+                               nthreads = 1;
+
+                       /* cores within one socket */
+                       ncores = CPU_COUNT_S(setsize, core_siblings) / nthreads;
+                       if (!ncores)
+                               ncores = 1;
+
+                       /* number of sockets within one book.  Because of odd /
+                        * non-present cpu maps and to keep calculation easy we make
+                        * sure that nsockets and nbooks is at least 1.
+                        */
+                       nsockets = ct->ncpus / nthreads / ncores;
+                       if (!nsockets)
+                               nsockets = 1;
+
+                       /* number of books */
+                       nbooks = cxt->npresents / nthreads / ncores / nsockets;
+                       if (!nbooks)
+                               ct->nbooks = 1;
+
+                       /* number of drawers */
+                       ndrawers = cxt->npresents / nbooks / nthreads / ncores / nsockets;
+                       if (!ndrawers)
+                               ndrawers = 1;
+
+                       ct->nthreads = ndrawers * nbooks * nsockets * ncores * nthreads;
+               }
+       }
+
+       return 0;
+}
+
+int lscpu_read_topology(struct lscpu_cxt *cxt)
+{
+       size_t i;
+       int rc = 0;
+
+       for (i = 0; i < cxt->ncputypes; i++)
+               rc += cputype_read_topology(cxt, cxt->cputypes[i]);
+
+       return rc;
+}
+
+
 /* Describes /proc/cpuinfo fields */
 struct cpuinfo_pattern {
        int id;                 /* field ID */
@@ -812,6 +948,7 @@ int main(int argc, char **argv)
        lscpu_read_archext(cxt);
        lscpu_read_vulnerabilities(cxt);
        lscpu_read_numas(cxt);
+       lscpu_read_topology(cxt);
 
        lscpu_decode_arm(cxt);