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

perf list: Reorganize to use callbacks to allow honouring command line options

Rather than controlling the list output with passed flags, add
callbacks that are called when an event or metric are
encountered. State is passed to the callback so that command line
options can be respected, alternatively the callbacks can be changed.

Fix a few bugs:
- wordwrap to columns metric descriptions and expressions;
- remove unnecessary whitespace after PMU event names;
- the metric filter is a glob but matched using strstr which will
always fail, switch to using a proper globmatch,
- the detail flag gives details for extra kernel PMU events like
branch-instructions.

In metricgroup.c switch from struct mep being a rbtree of metricgroups
containing a list of metrics, to the tree directly containing all the
metrics. In general the alias for a name is passed to the print
routine rather than being contained in the name with OR.

Committer notes:

Check the asprint() return to address this on fedora 36:

util/print-events.c: In function ‘print_sdt_events’:
util/print-events.c:183:33: error: ignoring return value of ‘asprintf’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
183 | asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

$ gcc --version | head -1
gcc (GCC) 12.2.1 20220819 (Red Hat 12.2.1-2)
$

Fix ps.pmu_glob setting when dealing with *:* events, it was being left
with a freed pointer that then at the end of cmd_list() would be double
freed.

Check if pmu_name is NULL in default_print_event() before calling
strglobmatch(pmu_name, ...) to avoid a segfault.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Xin Gao <gaoxin@cdjrlc.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: http://lore.kernel.org/lkml/20221114210723.2749751-10-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
e5c6109f a3720e96

