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