18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <api/fs/fs.h> 38c2ecf20Sopenharmony_ci#include "cpumap.h" 48c2ecf20Sopenharmony_ci#include "debug.h" 58c2ecf20Sopenharmony_ci#include "event.h" 68c2ecf20Sopenharmony_ci#include <assert.h> 78c2ecf20Sopenharmony_ci#include <dirent.h> 88c2ecf20Sopenharmony_ci#include <stdio.h> 98c2ecf20Sopenharmony_ci#include <stdlib.h> 108c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 118c2ecf20Sopenharmony_ci#include "asm/bug.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/ctype.h> 148c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int max_cpu_num; 178c2ecf20Sopenharmony_cistatic int max_present_cpu_num; 188c2ecf20Sopenharmony_cistatic int max_node_num; 198c2ecf20Sopenharmony_cistatic int *cpunode_map; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic struct perf_cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct perf_cpu_map *map; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci map = perf_cpu_map__empty_new(cpus->nr); 268c2ecf20Sopenharmony_ci if (map) { 278c2ecf20Sopenharmony_ci unsigned i; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci for (i = 0; i < cpus->nr; i++) { 308c2ecf20Sopenharmony_ci /* 318c2ecf20Sopenharmony_ci * Special treatment for -1, which is not real cpu number, 328c2ecf20Sopenharmony_ci * and we need to use (int) -1 to initialize map[i], 338c2ecf20Sopenharmony_ci * otherwise it would become 65535. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci if (cpus->cpu[i] == (u16) -1) 368c2ecf20Sopenharmony_ci map->map[i] = -1; 378c2ecf20Sopenharmony_ci else 388c2ecf20Sopenharmony_ci map->map[i] = (int) cpus->cpu[i]; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return map; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic struct perf_cpu_map *cpu_map__from_mask(struct perf_record_record_cpu_map *mask) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct perf_cpu_map *map; 488c2ecf20Sopenharmony_ci int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci nr = bitmap_weight(mask->mask, nbits); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci map = perf_cpu_map__empty_new(nr); 538c2ecf20Sopenharmony_ci if (map) { 548c2ecf20Sopenharmony_ci int cpu, i = 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci for_each_set_bit(cpu, mask->mask, nbits) 578c2ecf20Sopenharmony_ci map->map[i++] = cpu; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci return map; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci if (data->type == PERF_CPU_MAP__CPUS) 668c2ecf20Sopenharmony_ci return cpu_map__from_entries((struct cpu_map_entries *)data->data); 678c2ecf20Sopenharmony_ci else 688c2ecf20Sopenharmony_ci return cpu_map__from_mask((struct perf_record_record_cpu_map *)data->data); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cisize_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci#define BUFSIZE 1024 748c2ecf20Sopenharmony_ci char buf[BUFSIZE]; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci cpu_map__snprint(map, buf, sizeof(buf)); 778c2ecf20Sopenharmony_ci return fprintf(fp, "%s\n", buf); 788c2ecf20Sopenharmony_ci#undef BUFSIZE 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct perf_cpu_map *perf_cpu_map__empty_new(int nr) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (cpus != NULL) { 868c2ecf20Sopenharmony_ci int i; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci cpus->nr = nr; 898c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) 908c2ecf20Sopenharmony_ci cpus->map[i] = -1; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci refcount_set(&cpus->refcnt, 1); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return cpus; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int cpu__get_topology_int(int cpu, const char *name, int *value) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci char path[PATH_MAX]; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci snprintf(path, PATH_MAX, 1038c2ecf20Sopenharmony_ci "devices/system/cpu/cpu%d/topology/%s", cpu, name); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return sysfs__read_int(path, value); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciint cpu_map__get_socket_id(int cpu) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int value, ret = cpu__get_topology_int(cpu, "physical_package_id", &value); 1118c2ecf20Sopenharmony_ci return ret ?: value; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciint cpu_map__get_socket(struct perf_cpu_map *map, int idx, void *data __maybe_unused) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci int cpu; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (idx > map->nr) 1198c2ecf20Sopenharmony_ci return -1; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci cpu = map->map[idx]; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return cpu_map__get_socket_id(cpu); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int cmp_ids(const void *a, const void *b) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return *(int *)a - *(int *)b; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciint cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res, 1328c2ecf20Sopenharmony_ci int (*f)(struct perf_cpu_map *map, int cpu, void *data), 1338c2ecf20Sopenharmony_ci void *data) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct perf_cpu_map *c; 1368c2ecf20Sopenharmony_ci int nr = cpus->nr; 1378c2ecf20Sopenharmony_ci int cpu, s1, s2; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* allocate as much as possible */ 1408c2ecf20Sopenharmony_ci c = calloc(1, sizeof(*c) + nr * sizeof(int)); 1418c2ecf20Sopenharmony_ci if (!c) 1428c2ecf20Sopenharmony_ci return -1; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci for (cpu = 0; cpu < nr; cpu++) { 1458c2ecf20Sopenharmony_ci s1 = f(cpus, cpu, data); 1468c2ecf20Sopenharmony_ci for (s2 = 0; s2 < c->nr; s2++) { 1478c2ecf20Sopenharmony_ci if (s1 == c->map[s2]) 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci if (s2 == c->nr) { 1518c2ecf20Sopenharmony_ci c->map[c->nr] = s1; 1528c2ecf20Sopenharmony_ci c->nr++; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci /* ensure we process id in increasing order */ 1568c2ecf20Sopenharmony_ci qsort(c->map, c->nr, sizeof(int), cmp_ids); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci refcount_set(&c->refcnt, 1); 1598c2ecf20Sopenharmony_ci *res = c; 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ciint cpu_map__get_die_id(int cpu) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int value, ret = cpu__get_topology_int(cpu, "die_id", &value); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return ret ?: value; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint cpu_map__get_die(struct perf_cpu_map *map, int idx, void *data) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int cpu, die_id, s; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (idx > map->nr) 1758c2ecf20Sopenharmony_ci return -1; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci cpu = map->map[idx]; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci die_id = cpu_map__get_die_id(cpu); 1808c2ecf20Sopenharmony_ci /* There is no die_id on legacy system. */ 1818c2ecf20Sopenharmony_ci if (die_id == -1) 1828c2ecf20Sopenharmony_ci die_id = 0; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci s = cpu_map__get_socket(map, idx, data); 1858c2ecf20Sopenharmony_ci if (s == -1) 1868c2ecf20Sopenharmony_ci return -1; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * Encode socket in bit range 15:8 1908c2ecf20Sopenharmony_ci * die_id is relative to socket, and 1918c2ecf20Sopenharmony_ci * we need a global id. So we combine 1928c2ecf20Sopenharmony_ci * socket + die id 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci if (WARN_ONCE(die_id >> 8, "The die id number is too big.\n")) 1958c2ecf20Sopenharmony_ci return -1; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (WARN_ONCE(s >> 8, "The socket id number is too big.\n")) 1988c2ecf20Sopenharmony_ci return -1; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return (s << 8) | (die_id & 0xff); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciint cpu_map__get_core_id(int cpu) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int value, ret = cpu__get_topology_int(cpu, "core_id", &value); 2068c2ecf20Sopenharmony_ci return ret ?: value; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciint cpu_map__get_node_id(int cpu) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci return cpu__get_node(cpu); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciint cpu_map__get_core(struct perf_cpu_map *map, int idx, void *data) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci int cpu, s_die; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (idx > map->nr) 2198c2ecf20Sopenharmony_ci return -1; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci cpu = map->map[idx]; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci cpu = cpu_map__get_core_id(cpu); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* s_die is the combination of socket + die id */ 2268c2ecf20Sopenharmony_ci s_die = cpu_map__get_die(map, idx, data); 2278c2ecf20Sopenharmony_ci if (s_die == -1) 2288c2ecf20Sopenharmony_ci return -1; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * encode socket in bit range 31:24 2328c2ecf20Sopenharmony_ci * encode die id in bit range 23:16 2338c2ecf20Sopenharmony_ci * core_id is relative to socket and die, 2348c2ecf20Sopenharmony_ci * we need a global id. So we combine 2358c2ecf20Sopenharmony_ci * socket + die id + core id 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci if (WARN_ONCE(cpu >> 16, "The core id number is too big.\n")) 2388c2ecf20Sopenharmony_ci return -1; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return (s_die << 16) | (cpu & 0xffff); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciint cpu_map__get_node(struct perf_cpu_map *map, int idx, void *data __maybe_unused) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci if (idx < 0 || idx >= map->nr) 2468c2ecf20Sopenharmony_ci return -1; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return cpu_map__get_node_id(map->map[idx]); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciint cpu_map__build_socket_map(struct perf_cpu_map *cpus, struct perf_cpu_map **sockp) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciint cpu_map__build_die_map(struct perf_cpu_map *cpus, struct perf_cpu_map **diep) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci return cpu_map__build_map(cpus, diep, cpu_map__get_die, NULL); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciint cpu_map__build_core_map(struct perf_cpu_map *cpus, struct perf_cpu_map **corep) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ciint cpu_map__build_node_map(struct perf_cpu_map *cpus, struct perf_cpu_map **numap) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci return cpu_map__build_map(cpus, numap, cpu_map__get_node, NULL); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* setup simple routines to easily access node numbers given a cpu number */ 2728c2ecf20Sopenharmony_cistatic int get_max_num(char *path, int *max) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci size_t num; 2758c2ecf20Sopenharmony_ci char *buf; 2768c2ecf20Sopenharmony_ci int err = 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (filename__read_str(path, &buf, &num)) 2798c2ecf20Sopenharmony_ci return -1; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci buf[num] = '\0'; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* start on the right, to find highest node num */ 2848c2ecf20Sopenharmony_ci while (--num) { 2858c2ecf20Sopenharmony_ci if ((buf[num] == ',') || (buf[num] == '-')) { 2868c2ecf20Sopenharmony_ci num++; 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci if (sscanf(&buf[num], "%d", max) < 1) { 2918c2ecf20Sopenharmony_ci err = -1; 2928c2ecf20Sopenharmony_ci goto out; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* convert from 0-based to 1-based */ 2968c2ecf20Sopenharmony_ci (*max)++; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciout: 2998c2ecf20Sopenharmony_ci free(buf); 3008c2ecf20Sopenharmony_ci return err; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* Determine highest possible cpu in the system for sparse allocation */ 3048c2ecf20Sopenharmony_cistatic void set_max_cpu_num(void) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci const char *mnt; 3078c2ecf20Sopenharmony_ci char path[PATH_MAX]; 3088c2ecf20Sopenharmony_ci int ret = -1; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* set up default */ 3118c2ecf20Sopenharmony_ci max_cpu_num = 4096; 3128c2ecf20Sopenharmony_ci max_present_cpu_num = 4096; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci mnt = sysfs__mountpoint(); 3158c2ecf20Sopenharmony_ci if (!mnt) 3168c2ecf20Sopenharmony_ci goto out; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* get the highest possible cpu number for a sparse allocation */ 3198c2ecf20Sopenharmony_ci ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt); 3208c2ecf20Sopenharmony_ci if (ret >= PATH_MAX) { 3218c2ecf20Sopenharmony_ci pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 3228c2ecf20Sopenharmony_ci goto out; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci ret = get_max_num(path, &max_cpu_num); 3268c2ecf20Sopenharmony_ci if (ret) 3278c2ecf20Sopenharmony_ci goto out; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* get the highest present cpu number for a sparse allocation */ 3308c2ecf20Sopenharmony_ci ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/present", mnt); 3318c2ecf20Sopenharmony_ci if (ret >= PATH_MAX) { 3328c2ecf20Sopenharmony_ci pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 3338c2ecf20Sopenharmony_ci goto out; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ret = get_max_num(path, &max_present_cpu_num); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ciout: 3398c2ecf20Sopenharmony_ci if (ret) 3408c2ecf20Sopenharmony_ci pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/* Determine highest possible node in the system for sparse allocation */ 3448c2ecf20Sopenharmony_cistatic void set_max_node_num(void) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci const char *mnt; 3478c2ecf20Sopenharmony_ci char path[PATH_MAX]; 3488c2ecf20Sopenharmony_ci int ret = -1; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* set up default */ 3518c2ecf20Sopenharmony_ci max_node_num = 8; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci mnt = sysfs__mountpoint(); 3548c2ecf20Sopenharmony_ci if (!mnt) 3558c2ecf20Sopenharmony_ci goto out; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* get the highest possible cpu number for a sparse allocation */ 3588c2ecf20Sopenharmony_ci ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt); 3598c2ecf20Sopenharmony_ci if (ret >= PATH_MAX) { 3608c2ecf20Sopenharmony_ci pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 3618c2ecf20Sopenharmony_ci goto out; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ret = get_max_num(path, &max_node_num); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ciout: 3678c2ecf20Sopenharmony_ci if (ret) 3688c2ecf20Sopenharmony_ci pr_err("Failed to read max nodes, using default of %d\n", max_node_num); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ciint cpu__max_node(void) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci if (unlikely(!max_node_num)) 3748c2ecf20Sopenharmony_ci set_max_node_num(); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return max_node_num; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ciint cpu__max_cpu(void) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci if (unlikely(!max_cpu_num)) 3828c2ecf20Sopenharmony_ci set_max_cpu_num(); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return max_cpu_num; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciint cpu__max_present_cpu(void) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci if (unlikely(!max_present_cpu_num)) 3908c2ecf20Sopenharmony_ci set_max_cpu_num(); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return max_present_cpu_num; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ciint cpu__get_node(int cpu) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci if (unlikely(cpunode_map == NULL)) { 3998c2ecf20Sopenharmony_ci pr_debug("cpu_map not initialized\n"); 4008c2ecf20Sopenharmony_ci return -1; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return cpunode_map[cpu]; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int init_cpunode_map(void) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci int i; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci set_max_cpu_num(); 4118c2ecf20Sopenharmony_ci set_max_node_num(); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci cpunode_map = calloc(max_cpu_num, sizeof(int)); 4148c2ecf20Sopenharmony_ci if (!cpunode_map) { 4158c2ecf20Sopenharmony_ci pr_err("%s: calloc failed\n", __func__); 4168c2ecf20Sopenharmony_ci return -1; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci for (i = 0; i < max_cpu_num; i++) 4208c2ecf20Sopenharmony_ci cpunode_map[i] = -1; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ciint cpu__setup_cpunode_map(void) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct dirent *dent1, *dent2; 4288c2ecf20Sopenharmony_ci DIR *dir1, *dir2; 4298c2ecf20Sopenharmony_ci unsigned int cpu, mem; 4308c2ecf20Sopenharmony_ci char buf[PATH_MAX]; 4318c2ecf20Sopenharmony_ci char path[PATH_MAX]; 4328c2ecf20Sopenharmony_ci const char *mnt; 4338c2ecf20Sopenharmony_ci int n; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* initialize globals */ 4368c2ecf20Sopenharmony_ci if (init_cpunode_map()) 4378c2ecf20Sopenharmony_ci return -1; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci mnt = sysfs__mountpoint(); 4408c2ecf20Sopenharmony_ci if (!mnt) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt); 4448c2ecf20Sopenharmony_ci if (n >= PATH_MAX) { 4458c2ecf20Sopenharmony_ci pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 4468c2ecf20Sopenharmony_ci return -1; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci dir1 = opendir(path); 4508c2ecf20Sopenharmony_ci if (!dir1) 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* walk tree and setup map */ 4548c2ecf20Sopenharmony_ci while ((dent1 = readdir(dir1)) != NULL) { 4558c2ecf20Sopenharmony_ci if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1) 4568c2ecf20Sopenharmony_ci continue; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name); 4598c2ecf20Sopenharmony_ci if (n >= PATH_MAX) { 4608c2ecf20Sopenharmony_ci pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 4618c2ecf20Sopenharmony_ci continue; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci dir2 = opendir(buf); 4658c2ecf20Sopenharmony_ci if (!dir2) 4668c2ecf20Sopenharmony_ci continue; 4678c2ecf20Sopenharmony_ci while ((dent2 = readdir(dir2)) != NULL) { 4688c2ecf20Sopenharmony_ci if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1) 4698c2ecf20Sopenharmony_ci continue; 4708c2ecf20Sopenharmony_ci cpunode_map[cpu] = mem; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci closedir(dir2); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci closedir(dir1); 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cibool cpu_map__has(struct perf_cpu_map *cpus, int cpu) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci return perf_cpu_map__idx(cpus, cpu) != -1; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ciint cpu_map__cpu(struct perf_cpu_map *cpus, int idx) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci return cpus->map[idx]; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cisize_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci int i, cpu, start = -1; 4918c2ecf20Sopenharmony_ci bool first = true; 4928c2ecf20Sopenharmony_ci size_t ret = 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci#define COMMA first ? "" : "," 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci for (i = 0; i < map->nr + 1; i++) { 4978c2ecf20Sopenharmony_ci bool last = i == map->nr; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci cpu = last ? INT_MAX : map->map[i]; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (start == -1) { 5028c2ecf20Sopenharmony_ci start = i; 5038c2ecf20Sopenharmony_ci if (last) { 5048c2ecf20Sopenharmony_ci ret += snprintf(buf + ret, size - ret, 5058c2ecf20Sopenharmony_ci "%s%d", COMMA, 5068c2ecf20Sopenharmony_ci map->map[i]); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci } else if (((i - start) != (cpu - map->map[start])) || last) { 5098c2ecf20Sopenharmony_ci int end = i - 1; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (start == end) { 5128c2ecf20Sopenharmony_ci ret += snprintf(buf + ret, size - ret, 5138c2ecf20Sopenharmony_ci "%s%d", COMMA, 5148c2ecf20Sopenharmony_ci map->map[start]); 5158c2ecf20Sopenharmony_ci } else { 5168c2ecf20Sopenharmony_ci ret += snprintf(buf + ret, size - ret, 5178c2ecf20Sopenharmony_ci "%s%d-%d", COMMA, 5188c2ecf20Sopenharmony_ci map->map[start], map->map[end]); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci first = false; 5218c2ecf20Sopenharmony_ci start = i; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci#undef COMMA 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci pr_debug2("cpumask list: %s\n", buf); 5288c2ecf20Sopenharmony_ci return ret; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic char hex_char(unsigned char val) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci if (val < 10) 5348c2ecf20Sopenharmony_ci return val + '0'; 5358c2ecf20Sopenharmony_ci if (val < 16) 5368c2ecf20Sopenharmony_ci return val - 10 + 'a'; 5378c2ecf20Sopenharmony_ci return '?'; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cisize_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci int i, cpu; 5438c2ecf20Sopenharmony_ci char *ptr = buf; 5448c2ecf20Sopenharmony_ci unsigned char *bitmap; 5458c2ecf20Sopenharmony_ci int last_cpu = cpu_map__cpu(map, map->nr - 1); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (buf == NULL) 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci bitmap = zalloc(last_cpu / 8 + 1); 5518c2ecf20Sopenharmony_ci if (bitmap == NULL) { 5528c2ecf20Sopenharmony_ci buf[0] = '\0'; 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci for (i = 0; i < map->nr; i++) { 5578c2ecf20Sopenharmony_ci cpu = cpu_map__cpu(map, i); 5588c2ecf20Sopenharmony_ci bitmap[cpu / 8] |= 1 << (cpu % 8); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (cpu = last_cpu / 4 * 4; cpu >= 0; cpu -= 4) { 5628c2ecf20Sopenharmony_ci unsigned char bits = bitmap[cpu / 8]; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (cpu % 8) 5658c2ecf20Sopenharmony_ci bits >>= 4; 5668c2ecf20Sopenharmony_ci else 5678c2ecf20Sopenharmony_ci bits &= 0xf; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci *ptr++ = hex_char(bits); 5708c2ecf20Sopenharmony_ci if ((cpu % 32) == 0 && cpu > 0) 5718c2ecf20Sopenharmony_ci *ptr++ = ','; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci *ptr = '\0'; 5748c2ecf20Sopenharmony_ci free(bitmap); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci buf[size - 1] = '\0'; 5778c2ecf20Sopenharmony_ci return ptr - buf; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ciconst struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */ 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci static const struct perf_cpu_map *online = NULL; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (!online) 5858c2ecf20Sopenharmony_ci online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */ 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return online; 5888c2ecf20Sopenharmony_ci} 589