+620 -508
+281 -52
tools/perf/builtin-list.c
··· 15 15 #include "util/pmu-hybrid.h" 16 16 #include "util/debug.h" 17 17 #include "util/metricgroup.h" 18 + #include "util/string2.h" 19 + #include "util/strlist.h" 18 20 #include <subcmd/pager.h> 19 21 #include <subcmd/parse-options.h> 20 22 #include <stdio.h> 21 23 22 - static bool desc_flag = true; 23 - static bool details_flag; 24 + /** 25 + * struct print_state - State and configuration passed to the default_print 26 + * functions. 27 + */ 28 + struct print_state { 29 + /** 30 + * @pmu_glob: Optionally restrict PMU and metric matching to PMU or 31 + * debugfs subsystem name. 32 + */ 33 + char *pmu_glob; 34 + /** @event_glob: Optional pattern matching glob. */ 35 + char *event_glob; 36 + /** @name_only: Print event or metric names only. */ 37 + bool name_only; 38 + /** @desc: Print the event or metric description. */ 39 + bool desc; 40 + /** @long_desc: Print longer event or metric description. */ 41 + bool long_desc; 42 + /** @deprecated: Print deprecated events or metrics. */ 43 + bool deprecated; 44 + /** 45 + * @detailed: Print extra information on the perf event such as names 46 + * and expressions used internally by events. 47 + */ 48 + bool detailed; 49 + /** @metrics: Controls printing of metric and metric groups. */ 50 + bool metrics; 51 + /** @metricgroups: Controls printing of metric and metric groups. */ 52 + bool metricgroups; 53 + /** @last_topic: The last printed event topic. */ 54 + char *last_topic; 55 + /** @last_metricgroups: The last printed metric group. */ 56 + char *last_metricgroups; 57 + /** @visited_metrics: Metrics that are printed to avoid duplicates. */ 58 + struct strlist *visited_metrics; 59 + }; 60 + 61 + static void default_print_start(void *ps) 62 + { 63 + struct print_state *print_state = ps; 64 + 65 + if (!print_state->name_only && pager_in_use()) 66 + printf("\nList of pre-defined events (to be used in -e or -M):\n\n"); 67 + } 68 + 69 + static void default_print_end(void *print_state __maybe_unused) {} 70 + 71 + static void wordwrap(const char *s, int start, int max, int corr) 72 + { 73 + int column = start; 74 + int n; 75 + 76 + while (*s) { 77 + int wlen = strcspn(s, " \t"); 78 + 79 + if (column + wlen >= max && column > start) { 80 + printf("\n%*s", start, ""); 81 + column = start + corr; 82 + } 83 + n = printf("%s%.*s", column > start ? " " : "", wlen, s); 84 + if (n <= 0) 85 + break; 86 + s += wlen; 87 + column += n; 88 + s = skip_spaces(s); 89 + } 90 + } 91 + 92 + static void default_print_event(void *ps, const char *pmu_name, const char *topic, 93 + const char *event_name, const char *event_alias, 94 + const char *scale_unit __maybe_unused, 95 + bool deprecated, const char *event_type_desc, 96 + const char *desc, const char *long_desc, 97 + const char *encoding_desc, 98 + const char *metric_name, const char *metric_expr) 99 + { 100 + struct print_state *print_state = ps; 101 + int pos; 102 + 103 + if (deprecated && !print_state->deprecated) 104 + return; 105 + 106 + if (print_state->pmu_glob && pmu_name && !strglobmatch(pmu_name, print_state->pmu_glob)) 107 + return; 108 + 109 + if (print_state->event_glob && 110 + (!event_name || !strglobmatch(event_name, print_state->event_glob)) && 111 + (!event_alias || !strglobmatch(event_alias, print_state->event_glob)) && 112 + (!topic || !strglobmatch_nocase(topic, print_state->event_glob))) 113 + return; 114 + 115 + if (print_state->name_only) { 116 + if (event_alias && strlen(event_alias)) 117 + printf("%s ", event_alias); 118 + else 119 + printf("%s ", event_name); 120 + return; 121 + } 122 + 123 + if (strcmp(print_state->last_topic, topic ?: "")) { 124 + if (topic) 125 + printf("\n%s:\n", topic); 126 + free(print_state->last_topic); 127 + print_state->last_topic = strdup(topic ?: ""); 128 + } 129 + 130 + if (event_alias && strlen(event_alias)) 131 + pos = printf(" %s OR %s", event_name, event_alias); 132 + else 133 + pos = printf(" %s", event_name); 134 + 135 + if (!topic && event_type_desc) { 136 + for (; pos < 53; pos++) 137 + putchar(' '); 138 + printf("[%s]\n", event_type_desc); 139 + } else 140 + putchar('\n'); 141 + 142 + if (desc && print_state->desc) { 143 + printf("%*s", 8, "["); 144 + wordwrap(desc, 8, pager_get_columns(), 0); 145 + printf("]\n"); 146 + } 147 + 148 + if (long_desc && print_state->long_desc) { 149 + printf("%*s", 8, "["); 150 + wordwrap(long_desc, 8, pager_get_columns(), 0); 151 + printf("]\n"); 152 + } 153 + 154 + if (print_state->detailed && encoding_desc) { 155 + printf("%*s%s", 8, "", encoding_desc); 156 + if (metric_name) 157 + printf(" MetricName: %s", metric_name); 158 + if (metric_expr) 159 + printf(" MetricExpr: %s", metric_expr); 160 + putchar('\n'); 161 + } 162 + } 163 + 164 + static void default_print_metric(void *ps, 165 + const char *group, 166 + const char *name, 167 + const char *desc, 168 + const char *long_desc, 169 + const char *expr, 170 + const char *unit __maybe_unused) 171 + { 172 + struct print_state *print_state = ps; 173 + 174 + if (print_state->event_glob && 175 + (!print_state->metrics || !name || !strglobmatch(name, print_state->event_glob)) && 176 + (!print_state->metricgroups || !group || !strglobmatch(group, print_state->event_glob))) 177 + return; 178 + 179 + if (!print_state->name_only && !print_state->last_metricgroups) { 180 + if (print_state->metricgroups) { 181 + printf("\nMetric Groups:\n"); 182 + if (!print_state->metrics) 183 + putchar('\n'); 184 + } else { 185 + printf("\nMetrics:\n\n"); 186 + } 187 + } 188 + if (!print_state->last_metricgroups || 189 + strcmp(print_state->last_metricgroups, group ?: "")) { 190 + if (group && print_state->metricgroups) { 191 + if (print_state->name_only) 192 + printf("%s ", group); 193 + else if (print_state->metrics) 194 + printf("\n%s:\n", group); 195 + else 196 + printf("%s\n", group); 197 + } 198 + free(print_state->last_metricgroups); 199 + print_state->last_metricgroups = strdup(group ?: ""); 200 + } 201 + if (!print_state->metrics) 202 + return; 203 + 204 + if (print_state->name_only) { 205 + if (print_state->metrics && 206 + !strlist__has_entry(print_state->visited_metrics, name)) { 207 + printf("%s ", name); 208 + strlist__add(print_state->visited_metrics, name); 209 + } 210 + return; 211 + } 212 + printf(" %s\n", name); 213 + 214 + if (desc && print_state->desc) { 215 + printf("%*s", 8, "["); 216 + wordwrap(desc, 8, pager_get_columns(), 0); 217 + printf("]\n"); 218 + } 219 + if (long_desc && print_state->long_desc) { 220 + printf("%*s", 8, "["); 221 + wordwrap(long_desc, 8, pager_get_columns(), 0); 222 + printf("]\n"); 223 + } 224 + if (expr && print_state->detailed) { 225 + printf("%*s", 8, "["); 226 + wordwrap(expr, 8, pager_get_columns(), 0); 227 + printf("]\n"); 228 + } 229 + } 24 230 25 231 int cmd_list(int argc, const char **argv) 26 232 { 27 233 int i, ret = 0; 28 - bool raw_dump = false; 29 - bool long_desc_flag = false; 30 - bool deprecated = false; 31 - char *pmu_name = NULL; 234 + struct print_state ps = {}; 235 + struct print_callbacks print_cb = { 236 + .print_start = default_print_start, 237 + .print_end = default_print_end, 238 + .print_event = default_print_event, 239 + .print_metric = default_print_metric, 240 + }; 32 241 const char *hybrid_name = NULL; 33 242 const char *unit_name = NULL; 34 243 struct option list_options[] = { 35 - OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"), 36 - OPT_BOOLEAN('d', "desc", &desc_flag, 244 + OPT_BOOLEAN(0, "raw-dump", &ps.name_only, "Dump raw events"), 245 + OPT_BOOLEAN('d', "desc", &ps.desc, 37 246 "Print extra event descriptions. --no-desc to not print."), 38 - OPT_BOOLEAN('v', "long-desc", &long_desc_flag, 247 + OPT_BOOLEAN('v', "long-desc", &ps.long_desc, 39 248 "Print longer event descriptions."), 40 - OPT_BOOLEAN(0, "details", &details_flag, 249 + OPT_BOOLEAN(0, "details", &ps.detailed, 41 250 "Print information on the perf event names and expressions used internally by events."), 42 - OPT_BOOLEAN(0, "deprecated", &deprecated, 251 + OPT_BOOLEAN(0, "deprecated", &ps.deprecated, 43 252 "Print deprecated events."), 44 253 OPT_STRING(0, "cputype", &hybrid_name, "hybrid cpu type", 45 254 "Limit PMU or metric printing to the given hybrid PMU (e.g. core or atom)."), ··· 272 63 273 64 setup_pager(); 274 65 275 - if (!raw_dump && pager_in_use()) 276 - printf("\nList of pre-defined events (to be used in -e or -M):\n\n"); 66 + if (!ps.name_only) 67 + setup_pager(); 277 68 69 + ps.desc = !ps.long_desc; 70 + ps.last_topic = strdup(""); 71 + assert(ps.last_topic); 72 + ps.visited_metrics = strlist__new(NULL, NULL); 73 + assert(ps.visited_metrics); 278 74 if (unit_name) 279 - pmu_name = strdup(unit_name); 75 + ps.pmu_glob = strdup(unit_name); 280 76 else if (hybrid_name) { 281 - pmu_name = perf_pmu__hybrid_type_to_pmu(hybrid_name); 282 - if (!pmu_name) 77 + ps.pmu_glob = perf_pmu__hybrid_type_to_pmu(hybrid_name); 78 + if (!ps.pmu_glob) 283 79 pr_warning("WARNING: hybrid cputype is not supported!\n"); 284 80 } 285 81 82 + print_cb.print_start(&ps); 83 + 286 84 if (argc == 0) { 287 - print_events(NULL, raw_dump, !desc_flag, long_desc_flag, 288 - details_flag, deprecated, pmu_name); 85 + ps.metrics = true; 86 + ps.metricgroups = true; 87 + print_events(&print_cb, &ps); 289 88 goto out; 290 89 } 291 90 ··· 301 84 char *sep, *s; 302 85 303 86 if (strcmp(argv[i], "tracepoint") == 0) 304 - print_tracepoint_events(NULL, NULL, raw_dump); 87 + print_tracepoint_events(&print_cb, &ps); 305 88 else if (strcmp(argv[i], "hw") == 0 || 306 89 strcmp(argv[i], "hardware") == 0) 307 - print_symbol_events(NULL, PERF_TYPE_HARDWARE, 308 - event_symbols_hw, PERF_COUNT_HW_MAX, raw_dump); 90 + print_symbol_events(&print_cb, &ps, PERF_TYPE_HARDWARE, 91 + event_symbols_hw, PERF_COUNT_HW_MAX); 309 92 else if (strcmp(argv[i], "sw") == 0 || 310 93 strcmp(argv[i], "software") == 0) { 311 - print_symbol_events(NULL, PERF_TYPE_SOFTWARE, 312 - event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); 313 - print_tool_events(NULL, raw_dump); 94 + print_symbol_events(&print_cb, &ps, PERF_TYPE_SOFTWARE, 95 + event_symbols_sw, PERF_COUNT_SW_MAX); 96 + print_tool_events(&print_cb, &ps); 314 97 } else if (strcmp(argv[i], "cache") == 0 || 315 98 strcmp(argv[i], "hwcache") == 0) 316 - print_hwcache_events(NULL, raw_dump); 99 + print_hwcache_events(&print_cb, &ps); 317 100 else if (strcmp(argv[i], "pmu") == 0) 318 - print_pmu_events(NULL, raw_dump, !desc_flag, 319 - long_desc_flag, details_flag, 320 - deprecated, pmu_name); 101 + print_pmu_events(&print_cb, &ps); 321 102 else if (strcmp(argv[i], "sdt") == 0) 322 - print_sdt_events(NULL, NULL, raw_dump); 323 - else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) 324 - metricgroup__print(true, false, NULL, raw_dump, details_flag, pmu_name); 325 - else if (strcmp(argv[i], "metricgroup") == 0 || strcmp(argv[i], "metricgroups") == 0) 326 - metricgroup__print(false, true, NULL, raw_dump, details_flag, pmu_name); 327 - else if ((sep = strchr(argv[i], ':')) != NULL) { 103 + print_sdt_events(&print_cb, &ps); 104 + else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) { 105 + ps.metricgroups = false; 106 + ps.metrics = true; 107 + metricgroup__print(&print_cb, &ps); 108 + } else if (strcmp(argv[i], "metricgroup") == 0 || 109 + strcmp(argv[i], "metricgroups") == 0) { 110 + ps.metricgroups = true; 111 + ps.metrics = false; 112 + metricgroup__print(&print_cb, &ps); 113 + } else if ((sep = strchr(argv[i], ':')) != NULL) { 328 114 int sep_idx; 115 + char *old_pmu_glob = ps.pmu_glob; 329 116 330 117 sep_idx = sep - argv[i]; 331 118 s = strdup(argv[i]); ··· 339 118 } 340 119 341 120 s[sep_idx] = '\0'; 342 - print_tracepoint_events(s, s + sep_idx + 1, raw_dump); 343 - print_sdt_events(s, s + sep_idx + 1, raw_dump); 344 - metricgroup__print(true, true, s, raw_dump, details_flag, pmu_name); 121 + ps.pmu_glob = s; 122 + ps.event_glob = s + sep_idx + 1; 123 + print_tracepoint_events(&print_cb, &ps); 124 + print_sdt_events(&print_cb, &ps); 125 + ps.metrics = true; 126 + ps.metricgroups = true; 127 + metricgroup__print(&print_cb, &ps); 345 128 free(s); 129 + ps.pmu_glob = old_pmu_glob; 346 130 } else { 347 131 if (asprintf(&s, "*%s*", argv[i]) < 0) { 348 132 printf("Critical: Not enough memory! Trying to continue...\n"); 349 133 continue; 350 134 } 351 - print_symbol_events(s, PERF_TYPE_HARDWARE, 352 - event_symbols_hw, PERF_COUNT_HW_MAX, raw_dump); 353 - print_symbol_events(s, PERF_TYPE_SOFTWARE, 354 - event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); 355 - print_tool_events(s, raw_dump); 356 - print_hwcache_events(s, raw_dump); 357 - print_pmu_events(s, raw_dump, !desc_flag, 358 - long_desc_flag, 359 - details_flag, 360 - deprecated, 361 - pmu_name); 362 - print_tracepoint_events(NULL, s, raw_dump); 363 - print_sdt_events(NULL, s, raw_dump); 364 - metricgroup__print(true, true, s, raw_dump, details_flag, pmu_name); 135 + ps.event_glob = s; 136 + print_symbol_events(&print_cb, &ps, PERF_TYPE_HARDWARE, 137 + event_symbols_hw, PERF_COUNT_HW_MAX); 138 + print_symbol_events(&print_cb, &ps, PERF_TYPE_SOFTWARE, 139 + event_symbols_sw, PERF_COUNT_SW_MAX); 140 + print_tool_events(&print_cb, &ps); 141 + print_hwcache_events(&print_cb, &ps); 142 + print_pmu_events(&print_cb, &ps); 143 + print_tracepoint_events(&print_cb, &ps); 144 + print_sdt_events(&print_cb, &ps); 145 + ps.metrics = true; 146 + ps.metricgroups = true; 147 + metricgroup__print(&print_cb, &ps); 365 148 free(s); 366 149 } 367 150 } 368 151 369 152 out: 370 - free(pmu_name); 153 + print_cb.print_end(&ps); 154 + free(ps.pmu_glob); 155 + free(ps.last_topic); 156 + free(ps.last_metricgroups); 157 + strlist__delete(ps.visited_metrics); 371 158 return ret; 372 159 }
+68 -183
tools/perf/util/metricgroup.c
··· 12 12 #include "strbuf.h" 13 13 #include "pmu.h" 14 14 #include "pmu-hybrid.h" 15 + #include "print-events.h" 15 16 #include "expr.h" 16 17 #include "rblist.h" 17 18 #include <string.h> ··· 354 353 match_metric(pe->metric_name, metric); 355 354 } 356 355 356 + /** struct mep - RB-tree node for building printing information. */ 357 357 struct mep { 358 + /** nd - RB-tree element. */ 358 359 struct rb_node nd; 359 - const char *name; 360 - struct strlist *metrics; 360 + /** @metric_group: Owned metric group name, separated others with ';'. */ 361 + char *metric_group; 362 + const char *metric_name; 363 + const char *metric_desc; 364 + const char *metric_long_desc; 365 + const char *metric_expr; 366 + const char *metric_unit; 361 367 }; 362 368 363 369 static int mep_cmp(struct rb_node *rb_node, const void *entry) 364 370 { 365 371 struct mep *a = container_of(rb_node, struct mep, nd); 366 372 struct mep *b = (struct mep *)entry; 373 + int ret; 367 374 368 - return strcmp(a->name, b->name); 375 + ret = strcmp(a->metric_group, b->metric_group); 376 + if (ret) 377 + return ret; 378 + 379 + return strcmp(a->metric_name, b->metric_name); 369 380 } 370 381 371 - static struct rb_node *mep_new(struct rblist *rl __maybe_unused, 372 - const void *entry) 382 + static struct rb_node *mep_new(struct rblist *rl __maybe_unused, const void *entry) 373 383 { 374 384 struct mep *me = malloc(sizeof(struct mep)); 375 385 376 386 if (!me) 377 387 return NULL; 378 - memcpy(me, entry, sizeof(struct mep)); 379 - me->name = strdup(me->name); 380 - if (!me->name) 381 - goto out_me; 382 - me->metrics = strlist__new(NULL, NULL); 383 - if (!me->metrics) 384 - goto out_name; 385 - return &me->nd; 386 - out_name: 387 - zfree(&me->name); 388 - out_me: 389 - free(me); 390 - return NULL; 391 - } 392 388 393 - static struct mep *mep_lookup(struct rblist *groups, const char *name) 394 - { 395 - struct rb_node *nd; 396 - struct mep me = { 397 - .name = name 398 - }; 399 - nd = rblist__find(groups, &me); 400 - if (nd) 401 - return container_of(nd, struct mep, nd); 402 - rblist__add_node(groups, &me); 403 - nd = rblist__find(groups, &me); 404 - if (nd) 405 - return container_of(nd, struct mep, nd); 406 - return NULL; 389 + memcpy(me, entry, sizeof(struct mep)); 390 + return &me->nd; 407 391 } 408 392 409 393 static void mep_delete(struct rblist *rl __maybe_unused, ··· 396 410 { 397 411 struct mep *me = container_of(nd, struct mep, nd); 398 412 399 - strlist__delete(me->metrics); 400 - zfree(&me->name); 413 + zfree(&me->metric_group); 401 414 free(me); 402 415 } 403 416 404 - static void metricgroup__print_strlist(struct strlist *metrics, bool raw) 417 + static struct mep *mep_lookup(struct rblist *groups, const char *metric_group, 418 + const char *metric_name) 405 419 { 406 - struct str_node *sn; 407 - int n = 0; 408 - 409 - strlist__for_each_entry (sn, metrics) { 410 - if (raw) 411 - printf("%s%s", n > 0 ? " " : "", sn->s); 412 - else 413 - printf(" %s\n", sn->s); 414 - n++; 420 + struct rb_node *nd; 421 + struct mep me = { 422 + .metric_group = strdup(metric_group), 423 + .metric_name = metric_name, 424 + }; 425 + nd = rblist__find(groups, &me); 426 + if (nd) { 427 + free(me.metric_group); 428 + return container_of(nd, struct mep, nd); 415 429 } 416 - if (raw) 417 - putchar('\n'); 430 + rblist__add_node(groups, &me); 431 + nd = rblist__find(groups, &me); 432 + if (nd) 433 + return container_of(nd, struct mep, nd); 434 + return NULL; 418 435 } 419 436 420 - static int metricgroup__print_pmu_event(const struct pmu_event *pe, 421 - bool metricgroups, char *filter, 422 - bool raw, bool details, 423 - struct rblist *groups, 424 - struct strlist *metriclist) 437 + static int metricgroup__add_to_mep_groups(const struct pmu_event *pe, 438 + struct rblist *groups) 425 439 { 426 440 const char *g; 427 441 char *omg, *mg; 428 442 429 - g = pe->metric_group; 430 - if (!g && pe->metric_name) { 431 - if (pe->name) 432 - return 0; 433 - g = "No_group"; 434 - } 435 - 436 - if (!g) 437 - return 0; 438 - 439 - mg = strdup(g); 440 - 443 + mg = strdup(pe->metric_group ?: "No_group"); 441 444 if (!mg) 442 445 return -ENOMEM; 443 446 omg = mg; 444 447 while ((g = strsep(&mg, ";")) != NULL) { 445 448 struct mep *me; 446 - char *s; 447 449 448 450 g = skip_spaces(g); 449 - if (*g == 0) 450 - g = "No_group"; 451 - if (filter && !strstr(g, filter)) 452 - continue; 453 - if (raw) 454 - s = (char *)pe->metric_name; 455 - else { 456 - if (asprintf(&s, "%s\n%*s%s]", 457 - pe->metric_name, 8, "[", pe->desc) < 0) 458 - return -1; 459 - if (details) { 460 - if (asprintf(&s, "%s\n%*s%s]", 461 - s, 8, "[", pe->metric_expr) < 0) 462 - return -1; 463 - } 451 + if (strlen(g)) 452 + me = mep_lookup(groups, g, pe->metric_name); 453 + else 454 + me = mep_lookup(groups, "No_group", pe->metric_name); 455 + 456 + if (me) { 457 + me->metric_desc = pe->desc; 458 + me->metric_long_desc = pe->long_desc; 459 + me->metric_expr = pe->metric_expr; 460 + me->metric_unit = pe->unit; 464 461 } 465 - 466 - if (!s) 467 - continue; 468 - 469 - if (!metricgroups) { 470 - strlist__add(metriclist, s); 471 - } else { 472 - me = mep_lookup(groups, g); 473 - if (!me) 474 - continue; 475 - strlist__add(me->metrics, s); 476 - } 477 - 478 - if (!raw) 479 - free(s); 480 462 } 481 463 free(omg); 482 464 483 465 return 0; 484 466 } 485 - 486 - struct metricgroup_print_sys_idata { 487 - struct strlist *metriclist; 488 - char *filter; 489 - struct rblist *groups; 490 - bool metricgroups; 491 - bool raw; 492 - bool details; 493 - }; 494 467 495 468 struct metricgroup_iter_data { 496 469 pmu_event_iter_fn fn; ··· 473 528 474 529 return d->fn(pe, table, d->data); 475 530 } 476 - 477 531 return 0; 478 532 } 479 533 480 - static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, 481 - const struct pmu_events_table *table __maybe_unused, 482 - void *data) 534 + static int metricgroup__add_to_mep_groups_callback(const struct pmu_event *pe, 535 + const struct pmu_events_table *table __maybe_unused, 536 + void *vdata) 483 537 { 484 - struct metricgroup_print_sys_idata *d = data; 538 + struct rblist *groups = vdata; 485 539 486 - return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw, 487 - d->details, d->groups, d->metriclist); 488 - } 489 - 490 - struct metricgroup_print_data { 491 - const char *pmu_name; 492 - struct strlist *metriclist; 493 - char *filter; 494 - struct rblist *groups; 495 - bool metricgroups; 496 - bool raw; 497 - bool details; 498 - }; 499 - 500 - static int metricgroup__print_callback(const struct pmu_event *pe, 501 - const struct pmu_events_table *table __maybe_unused, 502 - void *vdata) 503 - { 504 - struct metricgroup_print_data *data = vdata; 505 - const char *pmu = pe->pmu ?: "cpu"; 506 - 507 - if (!pe->metric_expr) 540 + if (!pe->metric_name) 508 541 return 0; 509 542 510 - if (data->pmu_name && strcmp(data->pmu_name, pmu)) 511 - return 0; 512 - 513 - return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter, 514 - data->raw, data->details, data->groups, 515 - data->metriclist); 543 + return metricgroup__add_to_mep_groups(pe, groups); 516 544 } 517 545 518 - void metricgroup__print(bool metrics, bool metricgroups, char *filter, 519 - bool raw, bool details, const char *pmu_name) 546 + void metricgroup__print(const struct print_callbacks *print_cb, void *print_state) 520 547 { 521 548 struct rblist groups; 522 - struct rb_node *node, *next; 523 - struct strlist *metriclist = NULL; 524 549 const struct pmu_events_table *table; 525 - 526 - if (!metricgroups) { 527 - metriclist = strlist__new(NULL, NULL); 528 - if (!metriclist) 529 - return; 530 - } 550 + struct rb_node *node, *next; 531 551 532 552 rblist__init(&groups); 533 553 groups.node_new = mep_new; ··· 500 590 groups.node_delete = mep_delete; 501 591 table = pmu_events_table__find(); 502 592 if (table) { 503 - struct metricgroup_print_data data = { 504 - .pmu_name = pmu_name, 505 - .metriclist = metriclist, 506 - .metricgroups = metricgroups, 507 - .filter = filter, 508 - .raw = raw, 509 - .details = details, 510 - .groups = &groups, 511 - }; 512 - 513 593 pmu_events_table_for_each_event(table, 514 - metricgroup__print_callback, 515 - &data); 594 + metricgroup__add_to_mep_groups_callback, 595 + &groups); 516 596 } 517 597 { 518 598 struct metricgroup_iter_data data = { 519 - .fn = metricgroup__print_sys_event_iter, 520 - .data = (void *) &(struct metricgroup_print_sys_idata){ 521 - .metriclist = metriclist, 522 - .metricgroups = metricgroups, 523 - .filter = filter, 524 - .raw = raw, 525 - .details = details, 526 - .groups = &groups, 527 - }, 599 + .fn = metricgroup__add_to_mep_groups_callback, 600 + .data = &groups, 528 601 }; 529 - 530 602 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); 531 - } 532 - 533 - if (!filter || !rblist__empty(&groups)) { 534 - if (metricgroups && !raw) 535 - printf("\nMetric Groups:\n\n"); 536 - else if (metrics && !raw) 537 - printf("\nMetrics:\n\n"); 538 603 } 539 604 540 605 for (node = rb_first_cached(&groups.entries); node; node = next) { 541 606 struct mep *me = container_of(node, struct mep, nd); 542 607 543 - if (metricgroups) 544 - printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n"); 545 - if (metrics) 546 - metricgroup__print_strlist(me->metrics, raw); 608 + print_cb->print_metric(print_state, 609 + me->metric_group, 610 + me->metric_name, 611 + me->metric_desc, 612 + me->metric_long_desc, 613 + me->metric_expr, 614 + me->metric_unit); 547 615 next = rb_next(node); 548 616 rblist__remove_node(&groups, node); 549 617 } 550 - if (!metricgroups) 551 - metricgroup__print_strlist(metriclist, raw); 552 - strlist__delete(metriclist); 553 618 } 554 619 555 620 static const char *code_characters = ",-=@";
+2 -2
tools/perf/util/metricgroup.h
··· 10 10 struct evlist; 11 11 struct evsel; 12 12 struct option; 13 + struct print_callbacks; 13 14 struct rblist; 14 15 struct cgroup; 15 16 ··· 79 78 bool metric_no_merge, 80 79 struct rblist *metric_events); 81 80 82 - void metricgroup__print(bool metrics, bool groups, char *filter, 83 - bool raw, bool details, const char *pmu_name); 81 + void metricgroup__print(const struct print_callbacks *print_cb, void *print_state); 84 82 bool metricgroup__has_metric(const char *metric); 85 83 int arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused); 86 84 void metricgroup__rblist_exit(struct rblist *metric_events);
+52 -93
tools/perf/util/pmu.c
··· 23 23 #include "evsel.h" 24 24 #include "pmu.h" 25 25 #include "parse-events.h" 26 + #include "print-events.h" 26 27 #include "header.h" 27 28 #include "string2.h" 28 29 #include "strbuf.h" ··· 1580 1579 return buf; 1581 1580 } 1582 1581 1583 - static char *format_alias_or(char *buf, int len, const struct perf_pmu *pmu, 1584 - const struct perf_pmu_alias *alias) 1585 - { 1586 - snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1587 - return buf; 1588 - } 1589 - 1590 1582 /** Struct for ordering events as output in perf list. */ 1591 1583 struct sevent { 1592 1584 /** PMU for event. */ ··· 1623 1629 1624 1630 /* Order CPU core events to be first */ 1625 1631 if (as->is_cpu != bs->is_cpu) 1626 - return bs->is_cpu - as->is_cpu; 1632 + return as->is_cpu ? -1 : 1; 1627 1633 1628 1634 /* Order by PMU name. */ 1629 1635 a_pmu_name = as->pmu->name ?: ""; ··· 1634 1640 1635 1641 /* Order by event name. */ 1636 1642 return strcmp(a_name, b_name); 1637 - } 1638 - 1639 - static void wordwrap(char *s, int start, int max, int corr) 1640 - { 1641 - int column = start; 1642 - int n; 1643 - 1644 - while (*s) { 1645 - int wlen = strcspn(s, " \t"); 1646 - 1647 - if (column + wlen >= max && column > start) { 1648 - printf("\n%*s", start, ""); 1649 - column = start + corr; 1650 - } 1651 - n = printf("%s%.*s", column > start ? " " : "", wlen, s); 1652 - if (n <= 0) 1653 - break; 1654 - s += wlen; 1655 - column += n; 1656 - s = skip_spaces(s); 1657 - } 1658 1643 } 1659 1644 1660 1645 bool is_pmu_core(const char *name) ··· 1658 1685 return strcmp(a_pmu_name, b_pmu_name) == 0; 1659 1686 } 1660 1687 1661 - void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1662 - bool long_desc, bool details_flag, bool deprecated, 1663 - const char *pmu_name) 1688 + void print_pmu_events(const struct print_callbacks *print_cb, void *print_state) 1664 1689 { 1665 1690 struct perf_pmu *pmu; 1666 - struct perf_pmu_alias *alias; 1691 + struct perf_pmu_alias *event; 1667 1692 char buf[1024]; 1668 1693 int printed = 0; 1669 1694 int len, j; 1670 1695 struct sevent *aliases; 1671 - int numdesc = 0; 1672 - int columns = pager_get_columns(); 1673 - char *topic = NULL; 1674 1696 1675 1697 pmu = NULL; 1676 1698 len = 0; 1677 1699 while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1678 - list_for_each_entry(alias, &pmu->aliases, list) 1700 + list_for_each_entry(event, &pmu->aliases, list) 1679 1701 len++; 1680 1702 if (pmu->selectable) 1681 1703 len++; ··· 1683 1715 pmu = NULL; 1684 1716 j = 0; 1685 1717 while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1686 - bool is_cpu; 1718 + bool is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); 1687 1719 1688 - if (pmu_name && pmu->name && strcmp(pmu_name, pmu->name)) 1689 - continue; 1690 - 1691 - is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); 1692 - 1693 - list_for_each_entry(alias, &pmu->aliases, list) { 1694 - if (alias->deprecated && !deprecated) 1695 - continue; 1696 - 1697 - if (event_glob != NULL && 1698 - !(strglobmatch_nocase(alias->name, event_glob) || 1699 - (!is_cpu && 1700 - strglobmatch_nocase(alias->name, event_glob)) || 1701 - (alias->topic && 1702 - strglobmatch_nocase(alias->topic, event_glob)))) 1703 - continue; 1704 - 1705 - aliases[j].event = alias; 1720 + list_for_each_entry(event, &pmu->aliases, list) { 1721 + aliases[j].event = event; 1706 1722 aliases[j].pmu = pmu; 1707 1723 aliases[j].is_cpu = is_cpu; 1708 1724 j++; 1709 1725 } 1710 - if (pmu->selectable && 1711 - (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 1726 + if (pmu->selectable) { 1712 1727 aliases[j].event = NULL; 1713 1728 aliases[j].pmu = pmu; 1714 1729 aliases[j].is_cpu = is_cpu; ··· 1701 1750 len = j; 1702 1751 qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1703 1752 for (j = 0; j < len; j++) { 1704 - char *name, *desc; 1753 + const char *name, *alias = NULL, *scale_unit = NULL, 1754 + *desc = NULL, *long_desc = NULL, 1755 + *encoding_desc = NULL, *topic = NULL, 1756 + *metric_name = NULL, *metric_expr = NULL; 1757 + bool deprecated = false; 1758 + size_t buf_used; 1705 1759 1706 1760 /* Skip duplicates */ 1707 1761 if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) ··· 1714 1758 1715 1759 if (!aliases[j].event) { 1716 1760 /* A selectable event. */ 1717 - snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name); 1761 + buf_used = snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name) + 1; 1718 1762 name = buf; 1719 - } else if (aliases[j].event->desc) { 1720 - name = aliases[j].event->name; 1721 1763 } else { 1722 - if (!name_only && aliases[j].is_cpu) { 1723 - name = format_alias_or(buf, sizeof(buf), aliases[j].pmu, 1724 - aliases[j].event); 1764 + if (aliases[j].event->desc) { 1765 + name = aliases[j].event->name; 1766 + buf_used = 0; 1725 1767 } else { 1726 1768 name = format_alias(buf, sizeof(buf), aliases[j].pmu, 1727 1769 aliases[j].event); 1770 + if (aliases[j].is_cpu) { 1771 + alias = name; 1772 + name = aliases[j].event->name; 1773 + } 1774 + buf_used = strlen(buf) + 1; 1728 1775 } 1729 - } 1730 - if (name_only) { 1731 - printf("%s ", name); 1732 - continue; 1733 - } 1734 - printed++; 1735 - if (!aliases[j].event || !aliases[j].event->desc || quiet_flag) { 1736 - printf(" %-50s [Kernel PMU event]\n", name); 1737 - continue; 1738 - } 1739 - if (numdesc++ == 0) 1740 - printf("\n"); 1741 - if (aliases[j].event->topic && (!topic || 1742 - strcmp(topic, aliases[j].event->topic))) { 1743 - printf("%s%s:\n", topic ? "\n" : "", aliases[j].event->topic); 1776 + if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) { 1777 + scale_unit = buf + buf_used; 1778 + buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1779 + "%G%s", aliases[j].event->scale, 1780 + aliases[j].event->unit) + 1; 1781 + } 1782 + desc = aliases[j].event->desc; 1783 + long_desc = aliases[j].event->long_desc; 1744 1784 topic = aliases[j].event->topic; 1785 + encoding_desc = buf + buf_used; 1786 + buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1787 + "%s/%s/", aliases[j].pmu->name, 1788 + aliases[j].event->str) + 1; 1789 + metric_name = aliases[j].event->metric_name; 1790 + metric_expr = aliases[j].event->metric_expr; 1791 + deprecated = aliases[j].event->deprecated; 1745 1792 } 1746 - printf(" %-50s\n", name); 1747 - printf("%*s", 8, "["); 1748 - desc = long_desc ? aliases[j].event->long_desc : aliases[j].event->desc; 1749 - wordwrap(desc, 8, columns, 0); 1750 - printf("]\n"); 1751 - if (details_flag) { 1752 - printf("%*s%s/%s/ ", 8, "", aliases[j].pmu->name, aliases[j].event->str); 1753 - if (aliases[j].event->metric_name) 1754 - printf(" MetricName: %s", aliases[j].event->metric_name); 1755 - if (aliases[j].event->metric_expr) 1756 - printf(" MetricExpr: %s", aliases[j].event->metric_expr); 1757 - putchar('\n'); 1758 - } 1793 + print_cb->print_event(print_state, 1794 + aliases[j].pmu->name, 1795 + topic, 1796 + name, 1797 + alias, 1798 + scale_unit, 1799 + deprecated, 1800 + "Kernel PMU event", 1801 + desc, 1802 + long_desc, 1803 + encoding_desc, 1804 + metric_name, 1805 + metric_expr); 1759 1806 } 1760 1807 if (printed && pager_in_use()) 1761 1808 printf("\n");
+2 -3
tools/perf/util/pmu.h
··· 12 12 13 13 struct evsel_config_term; 14 14 struct perf_cpu_map; 15 + struct print_callbacks; 15 16 16 17 enum { 17 18 PERF_PMU_FORMAT_VALUE_CONFIG, ··· 226 225 struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 227 226 228 227 bool is_pmu_core(const char *name); 229 - void print_pmu_events(const char *event_glob, bool name_only, bool quiet, 230 - bool long_desc, bool details_flag, 231 - bool deprecated, const char *pmu_name); 228 + void print_pmu_events(const struct print_callbacks *print_cb, void *print_state); 232 229 bool pmu_have_event(const char *pname, const char *name); 233 230 234 231 int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4);
+185 -163
tools/perf/util/print-events.c
··· 28 28 29 29 #define MAX_NAME_LEN 100 30 30 31 + /** Strings corresponding to enum perf_type_id. */ 31 32 static const char * const event_type_descriptors[] = { 32 33 "Hardware event", 33 34 "Software event", ··· 56 55 /* 57 56 * Print the events from <debugfs_mount_point>/tracing/events 58 57 */ 59 - void print_tracepoint_events(const char *subsys_glob, 60 - const char *event_glob, bool name_only) 58 + void print_tracepoint_events(const struct print_callbacks *print_cb, void *print_state) 61 59 { 62 60 struct dirent **sys_namelist = NULL; 63 - bool printed = false; 64 61 int sys_items = tracing_events__scandir_alphasort(&sys_namelist); 65 62 66 63 for (int i = 0; i < sys_items; i++) { ··· 70 71 if (sys_dirent->d_type != DT_DIR || 71 72 !strcmp(sys_dirent->d_name, ".") || 72 73 !strcmp(sys_dirent->d_name, "..")) 73 - continue; 74 - 75 - if (subsys_glob != NULL && 76 - !strglobmatch(sys_dirent->d_name, subsys_glob)) 77 74 continue; 78 75 79 76 dir_path = get_events_file(sys_dirent->d_name); ··· 89 94 if (tp_event_has_id(dir_path, evt_dirent) != 0) 90 95 continue; 91 96 92 - if (event_glob != NULL && 93 - !strglobmatch(evt_dirent->d_name, event_glob)) 94 - continue; 95 - 96 97 snprintf(evt_path, MAXPATHLEN, "%s:%s", 97 98 sys_dirent->d_name, evt_dirent->d_name); 98 - if (name_only) 99 - printf("%s ", evt_path); 100 - else { 101 - printf(" %-50s [%s]\n", evt_path, 102 - event_type_descriptors[PERF_TYPE_TRACEPOINT]); 103 - } 104 - printed = true; 99 + print_cb->print_event(print_state, 100 + /*topic=*/NULL, 101 + /*pmu_name=*/NULL, 102 + evt_path, 103 + /*event_alias=*/NULL, 104 + /*scale_unit=*/NULL, 105 + /*deprecated=*/false, 106 + "Tracepoint event", 107 + /*desc=*/NULL, 108 + /*long_desc=*/NULL, 109 + /*encoding_desc=*/NULL, 110 + /*metric_name=*/NULL, 111 + /*metric_expr=*/NULL); 105 112 } 106 113 free(dir_path); 107 114 free(evt_namelist); 108 115 } 109 116 free(sys_namelist); 110 - if (printed && pager_in_use()) 111 - printf("\n"); 112 117 } 113 118 114 - void print_sdt_events(const char *subsys_glob, const char *event_glob, 115 - bool name_only) 119 + void print_sdt_events(const struct print_callbacks *print_cb, void *print_state) 116 120 { 117 - struct probe_cache *pcache; 118 - struct probe_cache_entry *ent; 119 121 struct strlist *bidlist, *sdtlist; 120 - struct strlist_config cfg = {.dont_dupstr = true}; 121 - struct str_node *nd, *nd2; 122 - char *buf, *path, *ptr = NULL; 123 - bool show_detail = false; 124 - int ret; 122 + struct str_node *bid_nd, *sdt_name, *next_sdt_name; 123 + const char *last_sdt_name = NULL; 125 124 126 - sdtlist = strlist__new(NULL, &cfg); 125 + /* 126 + * The implicitly sorted sdtlist will hold the tracepoint name followed 127 + * by @<buildid>. If the tracepoint name is unique (determined by 128 + * looking at the adjacent nodes) the @<buildid> is dropped otherwise 129 + * the executable path and buildid are added to the name. 130 + */ 131 + sdtlist = strlist__new(NULL, NULL); 127 132 if (!sdtlist) { 128 133 pr_debug("Failed to allocate new strlist for SDT\n"); 129 134 return; ··· 133 138 pr_debug("Failed to get buildids: %d\n", errno); 134 139 return; 135 140 } 136 - strlist__for_each_entry(nd, bidlist) { 137 - pcache = probe_cache__new(nd->s, NULL); 141 + strlist__for_each_entry(bid_nd, bidlist) { 142 + struct probe_cache *pcache; 143 + struct probe_cache_entry *ent; 144 + 145 + pcache = probe_cache__new(bid_nd->s, NULL); 138 146 if (!pcache) 139 147 continue; 140 148 list_for_each_entry(ent, &pcache->entries, node) { 141 - if (!ent->sdt) 142 - continue; 143 - if (subsys_glob && 144 - !strglobmatch(ent->pev.group, subsys_glob)) 145 - continue; 146 - if (event_glob && 147 - !strglobmatch(ent->pev.event, event_glob)) 148 - continue; 149 - ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, 150 - ent->pev.event, nd->s); 151 - if (ret > 0) 152 - strlist__add(sdtlist, buf); 149 + char buf[1024]; 150 + 151 + snprintf(buf, sizeof(buf), "%s:%s@%s", 152 + ent->pev.group, ent->pev.event, bid_nd->s); 153 + strlist__add(sdtlist, buf); 153 154 } 154 155 probe_cache__delete(pcache); 155 156 } 156 157 strlist__delete(bidlist); 157 158 158 - strlist__for_each_entry(nd, sdtlist) { 159 - buf = strchr(nd->s, '@'); 160 - if (buf) 161 - *(buf++) = '\0'; 162 - if (name_only) { 163 - printf("%s ", nd->s); 164 - continue; 165 - } 166 - nd2 = strlist__next(nd); 167 - if (nd2) { 168 - ptr = strchr(nd2->s, '@'); 169 - if (ptr) 170 - *ptr = '\0'; 171 - if (strcmp(nd->s, nd2->s) == 0) 172 - show_detail = true; 173 - } 174 - if (show_detail) { 175 - path = build_id_cache__origname(buf); 176 - ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); 177 - if (ret > 0) { 178 - printf(" %-50s [%s]\n", buf, "SDT event"); 179 - free(buf); 159 + strlist__for_each_entry(sdt_name, sdtlist) { 160 + bool show_detail = false; 161 + char *bid = strchr(sdt_name->s, '@'); 162 + char *evt_name = NULL; 163 + 164 + if (bid) 165 + *(bid++) = '\0'; 166 + 167 + if (last_sdt_name && !strcmp(last_sdt_name, sdt_name->s)) { 168 + show_detail = true; 169 + } else { 170 + next_sdt_name = strlist__next(sdt_name); 171 + if (next_sdt_name) { 172 + char *bid2 = strchr(next_sdt_name->s, '@'); 173 + 174 + if (bid2) 175 + *bid2 = '\0'; 176 + if (strcmp(sdt_name->s, next_sdt_name->s) == 0) 177 + show_detail = true; 178 + if (bid2) 179 + *bid2 = '@'; 180 180 } 181 - free(path); 182 - } else 183 - printf(" %-50s [%s]\n", nd->s, "SDT event"); 184 - if (nd2) { 185 - if (strcmp(nd->s, nd2->s) != 0) 186 - show_detail = false; 187 - if (ptr) 188 - *ptr = '@'; 189 181 } 182 + last_sdt_name = sdt_name->s; 183 + 184 + if (show_detail) { 185 + char *path = build_id_cache__origname(bid); 186 + 187 + if (path) { 188 + if (asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid) < 0) 189 + evt_name = NULL; 190 + free(path); 191 + } 192 + } 193 + print_cb->print_event(print_state, 194 + /*topic=*/NULL, 195 + /*pmu_name=*/NULL, 196 + evt_name ?: sdt_name->s, 197 + /*event_alias=*/NULL, 198 + /*deprecated=*/false, 199 + /*scale_unit=*/NULL, 200 + "SDT event", 201 + /*desc=*/NULL, 202 + /*long_desc=*/NULL, 203 + /*encoding_desc=*/NULL, 204 + /*metric_name=*/NULL, 205 + /*metric_expr=*/NULL); 206 + 207 + free(evt_name); 190 208 } 191 209 strlist__delete(sdtlist); 192 210 } 193 211 194 - int print_hwcache_events(const char *event_glob, bool name_only) 212 + int print_hwcache_events(const struct print_callbacks *print_cb, void *print_state) 195 213 { 196 214 struct strlist *evt_name_list = strlist__new(NULL, NULL); 197 215 struct str_node *nd; ··· 224 216 char name[64]; 225 217 226 218 __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); 227 - if (event_glob != NULL && !strglobmatch(name, event_glob)) 228 - continue; 229 - 230 219 if (!perf_pmu__has_hybrid()) { 231 220 if (is_event_supported(PERF_TYPE_HW_CACHE, 232 221 type | (op << 8) | (i << 16))) ··· 245 240 } 246 241 247 242 strlist__for_each_entry(nd, evt_name_list) { 248 - if (name_only) { 249 - printf("%s ", nd->s); 250 - continue; 251 - } 252 - printf(" %-50s [%s]\n", nd->s, event_type_descriptors[PERF_TYPE_HW_CACHE]); 243 + print_cb->print_event(print_state, 244 + "cache", 245 + /*pmu_name=*/NULL, 246 + nd->s, 247 + /*event_alias=*/NULL, 248 + /*scale_unit=*/NULL, 249 + /*deprecated=*/false, 250 + event_type_descriptors[PERF_TYPE_HW_CACHE], 251 + /*desc=*/NULL, 252 + /*long_desc=*/NULL, 253 + /*encoding_desc=*/NULL, 254 + /*metric_name=*/NULL, 255 + /*metric_expr=*/NULL); 253 256 } 254 - if (!strlist__empty(evt_name_list) && pager_in_use()) 255 - printf("\n"); 256 - 257 257 strlist__delete(evt_name_list); 258 258 return 0; 259 259 } 260 260 261 - static void print_tool_event(const struct event_symbol *syms, const char *event_glob, 262 - bool name_only) 261 + void print_tool_events(const struct print_callbacks *print_cb, void *print_state) 263 262 { 264 - if (syms->symbol == NULL) 265 - return; 266 - 267 - if (event_glob && !(strglobmatch(syms->symbol, event_glob) || 268 - (syms->alias && strglobmatch(syms->alias, event_glob)))) 269 - return; 270 - 271 - if (name_only) 272 - printf("%s ", syms->symbol); 273 - else { 274 - char name[MAX_NAME_LEN]; 275 - 276 - if (syms->alias && strlen(syms->alias)) 277 - snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); 278 - else 279 - strlcpy(name, syms->symbol, MAX_NAME_LEN); 280 - printf(" %-50s [%s]\n", name, "Tool event"); 263 + // Start at 1 because the first enum entry means no tool event. 264 + for (int i = 1; i < PERF_TOOL_MAX; ++i) { 265 + print_cb->print_event(print_state, 266 + "tool", 267 + /*pmu_name=*/NULL, 268 + event_symbols_tool[i].symbol, 269 + event_symbols_tool[i].alias, 270 + /*scale_unit=*/NULL, 271 + /*deprecated=*/false, 272 + "Tool event", 273 + /*desc=*/NULL, 274 + /*long_desc=*/NULL, 275 + /*encoding_desc=*/NULL, 276 + /*metric_name=*/NULL, 277 + /*metric_expr=*/NULL); 281 278 } 282 279 } 283 280 284 - void print_tool_events(const char *event_glob, bool name_only) 285 - { 286 - // Start at 1 because the first enum entry means no tool event. 287 - for (int i = 1; i < PERF_TOOL_MAX; ++i) 288 - print_tool_event(event_symbols_tool + i, event_glob, name_only); 289 - 290 - if (pager_in_use()) 291 - printf("\n"); 292 - } 293 - 294 - void print_symbol_events(const char *event_glob, unsigned int type, 295 - struct event_symbol *syms, unsigned int max, 296 - bool name_only) 281 + void print_symbol_events(const struct print_callbacks *print_cb, void *print_state, 282 + unsigned int type, const struct event_symbol *syms, 283 + unsigned int max) 297 284 { 298 285 struct strlist *evt_name_list = strlist__new(NULL, NULL); 299 286 struct str_node *nd; ··· 302 305 if (syms[i].symbol == NULL) 303 306 continue; 304 307 305 - if (event_glob != NULL && !(strglobmatch(syms[i].symbol, event_glob) || 306 - (syms[i].alias && strglobmatch(syms[i].alias, event_glob)))) 307 - continue; 308 - 309 308 if (!is_event_supported(type, i)) 310 309 continue; 311 310 ··· 315 322 } 316 323 317 324 strlist__for_each_entry(nd, evt_name_list) { 318 - if (name_only) { 319 - printf("%s ", nd->s); 320 - continue; 321 - } 322 - printf(" %-50s [%s]\n", nd->s, event_type_descriptors[type]); 323 - } 324 - if (!strlist__empty(evt_name_list) && pager_in_use()) 325 - printf("\n"); 325 + char *alias = strstr(nd->s, " OR "); 326 326 327 + if (alias) { 328 + *alias = '\0'; 329 + alias += 4; 330 + } 331 + print_cb->print_event(print_state, 332 + /*topic=*/NULL, 333 + /*pmu_name=*/NULL, 334 + nd->s, 335 + alias, 336 + /*scale_unit=*/NULL, 337 + /*deprecated=*/false, 338 + event_type_descriptors[type], 339 + /*desc=*/NULL, 340 + /*long_desc=*/NULL, 341 + /*encoding_desc=*/NULL, 342 + /*metric_name=*/NULL, 343 + /*metric_expr=*/NULL); 344 + } 327 345 strlist__delete(evt_name_list); 328 346 } 329 347 330 348 /* 331 349 * Print the help text for the event symbols: 332 350 */ 333 - void print_events(const char *event_glob, bool name_only, bool quiet_flag, 334 - bool long_desc, bool details_flag, bool deprecated, 335 - const char *pmu_name) 351 + void print_events(const struct print_callbacks *print_cb, void *print_state) 336 352 { 337 - print_symbol_events(event_glob, PERF_TYPE_HARDWARE, 338 - event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 353 + print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE, 354 + event_symbols_hw, PERF_COUNT_HW_MAX); 355 + print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE, 356 + event_symbols_sw, PERF_COUNT_SW_MAX); 339 357 340 - print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, 341 - event_symbols_sw, PERF_COUNT_SW_MAX, name_only); 342 - print_tool_events(event_glob, name_only); 358 + print_tool_events(print_cb, print_state); 343 359 344 - print_hwcache_events(event_glob, name_only); 360 + print_hwcache_events(print_cb, print_state); 345 361 346 - print_pmu_events(event_glob, name_only, quiet_flag, long_desc, 347 - details_flag, deprecated, pmu_name); 362 + print_pmu_events(print_cb, print_state); 348 363 349 - if (event_glob != NULL) 350 - return; 364 + print_cb->print_event(print_state, 365 + /*topic=*/NULL, 366 + /*pmu_name=*/NULL, 367 + "rNNN", 368 + /*event_alias=*/NULL, 369 + /*scale_unit=*/NULL, 370 + /*deprecated=*/false, 371 + event_type_descriptors[PERF_TYPE_RAW], 372 + /*desc=*/NULL, 373 + /*long_desc=*/NULL, 374 + /*encoding_desc=*/NULL, 375 + /*metric_name=*/NULL, 376 + /*metric_expr=*/NULL); 351 377 352 - if (!name_only) { 353 - printf(" %-50s [%s]\n", 354 - "rNNN", 355 - event_type_descriptors[PERF_TYPE_RAW]); 356 - printf(" %-50s [%s]\n", 357 - "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 358 - event_type_descriptors[PERF_TYPE_RAW]); 359 - if (pager_in_use()) 360 - printf(" (see 'man perf-list' on how to encode it)\n\n"); 378 + print_cb->print_event(print_state, 379 + /*topic=*/NULL, 380 + /*pmu_name=*/NULL, 381 + "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 382 + /*event_alias=*/NULL, 383 + /*scale_unit=*/NULL, 384 + /*deprecated=*/false, 385 + event_type_descriptors[PERF_TYPE_RAW], 386 + "(see 'man perf-list' on how to encode it)", 387 + /*long_desc=*/NULL, 388 + /*encoding_desc=*/NULL, 389 + /*metric_name=*/NULL, 390 + /*metric_expr=*/NULL); 361 391 362 - printf(" %-50s [%s]\n", 363 - "mem:<addr>[/len][:access]", 364 - event_type_descriptors[PERF_TYPE_BREAKPOINT]); 365 - if (pager_in_use()) 366 - printf("\n"); 367 - } 392 + print_cb->print_event(print_state, 393 + /*topic=*/NULL, 394 + /*pmu_name=*/NULL, 395 + "mem:<addr>[/len][:access]", 396 + /*scale_unit=*/NULL, 397 + /*event_alias=*/NULL, 398 + /*deprecated=*/false, 399 + event_type_descriptors[PERF_TYPE_BREAKPOINT], 400 + /*desc=*/NULL, 401 + /*long_desc=*/NULL, 402 + /*encoding_desc=*/NULL, 403 + /*metric_name=*/NULL, 404 + /*metric_expr=*/NULL); 368 405 369 - print_tracepoint_events(NULL, NULL, name_only); 406 + print_tracepoint_events(print_cb, print_state); 370 407 371 - print_sdt_events(NULL, NULL, name_only); 408 + print_sdt_events(print_cb, print_state); 372 409 373 - metricgroup__print(true, true, NULL, name_only, details_flag, 374 - pmu_name); 410 + metricgroup__print(print_cb, print_state); 375 411 376 - print_libpfm_events(name_only, long_desc); 412 + print_libpfm_events(print_cb, print_state); 377 413 }
+30 -12
tools/perf/util/print-events.h
··· 2 2 #ifndef __PERF_PRINT_EVENTS_H 3 3 #define __PERF_PRINT_EVENTS_H 4 4 5 + #include <linux/perf_event.h> 5 6 #include <stdbool.h> 6 7 7 8 struct event_symbol; 8 9 9 - void print_events(const char *event_glob, bool name_only, bool quiet_flag, 10 - bool long_desc, bool details_flag, bool deprecated, 11 - const char *pmu_name); 12 - int print_hwcache_events(const char *event_glob, bool name_only); 13 - void print_sdt_events(const char *subsys_glob, const char *event_glob, 14 - bool name_only); 15 - void print_symbol_events(const char *event_glob, unsigned int type, 16 - struct event_symbol *syms, unsigned int max, 17 - bool name_only); 18 - void print_tool_events(const char *event_glob, bool name_only); 19 - void print_tracepoint_events(const char *subsys_glob, const char *event_glob, 20 - bool name_only); 10 + struct print_callbacks { 11 + void (*print_start)(void *print_state); 12 + void (*print_end)(void *print_state); 13 + void (*print_event)(void *print_state, const char *topic, 14 + const char *pmu_name, 15 + const char *event_name, const char *event_alias, 16 + const char *scale_unit, 17 + bool deprecated, const char *event_type_desc, 18 + const char *desc, const char *long_desc, 19 + const char *encoding_desc, 20 + const char *metric_name, const char *metric_expr); 21 + void (*print_metric)(void *print_state, 22 + const char *group, 23 + const char *name, 24 + const char *desc, 25 + const char *long_desc, 26 + const char *expr, 27 + const char *unit); 28 + }; 29 + 30 + /** Print all events, the default when no options are specified. */ 31 + void print_events(const struct print_callbacks *print_cb, void *print_state); 32 + int print_hwcache_events(const struct print_callbacks *print_cb, void *print_state); 33 + void print_sdt_events(const struct print_callbacks *print_cb, void *print_state); 34 + void print_symbol_events(const struct print_callbacks *print_cb, void *print_state, 35 + unsigned int type, const struct event_symbol *syms, 36 + unsigned int max); 37 + void print_tool_events(const struct print_callbacks *print_cb, void *print_state); 38 + void print_tracepoint_events(const struct print_callbacks *print_cb, void *print_state); 21 39 22 40 #endif /* __PERF_PRINT_EVENTS_H */