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 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 /** 1119 * metric_list_cmp - list_sort comparator that sorts metrics with more events to 1120 * the front. duration_time is excluded from the count. 1121 */ 1122 static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, 1123 const struct list_head *r) 1124 { 1125 const struct metric *left = container_of(l, struct metric, nd); 1126 const struct metric *right = container_of(r, struct metric, nd); 1127 struct expr_id_data *data; 1128 int left_count, right_count; 1129 1130 left_count = hashmap__size(left->pctx->ids); 1131 if (!expr__get_id(left->pctx, "duration_time", &data)) 1132 left_count--; 1133 1134 right_count = hashmap__size(right->pctx->ids); 1135 if (!expr__get_id(right->pctx, "duration_time", &data)) 1136 right_count--; 1137 1138 return right_count - left_count; 1139 } 1140 1141 /** 1142 * metricgroup__add_metric - Find and add a metric, or a metric group. 1143 * @metric_name: The name of the metric or metric group. For example, "IPC" 1144 * could be the name of a metric and "TopDownL1" the name of a 1145 * metric group. 1146 * @modifier: if non-null event modifiers like "u". 1147 * @metric_no_group: Should events written to events be grouped "{}" or 1148 * global. Grouping is the default but due to multiplexing the 1149 * user may override. 1150 * @metric_list: The list that the metric or metric group are added to. 1151 * @map: The map that is searched for metrics, most commonly the table for the 1152 * architecture perf is running upon. 1153 */ 1154 static int metricgroup__add_metric(const char *metric_name, const char *modifier, 1155 bool metric_no_group, 1156 struct list_head *metric_list, 1157 const struct pmu_events_map *map) 1158 { 1159 const struct pmu_event *pe; 1160 LIST_HEAD(list); 1161 int i, ret; 1162 bool has_match = false; 1163 1164 /* 1165 * Iterate over all metrics seeing if metric matches either the name or 1166 * group. When it does add the metric to the list. 1167 */ 1168 map_for_each_metric(pe, i, map, metric_name) { 1169 has_match = true; 1170 ret = add_metric(&list, pe, modifier, metric_no_group, 1171 /*root_metric=*/NULL, 1172 /*visited_metrics=*/NULL, map); 1173 if (ret) 1174 goto out; 1175 } 1176 1177 { 1178 struct metricgroup_iter_data data = { 1179 .fn = metricgroup__add_metric_sys_event_iter, 1180 .data = (void *) &(struct metricgroup_add_iter_data) { 1181 .metric_list = &list, 1182 .metric_name = metric_name, 1183 .modifier = modifier, 1184 .metric_no_group = metric_no_group, 1185 .has_match = &has_match, 1186 .ret = &ret, 1187 .map = map, 1188 }, 1189 }; 1190 1191 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); 1192 } 1193 /* End of pmu events. */ 1194 if (!has_match) 1195 ret = -EINVAL; 1196 1197 out: 1198 /* 1199 * add to metric_list so that they can be released 1200 * even if it's failed 1201 */ 1202 list_splice(&list, metric_list); 1203 return ret; 1204 } 1205 1206 /** 1207 * metricgroup__add_metric_list - Find and add metrics, or metric groups, 1208 * specified in a list. 1209 * @list: the list of metrics or metric groups. For example, "IPC,CPI,TopDownL1" 1210 * would match the IPC and CPI metrics, and TopDownL1 would match all 1211 * the metrics in the TopDownL1 group. 1212 * @metric_no_group: Should events written to events be grouped "{}" or 1213 * global. Grouping is the default but due to multiplexing the 1214 * user may override. 1215 * @metric_list: The list that metrics are added to. 1216 * @map: The map that is searched for metrics, most commonly the table for the 1217 * architecture perf is running upon. 1218 */ 1219 static int metricgroup__add_metric_list(const char *list, bool metric_no_group, 1220 struct list_head *metric_list, 1221 const struct pmu_events_map *map) 1222 { 1223 char *list_itr, *list_copy, *metric_name, *modifier; 1224 int ret, count = 0; 1225 1226 list_copy = strdup(list); 1227 if (!list_copy) 1228 return -ENOMEM; 1229 list_itr = list_copy; 1230 1231 while ((metric_name = strsep(&list_itr, ",")) != NULL) { 1232 modifier = strchr(metric_name, ':'); 1233 if (modifier) 1234 *modifier++ = '\0'; 1235 1236 ret = metricgroup__add_metric(metric_name, modifier, 1237 metric_no_group, metric_list, 1238 map); 1239 if (ret == -EINVAL) 1240 pr_err("Cannot find metric or group `%s'\n", metric_name); 1241 1242 if (ret) 1243 break; 1244 1245 count++; 1246 } 1247 free(list_copy); 1248 1249 if (!ret) { 1250 /* 1251 * Warn about nmi_watchdog if any parsed metrics had the 1252 * NO_NMI_WATCHDOG constraint. 1253 */ 1254 metricgroup___watchdog_constraint_hint(NULL, true); 1255 /* No metrics. */ 1256 if (count == 0) 1257 return -EINVAL; 1258 } 1259 return ret; 1260 } 1261 1262 static void metricgroup__free_metrics(struct list_head *metric_list) 1263 { 1264 struct metric *m, *tmp; 1265 1266 list_for_each_entry_safe (m, tmp, metric_list, nd) { 1267 list_del_init(&m->nd); 1268 metric__free(m); 1269 } 1270 } 1271 1272 /** 1273 * build_combined_expr_ctx - Make an expr_parse_ctx with all has_constraint 1274 * metric IDs, as the IDs are held in a set, 1275 * duplicates will be removed. 1276 * @metric_list: List to take metrics from. 1277 * @combined: Out argument for result. 1278 */ 1279 static int build_combined_expr_ctx(const struct list_head *metric_list, 1280 struct expr_parse_ctx **combined) 1281 { 1282 struct hashmap_entry *cur; 1283 size_t bkt; 1284 struct metric *m; 1285 char *dup; 1286 int ret; 1287 1288 *combined = expr__ctx_new(); 1289 if (!*combined) 1290 return -ENOMEM; 1291 1292 list_for_each_entry(m, metric_list, nd) { 1293 if (m->has_constraint && !m->modifier) { 1294 hashmap__for_each_entry(m->pctx->ids, cur, bkt) { 1295 dup = strdup(cur->key); 1296 if (!dup) { 1297 ret = -ENOMEM; 1298 goto err_out; 1299 } 1300 ret = expr__add_id(*combined, dup); 1301 if (ret) 1302 goto err_out; 1303 } 1304 } 1305 } 1306 return 0; 1307 err_out: 1308 expr__ctx_free(*combined); 1309 *combined = NULL; 1310 return ret; 1311 } 1312 1313 /** 1314 * parse_ids - Build the event string for the ids and parse them creating an 1315 * evlist. The encoded metric_ids are decoded. 1316 * @metric_no_merge: is metric sharing explicitly disabled. 1317 * @fake_pmu: used when testing metrics not supported by the current CPU. 1318 * @ids: the event identifiers parsed from a metric. 1319 * @modifier: any modifiers added to the events. 1320 * @has_constraint: false if events should be placed in a weak group. 1321 * @out_evlist: the created list of events. 1322 */ 1323 static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu, 1324 struct expr_parse_ctx *ids, const char *modifier, 1325 bool has_constraint, struct evlist **out_evlist) 1326 { 1327 struct parse_events_error parse_error; 1328 struct evlist *parsed_evlist; 1329 struct strbuf events = STRBUF_INIT; 1330 int ret; 1331 1332 *out_evlist = NULL; 1333 if (!metric_no_merge || hashmap__size(ids->ids) == 0) { 1334 char *tmp; 1335 /* 1336 * We may fail to share events between metrics because 1337 * duration_time isn't present in one metric. For example, a 1338 * ratio of cache misses doesn't need duration_time but the same 1339 * events may be used for a misses per second. Events without 1340 * sharing implies multiplexing, that is best avoided, so place 1341 * duration_time in every group. 1342 * 1343 * Also, there may be no ids/events in the expression parsing 1344 * context because of constant evaluation, e.g.: 1345 * event1 if #smt_on else 0 1346 * Add a duration_time event to avoid a parse error on an empty 1347 * string. 1348 */ 1349 tmp = strdup("duration_time"); 1350 if (!tmp) 1351 return -ENOMEM; 1352 1353 ids__insert(ids->ids, tmp); 1354 } 1355 ret = metricgroup__build_event_string(&events, ids, modifier, 1356 has_constraint); 1357 if (ret) 1358 return ret; 1359 1360 parsed_evlist = evlist__new(); 1361 if (!parsed_evlist) { 1362 ret = -ENOMEM; 1363 goto err_out; 1364 } 1365 pr_debug("Parsing metric events '%s'\n", events.buf); 1366 parse_events_error__init(&parse_error); 1367 ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu); 1368 if (ret) { 1369 parse_events_error__print(&parse_error, events.buf); 1370 goto err_out; 1371 } 1372 ret = decode_all_metric_ids(parsed_evlist, modifier); 1373 if (ret) 1374 goto err_out; 1375 1376 *out_evlist = parsed_evlist; 1377 parsed_evlist = NULL; 1378 err_out: 1379 parse_events_error__exit(&parse_error); 1380 evlist__delete(parsed_evlist); 1381 strbuf_release(&events); 1382 return ret; 1383 } 1384 1385 static int parse_groups(struct evlist *perf_evlist, const char *str, 1386 bool metric_no_group, 1387 bool metric_no_merge, 1388 struct perf_pmu *fake_pmu, 1389 struct rblist *metric_events_list, 1390 const struct pmu_events_map *map) 1391 { 1392 struct evlist *combined_evlist = NULL; 1393 LIST_HEAD(metric_list); 1394 struct metric *m; 1395 int ret; 1396 1397 if (metric_events_list->nr_entries == 0) 1398 metricgroup__rblist_init(metric_events_list); 1399 ret = metricgroup__add_metric_list(str, metric_no_group, 1400 &metric_list, map); 1401 if (ret) 1402 goto out; 1403 1404 /* Sort metrics from largest to smallest. */ 1405 list_sort(NULL, &metric_list, metric_list_cmp); 1406 1407 if (!metric_no_merge) { 1408 struct expr_parse_ctx *combined = NULL; 1409 1410 ret = build_combined_expr_ctx(&metric_list, &combined); 1411 1412 if (!ret && combined && hashmap__size(combined->ids)) { 1413 ret = parse_ids(metric_no_merge, fake_pmu, combined, 1414 /*modifier=*/NULL, 1415 /*has_constraint=*/true, 1416 &combined_evlist); 1417 } 1418 if (combined) 1419 expr__ctx_free(combined); 1420 1421 if (ret) 1422 goto out; 1423 } 1424 1425 list_for_each_entry(m, &metric_list, nd) { 1426 struct metric_event *me; 1427 struct evsel **metric_events; 1428 struct evlist *metric_evlist = NULL; 1429 struct metric *n; 1430 struct metric_expr *expr; 1431 1432 if (combined_evlist && m->has_constraint) { 1433 metric_evlist = combined_evlist; 1434 } else if (!metric_no_merge) { 1435 /* 1436 * See if the IDs for this metric are a subset of an 1437 * earlier metric. 1438 */ 1439 list_for_each_entry(n, &metric_list, nd) { 1440 if (m == n) 1441 break; 1442 1443 if (n->evlist == NULL) 1444 continue; 1445 1446 if ((!m->modifier && n->modifier) || 1447 (m->modifier && !n->modifier) || 1448 (m->modifier && n->modifier && 1449 strcmp(m->modifier, n->modifier))) 1450 continue; 1451 1452 if (expr__subset_of_ids(n->pctx, m->pctx)) { 1453 pr_debug("Events in '%s' fully contained within '%s'\n", 1454 m->metric_name, n->metric_name); 1455 metric_evlist = n->evlist; 1456 break; 1457 } 1458 1459 } 1460 } 1461 if (!metric_evlist) { 1462 ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier, 1463 m->has_constraint, &m->evlist); 1464 if (ret) 1465 goto out; 1466 1467 metric_evlist = m->evlist; 1468 } 1469 ret = setup_metric_events(m->pctx->ids, metric_evlist, &metric_events); 1470 if (ret) { 1471 pr_debug("Cannot resolve IDs for %s: %s\n", 1472 m->metric_name, m->metric_expr); 1473 goto out; 1474 } 1475 1476 me = metricgroup__lookup(metric_events_list, metric_events[0], true); 1477 1478 expr = malloc(sizeof(struct metric_expr)); 1479 if (!expr) { 1480 ret = -ENOMEM; 1481 free(metric_events); 1482 goto out; 1483 } 1484 1485 expr->metric_refs = m->metric_refs; 1486 m->metric_refs = NULL; 1487 expr->metric_expr = m->metric_expr; 1488 if (m->modifier) { 1489 char *tmp; 1490 1491 if (asprintf(&tmp, "%s:%s", m->metric_name, m->modifier) < 0) 1492 expr->metric_name = NULL; 1493 else 1494 expr->metric_name = tmp; 1495 } else 1496 expr->metric_name = strdup(m->metric_name); 1497 1498 if (!expr->metric_name) { 1499 ret = -ENOMEM; 1500 free(metric_events); 1501 goto out; 1502 } 1503 expr->metric_unit = m->metric_unit; 1504 expr->metric_events = metric_events; 1505 expr->runtime = m->pctx->runtime; 1506 list_add(&expr->nd, &me->head); 1507 } 1508 1509 1510 if (combined_evlist) { 1511 evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries); 1512 evlist__delete(combined_evlist); 1513 } 1514 1515 list_for_each_entry(m, &metric_list, nd) { 1516 if (m->evlist) 1517 evlist__splice_list_tail(perf_evlist, &m->evlist->core.entries); 1518 } 1519 1520 out: 1521 metricgroup__free_metrics(&metric_list); 1522 return ret; 1523 } 1524 1525 int metricgroup__parse_groups(const struct option *opt, 1526 const char *str, 1527 bool metric_no_group, 1528 bool metric_no_merge, 1529 struct rblist *metric_events) 1530 { 1531 struct evlist *perf_evlist = *(struct evlist **)opt->value; 1532 const struct pmu_events_map *map = pmu_events_map__find(); 1533 1534 return parse_groups(perf_evlist, str, metric_no_group, 1535 metric_no_merge, NULL, metric_events, map); 1536 } 1537 1538 int metricgroup__parse_groups_test(struct evlist *evlist, 1539 const struct pmu_events_map *map, 1540 const char *str, 1541 bool metric_no_group, 1542 bool metric_no_merge, 1543 struct rblist *metric_events) 1544 { 1545 return parse_groups(evlist, str, metric_no_group, 1546 metric_no_merge, &perf_pmu__fake, metric_events, map); 1547 } 1548 1549 bool metricgroup__has_metric(const char *metric) 1550 { 1551 const struct pmu_events_map *map = pmu_events_map__find(); 1552 const struct pmu_event *pe; 1553 int i; 1554 1555 if (!map) 1556 return false; 1557 1558 for (i = 0; ; i++) { 1559 pe = &map->table[i]; 1560 1561 if (!pe->name && !pe->metric_group && !pe->metric_name) 1562 break; 1563 if (!pe->metric_expr) 1564 continue; 1565 if (match_metric(pe->metric_name, metric)) 1566 return true; 1567 } 1568 return false; 1569 } 1570 1571 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, 1572 struct rblist *new_metric_events, 1573 struct rblist *old_metric_events) 1574 { 1575 unsigned i; 1576 1577 for (i = 0; i < rblist__nr_entries(old_metric_events); i++) { 1578 struct rb_node *nd; 1579 struct metric_event *old_me, *new_me; 1580 struct metric_expr *old_expr, *new_expr; 1581 struct evsel *evsel; 1582 size_t alloc_size; 1583 int idx, nr; 1584 1585 nd = rblist__entry(old_metric_events, i); 1586 old_me = container_of(nd, struct metric_event, nd); 1587 1588 evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx); 1589 if (!evsel) 1590 return -EINVAL; 1591 new_me = metricgroup__lookup(new_metric_events, evsel, true); 1592 if (!new_me) 1593 return -ENOMEM; 1594 1595 pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n", 1596 cgrp ? cgrp->name : "root", evsel->name, evsel->core.idx); 1597 1598 list_for_each_entry(old_expr, &old_me->head, nd) { 1599 new_expr = malloc(sizeof(*new_expr)); 1600 if (!new_expr) 1601 return -ENOMEM; 1602 1603 new_expr->metric_expr = old_expr->metric_expr; 1604 new_expr->metric_name = strdup(old_expr->metric_name); 1605 if (!new_expr->metric_name) 1606 return -ENOMEM; 1607 1608 new_expr->metric_unit = old_expr->metric_unit; 1609 new_expr->runtime = old_expr->runtime; 1610 1611 if (old_expr->metric_refs) { 1612 /* calculate number of metric_events */ 1613 for (nr = 0; old_expr->metric_refs[nr].metric_name; nr++) 1614 continue; 1615 alloc_size = sizeof(*new_expr->metric_refs); 1616 new_expr->metric_refs = calloc(nr + 1, alloc_size); 1617 if (!new_expr->metric_refs) { 1618 free(new_expr); 1619 return -ENOMEM; 1620 } 1621 1622 memcpy(new_expr->metric_refs, old_expr->metric_refs, 1623 nr * alloc_size); 1624 } else { 1625 new_expr->metric_refs = NULL; 1626 } 1627 1628 /* calculate number of metric_events */ 1629 for (nr = 0; old_expr->metric_events[nr]; nr++) 1630 continue; 1631 alloc_size = sizeof(*new_expr->metric_events); 1632 new_expr->metric_events = calloc(nr + 1, alloc_size); 1633 if (!new_expr->metric_events) { 1634 free(new_expr->metric_refs); 1635 free(new_expr); 1636 return -ENOMEM; 1637 } 1638 1639 /* copy evsel in the same position */ 1640 for (idx = 0; idx < nr; idx++) { 1641 evsel = old_expr->metric_events[idx]; 1642 evsel = evlist__find_evsel(evlist, evsel->core.idx); 1643 if (evsel == NULL) { 1644 free(new_expr->metric_events); 1645 free(new_expr->metric_refs); 1646 free(new_expr); 1647 return -EINVAL; 1648 } 1649 new_expr->metric_events[idx] = evsel; 1650 } 1651 1652 list_add(&new_expr->nd, &new_me->head); 1653 } 1654 } 1655 return 0; 1656 } 1657