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 free(m); 213 expr__ctx_free(m->pctx); 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(metric_events[i]), 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 typedef int (*metricgroup_sys_event_iter_fn)(const struct pmu_event *pe, void *); 506 507 struct metricgroup_iter_data { 508 metricgroup_sys_event_iter_fn fn; 509 void *data; 510 }; 511 512 static 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 531 static 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 539 void 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 614 static const char *code_characters = ",-=@"; 615 616 static 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 640 static 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 665 static 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 724 static 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_duration = false; 732 int ret = 0; 733 734 #define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0) 735 736 hashmap__for_each_entry(ctx->ids, cur, bkt) { 737 const char *sep, *rsep, *id = cur->key; 738 739 pr_debug("found event %s\n", id); 740 /* 741 * Duration time maps to a software event and can make 742 * groups not count. Always use it outside a 743 * group. 744 */ 745 if (!strcmp(id, "duration_time")) { 746 has_duration = true; 747 continue; 748 } 749 /* Separate events with commas and open the group if necessary. */ 750 if (no_group) { 751 if (!has_constraint) { 752 ret = strbuf_addch(events, '{'); 753 RETURN_IF_NON_ZERO(ret); 754 } 755 756 no_group = false; 757 } else { 758 ret = strbuf_addch(events, ','); 759 RETURN_IF_NON_ZERO(ret); 760 } 761 /* 762 * Encode the ID as an event string. Add a qualifier for 763 * metric_id that is the original name except with characters 764 * that parse-events can't parse replaced. For example, 765 * 'msr@tsc@' gets added as msr/tsc,metric-id=msr!3tsc!3/ 766 */ 767 sep = strchr(id, '@'); 768 if (sep != NULL) { 769 ret = strbuf_add(events, id, sep - id); 770 RETURN_IF_NON_ZERO(ret); 771 ret = strbuf_addch(events, '/'); 772 RETURN_IF_NON_ZERO(ret); 773 rsep = strrchr(sep, '@'); 774 ret = strbuf_add(events, sep + 1, rsep - sep - 1); 775 RETURN_IF_NON_ZERO(ret); 776 ret = strbuf_addstr(events, ",metric-id="); 777 RETURN_IF_NON_ZERO(ret); 778 sep = rsep; 779 } else { 780 sep = strchr(id, ':'); 781 if (sep != NULL) { 782 ret = strbuf_add(events, id, sep - id); 783 RETURN_IF_NON_ZERO(ret); 784 } else { 785 ret = strbuf_addstr(events, id); 786 RETURN_IF_NON_ZERO(ret); 787 } 788 ret = strbuf_addstr(events, "/metric-id="); 789 RETURN_IF_NON_ZERO(ret); 790 } 791 ret = encode_metric_id(events, id); 792 RETURN_IF_NON_ZERO(ret); 793 ret = strbuf_addstr(events, "/"); 794 RETURN_IF_NON_ZERO(ret); 795 796 if (sep != NULL) { 797 ret = strbuf_addstr(events, sep + 1); 798 RETURN_IF_NON_ZERO(ret); 799 } 800 if (modifier) { 801 ret = strbuf_addstr(events, modifier); 802 RETURN_IF_NON_ZERO(ret); 803 } 804 } 805 if (has_duration) { 806 if (no_group) { 807 /* Strange case of a metric of just duration_time. */ 808 ret = strbuf_addf(events, "duration_time"); 809 } else if (!has_constraint) 810 ret = strbuf_addf(events, "}:W,duration_time"); 811 else 812 ret = strbuf_addf(events, ",duration_time"); 813 } else if (!no_group && !has_constraint) 814 ret = strbuf_addf(events, "}:W"); 815 816 return ret; 817 #undef RETURN_IF_NON_ZERO 818 } 819 820 int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused) 821 { 822 return 1; 823 } 824 825 /* 826 * A singly linked list on the stack of the names of metrics being 827 * processed. Used to identify recursion. 828 */ 829 struct visited_metric { 830 const char *name; 831 const struct visited_metric *parent; 832 }; 833 834 struct metricgroup_add_iter_data { 835 struct list_head *metric_list; 836 const char *metric_name; 837 const char *modifier; 838 int *ret; 839 bool *has_match; 840 bool metric_no_group; 841 struct metric *root_metric; 842 const struct visited_metric *visited; 843 const struct pmu_events_map *map; 844 }; 845 846 static int add_metric(struct list_head *metric_list, 847 const struct pmu_event *pe, 848 const char *modifier, 849 bool metric_no_group, 850 struct metric *root_metric, 851 const struct visited_metric *visited, 852 const struct pmu_events_map *map); 853 854 /** 855 * resolve_metric - Locate metrics within the root metric and recursively add 856 * references to them. 857 * @metric_list: The list the metric is added to. 858 * @modifier: if non-null event modifiers like "u". 859 * @metric_no_group: Should events written to events be grouped "{}" or 860 * global. Grouping is the default but due to multiplexing the 861 * user may override. 862 * @root_metric: Metrics may reference other metrics to form a tree. In this 863 * case the root_metric holds all the IDs and a list of referenced 864 * metrics. When adding a root this argument is NULL. 865 * @visited: A singly linked list of metric names being added that is used to 866 * detect recursion. 867 * @map: The map that is searched for metrics, most commonly the table for the 868 * architecture perf is running upon. 869 */ 870 static int resolve_metric(struct list_head *metric_list, 871 const char *modifier, 872 bool metric_no_group, 873 struct metric *root_metric, 874 const struct visited_metric *visited, 875 const struct pmu_events_map *map) 876 { 877 struct hashmap_entry *cur; 878 size_t bkt; 879 struct to_resolve { 880 /* The metric to resolve. */ 881 const struct pmu_event *pe; 882 /* 883 * The key in the IDs map, this may differ from in case, 884 * etc. from pe->metric_name. 885 */ 886 const char *key; 887 } *pending = NULL; 888 int i, ret = 0, pending_cnt = 0; 889 890 /* 891 * Iterate all the parsed IDs and if there's a matching metric and it to 892 * the pending array. 893 */ 894 hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) { 895 const struct pmu_event *pe; 896 897 pe = metricgroup__find_metric(cur->key, map); 898 if (pe) { 899 pending = realloc(pending, 900 (pending_cnt + 1) * sizeof(struct to_resolve)); 901 if (!pending) 902 return -ENOMEM; 903 904 pending[pending_cnt].pe = pe; 905 pending[pending_cnt].key = cur->key; 906 pending_cnt++; 907 } 908 } 909 910 /* Remove the metric IDs from the context. */ 911 for (i = 0; i < pending_cnt; i++) 912 expr__del_id(root_metric->pctx, pending[i].key); 913 914 /* 915 * Recursively add all the metrics, IDs are added to the root metric's 916 * context. 917 */ 918 for (i = 0; i < pending_cnt; i++) { 919 ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group, 920 root_metric, visited, map); 921 if (ret) 922 break; 923 } 924 925 free(pending); 926 return ret; 927 } 928 929 /** 930 * __add_metric - Add a metric to metric_list. 931 * @metric_list: The list the metric is added to. 932 * @pe: The pmu_event containing the metric to be added. 933 * @modifier: if non-null event modifiers like "u". 934 * @metric_no_group: Should events written to events be grouped "{}" or 935 * global. Grouping is the default but due to multiplexing the 936 * user may override. 937 * @runtime: A special argument for the parser only known at runtime. 938 * @root_metric: Metrics may reference other metrics to form a tree. In this 939 * case the root_metric holds all the IDs and a list of referenced 940 * metrics. When adding a root this argument is NULL. 941 * @visited: A singly linked list of metric names being added that is used to 942 * detect recursion. 943 * @map: The map that is searched for metrics, most commonly the table for the 944 * architecture perf is running upon. 945 */ 946 static int __add_metric(struct list_head *metric_list, 947 const struct pmu_event *pe, 948 const char *modifier, 949 bool metric_no_group, 950 int runtime, 951 struct metric *root_metric, 952 const struct visited_metric *visited, 953 const struct pmu_events_map *map) 954 { 955 const struct visited_metric *vm; 956 int ret; 957 bool is_root = !root_metric; 958 struct visited_metric visited_node = { 959 .name = pe->metric_name, 960 .parent = visited, 961 }; 962 963 for (vm = visited; vm; vm = vm->parent) { 964 if (!strcmp(pe->metric_name, vm->name)) { 965 pr_err("failed: recursion detected for %s\n", pe->metric_name); 966 return -1; 967 } 968 } 969 970 if (is_root) { 971 /* 972 * This metric is the root of a tree and may reference other 973 * metrics that are added recursively. 974 */ 975 root_metric = metric__new(pe, modifier, metric_no_group, runtime); 976 if (!root_metric) 977 return -ENOMEM; 978 979 } else { 980 int cnt = 0; 981 982 /* 983 * This metric was referenced in a metric higher in the 984 * tree. Check if the same metric is already resolved in the 985 * metric_refs list. 986 */ 987 if (root_metric->metric_refs) { 988 for (; root_metric->metric_refs[cnt].metric_name; cnt++) { 989 if (!strcmp(pe->metric_name, 990 root_metric->metric_refs[cnt].metric_name)) 991 return 0; 992 } 993 } 994 995 /* Create reference. Need space for the entry and the terminator. */ 996 root_metric->metric_refs = realloc(root_metric->metric_refs, 997 (cnt + 2) * sizeof(struct metric_ref)); 998 if (!root_metric->metric_refs) 999 return -ENOMEM; 1000 1001 /* 1002 * Intentionally passing just const char pointers, 1003 * from 'pe' object, so they never go away. We don't 1004 * need to change them, so there's no need to create 1005 * our own copy. 1006 */ 1007 root_metric->metric_refs[cnt].metric_name = pe->metric_name; 1008 root_metric->metric_refs[cnt].metric_expr = pe->metric_expr; 1009 1010 /* Null terminate array. */ 1011 root_metric->metric_refs[cnt+1].metric_name = NULL; 1012 root_metric->metric_refs[cnt+1].metric_expr = NULL; 1013 } 1014 1015 /* 1016 * For both the parent and referenced metrics, we parse 1017 * all the metric's IDs and add it to the root context. 1018 */ 1019 if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) { 1020 /* Broken metric. */ 1021 ret = -EINVAL; 1022 } else { 1023 /* Resolve referenced metrics. */ 1024 ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric, 1025 &visited_node, map); 1026 } 1027 1028 if (ret) { 1029 if (is_root) 1030 metric__free(root_metric); 1031 1032 } else if (is_root) 1033 list_add(&root_metric->nd, metric_list); 1034 1035 return ret; 1036 } 1037 1038 #define map_for_each_event(__pe, __idx, __map) \ 1039 if (__map) \ 1040 for (__idx = 0, __pe = &__map->table[__idx]; \ 1041 __pe->name || __pe->metric_group || __pe->metric_name; \ 1042 __pe = &__map->table[++__idx]) 1043 1044 #define map_for_each_metric(__pe, __idx, __map, __metric) \ 1045 map_for_each_event(__pe, __idx, __map) \ 1046 if (__pe->metric_expr && \ 1047 (match_metric(__pe->metric_group, __metric) || \ 1048 match_metric(__pe->metric_name, __metric))) 1049 1050 const struct pmu_event *metricgroup__find_metric(const char *metric, 1051 const struct pmu_events_map *map) 1052 { 1053 const struct pmu_event *pe; 1054 int i; 1055 1056 map_for_each_event(pe, i, map) { 1057 if (match_metric(pe->metric_name, metric)) 1058 return pe; 1059 } 1060 1061 return NULL; 1062 } 1063 1064 static int add_metric(struct list_head *metric_list, 1065 const struct pmu_event *pe, 1066 const char *modifier, 1067 bool metric_no_group, 1068 struct metric *root_metric, 1069 const struct visited_metric *visited, 1070 const struct pmu_events_map *map) 1071 { 1072 int ret = 0; 1073 1074 pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name); 1075 1076 if (!strstr(pe->metric_expr, "?")) { 1077 ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0, 1078 root_metric, visited, map); 1079 } else { 1080 int j, count; 1081 1082 count = arch_get_runtimeparam(pe); 1083 1084 /* This loop is added to create multiple 1085 * events depend on count value and add 1086 * those events to metric_list. 1087 */ 1088 1089 for (j = 0; j < count && !ret; j++) 1090 ret = __add_metric(metric_list, pe, modifier, metric_no_group, j, 1091 root_metric, visited, map); 1092 } 1093 1094 return ret; 1095 } 1096 1097 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe, 1098 void *data) 1099 { 1100 struct metricgroup_add_iter_data *d = data; 1101 int ret; 1102 1103 if (!match_pe_metric(pe, d->metric_name)) 1104 return 0; 1105 1106 ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group, 1107 d->root_metric, d->visited, d->map); 1108 if (ret) 1109 goto out; 1110 1111 *(d->has_match) = true; 1112 1113 out: 1114 *(d->ret) = ret; 1115 return ret; 1116 } 1117 1118 static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, 1119 const struct list_head *r) 1120 { 1121 const struct metric *left = container_of(l, struct metric, nd); 1122 const struct metric *right = container_of(r, struct metric, nd); 1123 1124 return hashmap__size(right->pctx->ids) - hashmap__size(left->pctx->ids); 1125 } 1126 1127 /** 1128 * metricgroup__add_metric - Find and add a metric, or a metric group. 1129 * @metric_name: The name of the metric or metric group. For example, "IPC" 1130 * could be the name of a metric and "TopDownL1" the name of a 1131 * metric group. 1132 * @modifier: if non-null event modifiers like "u". 1133 * @metric_no_group: Should events written to events be grouped "{}" or 1134 * global. Grouping is the default but due to multiplexing the 1135 * user may override. 1136 * @metric_list: The list that the metric or metric group are added to. 1137 * @map: The map that is searched for metrics, most commonly the table for the 1138 * architecture perf is running upon. 1139 */ 1140 static int metricgroup__add_metric(const char *metric_name, const char *modifier, 1141 bool metric_no_group, 1142 struct list_head *metric_list, 1143 const struct pmu_events_map *map) 1144 { 1145 const struct pmu_event *pe; 1146 LIST_HEAD(list); 1147 int i, ret; 1148 bool has_match = false; 1149 1150 /* 1151 * Iterate over all metrics seeing if metric matches either the name or 1152 * group. When it does add the metric to the list. 1153 */ 1154 map_for_each_metric(pe, i, map, metric_name) { 1155 has_match = true; 1156 ret = add_metric(&list, pe, modifier, metric_no_group, 1157 /*root_metric=*/NULL, 1158 /*visited_metrics=*/NULL, map); 1159 if (ret) 1160 goto out; 1161 } 1162 1163 { 1164 struct metricgroup_iter_data data = { 1165 .fn = metricgroup__add_metric_sys_event_iter, 1166 .data = (void *) &(struct metricgroup_add_iter_data) { 1167 .metric_list = &list, 1168 .metric_name = metric_name, 1169 .modifier = modifier, 1170 .metric_no_group = metric_no_group, 1171 .has_match = &has_match, 1172 .ret = &ret, 1173 .map = map, 1174 }, 1175 }; 1176 1177 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); 1178 } 1179 /* End of pmu events. */ 1180 if (!has_match) 1181 ret = -EINVAL; 1182 1183 out: 1184 /* 1185 * add to metric_list so that they can be released 1186 * even if it's failed 1187 */ 1188 list_splice(&list, metric_list); 1189 return ret; 1190 } 1191 1192 /** 1193 * metricgroup__add_metric_list - Find and add metrics, or metric groups, 1194 * specified in a list. 1195 * @list: the list of metrics or metric groups. For example, "IPC,CPI,TopDownL1" 1196 * would match the IPC and CPI metrics, and TopDownL1 would match all 1197 * the metrics in the TopDownL1 group. 1198 * @metric_no_group: Should events written to events be grouped "{}" or 1199 * global. Grouping is the default but due to multiplexing the 1200 * user may override. 1201 * @metric_list: The list that metrics are added to. 1202 * @map: The map that is searched for metrics, most commonly the table for the 1203 * architecture perf is running upon. 1204 */ 1205 static int metricgroup__add_metric_list(const char *list, bool metric_no_group, 1206 struct list_head *metric_list, 1207 const struct pmu_events_map *map) 1208 { 1209 char *list_itr, *list_copy, *metric_name, *modifier; 1210 int ret, count = 0; 1211 1212 list_copy = strdup(list); 1213 if (!list_copy) 1214 return -ENOMEM; 1215 list_itr = list_copy; 1216 1217 while ((metric_name = strsep(&list_itr, ",")) != NULL) { 1218 modifier = strchr(metric_name, ':'); 1219 if (modifier) 1220 *modifier++ = '\0'; 1221 1222 ret = metricgroup__add_metric(metric_name, modifier, 1223 metric_no_group, metric_list, 1224 map); 1225 if (ret == -EINVAL) 1226 pr_err("Cannot find metric or group `%s'\n", metric_name); 1227 1228 if (ret) 1229 break; 1230 1231 count++; 1232 } 1233 free(list_copy); 1234 1235 if (!ret) { 1236 /* 1237 * Warn about nmi_watchdog if any parsed metrics had the 1238 * NO_NMI_WATCHDOG constraint. 1239 */ 1240 metricgroup___watchdog_constraint_hint(NULL, true); 1241 /* No metrics. */ 1242 if (count == 0) 1243 return -EINVAL; 1244 } 1245 return ret; 1246 } 1247 1248 static void metricgroup__free_metrics(struct list_head *metric_list) 1249 { 1250 struct metric *m, *tmp; 1251 1252 list_for_each_entry_safe (m, tmp, metric_list, nd) { 1253 list_del_init(&m->nd); 1254 metric__free(m); 1255 } 1256 } 1257 1258 /** 1259 * build_combined_expr_ctx - Make an expr_parse_ctx with all has_constraint 1260 * metric IDs, as the IDs are held in a set, 1261 * duplicates will be removed. 1262 * @metric_list: List to take metrics from. 1263 * @combined: Out argument for result. 1264 */ 1265 static int build_combined_expr_ctx(const struct list_head *metric_list, 1266 struct expr_parse_ctx **combined) 1267 { 1268 struct hashmap_entry *cur; 1269 size_t bkt; 1270 struct metric *m; 1271 char *dup; 1272 int ret; 1273 1274 *combined = expr__ctx_new(); 1275 if (!*combined) 1276 return -ENOMEM; 1277 1278 list_for_each_entry(m, metric_list, nd) { 1279 if (m->has_constraint && !m->modifier) { 1280 hashmap__for_each_entry(m->pctx->ids, cur, bkt) { 1281 dup = strdup(cur->key); 1282 if (!dup) { 1283 ret = -ENOMEM; 1284 goto err_out; 1285 } 1286 ret = expr__add_id(*combined, dup); 1287 if (ret) 1288 goto err_out; 1289 } 1290 } 1291 } 1292 return 0; 1293 err_out: 1294 expr__ctx_free(*combined); 1295 *combined = NULL; 1296 return ret; 1297 } 1298 1299 /** 1300 * parse_ids - Build the event string for the ids and parse them creating an 1301 * evlist. The encoded metric_ids are decoded. 1302 * @fake_pmu: used when testing metrics not supported by the current CPU. 1303 * @ids: the event identifiers parsed from a metric. 1304 * @modifier: any modifiers added to the events. 1305 * @has_constraint: false if events should be placed in a weak group. 1306 * @out_evlist: the created list of events. 1307 */ 1308 static int parse_ids(struct perf_pmu *fake_pmu, struct expr_parse_ctx *ids, 1309 const char *modifier, bool has_constraint, struct evlist **out_evlist) 1310 { 1311 struct parse_events_error parse_error; 1312 struct evlist *parsed_evlist; 1313 struct strbuf events = STRBUF_INIT; 1314 int ret; 1315 1316 *out_evlist = NULL; 1317 if (hashmap__size(ids->ids) == 0) { 1318 char *tmp; 1319 /* 1320 * No ids/events in the expression parsing context. Events may 1321 * have been removed because of constant evaluation, e.g.: 1322 * event1 if #smt_on else 0 1323 * Add a duration_time event to avoid a parse error on an empty 1324 * string. 1325 */ 1326 tmp = strdup("duration_time"); 1327 if (!tmp) 1328 return -ENOMEM; 1329 1330 ids__insert(ids->ids, tmp); 1331 } 1332 ret = metricgroup__build_event_string(&events, ids, modifier, 1333 has_constraint); 1334 if (ret) 1335 return ret; 1336 1337 parsed_evlist = evlist__new(); 1338 if (!parsed_evlist) { 1339 ret = -ENOMEM; 1340 goto err_out; 1341 } 1342 pr_debug("Parsing metric events '%s'\n", events.buf); 1343 parse_events_error__init(&parse_error); 1344 ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu); 1345 if (ret) { 1346 parse_events_error__print(&parse_error, events.buf); 1347 goto err_out; 1348 } 1349 ret = decode_all_metric_ids(parsed_evlist, modifier); 1350 if (ret) 1351 goto err_out; 1352 1353 *out_evlist = parsed_evlist; 1354 parsed_evlist = NULL; 1355 err_out: 1356 parse_events_error__exit(&parse_error); 1357 evlist__delete(parsed_evlist); 1358 strbuf_release(&events); 1359 return ret; 1360 } 1361 1362 static int parse_groups(struct evlist *perf_evlist, const char *str, 1363 bool metric_no_group, 1364 bool metric_no_merge, 1365 struct perf_pmu *fake_pmu, 1366 struct rblist *metric_events_list, 1367 const struct pmu_events_map *map) 1368 { 1369 struct evlist *combined_evlist = NULL; 1370 LIST_HEAD(metric_list); 1371 struct metric *m; 1372 int ret; 1373 1374 if (metric_events_list->nr_entries == 0) 1375 metricgroup__rblist_init(metric_events_list); 1376 ret = metricgroup__add_metric_list(str, metric_no_group, 1377 &metric_list, map); 1378 if (ret) 1379 goto out; 1380 1381 /* Sort metrics from largest to smallest. */ 1382 list_sort(NULL, &metric_list, metric_list_cmp); 1383 1384 if (!metric_no_merge) { 1385 struct expr_parse_ctx *combined = NULL; 1386 1387 ret = build_combined_expr_ctx(&metric_list, &combined); 1388 1389 if (!ret && combined && hashmap__size(combined->ids)) { 1390 ret = parse_ids(fake_pmu, combined, /*modifier=*/NULL, 1391 /*has_constraint=*/true, 1392 &combined_evlist); 1393 } 1394 if (combined) 1395 expr__ctx_free(combined); 1396 1397 if (ret) 1398 goto out; 1399 } 1400 1401 list_for_each_entry(m, &metric_list, nd) { 1402 struct metric_event *me; 1403 struct evsel **metric_events; 1404 struct evlist *metric_evlist = NULL; 1405 struct metric *n; 1406 struct metric_expr *expr; 1407 1408 if (combined_evlist && m->has_constraint) { 1409 metric_evlist = combined_evlist; 1410 } else if (!metric_no_merge) { 1411 /* 1412 * See if the IDs for this metric are a subset of an 1413 * earlier metric. 1414 */ 1415 list_for_each_entry(n, &metric_list, nd) { 1416 if (m == n) 1417 break; 1418 1419 if (n->evlist == NULL) 1420 continue; 1421 1422 if ((!m->modifier && n->modifier) || 1423 (m->modifier && !n->modifier) || 1424 (m->modifier && n->modifier && 1425 strcmp(m->modifier, n->modifier))) 1426 continue; 1427 1428 if (expr__subset_of_ids(n->pctx, m->pctx)) { 1429 pr_debug("Events in '%s' fully contained within '%s'\n", 1430 m->metric_name, n->metric_name); 1431 metric_evlist = n->evlist; 1432 break; 1433 } 1434 1435 } 1436 } 1437 if (!metric_evlist) { 1438 ret = parse_ids(fake_pmu, m->pctx, m->modifier, 1439 m->has_constraint, &m->evlist); 1440 if (ret) 1441 goto out; 1442 1443 metric_evlist = m->evlist; 1444 } 1445 ret = setup_metric_events(m->pctx->ids, metric_evlist, &metric_events); 1446 if (ret) { 1447 pr_debug("Cannot resolve IDs for %s: %s\n", 1448 m->metric_name, m->metric_expr); 1449 goto out; 1450 } 1451 1452 me = metricgroup__lookup(metric_events_list, metric_events[0], true); 1453 1454 expr = malloc(sizeof(struct metric_expr)); 1455 if (!expr) { 1456 ret = -ENOMEM; 1457 free(metric_events); 1458 goto out; 1459 } 1460 1461 expr->metric_refs = m->metric_refs; 1462 m->metric_refs = NULL; 1463 expr->metric_expr = m->metric_expr; 1464 if (m->modifier) { 1465 char *tmp; 1466 1467 if (asprintf(&tmp, "%s:%s", m->metric_name, m->modifier) < 0) 1468 expr->metric_name = NULL; 1469 else 1470 expr->metric_name = tmp; 1471 } else 1472 expr->metric_name = strdup(m->metric_name); 1473 1474 if (!expr->metric_name) { 1475 ret = -ENOMEM; 1476 free(metric_events); 1477 goto out; 1478 } 1479 expr->metric_unit = m->metric_unit; 1480 expr->metric_events = metric_events; 1481 expr->runtime = m->pctx->runtime; 1482 list_add(&expr->nd, &me->head); 1483 } 1484 1485 1486 if (combined_evlist) { 1487 evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries); 1488 evlist__delete(combined_evlist); 1489 } 1490 1491 list_for_each_entry(m, &metric_list, nd) { 1492 if (m->evlist) 1493 evlist__splice_list_tail(perf_evlist, &m->evlist->core.entries); 1494 } 1495 1496 out: 1497 metricgroup__free_metrics(&metric_list); 1498 return ret; 1499 } 1500 1501 int metricgroup__parse_groups(const struct option *opt, 1502 const char *str, 1503 bool metric_no_group, 1504 bool metric_no_merge, 1505 struct rblist *metric_events) 1506 { 1507 struct evlist *perf_evlist = *(struct evlist **)opt->value; 1508 const struct pmu_events_map *map = pmu_events_map__find(); 1509 1510 return parse_groups(perf_evlist, str, metric_no_group, 1511 metric_no_merge, NULL, metric_events, map); 1512 } 1513 1514 int metricgroup__parse_groups_test(struct evlist *evlist, 1515 const struct pmu_events_map *map, 1516 const char *str, 1517 bool metric_no_group, 1518 bool metric_no_merge, 1519 struct rblist *metric_events) 1520 { 1521 return parse_groups(evlist, str, metric_no_group, 1522 metric_no_merge, &perf_pmu__fake, metric_events, map); 1523 } 1524 1525 bool metricgroup__has_metric(const char *metric) 1526 { 1527 const struct pmu_events_map *map = pmu_events_map__find(); 1528 const struct pmu_event *pe; 1529 int i; 1530 1531 if (!map) 1532 return false; 1533 1534 for (i = 0; ; i++) { 1535 pe = &map->table[i]; 1536 1537 if (!pe->name && !pe->metric_group && !pe->metric_name) 1538 break; 1539 if (!pe->metric_expr) 1540 continue; 1541 if (match_metric(pe->metric_name, metric)) 1542 return true; 1543 } 1544 return false; 1545 } 1546 1547 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, 1548 struct rblist *new_metric_events, 1549 struct rblist *old_metric_events) 1550 { 1551 unsigned i; 1552 1553 for (i = 0; i < rblist__nr_entries(old_metric_events); i++) { 1554 struct rb_node *nd; 1555 struct metric_event *old_me, *new_me; 1556 struct metric_expr *old_expr, *new_expr; 1557 struct evsel *evsel; 1558 size_t alloc_size; 1559 int idx, nr; 1560 1561 nd = rblist__entry(old_metric_events, i); 1562 old_me = container_of(nd, struct metric_event, nd); 1563 1564 evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx); 1565 if (!evsel) 1566 return -EINVAL; 1567 new_me = metricgroup__lookup(new_metric_events, evsel, true); 1568 if (!new_me) 1569 return -ENOMEM; 1570 1571 pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n", 1572 cgrp ? cgrp->name : "root", evsel->name, evsel->core.idx); 1573 1574 list_for_each_entry(old_expr, &old_me->head, nd) { 1575 new_expr = malloc(sizeof(*new_expr)); 1576 if (!new_expr) 1577 return -ENOMEM; 1578 1579 new_expr->metric_expr = old_expr->metric_expr; 1580 new_expr->metric_name = strdup(old_expr->metric_name); 1581 if (!new_expr->metric_name) 1582 return -ENOMEM; 1583 1584 new_expr->metric_unit = old_expr->metric_unit; 1585 new_expr->runtime = old_expr->runtime; 1586 1587 if (old_expr->metric_refs) { 1588 /* calculate number of metric_events */ 1589 for (nr = 0; old_expr->metric_refs[nr].metric_name; nr++) 1590 continue; 1591 alloc_size = sizeof(*new_expr->metric_refs); 1592 new_expr->metric_refs = calloc(nr + 1, alloc_size); 1593 if (!new_expr->metric_refs) { 1594 free(new_expr); 1595 return -ENOMEM; 1596 } 1597 1598 memcpy(new_expr->metric_refs, old_expr->metric_refs, 1599 nr * alloc_size); 1600 } else { 1601 new_expr->metric_refs = NULL; 1602 } 1603 1604 /* calculate number of metric_events */ 1605 for (nr = 0; old_expr->metric_events[nr]; nr++) 1606 continue; 1607 alloc_size = sizeof(*new_expr->metric_events); 1608 new_expr->metric_events = calloc(nr + 1, alloc_size); 1609 if (!new_expr->metric_events) { 1610 free(new_expr->metric_refs); 1611 free(new_expr); 1612 return -ENOMEM; 1613 } 1614 1615 /* copy evsel in the same position */ 1616 for (idx = 0; idx < nr; idx++) { 1617 evsel = old_expr->metric_events[idx]; 1618 evsel = evlist__find_evsel(evlist, evsel->core.idx); 1619 if (evsel == NULL) { 1620 free(new_expr->metric_events); 1621 free(new_expr->metric_refs); 1622 free(new_expr); 1623 return -EINVAL; 1624 } 1625 new_expr->metric_events[idx] = evsel; 1626 } 1627 1628 list_add(&new_expr->nd, &new_me->head); 1629 } 1630 } 1631 return 0; 1632 } 1633