metricgroup.c (43445B)
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 31struct 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 55static 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 69static 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 82static 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 98static 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 106void 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 */ 116struct 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 */ 126struct 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 159static 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 178static 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 192static 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 226static 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 235static 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 */ 254static 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 325static 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 346static 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 352struct mep { 353 struct rb_node nd; 354 const char *name; 355 struct strlist *metrics; 356}; 357 358static 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 366static 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; 381out_name: 382 zfree(&me->name); 383out_me: 384 free(me); 385 return NULL; 386} 387 388static 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 404static 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 414static 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 430static 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 496struct 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 505typedef int (*metricgroup_sys_event_iter_fn)(const struct pmu_event *pe, void *); 506 507struct metricgroup_iter_data { 508 metricgroup_sys_event_iter_fn fn; 509 void *data; 510}; 511 512static int metricgroup__sys_event_iter(const struct pmu_event *pe, 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, d->data); 526 } 527 528 return 0; 529} 530 531static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *data) 532{ 533 struct metricgroup_print_sys_idata *d = data; 534 535 return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw, 536 d->details, d->groups, d->metriclist); 537} 538 539void metricgroup__print(bool metrics, bool metricgroups, char *filter, 540 bool raw, bool details, const char *pmu_name) 541{ 542 const struct pmu_events_map *map = pmu_events_map__find(); 543 const struct pmu_event *pe; 544 int i; 545 struct rblist groups; 546 struct rb_node *node, *next; 547 struct strlist *metriclist = NULL; 548 549 if (!metricgroups) { 550 metriclist = strlist__new(NULL, NULL); 551 if (!metriclist) 552 return; 553 } 554 555 rblist__init(&groups); 556 groups.node_new = mep_new; 557 groups.node_cmp = mep_cmp; 558 groups.node_delete = mep_delete; 559 for (i = 0; map; i++) { 560 pe = &map->table[i]; 561 562 if (!pe->name && !pe->metric_group && !pe->metric_name) 563 break; 564 if (!pe->metric_expr) 565 continue; 566 if (pmu_name && perf_pmu__is_hybrid(pe->pmu) && 567 strcmp(pmu_name, pe->pmu)) { 568 continue; 569 } 570 if (metricgroup__print_pmu_event(pe, metricgroups, filter, 571 raw, details, &groups, 572 metriclist) < 0) 573 return; 574 } 575 576 { 577 struct metricgroup_iter_data data = { 578 .fn = metricgroup__print_sys_event_iter, 579 .data = (void *) &(struct metricgroup_print_sys_idata){ 580 .metriclist = metriclist, 581 .metricgroups = metricgroups, 582 .filter = filter, 583 .raw = raw, 584 .details = details, 585 .groups = &groups, 586 }, 587 }; 588 589 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); 590 } 591 592 if (!filter || !rblist__empty(&groups)) { 593 if (metricgroups && !raw) 594 printf("\nMetric Groups:\n\n"); 595 else if (metrics && !raw) 596 printf("\nMetrics:\n\n"); 597 } 598 599 for (node = rb_first_cached(&groups.entries); node; node = next) { 600 struct mep *me = container_of(node, struct mep, nd); 601 602 if (metricgroups) 603 printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n"); 604 if (metrics) 605 metricgroup__print_strlist(me->metrics, raw); 606 next = rb_next(node); 607 rblist__remove_node(&groups, node); 608 } 609 if (!metricgroups) 610 metricgroup__print_strlist(metriclist, raw); 611 strlist__delete(metriclist); 612} 613 614static const char *code_characters = ",-=@"; 615 616static int encode_metric_id(struct strbuf *sb, const char *x) 617{ 618 char *c; 619 int ret = 0; 620 621 for (; *x; x++) { 622 c = strchr(code_characters, *x); 623 if (c) { 624 ret = strbuf_addch(sb, '!'); 625 if (ret) 626 break; 627 628 ret = strbuf_addch(sb, '0' + (c - code_characters)); 629 if (ret) 630 break; 631 } else { 632 ret = strbuf_addch(sb, *x); 633 if (ret) 634 break; 635 } 636 } 637 return ret; 638} 639 640static int decode_metric_id(struct strbuf *sb, const char *x) 641{ 642 const char *orig = x; 643 size_t i; 644 char c; 645 int ret; 646 647 for (; *x; x++) { 648 c = *x; 649 if (*x == '!') { 650 x++; 651 i = *x - '0'; 652 if (i > strlen(code_characters)) { 653 pr_err("Bad metric-id encoding in: '%s'", orig); 654 return -1; 655 } 656 c = code_characters[i]; 657 } 658 ret = strbuf_addch(sb, c); 659 if (ret) 660 return ret; 661 } 662 return 0; 663} 664 665static int decode_all_metric_ids(struct evlist *perf_evlist, const char *modifier) 666{ 667 struct evsel *ev; 668 struct strbuf sb = STRBUF_INIT; 669 char *cur; 670 int ret = 0; 671 672 evlist__for_each_entry(perf_evlist, ev) { 673 if (!ev->metric_id) 674 continue; 675 676 ret = strbuf_setlen(&sb, 0); 677 if (ret) 678 break; 679 680 ret = decode_metric_id(&sb, ev->metric_id); 681 if (ret) 682 break; 683 684 free((char *)ev->metric_id); 685 ev->metric_id = strdup(sb.buf); 686 if (!ev->metric_id) { 687 ret = -ENOMEM; 688 break; 689 } 690 /* 691 * If the name is just the parsed event, use the metric-id to 692 * give a more friendly display version. 693 */ 694 if (strstr(ev->name, "metric-id=")) { 695 bool has_slash = false; 696 697 free(ev->name); 698 for (cur = strchr(sb.buf, '@') ; cur; cur = strchr(++cur, '@')) { 699 *cur = '/'; 700 has_slash = true; 701 } 702 703 if (modifier) { 704 if (!has_slash && !strchr(sb.buf, ':')) { 705 ret = strbuf_addch(&sb, ':'); 706 if (ret) 707 break; 708 } 709 ret = strbuf_addstr(&sb, modifier); 710 if (ret) 711 break; 712 } 713 ev->name = strdup(sb.buf); 714 if (!ev->name) { 715 ret = -ENOMEM; 716 break; 717 } 718 } 719 } 720 strbuf_release(&sb); 721 return ret; 722} 723 724static int metricgroup__build_event_string(struct strbuf *events, 725 const struct expr_parse_ctx *ctx, 726 const char *modifier, 727 bool has_constraint) 728{ 729 struct hashmap_entry *cur; 730 size_t bkt; 731 bool no_group = true, has_tool_events = false; 732 bool tool_events[PERF_TOOL_MAX] = {false}; 733 int ret = 0; 734 735#define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0) 736 737 hashmap__for_each_entry(ctx->ids, cur, bkt) { 738 const char *sep, *rsep, *id = cur->key; 739 enum perf_tool_event ev; 740 741 pr_debug("found event %s\n", id); 742 743 /* Always move tool events outside of the group. */ 744 ev = perf_tool_event__from_str(id); 745 if (ev != PERF_TOOL_NONE) { 746 has_tool_events = true; 747 tool_events[ev] = true; 748 continue; 749 } 750 /* Separate events with commas and open the group if necessary. */ 751 if (no_group) { 752 if (!has_constraint) { 753 ret = strbuf_addch(events, '{'); 754 RETURN_IF_NON_ZERO(ret); 755 } 756 757 no_group = false; 758 } else { 759 ret = strbuf_addch(events, ','); 760 RETURN_IF_NON_ZERO(ret); 761 } 762 /* 763 * Encode the ID as an event string. Add a qualifier for 764 * metric_id that is the original name except with characters 765 * that parse-events can't parse replaced. For example, 766 * 'msr@tsc@' gets added as msr/tsc,metric-id=msr!3tsc!3/ 767 */ 768 sep = strchr(id, '@'); 769 if (sep != NULL) { 770 ret = strbuf_add(events, id, sep - id); 771 RETURN_IF_NON_ZERO(ret); 772 ret = strbuf_addch(events, '/'); 773 RETURN_IF_NON_ZERO(ret); 774 rsep = strrchr(sep, '@'); 775 ret = strbuf_add(events, sep + 1, rsep - sep - 1); 776 RETURN_IF_NON_ZERO(ret); 777 ret = strbuf_addstr(events, ",metric-id="); 778 RETURN_IF_NON_ZERO(ret); 779 sep = rsep; 780 } else { 781 sep = strchr(id, ':'); 782 if (sep != NULL) { 783 ret = strbuf_add(events, id, sep - id); 784 RETURN_IF_NON_ZERO(ret); 785 } else { 786 ret = strbuf_addstr(events, id); 787 RETURN_IF_NON_ZERO(ret); 788 } 789 ret = strbuf_addstr(events, "/metric-id="); 790 RETURN_IF_NON_ZERO(ret); 791 } 792 ret = encode_metric_id(events, id); 793 RETURN_IF_NON_ZERO(ret); 794 ret = strbuf_addstr(events, "/"); 795 RETURN_IF_NON_ZERO(ret); 796 797 if (sep != NULL) { 798 ret = strbuf_addstr(events, sep + 1); 799 RETURN_IF_NON_ZERO(ret); 800 } 801 if (modifier) { 802 ret = strbuf_addstr(events, modifier); 803 RETURN_IF_NON_ZERO(ret); 804 } 805 } 806 if (!no_group && !has_constraint) { 807 ret = strbuf_addf(events, "}:W"); 808 RETURN_IF_NON_ZERO(ret); 809 } 810 if (has_tool_events) { 811 int i; 812 813 perf_tool_event__for_each_event(i) { 814 if (tool_events[i]) { 815 if (!no_group) { 816 ret = strbuf_addch(events, ','); 817 RETURN_IF_NON_ZERO(ret); 818 } 819 no_group = false; 820 ret = strbuf_addstr(events, perf_tool_event__to_str(i)); 821 RETURN_IF_NON_ZERO(ret); 822 } 823 } 824 } 825 826 return ret; 827#undef RETURN_IF_NON_ZERO 828} 829 830int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused) 831{ 832 return 1; 833} 834 835/* 836 * A singly linked list on the stack of the names of metrics being 837 * processed. Used to identify recursion. 838 */ 839struct visited_metric { 840 const char *name; 841 const struct visited_metric *parent; 842}; 843 844struct metricgroup_add_iter_data { 845 struct list_head *metric_list; 846 const char *metric_name; 847 const char *modifier; 848 int *ret; 849 bool *has_match; 850 bool metric_no_group; 851 struct metric *root_metric; 852 const struct visited_metric *visited; 853 const struct pmu_events_map *map; 854}; 855 856static int add_metric(struct list_head *metric_list, 857 const struct pmu_event *pe, 858 const char *modifier, 859 bool metric_no_group, 860 struct metric *root_metric, 861 const struct visited_metric *visited, 862 const struct pmu_events_map *map); 863 864/** 865 * resolve_metric - Locate metrics within the root metric and recursively add 866 * references to them. 867 * @metric_list: The list the metric is added to. 868 * @modifier: if non-null event modifiers like "u". 869 * @metric_no_group: Should events written to events be grouped "{}" or 870 * global. Grouping is the default but due to multiplexing the 871 * user may override. 872 * @root_metric: Metrics may reference other metrics to form a tree. In this 873 * case the root_metric holds all the IDs and a list of referenced 874 * metrics. When adding a root this argument is NULL. 875 * @visited: A singly linked list of metric names being added that is used to 876 * detect recursion. 877 * @map: The map that is searched for metrics, most commonly the table for the 878 * architecture perf is running upon. 879 */ 880static int resolve_metric(struct list_head *metric_list, 881 const char *modifier, 882 bool metric_no_group, 883 struct metric *root_metric, 884 const struct visited_metric *visited, 885 const struct pmu_events_map *map) 886{ 887 struct hashmap_entry *cur; 888 size_t bkt; 889 struct to_resolve { 890 /* The metric to resolve. */ 891 const struct pmu_event *pe; 892 /* 893 * The key in the IDs map, this may differ from in case, 894 * etc. from pe->metric_name. 895 */ 896 const char *key; 897 } *pending = NULL; 898 int i, ret = 0, pending_cnt = 0; 899 900 /* 901 * Iterate all the parsed IDs and if there's a matching metric and it to 902 * the pending array. 903 */ 904 hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) { 905 const struct pmu_event *pe; 906 907 pe = metricgroup__find_metric(cur->key, map); 908 if (pe) { 909 pending = realloc(pending, 910 (pending_cnt + 1) * sizeof(struct to_resolve)); 911 if (!pending) 912 return -ENOMEM; 913 914 pending[pending_cnt].pe = pe; 915 pending[pending_cnt].key = cur->key; 916 pending_cnt++; 917 } 918 } 919 920 /* Remove the metric IDs from the context. */ 921 for (i = 0; i < pending_cnt; i++) 922 expr__del_id(root_metric->pctx, pending[i].key); 923 924 /* 925 * Recursively add all the metrics, IDs are added to the root metric's 926 * context. 927 */ 928 for (i = 0; i < pending_cnt; i++) { 929 ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group, 930 root_metric, visited, map); 931 if (ret) 932 break; 933 } 934 935 free(pending); 936 return ret; 937} 938 939/** 940 * __add_metric - Add a metric to metric_list. 941 * @metric_list: The list the metric is added to. 942 * @pe: The pmu_event containing the metric to be added. 943 * @modifier: if non-null event modifiers like "u". 944 * @metric_no_group: Should events written to events be grouped "{}" or 945 * global. Grouping is the default but due to multiplexing the 946 * user may override. 947 * @runtime: A special argument for the parser only known at runtime. 948 * @root_metric: Metrics may reference other metrics to form a tree. In this 949 * case the root_metric holds all the IDs and a list of referenced 950 * metrics. When adding a root this argument is NULL. 951 * @visited: A singly linked list of metric names being added that is used to 952 * detect recursion. 953 * @map: The map that is searched for metrics, most commonly the table for the 954 * architecture perf is running upon. 955 */ 956static int __add_metric(struct list_head *metric_list, 957 const struct pmu_event *pe, 958 const char *modifier, 959 bool metric_no_group, 960 int runtime, 961 struct metric *root_metric, 962 const struct visited_metric *visited, 963 const struct pmu_events_map *map) 964{ 965 const struct visited_metric *vm; 966 int ret; 967 bool is_root = !root_metric; 968 struct visited_metric visited_node = { 969 .name = pe->metric_name, 970 .parent = visited, 971 }; 972 973 for (vm = visited; vm; vm = vm->parent) { 974 if (!strcmp(pe->metric_name, vm->name)) { 975 pr_err("failed: recursion detected for %s\n", pe->metric_name); 976 return -1; 977 } 978 } 979 980 if (is_root) { 981 /* 982 * This metric is the root of a tree and may reference other 983 * metrics that are added recursively. 984 */ 985 root_metric = metric__new(pe, modifier, metric_no_group, runtime); 986 if (!root_metric) 987 return -ENOMEM; 988 989 } else { 990 int cnt = 0; 991 992 /* 993 * This metric was referenced in a metric higher in the 994 * tree. Check if the same metric is already resolved in the 995 * metric_refs list. 996 */ 997 if (root_metric->metric_refs) { 998 for (; root_metric->metric_refs[cnt].metric_name; cnt++) { 999 if (!strcmp(pe->metric_name, 1000 root_metric->metric_refs[cnt].metric_name)) 1001 return 0; 1002 } 1003 } 1004 1005 /* Create reference. Need space for the entry and the terminator. */ 1006 root_metric->metric_refs = realloc(root_metric->metric_refs, 1007 (cnt + 2) * sizeof(struct metric_ref)); 1008 if (!root_metric->metric_refs) 1009 return -ENOMEM; 1010 1011 /* 1012 * Intentionally passing just const char pointers, 1013 * from 'pe' object, so they never go away. We don't 1014 * need to change them, so there's no need to create 1015 * our own copy. 1016 */ 1017 root_metric->metric_refs[cnt].metric_name = pe->metric_name; 1018 root_metric->metric_refs[cnt].metric_expr = pe->metric_expr; 1019 1020 /* Null terminate array. */ 1021 root_metric->metric_refs[cnt+1].metric_name = NULL; 1022 root_metric->metric_refs[cnt+1].metric_expr = NULL; 1023 } 1024 1025 /* 1026 * For both the parent and referenced metrics, we parse 1027 * all the metric's IDs and add it to the root context. 1028 */ 1029 if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) { 1030 /* Broken metric. */ 1031 ret = -EINVAL; 1032 } else { 1033 /* Resolve referenced metrics. */ 1034 ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric, 1035 &visited_node, map); 1036 } 1037 1038 if (ret) { 1039 if (is_root) 1040 metric__free(root_metric); 1041 1042 } else if (is_root) 1043 list_add(&root_metric->nd, metric_list); 1044 1045 return ret; 1046} 1047 1048#define map_for_each_event(__pe, __idx, __map) \ 1049 if (__map) \ 1050 for (__idx = 0, __pe = &__map->table[__idx]; \ 1051 __pe->name || __pe->metric_group || __pe->metric_name; \ 1052 __pe = &__map->table[++__idx]) 1053 1054#define map_for_each_metric(__pe, __idx, __map, __metric) \ 1055 map_for_each_event(__pe, __idx, __map) \ 1056 if (__pe->metric_expr && \ 1057 (match_metric(__pe->metric_group, __metric) || \ 1058 match_metric(__pe->metric_name, __metric))) 1059 1060const struct pmu_event *metricgroup__find_metric(const char *metric, 1061 const struct pmu_events_map *map) 1062{ 1063 const struct pmu_event *pe; 1064 int i; 1065 1066 map_for_each_event(pe, i, map) { 1067 if (match_metric(pe->metric_name, metric)) 1068 return pe; 1069 } 1070 1071 return NULL; 1072} 1073 1074static int add_metric(struct list_head *metric_list, 1075 const struct pmu_event *pe, 1076 const char *modifier, 1077 bool metric_no_group, 1078 struct metric *root_metric, 1079 const struct visited_metric *visited, 1080 const struct pmu_events_map *map) 1081{ 1082 int ret = 0; 1083 1084 pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name); 1085 1086 if (!strstr(pe->metric_expr, "?")) { 1087 ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0, 1088 root_metric, visited, map); 1089 } else { 1090 int j, count; 1091 1092 count = arch_get_runtimeparam(pe); 1093 1094 /* This loop is added to create multiple 1095 * events depend on count value and add 1096 * those events to metric_list. 1097 */ 1098 1099 for (j = 0; j < count && !ret; j++) 1100 ret = __add_metric(metric_list, pe, modifier, metric_no_group, j, 1101 root_metric, visited, map); 1102 } 1103 1104 return ret; 1105} 1106 1107static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe, 1108 void *data) 1109{ 1110 struct metricgroup_add_iter_data *d = data; 1111 int ret; 1112 1113 if (!match_pe_metric(pe, d->metric_name)) 1114 return 0; 1115 1116 ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group, 1117 d->root_metric, d->visited, d->map); 1118 if (ret) 1119 goto out; 1120 1121 *(d->has_match) = true; 1122 1123out: 1124 *(d->ret) = ret; 1125 return ret; 1126} 1127 1128/** 1129 * metric_list_cmp - list_sort comparator that sorts metrics with more events to 1130 * the front. tool events are excluded from the count. 1131 */ 1132static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, 1133 const struct list_head *r) 1134{ 1135 const struct metric *left = container_of(l, struct metric, nd); 1136 const struct metric *right = container_of(r, struct metric, nd); 1137 struct expr_id_data *data; 1138 int i, left_count, right_count; 1139 1140 left_count = hashmap__size(left->pctx->ids); 1141 perf_tool_event__for_each_event(i) { 1142 if (!expr__get_id(left->pctx, perf_tool_event__to_str(i), &data)) 1143 left_count--; 1144 } 1145 1146 right_count = hashmap__size(right->pctx->ids); 1147 perf_tool_event__for_each_event(i) { 1148 if (!expr__get_id(right->pctx, perf_tool_event__to_str(i), &data)) 1149 right_count--; 1150 } 1151 1152 return right_count - left_count; 1153} 1154 1155/** 1156 * metricgroup__add_metric - Find and add a metric, or a metric group. 1157 * @metric_name: The name of the metric or metric group. For example, "IPC" 1158 * could be the name of a metric and "TopDownL1" the name of a 1159 * metric group. 1160 * @modifier: if non-null event modifiers like "u". 1161 * @metric_no_group: Should events written to events be grouped "{}" or 1162 * global. Grouping is the default but due to multiplexing the 1163 * user may override. 1164 * @metric_list: The list that the metric or metric group are added to. 1165 * @map: The map that is searched for metrics, most commonly the table for the 1166 * architecture perf is running upon. 1167 */ 1168static int metricgroup__add_metric(const char *metric_name, const char *modifier, 1169 bool metric_no_group, 1170 struct list_head *metric_list, 1171 const struct pmu_events_map *map) 1172{ 1173 const struct pmu_event *pe; 1174 LIST_HEAD(list); 1175 int i, ret; 1176 bool has_match = false; 1177 1178 /* 1179 * Iterate over all metrics seeing if metric matches either the name or 1180 * group. When it does add the metric to the list. 1181 */ 1182 map_for_each_metric(pe, i, map, metric_name) { 1183 has_match = true; 1184 ret = add_metric(&list, pe, modifier, metric_no_group, 1185 /*root_metric=*/NULL, 1186 /*visited_metrics=*/NULL, map); 1187 if (ret) 1188 goto out; 1189 } 1190 1191 { 1192 struct metricgroup_iter_data data = { 1193 .fn = metricgroup__add_metric_sys_event_iter, 1194 .data = (void *) &(struct metricgroup_add_iter_data) { 1195 .metric_list = &list, 1196 .metric_name = metric_name, 1197 .modifier = modifier, 1198 .metric_no_group = metric_no_group, 1199 .has_match = &has_match, 1200 .ret = &ret, 1201 .map = map, 1202 }, 1203 }; 1204 1205 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); 1206 } 1207 /* End of pmu events. */ 1208 if (!has_match) 1209 ret = -EINVAL; 1210 1211out: 1212 /* 1213 * add to metric_list so that they can be released 1214 * even if it's failed 1215 */ 1216 list_splice(&list, metric_list); 1217 return ret; 1218} 1219 1220/** 1221 * metricgroup__add_metric_list - Find and add metrics, or metric groups, 1222 * specified in a list. 1223 * @list: the list of metrics or metric groups. For example, "IPC,CPI,TopDownL1" 1224 * would match the IPC and CPI metrics, and TopDownL1 would match all 1225 * the metrics in the TopDownL1 group. 1226 * @metric_no_group: Should events written to events be grouped "{}" or 1227 * global. Grouping is the default but due to multiplexing the 1228 * user may override. 1229 * @metric_list: The list that metrics are added to. 1230 * @map: The map that is searched for metrics, most commonly the table for the 1231 * architecture perf is running upon. 1232 */ 1233static int metricgroup__add_metric_list(const char *list, bool metric_no_group, 1234 struct list_head *metric_list, 1235 const struct pmu_events_map *map) 1236{ 1237 char *list_itr, *list_copy, *metric_name, *modifier; 1238 int ret, count = 0; 1239 1240 list_copy = strdup(list); 1241 if (!list_copy) 1242 return -ENOMEM; 1243 list_itr = list_copy; 1244 1245 while ((metric_name = strsep(&list_itr, ",")) != NULL) { 1246 modifier = strchr(metric_name, ':'); 1247 if (modifier) 1248 *modifier++ = '\0'; 1249 1250 ret = metricgroup__add_metric(metric_name, modifier, 1251 metric_no_group, metric_list, 1252 map); 1253 if (ret == -EINVAL) 1254 pr_err("Cannot find metric or group `%s'\n", metric_name); 1255 1256 if (ret) 1257 break; 1258 1259 count++; 1260 } 1261 free(list_copy); 1262 1263 if (!ret) { 1264 /* 1265 * Warn about nmi_watchdog if any parsed metrics had the 1266 * NO_NMI_WATCHDOG constraint. 1267 */ 1268 metricgroup___watchdog_constraint_hint(NULL, true); 1269 /* No metrics. */ 1270 if (count == 0) 1271 return -EINVAL; 1272 } 1273 return ret; 1274} 1275 1276static void metricgroup__free_metrics(struct list_head *metric_list) 1277{ 1278 struct metric *m, *tmp; 1279 1280 list_for_each_entry_safe (m, tmp, metric_list, nd) { 1281 list_del_init(&m->nd); 1282 metric__free(m); 1283 } 1284} 1285 1286/** 1287 * find_tool_events - Search for the pressence of tool events in metric_list. 1288 * @metric_list: List to take metrics from. 1289 * @tool_events: Array of false values, indices corresponding to tool events set 1290 * to true if tool event is found. 1291 */ 1292static void find_tool_events(const struct list_head *metric_list, 1293 bool tool_events[PERF_TOOL_MAX]) 1294{ 1295 struct metric *m; 1296 1297 list_for_each_entry(m, metric_list, nd) { 1298 int i; 1299 1300 perf_tool_event__for_each_event(i) { 1301 struct expr_id_data *data; 1302 1303 if (!tool_events[i] && 1304 !expr__get_id(m->pctx, perf_tool_event__to_str(i), &data)) 1305 tool_events[i] = true; 1306 } 1307 } 1308} 1309 1310/** 1311 * build_combined_expr_ctx - Make an expr_parse_ctx with all has_constraint 1312 * metric IDs, as the IDs are held in a set, 1313 * duplicates will be removed. 1314 * @metric_list: List to take metrics from. 1315 * @combined: Out argument for result. 1316 */ 1317static int build_combined_expr_ctx(const struct list_head *metric_list, 1318 struct expr_parse_ctx **combined) 1319{ 1320 struct hashmap_entry *cur; 1321 size_t bkt; 1322 struct metric *m; 1323 char *dup; 1324 int ret; 1325 1326 *combined = expr__ctx_new(); 1327 if (!*combined) 1328 return -ENOMEM; 1329 1330 list_for_each_entry(m, metric_list, nd) { 1331 if (m->has_constraint && !m->modifier) { 1332 hashmap__for_each_entry(m->pctx->ids, cur, bkt) { 1333 dup = strdup(cur->key); 1334 if (!dup) { 1335 ret = -ENOMEM; 1336 goto err_out; 1337 } 1338 ret = expr__add_id(*combined, dup); 1339 if (ret) 1340 goto err_out; 1341 } 1342 } 1343 } 1344 return 0; 1345err_out: 1346 expr__ctx_free(*combined); 1347 *combined = NULL; 1348 return ret; 1349} 1350 1351/** 1352 * parse_ids - Build the event string for the ids and parse them creating an 1353 * evlist. The encoded metric_ids are decoded. 1354 * @metric_no_merge: is metric sharing explicitly disabled. 1355 * @fake_pmu: used when testing metrics not supported by the current CPU. 1356 * @ids: the event identifiers parsed from a metric. 1357 * @modifier: any modifiers added to the events. 1358 * @has_constraint: false if events should be placed in a weak group. 1359 * @tool_events: entries set true if the tool event of index could be present in 1360 * the overall list of metrics. 1361 * @out_evlist: the created list of events. 1362 */ 1363static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu, 1364 struct expr_parse_ctx *ids, const char *modifier, 1365 bool has_constraint, const bool tool_events[PERF_TOOL_MAX], 1366 struct evlist **out_evlist) 1367{ 1368 struct parse_events_error parse_error; 1369 struct evlist *parsed_evlist; 1370 struct strbuf events = STRBUF_INIT; 1371 int ret; 1372 1373 *out_evlist = NULL; 1374 if (!metric_no_merge || hashmap__size(ids->ids) == 0) { 1375 bool added_event = false; 1376 int i; 1377 /* 1378 * We may fail to share events between metrics because a tool 1379 * event isn't present in one metric. For example, a ratio of 1380 * cache misses doesn't need duration_time but the same events 1381 * may be used for a misses per second. Events without sharing 1382 * implies multiplexing, that is best avoided, so place 1383 * all tool events in every group. 1384 * 1385 * Also, there may be no ids/events in the expression parsing 1386 * context because of constant evaluation, e.g.: 1387 * event1 if #smt_on else 0 1388 * Add a tool event to avoid a parse error on an empty string. 1389 */ 1390 perf_tool_event__for_each_event(i) { 1391 if (tool_events[i]) { 1392 char *tmp = strdup(perf_tool_event__to_str(i)); 1393 1394 if (!tmp) 1395 return -ENOMEM; 1396 ids__insert(ids->ids, tmp); 1397 added_event = true; 1398 } 1399 } 1400 if (!added_event && hashmap__size(ids->ids) == 0) { 1401 char *tmp = strdup("duration_time"); 1402 1403 if (!tmp) 1404 return -ENOMEM; 1405 ids__insert(ids->ids, tmp); 1406 } 1407 } 1408 ret = metricgroup__build_event_string(&events, ids, modifier, 1409 has_constraint); 1410 if (ret) 1411 return ret; 1412 1413 parsed_evlist = evlist__new(); 1414 if (!parsed_evlist) { 1415 ret = -ENOMEM; 1416 goto err_out; 1417 } 1418 pr_debug("Parsing metric events '%s'\n", events.buf); 1419 parse_events_error__init(&parse_error); 1420 ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu); 1421 if (ret) { 1422 parse_events_error__print(&parse_error, events.buf); 1423 goto err_out; 1424 } 1425 ret = decode_all_metric_ids(parsed_evlist, modifier); 1426 if (ret) 1427 goto err_out; 1428 1429 *out_evlist = parsed_evlist; 1430 parsed_evlist = NULL; 1431err_out: 1432 parse_events_error__exit(&parse_error); 1433 evlist__delete(parsed_evlist); 1434 strbuf_release(&events); 1435 return ret; 1436} 1437 1438static int parse_groups(struct evlist *perf_evlist, const char *str, 1439 bool metric_no_group, 1440 bool metric_no_merge, 1441 struct perf_pmu *fake_pmu, 1442 struct rblist *metric_events_list, 1443 const struct pmu_events_map *map) 1444{ 1445 struct evlist *combined_evlist = NULL; 1446 LIST_HEAD(metric_list); 1447 struct metric *m; 1448 bool tool_events[PERF_TOOL_MAX] = {false}; 1449 int ret; 1450 1451 if (metric_events_list->nr_entries == 0) 1452 metricgroup__rblist_init(metric_events_list); 1453 ret = metricgroup__add_metric_list(str, metric_no_group, 1454 &metric_list, map); 1455 if (ret) 1456 goto out; 1457 1458 /* Sort metrics from largest to smallest. */ 1459 list_sort(NULL, &metric_list, metric_list_cmp); 1460 1461 if (!metric_no_merge) { 1462 struct expr_parse_ctx *combined = NULL; 1463 1464 find_tool_events(&metric_list, tool_events); 1465 1466 ret = build_combined_expr_ctx(&metric_list, &combined); 1467 1468 if (!ret && combined && hashmap__size(combined->ids)) { 1469 ret = parse_ids(metric_no_merge, fake_pmu, combined, 1470 /*modifier=*/NULL, 1471 /*has_constraint=*/true, 1472 tool_events, 1473 &combined_evlist); 1474 } 1475 if (combined) 1476 expr__ctx_free(combined); 1477 1478 if (ret) 1479 goto out; 1480 } 1481 1482 list_for_each_entry(m, &metric_list, nd) { 1483 struct metric_event *me; 1484 struct evsel **metric_events; 1485 struct evlist *metric_evlist = NULL; 1486 struct metric *n; 1487 struct metric_expr *expr; 1488 1489 if (combined_evlist && m->has_constraint) { 1490 metric_evlist = combined_evlist; 1491 } else if (!metric_no_merge) { 1492 /* 1493 * See if the IDs for this metric are a subset of an 1494 * earlier metric. 1495 */ 1496 list_for_each_entry(n, &metric_list, nd) { 1497 if (m == n) 1498 break; 1499 1500 if (n->evlist == NULL) 1501 continue; 1502 1503 if ((!m->modifier && n->modifier) || 1504 (m->modifier && !n->modifier) || 1505 (m->modifier && n->modifier && 1506 strcmp(m->modifier, n->modifier))) 1507 continue; 1508 1509 if (expr__subset_of_ids(n->pctx, m->pctx)) { 1510 pr_debug("Events in '%s' fully contained within '%s'\n", 1511 m->metric_name, n->metric_name); 1512 metric_evlist = n->evlist; 1513 break; 1514 } 1515 1516 } 1517 } 1518 if (!metric_evlist) { 1519 ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier, 1520 m->has_constraint, tool_events, &m->evlist); 1521 if (ret) 1522 goto out; 1523 1524 metric_evlist = m->evlist; 1525 } 1526 ret = setup_metric_events(m->pctx->ids, metric_evlist, &metric_events); 1527 if (ret) { 1528 pr_debug("Cannot resolve IDs for %s: %s\n", 1529 m->metric_name, m->metric_expr); 1530 goto out; 1531 } 1532 1533 me = metricgroup__lookup(metric_events_list, metric_events[0], true); 1534 1535 expr = malloc(sizeof(struct metric_expr)); 1536 if (!expr) { 1537 ret = -ENOMEM; 1538 free(metric_events); 1539 goto out; 1540 } 1541 1542 expr->metric_refs = m->metric_refs; 1543 m->metric_refs = NULL; 1544 expr->metric_expr = m->metric_expr; 1545 if (m->modifier) { 1546 char *tmp; 1547 1548 if (asprintf(&tmp, "%s:%s", m->metric_name, m->modifier) < 0) 1549 expr->metric_name = NULL; 1550 else 1551 expr->metric_name = tmp; 1552 } else 1553 expr->metric_name = strdup(m->metric_name); 1554 1555 if (!expr->metric_name) { 1556 ret = -ENOMEM; 1557 free(metric_events); 1558 goto out; 1559 } 1560 expr->metric_unit = m->metric_unit; 1561 expr->metric_events = metric_events; 1562 expr->runtime = m->pctx->runtime; 1563 list_add(&expr->nd, &me->head); 1564 } 1565 1566 1567 if (combined_evlist) { 1568 evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries); 1569 evlist__delete(combined_evlist); 1570 } 1571 1572 list_for_each_entry(m, &metric_list, nd) { 1573 if (m->evlist) 1574 evlist__splice_list_tail(perf_evlist, &m->evlist->core.entries); 1575 } 1576 1577out: 1578 metricgroup__free_metrics(&metric_list); 1579 return ret; 1580} 1581 1582int metricgroup__parse_groups(const struct option *opt, 1583 const char *str, 1584 bool metric_no_group, 1585 bool metric_no_merge, 1586 struct rblist *metric_events) 1587{ 1588 struct evlist *perf_evlist = *(struct evlist **)opt->value; 1589 const struct pmu_events_map *map = pmu_events_map__find(); 1590 1591 return parse_groups(perf_evlist, str, metric_no_group, 1592 metric_no_merge, NULL, metric_events, map); 1593} 1594 1595int metricgroup__parse_groups_test(struct evlist *evlist, 1596 const struct pmu_events_map *map, 1597 const char *str, 1598 bool metric_no_group, 1599 bool metric_no_merge, 1600 struct rblist *metric_events) 1601{ 1602 return parse_groups(evlist, str, metric_no_group, 1603 metric_no_merge, &perf_pmu__fake, metric_events, map); 1604} 1605 1606bool metricgroup__has_metric(const char *metric) 1607{ 1608 const struct pmu_events_map *map = pmu_events_map__find(); 1609 const struct pmu_event *pe; 1610 int i; 1611 1612 if (!map) 1613 return false; 1614 1615 for (i = 0; ; i++) { 1616 pe = &map->table[i]; 1617 1618 if (!pe->name && !pe->metric_group && !pe->metric_name) 1619 break; 1620 if (!pe->metric_expr) 1621 continue; 1622 if (match_metric(pe->metric_name, metric)) 1623 return true; 1624 } 1625 return false; 1626} 1627 1628int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, 1629 struct rblist *new_metric_events, 1630 struct rblist *old_metric_events) 1631{ 1632 unsigned i; 1633 1634 for (i = 0; i < rblist__nr_entries(old_metric_events); i++) { 1635 struct rb_node *nd; 1636 struct metric_event *old_me, *new_me; 1637 struct metric_expr *old_expr, *new_expr; 1638 struct evsel *evsel; 1639 size_t alloc_size; 1640 int idx, nr; 1641 1642 nd = rblist__entry(old_metric_events, i); 1643 old_me = container_of(nd, struct metric_event, nd); 1644 1645 evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx); 1646 if (!evsel) 1647 return -EINVAL; 1648 new_me = metricgroup__lookup(new_metric_events, evsel, true); 1649 if (!new_me) 1650 return -ENOMEM; 1651 1652 pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n", 1653 cgrp ? cgrp->name : "root", evsel->name, evsel->core.idx); 1654 1655 list_for_each_entry(old_expr, &old_me->head, nd) { 1656 new_expr = malloc(sizeof(*new_expr)); 1657 if (!new_expr) 1658 return -ENOMEM; 1659 1660 new_expr->metric_expr = old_expr->metric_expr; 1661 new_expr->metric_name = strdup(old_expr->metric_name); 1662 if (!new_expr->metric_name) 1663 return -ENOMEM; 1664 1665 new_expr->metric_unit = old_expr->metric_unit; 1666 new_expr->runtime = old_expr->runtime; 1667 1668 if (old_expr->metric_refs) { 1669 /* calculate number of metric_events */ 1670 for (nr = 0; old_expr->metric_refs[nr].metric_name; nr++) 1671 continue; 1672 alloc_size = sizeof(*new_expr->metric_refs); 1673 new_expr->metric_refs = calloc(nr + 1, alloc_size); 1674 if (!new_expr->metric_refs) { 1675 free(new_expr); 1676 return -ENOMEM; 1677 } 1678 1679 memcpy(new_expr->metric_refs, old_expr->metric_refs, 1680 nr * alloc_size); 1681 } else { 1682 new_expr->metric_refs = NULL; 1683 } 1684 1685 /* calculate number of metric_events */ 1686 for (nr = 0; old_expr->metric_events[nr]; nr++) 1687 continue; 1688 alloc_size = sizeof(*new_expr->metric_events); 1689 new_expr->metric_events = calloc(nr + 1, alloc_size); 1690 if (!new_expr->metric_events) { 1691 free(new_expr->metric_refs); 1692 free(new_expr); 1693 return -ENOMEM; 1694 } 1695 1696 /* copy evsel in the same position */ 1697 for (idx = 0; idx < nr; idx++) { 1698 evsel = old_expr->metric_events[idx]; 1699 evsel = evlist__find_evsel(evlist, evsel->core.idx); 1700 if (evsel == NULL) { 1701 free(new_expr->metric_events); 1702 free(new_expr->metric_refs); 1703 free(new_expr); 1704 return -EINVAL; 1705 } 1706 new_expr->metric_events[idx] = evsel; 1707 } 1708 1709 list_add(&new_expr->nd, &new_me->head); 1710 } 1711 } 1712 return 0; 1713}