Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <sys/param.h>
0003 #include <sys/utsname.h>
0004 #include <inttypes.h>
0005 #include <stdlib.h>
0006 #include <string.h>
0007 #include <api/fs/fs.h>
0008 #include <linux/zalloc.h>
0009 #include <perf/cpumap.h>
0010 
0011 #include "cputopo.h"
0012 #include "cpumap.h"
0013 #include "debug.h"
0014 #include "env.h"
0015 #include "pmu-hybrid.h"
0016 
0017 #define PACKAGE_CPUS_FMT \
0018     "%s/devices/system/cpu/cpu%d/topology/package_cpus_list"
0019 #define PACKAGE_CPUS_FMT_OLD \
0020     "%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
0021 #define DIE_CPUS_FMT \
0022     "%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
0023 #define CORE_CPUS_FMT \
0024     "%s/devices/system/cpu/cpu%d/topology/core_cpus_list"
0025 #define CORE_CPUS_FMT_OLD \
0026     "%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
0027 #define NODE_ONLINE_FMT \
0028     "%s/devices/system/node/online"
0029 #define NODE_MEMINFO_FMT \
0030     "%s/devices/system/node/node%d/meminfo"
0031 #define NODE_CPULIST_FMT \
0032     "%s/devices/system/node/node%d/cpulist"
0033 
0034 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
0035 {
0036     FILE *fp;
0037     char filename[MAXPATHLEN];
0038     char *buf = NULL, *p;
0039     size_t len = 0;
0040     ssize_t sret;
0041     u32 i = 0;
0042     int ret = -1;
0043 
0044     scnprintf(filename, MAXPATHLEN, PACKAGE_CPUS_FMT,
0045           sysfs__mountpoint(), cpu);
0046     if (access(filename, F_OK) == -1) {
0047         scnprintf(filename, MAXPATHLEN, PACKAGE_CPUS_FMT_OLD,
0048             sysfs__mountpoint(), cpu);
0049     }
0050     fp = fopen(filename, "r");
0051     if (!fp)
0052         goto try_dies;
0053 
0054     sret = getline(&buf, &len, fp);
0055     fclose(fp);
0056     if (sret <= 0)
0057         goto try_dies;
0058 
0059     p = strchr(buf, '\n');
0060     if (p)
0061         *p = '\0';
0062 
0063     for (i = 0; i < tp->package_cpus_lists; i++) {
0064         if (!strcmp(buf, tp->package_cpus_list[i]))
0065             break;
0066     }
0067     if (i == tp->package_cpus_lists) {
0068         tp->package_cpus_list[i] = buf;
0069         tp->package_cpus_lists++;
0070         buf = NULL;
0071         len = 0;
0072     }
0073     ret = 0;
0074 
0075 try_dies:
0076     if (!tp->die_cpus_list)
0077         goto try_threads;
0078 
0079     scnprintf(filename, MAXPATHLEN, DIE_CPUS_FMT,
0080           sysfs__mountpoint(), cpu);
0081     fp = fopen(filename, "r");
0082     if (!fp)
0083         goto try_threads;
0084 
0085     sret = getline(&buf, &len, fp);
0086     fclose(fp);
0087     if (sret <= 0)
0088         goto try_threads;
0089 
0090     p = strchr(buf, '\n');
0091     if (p)
0092         *p = '\0';
0093 
0094     for (i = 0; i < tp->die_cpus_lists; i++) {
0095         if (!strcmp(buf, tp->die_cpus_list[i]))
0096             break;
0097     }
0098     if (i == tp->die_cpus_lists) {
0099         tp->die_cpus_list[i] = buf;
0100         tp->die_cpus_lists++;
0101         buf = NULL;
0102         len = 0;
0103     }
0104     ret = 0;
0105 
0106 try_threads:
0107     scnprintf(filename, MAXPATHLEN, CORE_CPUS_FMT,
0108           sysfs__mountpoint(), cpu);
0109     if (access(filename, F_OK) == -1) {
0110         scnprintf(filename, MAXPATHLEN, CORE_CPUS_FMT_OLD,
0111               sysfs__mountpoint(), cpu);
0112     }
0113     fp = fopen(filename, "r");
0114     if (!fp)
0115         goto done;
0116 
0117     if (getline(&buf, &len, fp) <= 0)
0118         goto done;
0119 
0120     p = strchr(buf, '\n');
0121     if (p)
0122         *p = '\0';
0123 
0124     for (i = 0; i < tp->core_cpus_lists; i++) {
0125         if (!strcmp(buf, tp->core_cpus_list[i]))
0126             break;
0127     }
0128     if (i == tp->core_cpus_lists) {
0129         tp->core_cpus_list[i] = buf;
0130         tp->core_cpus_lists++;
0131         buf = NULL;
0132     }
0133     ret = 0;
0134 done:
0135     if (fp)
0136         fclose(fp);
0137     free(buf);
0138     return ret;
0139 }
0140 
0141 void cpu_topology__delete(struct cpu_topology *tp)
0142 {
0143     u32 i;
0144 
0145     if (!tp)
0146         return;
0147 
0148     for (i = 0 ; i < tp->package_cpus_lists; i++)
0149         zfree(&tp->package_cpus_list[i]);
0150 
0151     for (i = 0 ; i < tp->die_cpus_lists; i++)
0152         zfree(&tp->die_cpus_list[i]);
0153 
0154     for (i = 0 ; i < tp->core_cpus_lists; i++)
0155         zfree(&tp->core_cpus_list[i]);
0156 
0157     free(tp);
0158 }
0159 
0160 static bool has_die_topology(void)
0161 {
0162     char filename[MAXPATHLEN];
0163     struct utsname uts;
0164 
0165     if (uname(&uts) < 0)
0166         return false;
0167 
0168     if (strncmp(uts.machine, "x86_64", 6) &&
0169         strncmp(uts.machine, "s390x", 5))
0170         return false;
0171 
0172     scnprintf(filename, MAXPATHLEN, DIE_CPUS_FMT,
0173           sysfs__mountpoint(), 0);
0174     if (access(filename, F_OK) == -1)
0175         return false;
0176 
0177     return true;
0178 }
0179 
0180 struct cpu_topology *cpu_topology__new(void)
0181 {
0182     struct cpu_topology *tp = NULL;
0183     void *addr;
0184     u32 nr, i, nr_addr;
0185     size_t sz;
0186     long ncpus;
0187     int ret = -1;
0188     struct perf_cpu_map *map;
0189     bool has_die = has_die_topology();
0190 
0191     ncpus = cpu__max_present_cpu().cpu;
0192 
0193     /* build online CPU map */
0194     map = perf_cpu_map__new(NULL);
0195     if (map == NULL) {
0196         pr_debug("failed to get system cpumap\n");
0197         return NULL;
0198     }
0199 
0200     nr = (u32)(ncpus & UINT_MAX);
0201 
0202     sz = nr * sizeof(char *);
0203     if (has_die)
0204         nr_addr = 3;
0205     else
0206         nr_addr = 2;
0207     addr = calloc(1, sizeof(*tp) + nr_addr * sz);
0208     if (!addr)
0209         goto out_free;
0210 
0211     tp = addr;
0212     addr += sizeof(*tp);
0213     tp->package_cpus_list = addr;
0214     addr += sz;
0215     if (has_die) {
0216         tp->die_cpus_list = addr;
0217         addr += sz;
0218     }
0219     tp->core_cpus_list = addr;
0220 
0221     for (i = 0; i < nr; i++) {
0222         if (!perf_cpu_map__has(map, (struct perf_cpu){ .cpu = i }))
0223             continue;
0224 
0225         ret = build_cpu_topology(tp, i);
0226         if (ret < 0)
0227             break;
0228     }
0229 
0230 out_free:
0231     perf_cpu_map__put(map);
0232     if (ret) {
0233         cpu_topology__delete(tp);
0234         tp = NULL;
0235     }
0236     return tp;
0237 }
0238 
0239 static int load_numa_node(struct numa_topology_node *node, int nr)
0240 {
0241     char str[MAXPATHLEN];
0242     char field[32];
0243     char *buf = NULL, *p;
0244     size_t len = 0;
0245     int ret = -1;
0246     FILE *fp;
0247     u64 mem;
0248 
0249     node->node = (u32) nr;
0250 
0251     scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
0252           sysfs__mountpoint(), nr);
0253     fp = fopen(str, "r");
0254     if (!fp)
0255         return -1;
0256 
0257     while (getline(&buf, &len, fp) > 0) {
0258         /* skip over invalid lines */
0259         if (!strchr(buf, ':'))
0260             continue;
0261         if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2)
0262             goto err;
0263         if (!strcmp(field, "MemTotal:"))
0264             node->mem_total = mem;
0265         if (!strcmp(field, "MemFree:"))
0266             node->mem_free = mem;
0267         if (node->mem_total && node->mem_free)
0268             break;
0269     }
0270 
0271     fclose(fp);
0272     fp = NULL;
0273 
0274     scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
0275           sysfs__mountpoint(), nr);
0276 
0277     fp = fopen(str, "r");
0278     if (!fp)
0279         return -1;
0280 
0281     if (getline(&buf, &len, fp) <= 0)
0282         goto err;
0283 
0284     p = strchr(buf, '\n');
0285     if (p)
0286         *p = '\0';
0287 
0288     node->cpus = buf;
0289     fclose(fp);
0290     return 0;
0291 
0292 err:
0293     free(buf);
0294     if (fp)
0295         fclose(fp);
0296     return ret;
0297 }
0298 
0299 struct numa_topology *numa_topology__new(void)
0300 {
0301     struct perf_cpu_map *node_map = NULL;
0302     struct numa_topology *tp = NULL;
0303     char path[MAXPATHLEN];
0304     char *buf = NULL;
0305     size_t len = 0;
0306     u32 nr, i;
0307     FILE *fp;
0308     char *c;
0309 
0310     scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
0311           sysfs__mountpoint());
0312 
0313     fp = fopen(path, "r");
0314     if (!fp)
0315         return NULL;
0316 
0317     if (getline(&buf, &len, fp) <= 0)
0318         goto out;
0319 
0320     c = strchr(buf, '\n');
0321     if (c)
0322         *c = '\0';
0323 
0324     node_map = perf_cpu_map__new(buf);
0325     if (!node_map)
0326         goto out;
0327 
0328     nr = (u32) perf_cpu_map__nr(node_map);
0329 
0330     tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
0331     if (!tp)
0332         goto out;
0333 
0334     tp->nr = nr;
0335 
0336     for (i = 0; i < nr; i++) {
0337         if (load_numa_node(&tp->nodes[i], perf_cpu_map__cpu(node_map, i).cpu)) {
0338             numa_topology__delete(tp);
0339             tp = NULL;
0340             break;
0341         }
0342     }
0343 
0344 out:
0345     free(buf);
0346     fclose(fp);
0347     perf_cpu_map__put(node_map);
0348     return tp;
0349 }
0350 
0351 void numa_topology__delete(struct numa_topology *tp)
0352 {
0353     u32 i;
0354 
0355     for (i = 0; i < tp->nr; i++)
0356         zfree(&tp->nodes[i].cpus);
0357 
0358     free(tp);
0359 }
0360 
0361 static int load_hybrid_node(struct hybrid_topology_node *node,
0362                 struct perf_pmu *pmu)
0363 {
0364     const char *sysfs;
0365     char path[PATH_MAX];
0366     char *buf = NULL, *p;
0367     FILE *fp;
0368     size_t len = 0;
0369 
0370     node->pmu_name = strdup(pmu->name);
0371     if (!node->pmu_name)
0372         return -1;
0373 
0374     sysfs = sysfs__mountpoint();
0375     if (!sysfs)
0376         goto err;
0377 
0378     snprintf(path, PATH_MAX, CPUS_TEMPLATE_CPU, sysfs, pmu->name);
0379     fp = fopen(path, "r");
0380     if (!fp)
0381         goto err;
0382 
0383     if (getline(&buf, &len, fp) <= 0) {
0384         fclose(fp);
0385         goto err;
0386     }
0387 
0388     p = strchr(buf, '\n');
0389     if (p)
0390         *p = '\0';
0391 
0392     fclose(fp);
0393     node->cpus = buf;
0394     return 0;
0395 
0396 err:
0397     zfree(&node->pmu_name);
0398     free(buf);
0399     return -1;
0400 }
0401 
0402 struct hybrid_topology *hybrid_topology__new(void)
0403 {
0404     struct perf_pmu *pmu;
0405     struct hybrid_topology *tp = NULL;
0406     u32 nr, i = 0;
0407 
0408     nr = perf_pmu__hybrid_pmu_num();
0409     if (nr == 0)
0410         return NULL;
0411 
0412     tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0]) * nr);
0413     if (!tp)
0414         return NULL;
0415 
0416     tp->nr = nr;
0417     perf_pmu__for_each_hybrid_pmu(pmu) {
0418         if (load_hybrid_node(&tp->nodes[i], pmu)) {
0419             hybrid_topology__delete(tp);
0420             return NULL;
0421         }
0422         i++;
0423     }
0424 
0425     return tp;
0426 }
0427 
0428 void hybrid_topology__delete(struct hybrid_topology *tp)
0429 {
0430     u32 i;
0431 
0432     for (i = 0; i < tp->nr; i++) {
0433         zfree(&tp->nodes[i].pmu_name);
0434         zfree(&tp->nodes[i].cpus);
0435     }
0436 
0437     free(tp);
0438 }