1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017, Intel Corporation. 4 */ 5 6 /* Manage metrics and groups of metrics from JSON files */ 7 8 #include "metricgroup.h" 9 #include "debug.h" 10 #include "evlist.h" 11 #include "evsel.h" 12 #include "strbuf.h" 13 #include "pmu.h" 14 #include "pmu-hybrid.h" 15 #include "expr.h" 16 #include "rblist.h" 17 #include <string.h> 18 #include <errno.h> 19 #include "strlist.h" 20 #include <assert.h> 21 #include <linux/ctype.h> 22 #include <linux/list_sort.h> 23 #include <linux/string.h> 24 #include <linux/zalloc.h> 25 #include <perf/cpumap.h> 26 #include <subcmd/parse-options.h> 27 #include <api/fs/fs.h> 28 #include "util.h" 29 #include <asm/bug.h> 30 #include "cgroup.h" 31 #include "util/hashmap.h" 32 33 struct metric_event *metricgroup__lookup(struct rblist *metric_events, 34 struct evsel *evsel, 35 bool create) 36 { 37 struct rb_node *nd; 38 struct metric_event me = { 39 .evsel = evsel 40 }; 41 42 if (!metric_events) 43 return NULL; 44 45 nd = rblist__find(metric_events, &me); 46 if (nd) 47 return container_of(nd, struct metric_event, nd); 48 if (create) { 49 rblist__add_node(metric_events, &me); 50 nd = rblist__find(metric_events, &me); 51 if (nd) 52 return container_of(nd, struct metric_event, nd); 53 } 54 return NULL; 55 } 56 57 static int metric_event_cmp(struct rb_node *rb_node, const void *entry) 58 { 59 struct metric_event *a = container_of(rb_node, 60 struct metric_event, 61 nd); 62 const struct metric_event *b = entry; 63 64 if (a->evsel == b->evsel) 65 return 0; 66 if ((char *)a->evsel < (char *)b->evsel) 67 return -1; 68 return +1; 69 } 70 71 static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused, 72 const void *entry) 73 { 74 struct metric_event *me = malloc(sizeof(struct metric_event)); 75 76 if (!me) 77 return NULL; 78 memcpy(me, entry, sizeof(struct metric_event)); 79 me->evsel = ((struct metric_event *)entry)->evsel; 80 INIT_LIST_HEAD(&me->head); 81 return &me->nd; 82 } 83 84 static void metric_event_delete(struct rblist *rblist __maybe_unused, 85 struct rb_node *rb_node) 86 { 87 struct metric_event *me = container_of(rb_node, struct metric_event, nd); 88 struct metric_expr *expr, *tmp; 89 90 list_for_each_entry_safe(expr, tmp, &me->head, nd) { 91 free((char *)expr->metric_name); 92 free(expr->metric_refs); 93 free(expr->metric_events); 94 free(expr); 95 } 96 97 free(me); 98 } 99 100 static void metricgroup__rblist_init(struct rblist *metric_events) 101 { 102 rblist__init(metric_events); 103 metric_events->node_cmp = metric_event_cmp; 104 metric_events->node_new = metric_event_new; 105 metric_events->node_delete = metric_event_delete; 106 } 107 108 void metricgroup__rblist_exit(struct rblist *metric_events) 109 { 110 rblist__exit(metric_events); 111 } 112 113 /** 114 * The metric under construction. The data held here will be placed in a 115 * metric_expr. 116 */ 117 struct metric { 118 struct list_head nd; 119 /** 120 * The expression parse context importantly holding the IDs contained 121 * within the expression. 122 */ 123 struct expr_parse_ctx *pctx; 124 /** The name of the metric such as "IPC". */ 125 const char *metric_name; 126 /** Modifier on the metric such as "u" or NULL for none. */ 127 const char *modifier; 128 /** The expression to parse, for example, "instructions/cycles". */ 129 const char *metric_expr; 130 /** 131 * The "ScaleUnit" that scales and adds a unit to the metric during 132 * output. 133 */ 134 const char *metric_unit; 135 /** Optional null terminated array of referenced metrics. */ 136 struct metric_ref *metric_refs; 137 /** 138 * Is there a constraint on the group of events? In which case the 139 * events won't be grouped. 140 */ 141 bool has_constraint; 142 /** 143 * Parsed events for the metric. Optional as events may be taken from a 144 * different metric whose group contains all the IDs necessary for this 145 * one. 146 */ 147 struct evlist *evlist; 148 }; 149 150 static void metricgroup___watchdog_constraint_hint(const char *name, bool foot) 151 { 152 static bool violate_nmi_constraint; 153 154 if (!foot) { 155 pr_warning("Splitting metric group %s into standalone metrics.\n", name); 156 violate_nmi_constraint = true; 157 return; 158 } 159 160 if (!violate_nmi_constraint) 161 return; 162 163 pr_warning("Try disabling the NMI watchdog to comply NO_NMI_WATCHDOG metric constraint:\n" 164 " echo 0 > /proc/sys/kernel/nmi_watchdog\n" 165 " perf stat ...\n" 166 " echo 1 > /proc/sys/kernel/nmi_watchdog\n"); 167 } 168 169 static bool metricgroup__has_constraint(const struct pmu_event *pe) 170 { 171 if (!pe->metric_constraint) 172 return false; 173 174 if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") && 175 sysctl__nmi_watchdog_enabled()) { 176 metricgroup___watchdog_constraint_hint(pe->metric_name, false); 177 return true; 178 } 179 180 return false; 181 } 182 183 static void metric__free(struct metric *m) 184 { 185 if (!m) 186 return; 187 188 free(m->metric_refs); 189 expr__ctx_free(m->pctx); 190 free((char *)m->modifier); 191 evlist__delete(m->evlist); 192 free(m); 193 } 194 195 static struct metric *metric__new(const struct pmu_event *pe, 196 const char *modifier, 197 bool metric_no_group, 198 int runtime, 199 const char *user_requested_cpu_list, 200 bool system_wide) 201 { 202 struct metric *m; 203 204 m = zalloc(sizeof(*m)); 205 if (!m) 206 return NULL; 207 208 m->pctx = expr__ctx_new(); 209 if (!m->pctx) 210 goto out_err; 211 212 m->metric_name = pe->metric_name; 213 m->modifier = NULL; 214 if (modifier) { 215 m->modifier = strdup(modifier); 216 if (!m->modifier) 217 goto out_err; 218 } 219 m->metric_expr = pe->metric_expr; 220 m->metric_unit = pe->unit; 221 m->pctx->sctx.user_requested_cpu_list = NULL; 222 if (user_requested_cpu_list) { 223 m->pctx->sctx.user_requested_cpu_list = strdup(user_requested_cpu_list); 224 if (!m->pctx->sctx.user_requested_cpu_list) 225 goto out_err; 226 } 227 m->pctx->sctx.runtime = runtime; 228 m->pctx->sctx.system_wide = system_wide; 229 m->has_constraint = metric_no_group || metricgroup__has_constraint(pe); 230 m->metric_refs = NULL; 231 m->evlist = NULL; 232 233 return m; 234 out_err: 235 metric__free(m); 236 return NULL; 237 } 238 239 static bool contains_metric_id(struct evsel **metric_events, int num_events, 240 const char *metric_id) 241 { 242 int i; 243 244 for (i = 0; i < num_events; i++) { 245 if (!strcmp(evsel__metric_id(metric_events[i]), metric_id)) 246 return true; 247 } 248 return false; 249 } 250 251 /** 252 * setup_metric_events - Find a group of events in metric_evlist that correspond 253 * to the IDs from a parsed metric expression. 254 * @ids: the metric IDs to match. 255 * @metric_evlist: the list of perf events. 256 * @out_metric_events: holds the created metric events array. 257 */ 258 static int setup_metric_events(struct hashmap *ids, 259 struct evlist *metric_evlist, 260 struct evsel ***out_metric_events) 261 { 262 struct evsel **metric_events; 263 const char *metric_id; 264 struct evsel *ev; 265 size_t ids_size, matched_events, i; 266 267 *out_metric_events = NULL; 268 ids_size = hashmap__size(ids); 269 270 metric_events = calloc(sizeof(void *), ids_size + 1); 271 if (!metric_events) 272 return -ENOMEM; 273 274 matched_events = 0; 275 evlist__for_each_entry(metric_evlist, ev) { 276 struct expr_id_data *val_ptr; 277 278 /* 279 * Check for duplicate events with the same name. For 280 * example, uncore_imc/cas_count_read/ will turn into 6 281 * events per socket on skylakex. Only the first such 282 * event is placed in metric_events. 283 */ 284 metric_id = evsel__metric_id(ev); 285 if (contains_metric_id(metric_events, matched_events, metric_id)) 286 continue; 287 /* 288 * Does this event belong to the parse context? For 289 * combined or shared groups, this metric may not care 290 * about this event. 291 */ 292 if (hashmap__find(ids, metric_id, (void **)&val_ptr)) { 293 metric_events[matched_events++] = ev; 294 295 if (matched_events >= ids_size) 296 break; 297 } 298 } 299 if (matched_events < ids_size) { 300 free(metric_events); 301 return -EINVAL; 302 } 303 for (i = 0; i < ids_size; i++) { 304 ev = metric_events[i]; 305 ev->collect_stat = true; 306 307 /* 308 * The metric leader points to the identically named 309 * event in metric_events. 310 */ 311 ev->metric_leader = ev; 312 /* 313 * Mark two events with identical names in the same 314 * group (or globally) as being in use as uncore events 315 * may be duplicated for each pmu. Set the metric leader 316 * of such events to be the event that appears in 317 * metric_events. 318 */ 319 metric_id = evsel__metric_id(ev); 320 evlist__for_each_entry_continue(metric_evlist, ev) { 321 if (!strcmp(evsel__metric_id(ev), metric_id)) 322 ev->metric_leader = metric_events[i]; 323 } 324 } 325 *out_metric_events = metric_events; 326 return 0; 327 } 328 329 static bool match_metric(const char *n, const char *list) 330 { 331 int len; 332 char *m; 333 334 if (!list) 335 return false; 336 if (!strcmp(list, "all")) 337 return true; 338 if (!n) 339 return !strcasecmp(list, "No_group"); 340 len = strlen(list); 341 m = strcasestr(n, list); 342 if (!m) 343 return false; 344 if ((m == n || m[-1] == ';' || m[-1] == ' ') && 345 (m[len] == 0 || m[len] == ';')) 346 return true; 347 return false; 348 } 349 350 static bool match_pe_metric(const struct pmu_event *pe, const char *metric) 351 { 352 return match_metric(pe->metric_group, metric) || 353 match_metric(pe->metric_name, metric); 354 } 355 356 struct mep { 357 struct rb_node nd; 358 const char *name; 359 struct strlist *metrics; 360 }; 361 362 static int mep_cmp(struct rb_node *rb_node, const void *entry) 363 { 364 struct mep *a = container_of(rb_node, struct mep, nd); 365 struct mep *b = (struct mep *)entry; 366 367 return strcmp(a->name, b->name); 368 } 369 370 static struct rb_node *mep_new(struct rblist *rl __maybe_unused, 371 const void *entry) 372 { 373 struct mep *me = malloc(sizeof(struct mep)); 374 375 if (!me) 376 return NULL; 377 memcpy(me, entry, sizeof(struct mep)); 378 me->name = strdup(me->name); 379 if (!me->name) 380 goto out_me; 381 me->metrics = strlist__new(NULL, NULL); 382 if (!me->metrics) 383 goto out_name; 384 return &me->nd; 385 out_name: 386 zfree(&me->name); 387 out_me: 388 free(me); 389 return NULL; 390 } 391 392 static struct mep *mep_lookup(struct rblist *groups, const char *name) 393 { 394 struct rb_node *nd; 395 struct mep me = { 396 .name = name 397 }; 398 nd = rblist__find(groups, &me); 399 if (nd) 400 return container_of(nd, struct mep, nd); 401 rblist__add_node(groups, &me); 402 nd = rblist__find(groups, &me); 403 if (nd) 404 return container_of(nd, struct mep, nd); 405 return NULL; 406 } 407 408 static void mep_delete(struct rblist *rl __maybe_unused, 409 struct rb_node *nd) 410 { 411 struct mep *me = container_of(nd, struct mep, nd); 412 413 strlist__delete(me->metrics); 414 zfree(&me->name); 415 free(me); 416 } 417 418 static void metricgroup__print_strlist(struct strlist *metrics, bool raw) 419 { 420 struct str_node *sn; 421 int n = 0; 422 423 strlist__for_each_entry (sn, metrics) { 424 if (raw) 425 printf("%s%s", n > 0 ? " " : "", sn->s); 426 else 427 printf(" %s\n", sn->s); 428 n++; 429 } 430 if (raw) 431 putchar('\n'); 432 } 433 434 static int metricgroup__print_pmu_event(const struct pmu_event *pe, 435 bool metricgroups, char *filter, 436 bool raw, bool details, 437 struct rblist *groups, 438 struct strlist *metriclist) 439 { 440 const char *g; 441 char *omg, *mg; 442 443 g = pe->metric_group; 444 if (!g && pe->metric_name) { 445 if (pe->name) 446 return 0; 447 g = "No_group"; 448 } 449 450 if (!g) 451 return 0; 452 453 mg = strdup(g); 454 455 if (!mg) 456 return -ENOMEM; 457 omg = mg; 458 while ((g = strsep(&mg, ";")) != NULL) { 459 struct mep *me; 460 char *s; 461 462 g = skip_spaces(g); 463 if (*g == 0) 464 g = "No_group"; 465 if (filter && !strstr(g, filter)) 466 continue; 467 if (raw) 468 s = (char *)pe->metric_name; 469 else { 470 if (asprintf(&s, "%s\n%*s%s]", 471 pe->metric_name, 8, "[", pe->desc) < 0) 472 return -1; 473 if (details) { 474 if (asprintf(&s, "%s\n%*s%s]", 475 s, 8, "[", pe->metric_expr) < 0) 476 return -1; 477 } 478 } 479 480 if (!s) 481 continue; 482 483 if (!metricgroups) { 484 strlist__add(metriclist, s); 485 } else { 486 me = mep_lookup(groups, g); 487 if (!me) 488 continue; 489 strlist__add(me->metrics, s); 490 } 491 492 if (!raw) 493 free(s); 494 } 495 free(omg); 496 497 return 0; 498 } 499 500 struct metricgroup_print_sys_idata { 501 struct strlist *metriclist; 502 char *filter; 503 struct rblist *groups; 504 bool metricgroups; 505 bool raw; 506 bool details; 507 }; 508 509 struct metricgroup_iter_data { 510 pmu_event_iter_fn fn; 511 void *data; 512 }; 513 514 static int metricgroup__sys_event_iter(const struct pmu_event *pe, 515 const struct pmu_events_table *table, 516 void *data) 517 { 518 struct metricgroup_iter_data *d = data; 519 struct perf_pmu *pmu = NULL; 520 521 if (!pe->metric_expr || !pe->compat) 522 return 0; 523 524 while ((pmu = perf_pmu__scan(pmu))) { 525 526 if (!pmu->id || strcmp(pmu->id, pe->compat)) 527 continue; 528 529 return d->fn(pe, table, d->data); 530 } 531 532 return 0; 533 } 534 535 static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, 536 const struct pmu_events_table *table __maybe_unused, 537 void *data) 538 { 539 struct metricgroup_print_sys_idata *d = data; 540 541 return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw, 542 d->details, d->groups, d->metriclist); 543 } 544 545 struct metricgroup_print_data { 546 const char *pmu_name; 547 struct strlist *metriclist; 548 char *filter; 549 struct rblist *groups; 550 bool metricgroups; 551 bool raw; 552 bool details; 553 }; 554 555 static int metricgroup__print_callback(const struct pmu_event *pe, 556 const struct pmu_events_table *table __maybe_unused, 557 void *vdata) 558 { 559 struct metricgroup_print_data *data = vdata; 560 const char *pmu = pe->pmu ?: "cpu"; 561 562 if (!pe->metric_expr) 563 return 0; 564 565 if (data->pmu_name && strcmp(data->pmu_name, pmu)) 566 return 0; 567 568 return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter, 569 data->raw, data->details, data->groups, 570 data->metriclist); 571 } 572 573 void metricgroup__print(bool metrics, bool metricgroups, char *filter, 574 bool raw, bool details, const char *pmu_name) 575 { 576 struct rblist groups; 577 struct rb_node *node, *next; 578 struct strlist *metriclist = NULL; 579 const struct pmu_events_table *table; 580 581 if (!metricgroups) { 582 metriclist = strlist__new(NULL, NULL); 583 if (!metriclist) 584 return; 585 } 586 587 rblist__init(&groups); 588 groups.node_new = mep_new; 589 groups.node_cmp = mep_cmp; 590 groups.node_delete = mep_delete; 591 table = pmu_events_table__find(); 592 if (table) { 593 struct metricgroup_print_data data = { 594 .pmu_name = pmu_name, 595 .metriclist = metriclist, 596 .metricgroups = metricgroups, 597 .filter = filter, 598 .raw = raw, 599 .details = details, 600 .groups = &groups, 601 }; 602 603 pmu_events_table_for_each_event(table, 604 metricgroup__print_callback, 605 &data); 606 } 607 { 608 struct metricgroup_iter_data data = { 609 .fn = metricgroup__print_sys_event_iter, 610 .data = (void *) &(struct metricgroup_print_sys_idata){ 611 .metriclist = metriclist, 612 .metricgroups = metricgroups, 613 .filter = filter, 614 .raw = raw, 615 .details = details, 616 .groups = &groups, 617 }, 618 }; 619 620 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); 621 } 622 623 if (!filter || !rblist__empty(&groups)) { 624 if (metricgroups && !raw) 625 printf("\nMetric Groups:\n\n"); 626 else if (metrics && !raw) 627 printf("\nMetrics:\n\n"); 628 } 629 630 for (node = rb_first_cached(&groups.entries); node; node = next) { 631 struct mep *me = container_of(node, struct mep, nd); 632 633 if (metricgroups) 634 printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n"); 635 if (metrics) 636 metricgroup__print_strlist(me->metrics, raw); 637 next = rb_next(node); 638 rblist__remove_node(&groups, node); 639 } 640 if (!metricgroups) 641 metricgroup__print_strlist(metriclist, raw); 642 strlist__delete(metriclist); 643 } 644 645 static const char *code_characters = ",-=@"; 646 647 static int encode_metric_id(struct strbuf *sb, const char *x) 648 { 649 char *c; 650 int ret = 0; 651 652 for (; *x; x++) { 653 c = strchr(code_characters, *x); 654 if (c) { 655 ret = strbuf_addch(sb, '!'); 656 if (ret) 657 break; 658 659 ret = strbuf_addch(sb, '0' + (c - code_characters)); 660 if (ret) 661 break; 662 } else { 663 ret = strbuf_addch(sb, *x); 664 if (ret) 665 break; 666 } 667 } 668 return ret; 669 } 670 671 static int decode_metric_id(struct strbuf *sb, const char *x) 672 { 673 const char *orig = x; 674 size_t i; 675 char c; 676 int ret; 677 678 for (; *x; x++) { 679 c = *x; 680 if (*x == '!') { 681 x++; 682 i = *x - '0'; 683 if (i > strlen(code_characters)) { 684 pr_err("Bad metric-id encoding in: '%s'", orig); 685 return -1; 686 } 687 c = code_characters[i]; 688 } 689 ret = strbuf_addch(sb, c); 690 if (ret) 691 return ret; 692 } 693 return 0; 694 } 695 696 static int decode_all_metric_ids(struct evlist *perf_evlist, const char *modifier) 697 { 698 struct evsel *ev; 699 struct strbuf sb = STRBUF_INIT; 700 char *cur; 701 int ret = 0; 702 703 evlist__for_each_entry(perf_evlist, ev) { 704 if (!ev->metric_id) 705 continue; 706 707 ret = strbuf_setlen(&sb, 0); 708 if (ret) 709 break; 710 711 ret = decode_metric_id(&sb, ev->metric_id); 712 if (ret) 713 break; 714 715 free((char *)ev->metric_id); 716 ev->metric_id = strdup(sb.buf); 717 if (!ev->metric_id) { 718 ret = -ENOMEM; 719 break; 720 } 721 /* 722 * If the name is just the parsed event, use the metric-id to 723 * give a more friendly display version. 724 */ 725 if (strstr(ev->name, "metric-id=")) { 726 bool has_slash = false; 727 728 free(ev->name); 729 for (cur = strchr(sb.buf, '@') ; cur; cur = strchr(++cur, '@')) { 730 *cur = '/'; 731 has_slash = true; 732 } 733 734 if (modifier) { 735 if (!has_slash && !strchr(sb.buf, ':')) { 736 ret = strbuf_addch(&sb, ':'); 737 if (ret) 738 break; 739 } 740 ret = strbuf_addstr(&sb, modifier); 741 if (ret) 742 break; 743 } 744 ev->name = strdup(sb.buf); 745 if (!ev->name) { 746 ret = -ENOMEM; 747 break; 748 } 749 } 750 } 751 strbuf_release(&sb); 752 return ret; 753 } 754 755 static int metricgroup__build_event_string(struct strbuf *events, 756 const struct expr_parse_ctx *ctx, 757 const char *modifier, 758 bool has_constraint) 759 { 760 struct hashmap_entry *cur; 761 size_t bkt; 762 bool no_group = true, has_tool_events = false; 763 bool tool_events[PERF_TOOL_MAX] = {false}; 764 int ret = 0; 765 766 #define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0) 767 768 hashmap__for_each_entry(ctx->ids, cur, bkt) { 769 const char *sep, *rsep, *id = cur->key; 770 enum perf_tool_event ev; 771 772 pr_debug("found event %s\n", id); 773 774 /* Always move tool events outside of the group. */ 775 ev = perf_tool_event__from_str(id); 776 if (ev != PERF_TOOL_NONE) { 777 has_tool_events = true; 778 tool_events[ev] = true; 779 continue; 780 } 781 /* Separate events with commas and open the group if necessary. */ 782 if (no_group) { 783 if (!has_constraint) { 784 ret = strbuf_addch(events, '{'); 785 RETURN_IF_NON_ZERO(ret); 786 } 787 788 no_group = false; 789 } else { 790 ret = strbuf_addch(events, ','); 791 RETURN_IF_NON_ZERO(ret); 792 } 793 /* 794 * Encode the ID as an event string. Add a qualifier for 795 * metric_id that is the original name except with characters 796 * that parse-events can't parse replaced. For example, 797 * 'msr@tsc@' gets added as msr/tsc,metric-id=msr!3tsc!3/ 798 */ 799 sep = strchr(id, '@'); 800 if (sep != NULL) { 801 ret = strbuf_add(events, id, sep - id); 802 RETURN_IF_NON_ZERO(ret); 803 ret = strbuf_addch(events, '/'); 804 RETURN_IF_NON_ZERO(ret); 805 rsep = strrchr(sep, '@'); 806 ret = strbuf_add(events, sep + 1, rsep - sep - 1); 807 RETURN_IF_NON_ZERO(ret); 808 ret = strbuf_addstr(events, ",metric-id="); 809 RETURN_IF_NON_ZERO(ret); 810 sep = rsep; 811 } else { 812 sep = strchr(id, ':'); 813 if (sep != NULL) { 814 ret = strbuf_add(events, id, sep - id); 815 RETURN_IF_NON_ZERO(ret); 816 } else { 817 ret = strbuf_addstr(events, id); 818 RETURN_IF_NON_ZERO(ret); 819 } 820 ret = strbuf_addstr(events, "/metric-id="); 821 RETURN_IF_NON_ZERO(ret); 822 } 823 ret = encode_metric_id(events, id); 824 RETURN_IF_NON_ZERO(ret); 825 ret = strbuf_addstr(events, "/"); 826 RETURN_IF_NON_ZERO(ret); 827 828 if (sep != NULL) { 829 ret = strbuf_addstr(events, sep + 1); 830 RETURN_IF_NON_ZERO(ret); 831 } 832 if (modifier) { 833 ret = strbuf_addstr(events, modifier); 834 RETURN_IF_NON_ZERO(ret); 835 } 836 } 837 if (!no_group && !has_constraint) { 838 ret = strbuf_addf(events, "}:W"); 839 RETURN_IF_NON_ZERO(ret); 840 } 841 if (has_tool_events) { 842 int i; 843 844 perf_tool_event__for_each_event(i) { 845 if (tool_events[i]) { 846 if (!no_group) { 847 ret = strbuf_addch(events, ','); 848 RETURN_IF_NON_ZERO(ret); 849 } 850 no_group = false; 851 ret = strbuf_addstr(events, perf_tool_event__to_str(i)); 852 RETURN_IF_NON_ZERO(ret); 853 } 854 } 855 } 856 857 return ret; 858 #undef RETURN_IF_NON_ZERO 859 } 860 861 int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused) 862 { 863 return 1; 864 } 865 866 /* 867 * A singly linked list on the stack of the names of metrics being 868 * processed. Used to identify recursion. 869 */ 870 struct visited_metric { 871 const char *name; 872 const struct visited_metric *parent; 873 }; 874 875 struct metricgroup_add_iter_data { 876 struct list_head *metric_list; 877 const char *metric_name; 878 const char *modifier; 879 int *ret; 880 bool *has_match; 881 bool metric_no_group; 882 const char *user_requested_cpu_list; 883 bool system_wide; 884 struct metric *root_metric; 885 const struct visited_metric *visited; 886 const struct pmu_events_table *table; 887 }; 888 889 static bool metricgroup__find_metric(const char *metric, 890 const struct pmu_events_table *table, 891 struct pmu_event *pe); 892 893 static int add_metric(struct list_head *metric_list, 894 const struct pmu_event *pe, 895 const char *modifier, 896 bool metric_no_group, 897 const char *user_requested_cpu_list, 898 bool system_wide, 899 struct metric *root_metric, 900 const struct visited_metric *visited, 901 const struct pmu_events_table *table); 902 903 /** 904 * resolve_metric - Locate metrics within the root metric and recursively add 905 * references to them. 906 * @metric_list: The list the metric is added to. 907 * @modifier: if non-null event modifiers like "u". 908 * @metric_no_group: Should events written to events be grouped "{}" or 909 * global. Grouping is the default but due to multiplexing the 910 * user may override. 911 * @user_requested_cpu_list: Command line specified CPUs to record on. 912 * @system_wide: Are events for all processes recorded. 913 * @root_metric: Metrics may reference other metrics to form a tree. In this 914 * case the root_metric holds all the IDs and a list of referenced 915 * metrics. When adding a root this argument is NULL. 916 * @visited: A singly linked list of metric names being added that is used to 917 * detect recursion. 918 * @table: The table that is searched for metrics, most commonly the table for the 919 * architecture perf is running upon. 920 */ 921 static int resolve_metric(struct list_head *metric_list, 922 const char *modifier, 923 bool metric_no_group, 924 const char *user_requested_cpu_list, 925 bool system_wide, 926 struct metric *root_metric, 927 const struct visited_metric *visited, 928 const struct pmu_events_table *table) 929 { 930 struct hashmap_entry *cur; 931 size_t bkt; 932 struct to_resolve { 933 /* The metric to resolve. */ 934 struct pmu_event pe; 935 /* 936 * The key in the IDs map, this may differ from in case, 937 * etc. from pe->metric_name. 938 */ 939 const char *key; 940 } *pending = NULL; 941 int i, ret = 0, pending_cnt = 0; 942 943 /* 944 * Iterate all the parsed IDs and if there's a matching metric and it to 945 * the pending array. 946 */ 947 hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) { 948 struct pmu_event pe; 949 950 if (metricgroup__find_metric(cur->key, table, &pe)) { 951 pending = realloc(pending, 952 (pending_cnt + 1) * sizeof(struct to_resolve)); 953 if (!pending) 954 return -ENOMEM; 955 956 memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe)); 957 pending[pending_cnt].key = cur->key; 958 pending_cnt++; 959 } 960 } 961 962 /* Remove the metric IDs from the context. */ 963 for (i = 0; i < pending_cnt; i++) 964 expr__del_id(root_metric->pctx, pending[i].key); 965 966 /* 967 * Recursively add all the metrics, IDs are added to the root metric's 968 * context. 969 */ 970 for (i = 0; i < pending_cnt; i++) { 971 ret = add_metric(metric_list, &pending[i].pe, modifier, metric_no_group, 972 user_requested_cpu_list, system_wide, root_metric, visited, 973 table); 974 if (ret) 975 break; 976 } 977 978 free(pending); 979 return ret; 980 } 981 982 /** 983 * __add_metric - Add a metric to metric_list. 984 * @metric_list: The list the metric is added to. 985 * @pe: The pmu_event containing the metric to be added. 986 * @modifier: if non-null event modifiers like "u". 987 * @metric_no_group: Should events written to events be grouped "{}" or 988 * global. Grouping is the default but due to multiplexing the 989 * user may override. 990 * @runtime: A special argument for the parser only known at runtime. 991 * @user_requested_cpu_list: Command line specified CPUs to record on. 992 * @system_wide: Are events for all processes recorded. 993 * @root_metric: Metrics may reference other metrics to form a tree. In this 994 * case the root_metric holds all the IDs and a list of referenced 995 * metrics. When adding a root this argument is NULL. 996 * @visited: A singly linked list of metric names being added that is used to 997 * detect recursion. 998 * @table: The table that is searched for metrics, most commonly the table for the 999 * architecture perf is running upon. 1000 */ 1001 static int __add_metric(struct list_head *metric_list, 1002 const struct pmu_event *pe, 1003 const char *modifier, 1004 bool metric_no_group, 1005 int runtime, 1006 const char *user_requested_cpu_list, 1007 bool system_wide, 1008 struct metric *root_metric, 1009 const struct visited_metric *visited, 1010 const struct pmu_events_table *table) 1011 { 1012 const struct visited_metric *vm; 1013 int ret; 1014 bool is_root = !root_metric; 1015 struct visited_metric visited_node = { 1016 .name = pe->metric_name, 1017 .parent = visited, 1018 }; 1019 1020 for (vm = visited; vm; vm = vm->parent) { 1021 if (!strcmp(pe->metric_name, vm->name)) { 1022 pr_err("failed: recursion detected for %s\n", pe->metric_name); 1023 return -1; 1024 } 1025 } 1026 1027 if (is_root) { 1028 /* 1029 * This metric is the root of a tree and may reference other 1030 * metrics that are added recursively. 1031 */ 1032 root_metric = metric__new(pe, modifier, metric_no_group, runtime, 1033 user_requested_cpu_list, system_wide); 1034 if (!root_metric) 1035 return -ENOMEM; 1036 1037 } else { 1038 int cnt = 0; 1039 1040 /* 1041 * This metric was referenced in a metric higher in the 1042 * tree. Check if the same metric is already resolved in the 1043 * metric_refs list. 1044 */ 1045 if (root_metric->metric_refs) { 1046 for (; root_metric->metric_refs[cnt].metric_name; cnt++) { 1047 if (!strcmp(pe->metric_name, 1048 root_metric->metric_refs[cnt].metric_name)) 1049 return 0; 1050 } 1051 } 1052 1053 /* Create reference. Need space for the entry and the terminator. */ 1054 root_metric->metric_refs = realloc(root_metric->metric_refs, 1055 (cnt + 2) * sizeof(struct metric_ref)); 1056 if (!root_metric->metric_refs) 1057 return -ENOMEM; 1058 1059 /* 1060 * Intentionally passing just const char pointers, 1061 * from 'pe' object, so they never go away. We don't 1062 * need to change them, so there's no need to create 1063 * our own copy. 1064 */ 1065 root_metric->metric_refs[cnt].metric_name = pe->metric_name; 1066 root_metric->metric_refs[cnt].metric_expr = pe->metric_expr; 1067 1068 /* Null terminate array. */ 1069 root_metric->metric_refs[cnt+1].metric_name = NULL; 1070 root_metric->metric_refs[cnt+1].metric_expr = NULL; 1071 } 1072 1073 /* 1074 * For both the parent and referenced metrics, we parse 1075 * all the metric's IDs and add it to the root context. 1076 */ 1077 if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) { 1078 /* Broken metric. */ 1079 ret = -EINVAL; 1080 } else { 1081 /* Resolve referenced metrics. */ 1082 ret = resolve_metric(metric_list, modifier, metric_no_group, 1083 user_requested_cpu_list, system_wide, 1084 root_metric, &visited_node, table); 1085 } 1086 1087 if (ret) { 1088 if (is_root) 1089 metric__free(root_metric); 1090 1091 } else if (is_root) 1092 list_add(&root_metric->nd, metric_list); 1093 1094 return ret; 1095 } 1096 1097 struct metricgroup__find_metric_data { 1098 const char *metric; 1099 struct pmu_event *pe; 1100 }; 1101 1102 static int metricgroup__find_metric_callback(const struct pmu_event *pe, 1103 const struct pmu_events_table *table __maybe_unused, 1104 void *vdata) 1105 { 1106 struct metricgroup__find_metric_data *data = vdata; 1107 1108 if (!match_metric(pe->metric_name, data->metric)) 1109 return 0; 1110 1111 memcpy(data->pe, pe, sizeof(*pe)); 1112 return 1; 1113 } 1114 1115 static bool metricgroup__find_metric(const char *metric, 1116 const struct pmu_events_table *table, 1117 struct pmu_event *pe) 1118 { 1119 struct metricgroup__find_metric_data data = { 1120 .metric = metric, 1121 .pe = pe, 1122 }; 1123 1124 return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data) 1125 ? true : false; 1126 } 1127 1128 static int add_metric(struct list_head *metric_list, 1129 const struct pmu_event *pe, 1130 const char *modifier, 1131 bool metric_no_group, 1132 const char *user_requested_cpu_list, 1133 bool system_wide, 1134 struct metric *root_metric, 1135 const struct visited_metric *visited, 1136 const struct pmu_events_table *table) 1137 { 1138 int ret = 0; 1139 1140 pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name); 1141 1142 if (!strstr(pe->metric_expr, "?")) { 1143 ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0, 1144 user_requested_cpu_list, system_wide, root_metric, 1145 visited, table); 1146 } else { 1147 int j, count; 1148 1149 count = arch_get_runtimeparam(pe); 1150 1151 /* This loop is added to create multiple 1152 * events depend on count value and add 1153 * those events to metric_list. 1154 */ 1155 1156 for (j = 0; j < count && !ret; j++) 1157 ret = __add_metric(metric_list, pe, modifier, metric_no_group, j, 1158 user_requested_cpu_list, system_wide, 1159 root_metric, visited, table); 1160 } 1161 1162 return ret; 1163 } 1164 1165 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe, 1166 const struct pmu_events_table *table __maybe_unused, 1167 void *data) 1168 { 1169 struct metricgroup_add_iter_data *d = data; 1170 int ret; 1171 1172 if (!match_pe_metric(pe, d->metric_name)) 1173 return 0; 1174 1175 ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group, 1176 d->user_requested_cpu_list, d->system_wide, 1177 d->root_metric, d->visited, d->table); 1178 if (ret) 1179 goto out; 1180 1181 *(d->has_match) = true; 1182 1183 out: 1184 *(d->ret) = ret; 1185 return ret; 1186 } 1187 1188 /** 1189 * metric_list_cmp - list_sort comparator that sorts metrics with more events to 1190 * the front. tool events are excluded from the count. 1191 */ 1192 static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, 1193 const struct list_head *r) 1194 { 1195 const struct metric *left = container_of(l, struct metric, nd); 1196 const struct metric *right = container_of(r, struct metric, nd); 1197 struct expr_id_data *data; 1198 int i, left_count, right_count; 1199 1200 left_count = hashmap__size(left->pctx->ids); 1201 perf_tool_event__for_each_event(i) { 1202 if (!expr__get_id(left->pctx, perf_tool_event__to_str(i), &data)) 1203 left_count--; 1204 } 1205 1206 right_count = hashmap__size(right->pctx->ids); 1207 perf_tool_event__for_each_event(i) { 1208 if (!expr__get_id(right->pctx, perf_tool_event__to_str(i), &data)) 1209 right_count--; 1210 } 1211 1212 return right_count - left_count; 1213 } 1214 1215 struct metricgroup__add_metric_data { 1216 struct list_head *list; 1217 const char *metric_name; 1218 const char *modifier; 1219 const char *user_requested_cpu_list; 1220 bool metric_no_group; 1221 bool system_wide; 1222 bool has_match; 1223 }; 1224 1225 static int metricgroup__add_metric_callback(const struct pmu_event *pe, 1226 const struct pmu_events_table *table, 1227 void *vdata) 1228 { 1229 struct metricgroup__add_metric_data *data = vdata; 1230 int ret = 0; 1231 1232 if (pe->metric_expr && 1233 (match_metric(pe->metric_group, data->metric_name) || 1234 match_metric(pe->metric_name, data->metric_name))) { 1235 1236 data->has_match = true; 1237 ret = add_metric(data->list, pe, data->modifier, data->metric_no_group, 1238 data->user_requested_cpu_list, data->system_wide, 1239 /*root_metric=*/NULL, /*visited_metrics=*/NULL, table); 1240 } 1241 return ret; 1242 } 1243 1244 /** 1245 * metricgroup__add_metric - Find and add a metric, or a metric group. 1246 * @metric_name: The name of the metric or metric group. For example, "IPC" 1247 * could be the name of a metric and "TopDownL1" the name of a 1248 * metric group. 1249 * @modifier: if non-null event modifiers like "u". 1250 * @metric_no_group: Should events written to events be grouped "{}" or 1251 * global. Grouping is the default but due to multiplexing the 1252 * user may override. 1253 * @user_requested_cpu_list: Command line specified CPUs to record on. 1254 * @system_wide: Are events for all processes recorded. 1255 * @metric_list: The list that the metric or metric group are added to. 1256 * @table: The table that is searched for metrics, most commonly the table for the 1257 * architecture perf is running upon. 1258 */ 1259 static int metricgroup__add_metric(const char *metric_name, const char *modifier, 1260 bool metric_no_group, 1261 const char *user_requested_cpu_list, 1262 bool system_wide, 1263 struct list_head *metric_list, 1264 const struct pmu_events_table *table) 1265 { 1266 LIST_HEAD(list); 1267 int ret; 1268 bool has_match = false; 1269 1270 { 1271 struct metricgroup__add_metric_data data = { 1272 .list = &list, 1273 .metric_name = metric_name, 1274 .modifier = modifier, 1275 .metric_no_group = metric_no_group, 1276 .user_requested_cpu_list = user_requested_cpu_list, 1277 .system_wide = system_wide, 1278 .has_match = false, 1279 }; 1280 /* 1281 * Iterate over all metrics seeing if metric matches either the 1282 * name or group. When it does add the metric to the list. 1283 */ 1284 ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback, 1285 &data); 1286 if (ret) 1287 goto out; 1288 1289 has_match = data.has_match; 1290 } 1291 { 1292 struct metricgroup_iter_data data = { 1293 .fn = metricgroup__add_metric_sys_event_iter, 1294 .data = (void *) &(struct metricgroup_add_iter_data) { 1295 .metric_list = &list, 1296 .metric_name = metric_name, 1297 .modifier = modifier, 1298 .metric_no_group = metric_no_group, 1299 .user_requested_cpu_list = user_requested_cpu_list, 1300 .system_wide = system_wide, 1301 .has_match = &has_match, 1302 .ret = &ret, 1303 .table = table, 1304 }, 1305 }; 1306 1307 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); 1308 } 1309 /* End of pmu events. */ 1310 if (!has_match) 1311 ret = -EINVAL; 1312 1313 out: 1314 /* 1315 * add to metric_list so that they can be released 1316 * even if it's failed 1317 */ 1318 list_splice(&list, metric_list); 1319 return ret; 1320 } 1321 1322 /** 1323 * metricgroup__add_metric_list - Find and add metrics, or metric groups, 1324 * specified in a list. 1325 * @list: the list of metrics or metric groups. For example, "IPC,CPI,TopDownL1" 1326 * would match the IPC and CPI metrics, and TopDownL1 would match all 1327 * the metrics in the TopDownL1 group. 1328 * @metric_no_group: Should events written to events be grouped "{}" or 1329 * global. Grouping is the default but due to multiplexing the 1330 * user may override. 1331 * @user_requested_cpu_list: Command line specified CPUs to record on. 1332 * @system_wide: Are events for all processes recorded. 1333 * @metric_list: The list that metrics are added to. 1334 * @table: The table that is searched for metrics, most commonly the table for the 1335 * architecture perf is running upon. 1336 */ 1337 static int metricgroup__add_metric_list(const char *list, bool metric_no_group, 1338 const char *user_requested_cpu_list, 1339 bool system_wide, struct list_head *metric_list, 1340 const struct pmu_events_table *table) 1341 { 1342 char *list_itr, *list_copy, *metric_name, *modifier; 1343 int ret, count = 0; 1344 1345 list_copy = strdup(list); 1346 if (!list_copy) 1347 return -ENOMEM; 1348 list_itr = list_copy; 1349 1350 while ((metric_name = strsep(&list_itr, ",")) != NULL) { 1351 modifier = strchr(metric_name, ':'); 1352 if (modifier) 1353 *modifier++ = '\0'; 1354 1355 ret = metricgroup__add_metric(metric_name, modifier, 1356 metric_no_group, user_requested_cpu_list, 1357 system_wide, metric_list, table); 1358 if (ret == -EINVAL) 1359 pr_err("Cannot find metric or group `%s'\n", metric_name); 1360 1361 if (ret) 1362 break; 1363 1364 count++; 1365 } 1366 free(list_copy); 1367 1368 if (!ret) { 1369 /* 1370 * Warn about nmi_watchdog if any parsed metrics had the 1371 * NO_NMI_WATCHDOG constraint. 1372 */ 1373 metricgroup___watchdog_constraint_hint(NULL, true); 1374 /* No metrics. */ 1375 if (count == 0) 1376 return -EINVAL; 1377 } 1378 return ret; 1379 } 1380 1381 static void metricgroup__free_metrics(struct list_head *metric_list) 1382 { 1383 struct metric *m, *tmp; 1384 1385 list_for_each_entry_safe (m, tmp, metric_list, nd) { 1386 list_del_init(&m->nd); 1387 metric__free(m); 1388 } 1389 } 1390 1391 /** 1392 * find_tool_events - Search for the pressence of tool events in metric_list. 1393 * @metric_list: List to take metrics from. 1394 * @tool_events: Array of false values, indices corresponding to tool events set 1395 * to true if tool event is found. 1396 */ 1397 static void find_tool_events(const struct list_head *metric_list, 1398 bool tool_events[PERF_TOOL_MAX]) 1399 { 1400 struct metric *m; 1401 1402 list_for_each_entry(m, metric_list, nd) { 1403 int i; 1404 1405 perf_tool_event__for_each_event(i) { 1406 struct expr_id_data *data; 1407 1408 if (!tool_events[i] && 1409 !expr__get_id(m->pctx, perf_tool_event__to_str(i), &data)) 1410 tool_events[i] = true; 1411 } 1412 } 1413 } 1414 1415 /** 1416 * build_combined_expr_ctx - Make an expr_parse_ctx with all has_constraint 1417 * metric IDs, as the IDs are held in a set, 1418 * duplicates will be removed. 1419 * @metric_list: List to take metrics from. 1420 * @combined: Out argument for result. 1421 */ 1422 static int build_combined_expr_ctx(const struct list_head *metric_list, 1423 struct expr_parse_ctx **combined) 1424 { 1425 struct hashmap_entry *cur; 1426 size_t bkt; 1427 struct metric *m; 1428 char *dup; 1429 int ret; 1430 1431 *combined = expr__ctx_new(); 1432 if (!*combined) 1433 return -ENOMEM; 1434 1435 list_for_each_entry(m, metric_list, nd) { 1436 if (m->has_constraint && !m->modifier) { 1437 hashmap__for_each_entry(m->pctx->ids, cur, bkt) { 1438 dup = strdup(cur->key); 1439 if (!dup) { 1440 ret = -ENOMEM; 1441 goto err_out; 1442 } 1443 ret = expr__add_id(*combined, dup); 1444 if (ret) 1445 goto err_out; 1446 } 1447 } 1448 } 1449 return 0; 1450 err_out: 1451 expr__ctx_free(*combined); 1452 *combined = NULL; 1453 return ret; 1454 } 1455 1456 /** 1457 * parse_ids - Build the event string for the ids and parse them creating an 1458 * evlist. The encoded metric_ids are decoded. 1459 * @metric_no_merge: is metric sharing explicitly disabled. 1460 * @fake_pmu: used when testing metrics not supported by the current CPU. 1461 * @ids: the event identifiers parsed from a metric. 1462 * @modifier: any modifiers added to the events. 1463 * @has_constraint: false if events should be placed in a weak group. 1464 * @tool_events: entries set true if the tool event of index could be present in 1465 * the overall list of metrics. 1466 * @out_evlist: the created list of events. 1467 */ 1468 static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu, 1469 struct expr_parse_ctx *ids, const char *modifier, 1470 bool has_constraint, const bool tool_events[PERF_TOOL_MAX], 1471 struct evlist **out_evlist) 1472 { 1473 struct parse_events_error parse_error; 1474 struct evlist *parsed_evlist; 1475 struct strbuf events = STRBUF_INIT; 1476 int ret; 1477 1478 *out_evlist = NULL; 1479 if (!metric_no_merge || hashmap__size(ids->ids) == 0) { 1480 bool added_event = false; 1481 int i; 1482 /* 1483 * We may fail to share events between metrics because a tool 1484 * event isn't present in one metric. For example, a ratio of 1485 * cache misses doesn't need duration_time but the same events 1486 * may be used for a misses per second. Events without sharing 1487 * implies multiplexing, that is best avoided, so place 1488 * all tool events in every group. 1489 * 1490 * Also, there may be no ids/events in the expression parsing 1491 * context because of constant evaluation, e.g.: 1492 * event1 if #smt_on else 0 1493 * Add a tool event to avoid a parse error on an empty string. 1494 */ 1495 perf_tool_event__for_each_event(i) { 1496 if (tool_events[i]) { 1497 char *tmp = strdup(perf_tool_event__to_str(i)); 1498 1499 if (!tmp) 1500 return -ENOMEM; 1501 ids__insert(ids->ids, tmp); 1502 added_event = true; 1503 } 1504 } 1505 if (!added_event && hashmap__size(ids->ids) == 0) { 1506 char *tmp = strdup("duration_time"); 1507 1508 if (!tmp) 1509 return -ENOMEM; 1510 ids__insert(ids->ids, tmp); 1511 } 1512 } 1513 ret = metricgroup__build_event_string(&events, ids, modifier, 1514 has_constraint); 1515 if (ret) 1516 return ret; 1517 1518 parsed_evlist = evlist__new(); 1519 if (!parsed_evlist) { 1520 ret = -ENOMEM; 1521 goto err_out; 1522 } 1523 pr_debug("Parsing metric events '%s'\n", events.buf); 1524 parse_events_error__init(&parse_error); 1525 ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu); 1526 if (ret) { 1527 parse_events_error__print(&parse_error, events.buf); 1528 goto err_out; 1529 } 1530 ret = decode_all_metric_ids(parsed_evlist, modifier); 1531 if (ret) 1532 goto err_out; 1533 1534 *out_evlist = parsed_evlist; 1535 parsed_evlist = NULL; 1536 err_out: 1537 parse_events_error__exit(&parse_error); 1538 evlist__delete(parsed_evlist); 1539 strbuf_release(&events); 1540 return ret; 1541 } 1542 1543 static int parse_groups(struct evlist *perf_evlist, const char *str, 1544 bool metric_no_group, 1545 bool metric_no_merge, 1546 const char *user_requested_cpu_list, 1547 bool system_wide, 1548 struct perf_pmu *fake_pmu, 1549 struct rblist *metric_events_list, 1550 const struct pmu_events_table *table) 1551 { 1552 struct evlist *combined_evlist = NULL; 1553 LIST_HEAD(metric_list); 1554 struct metric *m; 1555 bool tool_events[PERF_TOOL_MAX] = {false}; 1556 int ret; 1557 1558 if (metric_events_list->nr_entries == 0) 1559 metricgroup__rblist_init(metric_events_list); 1560 ret = metricgroup__add_metric_list(str, metric_no_group, 1561 user_requested_cpu_list, 1562 system_wide, &metric_list, table); 1563 if (ret) 1564 goto out; 1565 1566 /* Sort metrics from largest to smallest. */ 1567 list_sort(NULL, &metric_list, metric_list_cmp); 1568 1569 if (!metric_no_merge) { 1570 struct expr_parse_ctx *combined = NULL; 1571 1572 find_tool_events(&metric_list, tool_events); 1573 1574 ret = build_combined_expr_ctx(&metric_list, &combined); 1575 1576 if (!ret && combined && hashmap__size(combined->ids)) { 1577 ret = parse_ids(metric_no_merge, fake_pmu, combined, 1578 /*modifier=*/NULL, 1579 /*has_constraint=*/true, 1580 tool_events, 1581 &combined_evlist); 1582 } 1583 if (combined) 1584 expr__ctx_free(combined); 1585 1586 if (ret) 1587 goto out; 1588 } 1589 1590 list_for_each_entry(m, &metric_list, nd) { 1591 struct metric_event *me; 1592 struct evsel **metric_events; 1593 struct evlist *metric_evlist = NULL; 1594 struct metric *n; 1595 struct metric_expr *expr; 1596 1597 if (combined_evlist && m->has_constraint) { 1598 metric_evlist = combined_evlist; 1599 } else if (!metric_no_merge) { 1600 /* 1601 * See if the IDs for this metric are a subset of an 1602 * earlier metric. 1603 */ 1604 list_for_each_entry(n, &metric_list, nd) { 1605 if (m == n) 1606 break; 1607 1608 if (n->evlist == NULL) 1609 continue; 1610 1611 if ((!m->modifier && n->modifier) || 1612 (m->modifier && !n->modifier) || 1613 (m->modifier && n->modifier && 1614 strcmp(m->modifier, n->modifier))) 1615 continue; 1616 1617 if (expr__subset_of_ids(n->pctx, m->pctx)) { 1618 pr_debug("Events in '%s' fully contained within '%s'\n", 1619 m->metric_name, n->metric_name); 1620 metric_evlist = n->evlist; 1621 break; 1622 } 1623 1624 } 1625 } 1626 if (!metric_evlist) { 1627 ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier, 1628 m->has_constraint, tool_events, &m->evlist); 1629 if (ret) 1630 goto out; 1631 1632 metric_evlist = m->evlist; 1633 } 1634 ret = setup_metric_events(m->pctx->ids, metric_evlist, &metric_events); 1635 if (ret) { 1636 pr_debug("Cannot resolve IDs for %s: %s\n", 1637 m->metric_name, m->metric_expr); 1638 goto out; 1639 } 1640 1641 me = metricgroup__lookup(metric_events_list, metric_events[0], true); 1642 1643 expr = malloc(sizeof(struct metric_expr)); 1644 if (!expr) { 1645 ret = -ENOMEM; 1646 free(metric_events); 1647 goto out; 1648 } 1649 1650 expr->metric_refs = m->metric_refs; 1651 m->metric_refs = NULL; 1652 expr->metric_expr = m->metric_expr; 1653 if (m->modifier) { 1654 char *tmp; 1655 1656 if (asprintf(&tmp, "%s:%s", m->metric_name, m->modifier) < 0) 1657 expr->metric_name = NULL; 1658 else 1659 expr->metric_name = tmp; 1660 } else 1661 expr->metric_name = strdup(m->metric_name); 1662 1663 if (!expr->metric_name) { 1664 ret = -ENOMEM; 1665 free(metric_events); 1666 goto out; 1667 } 1668 expr->metric_unit = m->metric_unit; 1669 expr->metric_events = metric_events; 1670 expr->runtime = m->pctx->sctx.runtime; 1671 list_add(&expr->nd, &me->head); 1672 } 1673 1674 1675 if (combined_evlist) { 1676 evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries); 1677 evlist__delete(combined_evlist); 1678 } 1679 1680 list_for_each_entry(m, &metric_list, nd) { 1681 if (m->evlist) 1682 evlist__splice_list_tail(perf_evlist, &m->evlist->core.entries); 1683 } 1684 1685 out: 1686 metricgroup__free_metrics(&metric_list); 1687 return ret; 1688 } 1689 1690 int metricgroup__parse_groups(struct evlist *perf_evlist, 1691 const char *str, 1692 bool metric_no_group, 1693 bool metric_no_merge, 1694 const char *user_requested_cpu_list, 1695 bool system_wide, 1696 struct rblist *metric_events) 1697 { 1698 const struct pmu_events_table *table = pmu_events_table__find(); 1699 1700 if (!table) 1701 return -EINVAL; 1702 1703 return parse_groups(perf_evlist, str, metric_no_group, metric_no_merge, 1704 user_requested_cpu_list, system_wide, 1705 /*fake_pmu=*/NULL, metric_events, table); 1706 } 1707 1708 int metricgroup__parse_groups_test(struct evlist *evlist, 1709 const struct pmu_events_table *table, 1710 const char *str, 1711 bool metric_no_group, 1712 bool metric_no_merge, 1713 struct rblist *metric_events) 1714 { 1715 return parse_groups(evlist, str, metric_no_group, metric_no_merge, 1716 /*user_requested_cpu_list=*/NULL, 1717 /*system_wide=*/false, 1718 &perf_pmu__fake, metric_events, table); 1719 } 1720 1721 static int metricgroup__has_metric_callback(const struct pmu_event *pe, 1722 const struct pmu_events_table *table __maybe_unused, 1723 void *vdata) 1724 { 1725 const char *metric = vdata; 1726 1727 if (!pe->metric_expr) 1728 return 0; 1729 1730 if (match_metric(pe->metric_name, metric)) 1731 return 1; 1732 1733 return 0; 1734 } 1735 1736 bool metricgroup__has_metric(const char *metric) 1737 { 1738 const struct pmu_events_table *table = pmu_events_table__find(); 1739 1740 if (!table) 1741 return false; 1742 1743 return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback, 1744 (void *)metric) ? true : false; 1745 } 1746 1747 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, 1748 struct rblist *new_metric_events, 1749 struct rblist *old_metric_events) 1750 { 1751 unsigned int i; 1752 1753 for (i = 0; i < rblist__nr_entries(old_metric_events); i++) { 1754 struct rb_node *nd; 1755 struct metric_event *old_me, *new_me; 1756 struct metric_expr *old_expr, *new_expr; 1757 struct evsel *evsel; 1758 size_t alloc_size; 1759 int idx, nr; 1760 1761 nd = rblist__entry(old_metric_events, i); 1762 old_me = container_of(nd, struct metric_event, nd); 1763 1764 evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx); 1765 if (!evsel) 1766 return -EINVAL; 1767 new_me = metricgroup__lookup(new_metric_events, evsel, true); 1768 if (!new_me) 1769 return -ENOMEM; 1770 1771 pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n", 1772 cgrp ? cgrp->name : "root", evsel->name, evsel->core.idx); 1773 1774 list_for_each_entry(old_expr, &old_me->head, nd) { 1775 new_expr = malloc(sizeof(*new_expr)); 1776 if (!new_expr) 1777 return -ENOMEM; 1778 1779 new_expr->metric_expr = old_expr->metric_expr; 1780 new_expr->metric_name = strdup(old_expr->metric_name); 1781 if (!new_expr->metric_name) 1782 return -ENOMEM; 1783 1784 new_expr->metric_unit = old_expr->metric_unit; 1785 new_expr->runtime = old_expr->runtime; 1786 1787 if (old_expr->metric_refs) { 1788 /* calculate number of metric_events */ 1789 for (nr = 0; old_expr->metric_refs[nr].metric_name; nr++) 1790 continue; 1791 alloc_size = sizeof(*new_expr->metric_refs); 1792 new_expr->metric_refs = calloc(nr + 1, alloc_size); 1793 if (!new_expr->metric_refs) { 1794 free(new_expr); 1795 return -ENOMEM; 1796 } 1797 1798 memcpy(new_expr->metric_refs, old_expr->metric_refs, 1799 nr * alloc_size); 1800 } else { 1801 new_expr->metric_refs = NULL; 1802 } 1803 1804 /* calculate number of metric_events */ 1805 for (nr = 0; old_expr->metric_events[nr]; nr++) 1806 continue; 1807 alloc_size = sizeof(*new_expr->metric_events); 1808 new_expr->metric_events = calloc(nr + 1, alloc_size); 1809 if (!new_expr->metric_events) { 1810 free(new_expr->metric_refs); 1811 free(new_expr); 1812 return -ENOMEM; 1813 } 1814 1815 /* copy evsel in the same position */ 1816 for (idx = 0; idx < nr; idx++) { 1817 evsel = old_expr->metric_events[idx]; 1818 evsel = evlist__find_evsel(evlist, evsel->core.idx); 1819 if (evsel == NULL) { 1820 free(new_expr->metric_events); 1821 free(new_expr->metric_refs); 1822 free(new_expr); 1823 return -EINVAL; 1824 } 1825 new_expr->metric_events[idx] = evsel; 1826 } 1827 1828 list_add(&new_expr->nd, &new_me->head); 1829 } 1830 } 1831 return 0; 1832 } 1833