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

perf python: Correct copying of metric_leader in an evsel

Ensure the metric_leader is copied and set up correctly. In
compute_metric determine the correct metric_leader event to match the
requested CPU. Fixes the handling of metrics particularly on hybrid
machines.

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
6603c3c1 c9cd0c7e

+61 -22
+1
tools/perf/util/evsel.c
··· 538 538 #endif 539 539 evsel->handler = orig->handler; 540 540 evsel->core.leader = orig->core.leader; 541 + evsel->metric_leader = orig->metric_leader; 541 542 542 543 evsel->max_events = orig->max_events; 543 544 zfree(&evsel->unit);
+60 -22
tools/perf/util/python.c
··· 1340 1340 struct metric_ref *metric_refs = mexp->metric_refs; 1341 1341 1342 1342 for (int i = 0; metric_events[i]; i++) { 1343 - char *n = strdup(evsel__metric_id(metric_events[i])); 1343 + struct evsel *cur = metric_events[i]; 1344 1344 double val, ena, run; 1345 - int source_count = evsel__source_count(metric_events[i]); 1346 - int ret; 1345 + int ret, source_count = 0; 1347 1346 struct perf_counts_values *old_count, *new_count; 1347 + char *n = strdup(evsel__metric_id(cur)); 1348 1348 1349 1349 if (!n) 1350 1350 return -ENOMEM; 1351 1351 1352 - if (source_count == 0) 1353 - source_count = 1; 1352 + /* 1353 + * If there are multiple uncore PMUs and we're not reading the 1354 + * leader's stats, determine the stats for the appropriate 1355 + * uncore PMU. 1356 + */ 1357 + if (evsel && evsel->metric_leader && 1358 + evsel->pmu != evsel->metric_leader->pmu && 1359 + cur->pmu == evsel->metric_leader->pmu) { 1360 + struct evsel *pos; 1354 1361 1355 - ret = evsel__ensure_counts(metric_events[i]); 1362 + evlist__for_each_entry(evsel->evlist, pos) { 1363 + if (pos->pmu != evsel->pmu) 1364 + continue; 1365 + if (pos->metric_leader != cur) 1366 + continue; 1367 + cur = pos; 1368 + source_count = 1; 1369 + break; 1370 + } 1371 + } 1372 + 1373 + if (source_count == 0) 1374 + source_count = evsel__source_count(cur); 1375 + 1376 + ret = evsel__ensure_counts(cur); 1356 1377 if (ret) 1357 1378 return ret; 1358 1379 1359 1380 /* Set up pointers to the old and newly read counter values. */ 1360 - old_count = perf_counts(metric_events[i]->prev_raw_counts, cpu_idx, thread_idx); 1361 - new_count = perf_counts(metric_events[i]->counts, cpu_idx, thread_idx); 1362 - /* Update the value in metric_events[i]->counts. */ 1363 - evsel__read_counter(metric_events[i], cpu_idx, thread_idx); 1381 + old_count = perf_counts(cur->prev_raw_counts, cpu_idx, thread_idx); 1382 + new_count = perf_counts(cur->counts, cpu_idx, thread_idx); 1383 + /* Update the value in cur->counts. */ 1384 + evsel__read_counter(cur, cpu_idx, thread_idx); 1364 1385 1365 1386 val = new_count->val - old_count->val; 1366 1387 ena = new_count->ena - old_count->ena; ··· 1413 1392 struct metric_expr *mexp = NULL; 1414 1393 struct expr_parse_ctx *pctx; 1415 1394 double result = 0; 1395 + struct evsel *metric_evsel = NULL; 1416 1396 1417 1397 if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread)) 1418 1398 return NULL; ··· 1426 1404 1427 1405 list_for_each(pos, &me->head) { 1428 1406 struct metric_expr *e = container_of(pos, struct metric_expr, nd); 1407 + struct evsel *pos2; 1429 1408 1430 1409 if (strcmp(e->metric_name, metric)) 1431 1410 continue; ··· 1434 1411 if (e->metric_events[0] == NULL) 1435 1412 continue; 1436 1413 1437 - cpu_idx = perf_cpu_map__idx(e->metric_events[0]->core.cpus, 1438 - (struct perf_cpu){.cpu = cpu}); 1439 - if (cpu_idx < 0) 1440 - continue; 1414 + evlist__for_each_entry(&pevlist->evlist, pos2) { 1415 + if (pos2->metric_leader != e->metric_events[0]) 1416 + continue; 1417 + cpu_idx = perf_cpu_map__idx(pos2->core.cpus, 1418 + (struct perf_cpu){.cpu = cpu}); 1419 + if (cpu_idx < 0) 1420 + continue; 1441 1421 1442 - thread_idx = perf_thread_map__idx(e->metric_events[0]->core.threads, 1443 - thread); 1444 - if (thread_idx < 0) 1445 - continue; 1446 - 1447 - mexp = e; 1448 - break; 1422 + thread_idx = perf_thread_map__idx(pos2->core.threads, thread); 1423 + if (thread_idx < 0) 1424 + continue; 1425 + metric_evsel = pos2; 1426 + mexp = e; 1427 + goto done; 1428 + } 1449 1429 } 1450 1430 } 1431 + done: 1451 1432 if (!mexp) { 1452 1433 PyErr_Format(PyExc_TypeError, "Unknown metric '%s' for CPU '%d' and thread '%d'", 1453 1434 metric, cpu, thread); ··· 1462 1435 if (!pctx) 1463 1436 return PyErr_NoMemory(); 1464 1437 1465 - ret = prepare_metric(mexp, mexp->metric_events[0], pctx, cpu_idx, thread_idx); 1438 + ret = prepare_metric(mexp, metric_evsel, pctx, cpu_idx, thread_idx); 1466 1439 if (ret) { 1467 1440 expr__ctx_free(pctx); 1468 1441 errno = -ret; ··· 2022 1995 evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx)); 2023 1996 else if (leader == NULL) 2024 1997 evsel__set_leader(pos, pos); 1998 + } 1999 + 2000 + leader = pos->metric_leader; 2001 + 2002 + if (pos != leader) { 2003 + int idx = evlist__pos(evlist, leader); 2004 + 2005 + if (idx >= 0) 2006 + pos->metric_leader = evlist__at(&pevlist->evlist, idx); 2007 + else if (leader == NULL) 2008 + pos->metric_leader = pos; 2025 2009 } 2026 2010 } 2027 2011 metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,