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