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 11 struct perf_env perf_env; 12 13 void 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++; 40 out: 41 up_write(&env->bpf_progs.lock); 42 } 43 44 struct 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 67 void 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++; 93 out: 94 up_write(&env->bpf_progs.lock); 95 } 96 97 struct 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 */ 120 static 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 158 void 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 189 void 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 196 int 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; 218 out_free: 219 zfree(&env->cmdline_argv); 220 out_enomem: 221 return -ENOMEM; 222 } 223 224 int 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 251 static 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 264 static 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 272 const char *perf_env__raw_arch(struct perf_env *env) 273 { 274 return env && !perf_env__read_arch(env) ? env->arch : "unknown"; 275 } 276 277 int 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 282 void 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 */ 293 static 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 319 const 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 } 333