Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf parse-events: Copy fewer term lists

When trying to add events to multiple PMUs the term list is copied first
as adding the event will rewrite the event's name term into the sysfs
and/or json encoding terms (see perf_pmu__check_alias).

Change the parse events add API so the passed in term list is const,
then copy the list when modification is necessary.

Reviewed-by: James Clark <james.clark@arm.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20230901233949.2930562-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
727adeed 41636448

+65 -67
+60 -48
tools/perf/util/parse-events.c
··· 35 35 extern int parse_events_debug; 36 36 #endif 37 37 static int get_config_terms(struct list_head *head_config, struct list_head *head_terms); 38 + static int parse_events_terms__copy(const struct list_head *src, struct list_head *dest); 38 39 39 40 struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { 40 41 [PERF_COUNT_HW_CPU_CYCLES] = { ··· 1368 1367 1369 1368 int parse_events_add_pmu(struct parse_events_state *parse_state, 1370 1369 struct list_head *list, const char *name, 1371 - struct list_head *head_config, 1370 + const struct list_head *const_head_terms, 1372 1371 bool auto_merge_stats, void *loc_) 1373 1372 { 1374 1373 struct perf_event_attr attr; ··· 1378 1377 struct parse_events_error *err = parse_state->error; 1379 1378 YYLTYPE *loc = loc_; 1380 1379 LIST_HEAD(config_terms); 1380 + LIST_HEAD(head_terms); 1381 1381 1382 1382 pmu = parse_state->fake_pmu ?: perf_pmus__find(name); 1383 1383 ··· 1392 1390 return -EINVAL; 1393 1391 } 1394 1392 1393 + if (const_head_terms) { 1394 + int ret = parse_events_terms__copy(const_head_terms, &head_terms); 1395 + 1396 + if (ret) 1397 + return ret; 1398 + } 1399 + 1395 1400 if (verbose > 1) { 1396 1401 struct strbuf sb; 1397 1402 1398 1403 strbuf_init(&sb, /*hint=*/ 0); 1399 - if (pmu->selectable && !head_config) { 1404 + if (pmu->selectable && list_empty(&head_terms)) { 1400 1405 strbuf_addf(&sb, "%s//", name); 1401 1406 } else { 1402 1407 strbuf_addf(&sb, "%s/", name); 1403 - parse_events_term__to_strbuf(head_config, &sb); 1408 + parse_events_term__to_strbuf(&head_terms, &sb); 1404 1409 strbuf_addch(&sb, '/'); 1405 1410 } 1406 1411 fprintf(stderr, "Attempt to add: %s\n", sb.buf); 1407 1412 strbuf_release(&sb); 1408 1413 } 1409 - if (head_config) 1410 - fix_raw(head_config, pmu); 1414 + fix_raw(&head_terms, pmu); 1411 1415 1412 1416 if (pmu->default_config) { 1413 - memcpy(&attr, pmu->default_config, 1414 - sizeof(struct perf_event_attr)); 1417 + memcpy(&attr, pmu->default_config, sizeof(struct perf_event_attr)); 1415 1418 } else { 1416 1419 memset(&attr, 0, sizeof(attr)); 1417 1420 } 1418 1421 attr.type = pmu->type; 1419 1422 1420 - if (!head_config) { 1423 + if (list_empty(&head_terms)) { 1421 1424 evsel = __add_event(list, &parse_state->idx, &attr, 1422 1425 /*init_attr=*/true, /*name=*/NULL, 1423 1426 /*metric_id=*/NULL, pmu, ··· 1431 1424 return evsel ? 0 : -ENOMEM; 1432 1425 } 1433 1426 1434 - if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, head_config, &info, err)) 1427 + if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, &head_terms, &info, err)) { 1428 + parse_events_terms__purge(&head_terms); 1435 1429 return -EINVAL; 1430 + } 1436 1431 1437 1432 if (verbose > 1) { 1438 1433 struct strbuf sb; 1439 1434 1440 1435 strbuf_init(&sb, /*hint=*/ 0); 1441 - parse_events_term__to_strbuf(head_config, &sb); 1436 + parse_events_term__to_strbuf(&head_terms, &sb); 1442 1437 fprintf(stderr, "..after resolving event: %s/%s/\n", name, sb.buf); 1443 1438 strbuf_release(&sb); 1444 1439 } ··· 1449 1440 * Configure hardcoded terms first, no need to check 1450 1441 * return value when called with fail == 0 ;) 1451 1442 */ 1452 - if (config_attr(&attr, head_config, parse_state->error, config_term_pmu)) 1443 + if (config_attr(&attr, &head_terms, parse_state->error, config_term_pmu)) { 1444 + parse_events_terms__purge(&head_terms); 1453 1445 return -EINVAL; 1446 + } 1454 1447 1455 - if (get_config_terms(head_config, &config_terms)) 1448 + if (get_config_terms(&head_terms, &config_terms)) { 1449 + parse_events_terms__purge(&head_terms); 1456 1450 return -ENOMEM; 1451 + } 1457 1452 1458 1453 /* 1459 1454 * When using default config, record which bits of attr->config were 1460 1455 * changed by the user. 1461 1456 */ 1462 - if (pmu->default_config && get_config_chgs(pmu, head_config, &config_terms)) 1457 + if (pmu->default_config && get_config_chgs(pmu, &head_terms, &config_terms)) { 1458 + parse_events_terms__purge(&head_terms); 1463 1459 return -ENOMEM; 1460 + } 1464 1461 1465 - if (!parse_state->fake_pmu && perf_pmu__config(pmu, &attr, head_config, parse_state->error)) { 1462 + if (!parse_state->fake_pmu && 1463 + perf_pmu__config(pmu, &attr, &head_terms, parse_state->error)) { 1466 1464 free_config_terms(&config_terms); 1465 + parse_events_terms__purge(&head_terms); 1467 1466 return -EINVAL; 1468 1467 } 1469 1468 1470 1469 evsel = __add_event(list, &parse_state->idx, &attr, /*init_attr=*/true, 1471 - get_config_name(head_config), 1472 - get_config_metric_id(head_config), pmu, 1470 + get_config_name(&head_terms), 1471 + get_config_metric_id(&head_terms), pmu, 1473 1472 &config_terms, auto_merge_stats, /*cpu_list=*/NULL); 1474 - if (!evsel) 1473 + if (!evsel) { 1474 + parse_events_terms__purge(&head_terms); 1475 1475 return -ENOMEM; 1476 + } 1476 1477 1477 1478 if (evsel->name) 1478 1479 evsel->use_config_name = true; 1479 1480 1480 1481 evsel->percore = config_term_percore(&evsel->config_terms); 1481 1482 1482 - if (parse_state->fake_pmu) 1483 + if (parse_state->fake_pmu) { 1484 + parse_events_terms__purge(&head_terms); 1483 1485 return 0; 1486 + } 1484 1487 1488 + parse_events_terms__purge(&head_terms); 1485 1489 free((char *)evsel->unit); 1486 1490 evsel->unit = strdup(info.unit); 1487 1491 evsel->scale = info.scale; ··· 1504 1482 } 1505 1483 1506 1484 int parse_events_multi_pmu_add(struct parse_events_state *parse_state, 1507 - const char *event_name, struct list_head *head, 1485 + const char *event_name, 1486 + const struct list_head *const_head_terms, 1508 1487 struct list_head **listp, void *loc_) 1509 1488 { 1510 1489 struct parse_events_term *term; 1511 1490 struct list_head *list = NULL; 1512 - struct list_head *orig_head = NULL; 1513 1491 struct perf_pmu *pmu = NULL; 1514 1492 YYLTYPE *loc = loc_; 1515 1493 int ok = 0; 1516 1494 const char *config; 1495 + LIST_HEAD(head_terms); 1517 1496 1518 1497 *listp = NULL; 1519 1498 1520 - if (!head) { 1521 - head = malloc(sizeof(struct list_head)); 1522 - if (!head) 1523 - goto out_err; 1499 + if (const_head_terms) { 1500 + int ret = parse_events_terms__copy(const_head_terms, &head_terms); 1524 1501 1525 - INIT_LIST_HEAD(head); 1502 + if (ret) 1503 + return ret; 1526 1504 } 1527 1505 1528 1506 config = strdup(event_name); ··· 1536 1514 zfree(&config); 1537 1515 goto out_err; 1538 1516 } 1539 - list_add_tail(&term->list, head); 1517 + list_add_tail(&term->list, &head_terms); 1540 1518 1541 1519 /* Add it for all PMUs that support the alias */ 1542 1520 list = malloc(sizeof(struct list_head)); ··· 1555 1533 continue; 1556 1534 1557 1535 auto_merge_stats = perf_pmu__auto_merge_stats(pmu); 1558 - parse_events_copy_term_list(head, &orig_head); 1559 1536 if (!parse_events_add_pmu(parse_state, list, pmu->name, 1560 - orig_head, auto_merge_stats, loc)) { 1537 + &head_terms, auto_merge_stats, loc)) { 1561 1538 struct strbuf sb; 1562 1539 1563 1540 strbuf_init(&sb, /*hint=*/ 0); 1564 - parse_events_term__to_strbuf(orig_head, &sb); 1541 + parse_events_term__to_strbuf(&head_terms, &sb); 1565 1542 pr_debug("%s -> %s/%s/\n", event_name, pmu->name, sb.buf); 1566 1543 strbuf_release(&sb); 1567 1544 ok++; 1568 1545 } 1569 - parse_events_terms__delete(orig_head); 1570 1546 } 1571 1547 1572 1548 if (parse_state->fake_pmu) { 1573 - if (!parse_events_add_pmu(parse_state, list, event_name, head, 1549 + if (!parse_events_add_pmu(parse_state, list, event_name, &head_terms, 1574 1550 /*auto_merge_stats=*/true, loc)) { 1575 1551 struct strbuf sb; 1576 1552 1577 1553 strbuf_init(&sb, /*hint=*/ 0); 1578 - parse_events_term__to_strbuf(head, &sb); 1554 + parse_events_term__to_strbuf(&head_terms, &sb); 1579 1555 pr_debug("%s -> %s/%s/\n", event_name, "fake_pmu", sb.buf); 1580 1556 strbuf_release(&sb); 1581 1557 ok++; ··· 1581 1561 } 1582 1562 1583 1563 out_err: 1564 + parse_events_terms__purge(&head_terms); 1584 1565 if (ok) 1585 1566 *listp = list; 1586 1567 else 1587 1568 free(list); 1588 1569 1589 - parse_events_terms__delete(head); 1590 1570 return ok ? 0 : -1; 1591 1571 } 1592 1572 ··· 2563 2543 free(term); 2564 2544 } 2565 2545 2566 - int parse_events_copy_term_list(struct list_head *old, 2567 - struct list_head **new) 2546 + static int parse_events_terms__copy(const struct list_head *src, struct list_head *dest) 2568 2547 { 2569 - struct parse_events_term *term, *n; 2570 - int ret; 2548 + struct parse_events_term *term; 2571 2549 2572 - if (!old) { 2573 - *new = NULL; 2574 - return 0; 2575 - } 2550 + list_for_each_entry (term, src, list) { 2551 + struct parse_events_term *n; 2552 + int ret; 2576 2553 2577 - *new = malloc(sizeof(struct list_head)); 2578 - if (!*new) 2579 - return -ENOMEM; 2580 - INIT_LIST_HEAD(*new); 2581 - 2582 - list_for_each_entry (term, old, list) { 2583 2554 ret = parse_events_term__clone(&n, term); 2584 2555 if (ret) 2585 2556 return ret; 2586 - list_add_tail(&n->list, *new); 2557 + 2558 + list_add_tail(&n->list, dest); 2587 2559 } 2588 2560 return 0; 2589 2561 }
+2 -5
tools/perf/util/parse-events.h
··· 209 209 struct list_head *head_config); 210 210 int parse_events_add_pmu(struct parse_events_state *parse_state, 211 211 struct list_head *list, const char *name, 212 - struct list_head *head_config, 212 + const struct list_head *const_head_terms, 213 213 bool auto_merge_stats, void *loc); 214 214 215 215 struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, ··· 218 218 219 219 int parse_events_multi_pmu_add(struct parse_events_state *parse_state, 220 220 const char *event_name, 221 - struct list_head *head_config, 221 + const struct list_head *head_terms, 222 222 struct list_head **listp, void *loc); 223 - 224 - int parse_events_copy_term_list(struct list_head *old, 225 - struct list_head **new); 226 223 227 224 void parse_events__set_leader(char *name, struct list_head *list); 228 225 void parse_events_update_lists(struct list_head *list_event,
+3 -14
tools/perf/util/parse-events.y
··· 274 274 PE_NAME opt_pmu_config 275 275 { 276 276 struct parse_events_state *parse_state = _parse_state; 277 - struct list_head *list = NULL, *orig_terms = NULL, *terms= NULL; 277 + /* List of created evsels. */ 278 + struct list_head *list = NULL; 278 279 char *pattern = NULL; 279 280 280 281 #define CLEANUP \ 281 282 do { \ 282 283 parse_events_terms__delete($2); \ 283 - parse_events_terms__delete(orig_terms); \ 284 284 free(list); \ 285 285 free($1); \ 286 286 free(pattern); \ 287 287 } while(0) 288 - 289 - if (parse_events_copy_term_list($2, &orig_terms)) { 290 - CLEANUP; 291 - YYNOMEM; 292 - } 293 288 294 289 list = alloc_list(); 295 290 if (!list) { ··· 315 320 !perf_pmu__match(pattern, pmu->alias_name, $1)) { 316 321 bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu); 317 322 318 - if (parse_events_copy_term_list(orig_terms, &terms)) { 319 - CLEANUP; 320 - YYNOMEM; 321 - } 322 - if (!parse_events_add_pmu(parse_state, list, pmu->name, terms, 323 + if (!parse_events_add_pmu(parse_state, list, pmu->name, $2, 323 324 auto_merge_stats, &@1)) { 324 325 ok++; 325 326 parse_state->wild_card_pmus = true; 326 327 } 327 - parse_events_terms__delete(terms); 328 328 } 329 329 } 330 330 ··· 327 337 /* Failure to add, assume $1 is an event name. */ 328 338 zfree(&list); 329 339 ok = !parse_events_multi_pmu_add(parse_state, $1, $2, &list, &@1); 330 - $2 = NULL; 331 340 } 332 341 if (!ok) { 333 342 struct parse_events_error *error = parse_state->error;