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