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