Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf header: Store PMU caps in an array of strings

Currently all capabilities are stored in a single string separated by
NULL character. Instead, store them in an array which makes searching of
capability easier.

Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Ravi Bangoria <ravi.bangoria@amd.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Ananth Narayan <ananth.narayan@amd.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kim Phillips <kim.phillips@amd.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Robert Richter <rrichter@amd.com>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Santosh Shukla <santosh.shukla@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: like.xu.linux@gmail.com
Cc: x86@kernel.org
Link: https://lore.kernel.org/r/20220604044519.594-5-ravi.bangoria@amd.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ravi Bangoria and committed by
Arnaldo Carvalho de Melo
ff34eaa8 2a12bef4

+41 -32
+5 -1
tools/perf/util/env.c
··· 179 179 180 180 void perf_env__exit(struct perf_env *env) 181 181 { 182 - int i; 182 + int i, j; 183 183 184 184 perf_env__purge_bpf(env); 185 185 perf_env__purge_cgroups(env); ··· 196 196 zfree(&env->sibling_threads); 197 197 zfree(&env->pmu_mappings); 198 198 zfree(&env->cpu); 199 + for (i = 0; i < env->nr_cpu_pmu_caps; i++) 200 + zfree(&env->cpu_pmu_caps[i]); 199 201 zfree(&env->cpu_pmu_caps); 200 202 zfree(&env->numa_map); 201 203 ··· 220 218 zfree(&env->hybrid_nodes); 221 219 222 220 for (i = 0; i < env->nr_hybrid_cpc_nodes; i++) { 221 + for (j = 0; j < env->hybrid_cpc_nodes[i].nr_cpu_pmu_caps; j++) 222 + zfree(&env->hybrid_cpc_nodes[i].cpu_pmu_caps[j]); 223 223 zfree(&env->hybrid_cpc_nodes[i].cpu_pmu_caps); 224 224 zfree(&env->hybrid_cpc_nodes[i].pmu_name); 225 225 }
+2 -2
tools/perf/util/env.h
··· 46 46 struct hybrid_cpc_node { 47 47 int nr_cpu_pmu_caps; 48 48 unsigned int max_branches; 49 - char *cpu_pmu_caps; 49 + char **cpu_pmu_caps; 50 50 char *pmu_name; 51 51 }; 52 52 ··· 81 81 char *sibling_dies; 82 82 char *sibling_threads; 83 83 char *pmu_mappings; 84 - char *cpu_pmu_caps; 84 + char **cpu_pmu_caps; 85 85 struct cpu_topology_map *cpu; 86 86 struct cpu_cache_level *caches; 87 87 int caches_cnt;
+34 -29
tools/perf/util/header.c
··· 2051 2051 ff->ph->env.comp_level, ff->ph->env.comp_ratio); 2052 2052 } 2053 2053 2054 - static void print_per_cpu_pmu_caps(FILE *fp, int nr_caps, char *cpu_pmu_caps, 2054 + static void print_per_cpu_pmu_caps(FILE *fp, int nr_caps, char **cpu_pmu_caps, 2055 2055 char *pmu_name) 2056 2056 { 2057 - const char *delimiter; 2058 - char *str, buf[128]; 2057 + const char *delimiter = ""; 2058 + int i; 2059 2059 2060 2060 if (!nr_caps) { 2061 2061 fprintf(fp, "# %s pmu capabilities: not available\n", pmu_name); 2062 2062 return; 2063 2063 } 2064 2064 2065 - scnprintf(buf, sizeof(buf), "# %s pmu capabilities: ", pmu_name); 2066 - 2067 - delimiter = buf; 2068 - 2069 - str = cpu_pmu_caps; 2070 - while (nr_caps--) { 2071 - fprintf(fp, "%s%s", delimiter, str); 2065 + fprintf(fp, "# %s pmu capabilities: ", pmu_name); 2066 + for (i = 0; i < nr_caps; i++) { 2067 + fprintf(fp, "%s%s", delimiter, cpu_pmu_caps[i]); 2072 2068 delimiter = ", "; 2073 - str += strlen(str) + 1; 2074 2069 } 2075 2070 2076 2071 fprintf(fp, "\n"); ··· 3197 3202 } 3198 3203 3199 3204 static int process_per_cpu_pmu_caps(struct feat_fd *ff, int *nr_cpu_pmu_caps, 3200 - char **cpu_pmu_caps, 3205 + char ***cpu_pmu_caps, 3201 3206 unsigned int *max_branches) 3202 3207 { 3203 - char *name, *value; 3204 - struct strbuf sb; 3205 - u32 nr_caps; 3208 + char *name, *value, *ptr; 3209 + u32 nr_caps, i; 3210 + 3211 + *nr_cpu_pmu_caps = 0; 3212 + *cpu_pmu_caps = NULL; 3206 3213 3207 3214 if (do_read_u32(ff, &nr_caps)) 3208 3215 return -1; 3209 3216 3210 - if (!nr_caps) { 3211 - pr_debug("cpu pmu capabilities not available\n"); 3217 + if (!nr_caps) 3212 3218 return 0; 3213 - } 3214 3219 3215 - *nr_cpu_pmu_caps = nr_caps; 3216 - 3217 - if (strbuf_init(&sb, 128) < 0) 3220 + *cpu_pmu_caps = zalloc(sizeof(char *) * nr_caps); 3221 + if (!*cpu_pmu_caps) 3218 3222 return -1; 3219 3223 3220 - while (nr_caps--) { 3224 + for (i = 0; i < nr_caps; i++) { 3221 3225 name = do_read_string(ff); 3222 3226 if (!name) 3223 3227 goto error; ··· 3225 3231 if (!value) 3226 3232 goto free_name; 3227 3233 3228 - if (strbuf_addf(&sb, "%s=%s", name, value) < 0) 3234 + if (asprintf(&ptr, "%s=%s", name, value) < 0) 3229 3235 goto free_value; 3230 3236 3231 - /* include a NULL character at the end */ 3232 - if (strbuf_add(&sb, "", 1) < 0) 3233 - goto free_value; 3237 + (*cpu_pmu_caps)[i] = ptr; 3234 3238 3235 3239 if (!strcmp(name, "branches")) 3236 3240 *max_branches = atoi(value); ··· 3236 3244 free(value); 3237 3245 free(name); 3238 3246 } 3239 - *cpu_pmu_caps = strbuf_detach(&sb, NULL); 3247 + *nr_cpu_pmu_caps = nr_caps; 3240 3248 return 0; 3241 3249 3242 3250 free_value: ··· 3244 3252 free_name: 3245 3253 free(name); 3246 3254 error: 3247 - strbuf_release(&sb); 3255 + for (; i > 0; i--) 3256 + free((*cpu_pmu_caps)[i - 1]); 3257 + free(*cpu_pmu_caps); 3258 + *cpu_pmu_caps = NULL; 3259 + *nr_cpu_pmu_caps = 0; 3248 3260 return -1; 3249 3261 } 3250 3262 3251 3263 static int process_cpu_pmu_caps(struct feat_fd *ff, 3252 3264 void *data __maybe_unused) 3253 3265 { 3254 - return process_per_cpu_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps, 3266 + int ret = process_per_cpu_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps, 3255 3267 &ff->ph->env.cpu_pmu_caps, 3256 3268 &ff->ph->env.max_branches); 3269 + 3270 + if (!ret && !ff->ph->env.cpu_pmu_caps) 3271 + pr_debug("cpu pmu capabilities not available\n"); 3272 + return ret; 3257 3273 } 3258 3274 3259 3275 static int process_hybrid_cpu_pmu_caps(struct feat_fd *ff, ··· 3270 3270 struct hybrid_cpc_node *nodes; 3271 3271 u32 nr_pmu, i; 3272 3272 int ret; 3273 + int j; 3273 3274 3274 3275 if (do_read_u32(ff, &nr_pmu)) 3275 3276 return -1; ··· 3298 3297 ret = -1; 3299 3298 goto err; 3300 3299 } 3300 + if (!n->nr_cpu_pmu_caps) 3301 + pr_debug("%s pmu capabilities not available\n", n->pmu_name); 3301 3302 } 3302 3303 3303 3304 ff->ph->env.nr_hybrid_cpc_nodes = nr_pmu; ··· 3308 3305 3309 3306 err: 3310 3307 for (i = 0; i < nr_pmu; i++) { 3308 + for (j = 0; j < nodes[i].nr_cpu_pmu_caps; j++) 3309 + free(nodes[i].cpu_pmu_caps[j]); 3311 3310 free(nodes[i].cpu_pmu_caps); 3312 3311 free(nodes[i].pmu_name); 3313 3312 }