root/tools/perf/util/cputopo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. build_cpu_topology
  2. cpu_topology__delete
  3. has_die_topology
  4. cpu_topology__new
  5. load_numa_node
  6. numa_topology__new
  7. numa_topology__delete

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <sys/param.h>
   3 #include <sys/utsname.h>
   4 #include <inttypes.h>
   5 #include <stdlib.h>
   6 #include <string.h>
   7 #include <api/fs/fs.h>
   8 #include <linux/zalloc.h>
   9 #include <perf/cpumap.h>
  10 
  11 #include "cputopo.h"
  12 #include "cpumap.h"
  13 #include "debug.h"
  14 #include "env.h"
  15 
  16 #define CORE_SIB_FMT \
  17         "%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
  18 #define DIE_SIB_FMT \
  19         "%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
  20 #define THRD_SIB_FMT \
  21         "%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
  22 #define THRD_SIB_FMT_NEW \
  23         "%s/devices/system/cpu/cpu%d/topology/core_cpus_list"
  24 #define NODE_ONLINE_FMT \
  25         "%s/devices/system/node/online"
  26 #define NODE_MEMINFO_FMT \
  27         "%s/devices/system/node/node%d/meminfo"
  28 #define NODE_CPULIST_FMT \
  29         "%s/devices/system/node/node%d/cpulist"
  30 
  31 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
  32 {
  33         FILE *fp;
  34         char filename[MAXPATHLEN];
  35         char *buf = NULL, *p;
  36         size_t len = 0;
  37         ssize_t sret;
  38         u32 i = 0;
  39         int ret = -1;
  40 
  41         scnprintf(filename, MAXPATHLEN, CORE_SIB_FMT,
  42                   sysfs__mountpoint(), cpu);
  43         fp = fopen(filename, "r");
  44         if (!fp)
  45                 goto try_dies;
  46 
  47         sret = getline(&buf, &len, fp);
  48         fclose(fp);
  49         if (sret <= 0)
  50                 goto try_dies;
  51 
  52         p = strchr(buf, '\n');
  53         if (p)
  54                 *p = '\0';
  55 
  56         for (i = 0; i < tp->core_sib; i++) {
  57                 if (!strcmp(buf, tp->core_siblings[i]))
  58                         break;
  59         }
  60         if (i == tp->core_sib) {
  61                 tp->core_siblings[i] = buf;
  62                 tp->core_sib++;
  63                 buf = NULL;
  64                 len = 0;
  65         }
  66         ret = 0;
  67 
  68 try_dies:
  69         if (!tp->die_siblings)
  70                 goto try_threads;
  71 
  72         scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
  73                   sysfs__mountpoint(), cpu);
  74         fp = fopen(filename, "r");
  75         if (!fp)
  76                 goto try_threads;
  77 
  78         sret = getline(&buf, &len, fp);
  79         fclose(fp);
  80         if (sret <= 0)
  81                 goto try_threads;
  82 
  83         p = strchr(buf, '\n');
  84         if (p)
  85                 *p = '\0';
  86 
  87         for (i = 0; i < tp->die_sib; i++) {
  88                 if (!strcmp(buf, tp->die_siblings[i]))
  89                         break;
  90         }
  91         if (i == tp->die_sib) {
  92                 tp->die_siblings[i] = buf;
  93                 tp->die_sib++;
  94                 buf = NULL;
  95                 len = 0;
  96         }
  97         ret = 0;
  98 
  99 try_threads:
 100         scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT_NEW,
 101                   sysfs__mountpoint(), cpu);
 102         if (access(filename, F_OK) == -1) {
 103                 scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
 104                           sysfs__mountpoint(), cpu);
 105         }
 106         fp = fopen(filename, "r");
 107         if (!fp)
 108                 goto done;
 109 
 110         if (getline(&buf, &len, fp) <= 0)
 111                 goto done;
 112 
 113         p = strchr(buf, '\n');
 114         if (p)
 115                 *p = '\0';
 116 
 117         for (i = 0; i < tp->thread_sib; i++) {
 118                 if (!strcmp(buf, tp->thread_siblings[i]))
 119                         break;
 120         }
 121         if (i == tp->thread_sib) {
 122                 tp->thread_siblings[i] = buf;
 123                 tp->thread_sib++;
 124                 buf = NULL;
 125         }
 126         ret = 0;
 127 done:
 128         if (fp)
 129                 fclose(fp);
 130         free(buf);
 131         return ret;
 132 }
 133 
 134 void cpu_topology__delete(struct cpu_topology *tp)
 135 {
 136         u32 i;
 137 
 138         if (!tp)
 139                 return;
 140 
 141         for (i = 0 ; i < tp->core_sib; i++)
 142                 zfree(&tp->core_siblings[i]);
 143 
 144         if (tp->die_sib) {
 145                 for (i = 0 ; i < tp->die_sib; i++)
 146                         zfree(&tp->die_siblings[i]);
 147         }
 148 
 149         for (i = 0 ; i < tp->thread_sib; i++)
 150                 zfree(&tp->thread_siblings[i]);
 151 
 152         free(tp);
 153 }
 154 
 155 static bool has_die_topology(void)
 156 {
 157         char filename[MAXPATHLEN];
 158         struct utsname uts;
 159 
 160         if (uname(&uts) < 0)
 161                 return false;
 162 
 163         if (strncmp(uts.machine, "x86_64", 6))
 164                 return false;
 165 
 166         scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
 167                   sysfs__mountpoint(), 0);
 168         if (access(filename, F_OK) == -1)
 169                 return false;
 170 
 171         return true;
 172 }
 173 
 174 struct cpu_topology *cpu_topology__new(void)
 175 {
 176         struct cpu_topology *tp = NULL;
 177         void *addr;
 178         u32 nr, i, nr_addr;
 179         size_t sz;
 180         long ncpus;
 181         int ret = -1;
 182         struct perf_cpu_map *map;
 183         bool has_die = has_die_topology();
 184 
 185         ncpus = cpu__max_present_cpu();
 186 
 187         /* build online CPU map */
 188         map = perf_cpu_map__new(NULL);
 189         if (map == NULL) {
 190                 pr_debug("failed to get system cpumap\n");
 191                 return NULL;
 192         }
 193 
 194         nr = (u32)(ncpus & UINT_MAX);
 195 
 196         sz = nr * sizeof(char *);
 197         if (has_die)
 198                 nr_addr = 3;
 199         else
 200                 nr_addr = 2;
 201         addr = calloc(1, sizeof(*tp) + nr_addr * sz);
 202         if (!addr)
 203                 goto out_free;
 204 
 205         tp = addr;
 206         addr += sizeof(*tp);
 207         tp->core_siblings = addr;
 208         addr += sz;
 209         if (has_die) {
 210                 tp->die_siblings = addr;
 211                 addr += sz;
 212         }
 213         tp->thread_siblings = addr;
 214 
 215         for (i = 0; i < nr; i++) {
 216                 if (!cpu_map__has(map, i))
 217                         continue;
 218 
 219                 ret = build_cpu_topology(tp, i);
 220                 if (ret < 0)
 221                         break;
 222         }
 223 
 224 out_free:
 225         perf_cpu_map__put(map);
 226         if (ret) {
 227                 cpu_topology__delete(tp);
 228                 tp = NULL;
 229         }
 230         return tp;
 231 }
 232 
 233 static int load_numa_node(struct numa_topology_node *node, int nr)
 234 {
 235         char str[MAXPATHLEN];
 236         char field[32];
 237         char *buf = NULL, *p;
 238         size_t len = 0;
 239         int ret = -1;
 240         FILE *fp;
 241         u64 mem;
 242 
 243         node->node = (u32) nr;
 244 
 245         scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
 246                   sysfs__mountpoint(), nr);
 247         fp = fopen(str, "r");
 248         if (!fp)
 249                 return -1;
 250 
 251         while (getline(&buf, &len, fp) > 0) {
 252                 /* skip over invalid lines */
 253                 if (!strchr(buf, ':'))
 254                         continue;
 255                 if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2)
 256                         goto err;
 257                 if (!strcmp(field, "MemTotal:"))
 258                         node->mem_total = mem;
 259                 if (!strcmp(field, "MemFree:"))
 260                         node->mem_free = mem;
 261                 if (node->mem_total && node->mem_free)
 262                         break;
 263         }
 264 
 265         fclose(fp);
 266         fp = NULL;
 267 
 268         scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
 269                   sysfs__mountpoint(), nr);
 270 
 271         fp = fopen(str, "r");
 272         if (!fp)
 273                 return -1;
 274 
 275         if (getline(&buf, &len, fp) <= 0)
 276                 goto err;
 277 
 278         p = strchr(buf, '\n');
 279         if (p)
 280                 *p = '\0';
 281 
 282         node->cpus = buf;
 283         fclose(fp);
 284         return 0;
 285 
 286 err:
 287         free(buf);
 288         if (fp)
 289                 fclose(fp);
 290         return ret;
 291 }
 292 
 293 struct numa_topology *numa_topology__new(void)
 294 {
 295         struct perf_cpu_map *node_map = NULL;
 296         struct numa_topology *tp = NULL;
 297         char path[MAXPATHLEN];
 298         char *buf = NULL;
 299         size_t len = 0;
 300         u32 nr, i;
 301         FILE *fp;
 302         char *c;
 303 
 304         scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
 305                   sysfs__mountpoint());
 306 
 307         fp = fopen(path, "r");
 308         if (!fp)
 309                 return NULL;
 310 
 311         if (getline(&buf, &len, fp) <= 0)
 312                 goto out;
 313 
 314         c = strchr(buf, '\n');
 315         if (c)
 316                 *c = '\0';
 317 
 318         node_map = perf_cpu_map__new(buf);
 319         if (!node_map)
 320                 goto out;
 321 
 322         nr = (u32) node_map->nr;
 323 
 324         tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
 325         if (!tp)
 326                 goto out;
 327 
 328         tp->nr = nr;
 329 
 330         for (i = 0; i < nr; i++) {
 331                 if (load_numa_node(&tp->nodes[i], node_map->map[i])) {
 332                         numa_topology__delete(tp);
 333                         tp = NULL;
 334                         break;
 335                 }
 336         }
 337 
 338 out:
 339         free(buf);
 340         fclose(fp);
 341         perf_cpu_map__put(node_map);
 342         return tp;
 343 }
 344 
 345 void numa_topology__delete(struct numa_topology *tp)
 346 {
 347         u32 i;
 348 
 349         for (i = 0; i < tp->nr; i++)
 350                 zfree(&tp->nodes[i].cpus);
 351 
 352         free(tp);
 353 }

/* [<][>][^][v][top][bottom][index][help] */