at v5.1-rc3 332 lines 7.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include "cpumap.h" 3#include "env.h" 4#include "sane_ctype.h" 5#include "util.h" 6#include "bpf-event.h" 7#include <errno.h> 8#include <sys/utsname.h> 9#include <bpf/libbpf.h> 10 11struct perf_env perf_env; 12 13void perf_env__insert_bpf_prog_info(struct perf_env *env, 14 struct bpf_prog_info_node *info_node) 15{ 16 __u32 prog_id = info_node->info_linear->info.id; 17 struct bpf_prog_info_node *node; 18 struct rb_node *parent = NULL; 19 struct rb_node **p; 20 21 down_write(&env->bpf_progs.lock); 22 p = &env->bpf_progs.infos.rb_node; 23 24 while (*p != NULL) { 25 parent = *p; 26 node = rb_entry(parent, struct bpf_prog_info_node, rb_node); 27 if (prog_id < node->info_linear->info.id) { 28 p = &(*p)->rb_left; 29 } else if (prog_id > node->info_linear->info.id) { 30 p = &(*p)->rb_right; 31 } else { 32 pr_debug("duplicated bpf prog info %u\n", prog_id); 33 goto out; 34 } 35 } 36 37 rb_link_node(&info_node->rb_node, parent, p); 38 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos); 39 env->bpf_progs.infos_cnt++; 40out: 41 up_write(&env->bpf_progs.lock); 42} 43 44struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, 45 __u32 prog_id) 46{ 47 struct bpf_prog_info_node *node = NULL; 48 struct rb_node *n; 49 50 down_read(&env->bpf_progs.lock); 51 n = env->bpf_progs.infos.rb_node; 52 53 while (n) { 54 node = rb_entry(n, struct bpf_prog_info_node, rb_node); 55 if (prog_id < node->info_linear->info.id) 56 n = n->rb_left; 57 else if (prog_id > node->info_linear->info.id) 58 n = n->rb_right; 59 else 60 break; 61 } 62 63 up_read(&env->bpf_progs.lock); 64 return node; 65} 66 67void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) 68{ 69 struct rb_node *parent = NULL; 70 __u32 btf_id = btf_node->id; 71 struct btf_node *node; 72 struct rb_node **p; 73 74 down_write(&env->bpf_progs.lock); 75 p = &env->bpf_progs.btfs.rb_node; 76 77 while (*p != NULL) { 78 parent = *p; 79 node = rb_entry(parent, struct btf_node, rb_node); 80 if (btf_id < node->id) { 81 p = &(*p)->rb_left; 82 } else if (btf_id > node->id) { 83 p = &(*p)->rb_right; 84 } else { 85 pr_debug("duplicated btf %u\n", btf_id); 86 goto out; 87 } 88 } 89 90 rb_link_node(&btf_node->rb_node, parent, p); 91 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs); 92 env->bpf_progs.btfs_cnt++; 93out: 94 up_write(&env->bpf_progs.lock); 95} 96 97struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) 98{ 99 struct btf_node *node = NULL; 100 struct rb_node *n; 101 102 down_read(&env->bpf_progs.lock); 103 n = env->bpf_progs.btfs.rb_node; 104 105 while (n) { 106 node = rb_entry(n, struct btf_node, rb_node); 107 if (btf_id < node->id) 108 n = n->rb_left; 109 else if (btf_id > node->id) 110 n = n->rb_right; 111 else 112 break; 113 } 114 115 up_read(&env->bpf_progs.lock); 116 return node; 117} 118 119/* purge data in bpf_progs.infos tree */ 120static void perf_env__purge_bpf(struct perf_env *env) 121{ 122 struct rb_root *root; 123 struct rb_node *next; 124 125 down_write(&env->bpf_progs.lock); 126 127 root = &env->bpf_progs.infos; 128 next = rb_first(root); 129 130 while (next) { 131 struct bpf_prog_info_node *node; 132 133 node = rb_entry(next, struct bpf_prog_info_node, rb_node); 134 next = rb_next(&node->rb_node); 135 rb_erase(&node->rb_node, root); 136 free(node); 137 } 138 139 env->bpf_progs.infos_cnt = 0; 140 141 root = &env->bpf_progs.btfs; 142 next = rb_first(root); 143 144 while (next) { 145 struct btf_node *node; 146 147 node = rb_entry(next, struct btf_node, rb_node); 148 next = rb_next(&node->rb_node); 149 rb_erase(&node->rb_node, root); 150 free(node); 151 } 152 153 env->bpf_progs.btfs_cnt = 0; 154 155 up_write(&env->bpf_progs.lock); 156} 157 158void perf_env__exit(struct perf_env *env) 159{ 160 int i; 161 162 perf_env__purge_bpf(env); 163 zfree(&env->hostname); 164 zfree(&env->os_release); 165 zfree(&env->version); 166 zfree(&env->arch); 167 zfree(&env->cpu_desc); 168 zfree(&env->cpuid); 169 zfree(&env->cmdline); 170 zfree(&env->cmdline_argv); 171 zfree(&env->sibling_cores); 172 zfree(&env->sibling_threads); 173 zfree(&env->pmu_mappings); 174 zfree(&env->cpu); 175 176 for (i = 0; i < env->nr_numa_nodes; i++) 177 cpu_map__put(env->numa_nodes[i].map); 178 zfree(&env->numa_nodes); 179 180 for (i = 0; i < env->caches_cnt; i++) 181 cpu_cache_level__free(&env->caches[i]); 182 zfree(&env->caches); 183 184 for (i = 0; i < env->nr_memory_nodes; i++) 185 free(env->memory_nodes[i].set); 186 zfree(&env->memory_nodes); 187} 188 189void perf_env__init(struct perf_env *env) 190{ 191 env->bpf_progs.infos = RB_ROOT; 192 env->bpf_progs.btfs = RB_ROOT; 193 init_rwsem(&env->bpf_progs.lock); 194} 195 196int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) 197{ 198 int i; 199 200 /* do not include NULL termination */ 201 env->cmdline_argv = calloc(argc, sizeof(char *)); 202 if (env->cmdline_argv == NULL) 203 goto out_enomem; 204 205 /* 206 * Must copy argv contents because it gets moved around during option 207 * parsing: 208 */ 209 for (i = 0; i < argc ; i++) { 210 env->cmdline_argv[i] = argv[i]; 211 if (env->cmdline_argv[i] == NULL) 212 goto out_free; 213 } 214 215 env->nr_cmdline = argc; 216 217 return 0; 218out_free: 219 zfree(&env->cmdline_argv); 220out_enomem: 221 return -ENOMEM; 222} 223 224int perf_env__read_cpu_topology_map(struct perf_env *env) 225{ 226 int cpu, nr_cpus; 227 228 if (env->cpu != NULL) 229 return 0; 230 231 if (env->nr_cpus_avail == 0) 232 env->nr_cpus_avail = cpu__max_present_cpu(); 233 234 nr_cpus = env->nr_cpus_avail; 235 if (nr_cpus == -1) 236 return -EINVAL; 237 238 env->cpu = calloc(nr_cpus, sizeof(env->cpu[0])); 239 if (env->cpu == NULL) 240 return -ENOMEM; 241 242 for (cpu = 0; cpu < nr_cpus; ++cpu) { 243 env->cpu[cpu].core_id = cpu_map__get_core_id(cpu); 244 env->cpu[cpu].socket_id = cpu_map__get_socket_id(cpu); 245 } 246 247 env->nr_cpus_avail = nr_cpus; 248 return 0; 249} 250 251static int perf_env__read_arch(struct perf_env *env) 252{ 253 struct utsname uts; 254 255 if (env->arch) 256 return 0; 257 258 if (!uname(&uts)) 259 env->arch = strdup(uts.machine); 260 261 return env->arch ? 0 : -ENOMEM; 262} 263 264static int perf_env__read_nr_cpus_avail(struct perf_env *env) 265{ 266 if (env->nr_cpus_avail == 0) 267 env->nr_cpus_avail = cpu__max_present_cpu(); 268 269 return env->nr_cpus_avail ? 0 : -ENOENT; 270} 271 272const char *perf_env__raw_arch(struct perf_env *env) 273{ 274 return env && !perf_env__read_arch(env) ? env->arch : "unknown"; 275} 276 277int perf_env__nr_cpus_avail(struct perf_env *env) 278{ 279 return env && !perf_env__read_nr_cpus_avail(env) ? env->nr_cpus_avail : 0; 280} 281 282void cpu_cache_level__free(struct cpu_cache_level *cache) 283{ 284 free(cache->type); 285 free(cache->map); 286 free(cache->size); 287} 288 289/* 290 * Return architecture name in a normalized form. 291 * The conversion logic comes from the Makefile. 292 */ 293static const char *normalize_arch(char *arch) 294{ 295 if (!strcmp(arch, "x86_64")) 296 return "x86"; 297 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') 298 return "x86"; 299 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) 300 return "sparc"; 301 if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64")) 302 return "arm64"; 303 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) 304 return "arm"; 305 if (!strncmp(arch, "s390", 4)) 306 return "s390"; 307 if (!strncmp(arch, "parisc", 6)) 308 return "parisc"; 309 if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3)) 310 return "powerpc"; 311 if (!strncmp(arch, "mips", 4)) 312 return "mips"; 313 if (!strncmp(arch, "sh", 2) && isdigit(arch[2])) 314 return "sh"; 315 316 return arch; 317} 318 319const char *perf_env__arch(struct perf_env *env) 320{ 321 struct utsname uts; 322 char *arch_name; 323 324 if (!env || !env->arch) { /* Assume local operation */ 325 if (uname(&uts) < 0) 326 return NULL; 327 arch_name = uts.machine; 328 } else 329 arch_name = env->arch; 330 331 return normalize_arch(arch_name); 332}