Skip to content

Commit 4102ff8

Browse files
captain5050acmel
authored andcommitted
perf metricgroup: Binary search when resolving referred to metrics
Unlike with events, metrics can be matched by name or a list of metric groups. However, when a metric refers to another metric it isn't referring to a group but the singular metric in question. Prior to this change every "id" in a metric expression is checked to see if it is a metric by scanning all the metrics in the metrics table. As the table is sorted my metric name we can speed the search in the resolution case by binary searching for the metric. Rename some of the metricgroup functions to make it clearer whether they match a metric by name or by both name and group. Before: ``` $ time perf test -v 10 10: PMU JSON event tests : 10.1: PMU event table sanity : Ok 10.2: PMU event map aliases : Ok 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok 10.5: Parsing of metric thresholds with fake PMUs : Ok real 0m15.972s user 0m13.176s sys 0m3.001s ``` After: ``` $ time perf test -v 10 10: PMU JSON event tests : 10.1: PMU event table sanity : Ok 10.2: PMU event map aliases : Ok 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok 10.5: Parsing of metric thresholds with fake PMUs : Ok real 0m5.343s user 0m1.871s sys 0m2.128s ``` Committer testing: root@number:~# grep -m1 'model name' /proc/cpuinfo model name : AMD Ryzen 9 9950X3D 16-Core Processor root@number:~# Before: root@number:~# time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m9.286s user 0m9.354s sys 0m0.062s root@number:~# After: root@number:~# time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m0.689s user 0m0.766s sys 0m0.042s root@number:~# time perf test 10 10: PMU JSON event tests : 10.1: PMU event table sanity : Ok 10.2: PMU event map aliases : Ok 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok 10.5: Parsing of metric thresholds with fake PMUs : Ok real 0m0.696s user 0m0.807s sys 0m0.064s root@number:~# Signed-off-by: Ian Rogers <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Tested-by: Namhyung Kim <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: James Clark <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Kan Liang <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ravi Bangoria <[email protected]> Cc: Thomas Richter <[email protected]> Cc: Xu Yang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 754baf4 commit 4102ff8

File tree

6 files changed

+192
-73
lines changed

6 files changed

+192
-73
lines changed

tools/perf/builtin-stat.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,7 +1854,7 @@ static int add_default_events(void)
18541854
* will use this approach. To determine transaction support
18551855
* on an architecture test for such a metric name.
18561856
*/
1857-
if (!metricgroup__has_metric(pmu, "transaction")) {
1857+
if (!metricgroup__has_metric_or_groups(pmu, "transaction")) {
18581858
pr_err("Missing transaction metrics\n");
18591859
ret = -1;
18601860
goto out;
@@ -1888,7 +1888,7 @@ static int add_default_events(void)
18881888
smi_reset = true;
18891889
}
18901890

1891-
if (!metricgroup__has_metric(pmu, "smi")) {
1891+
if (!metricgroup__has_metric_or_groups(pmu, "smi")) {
18921892
pr_err("Missing smi metrics\n");
18931893
ret = -1;
18941894
goto out;
@@ -1978,7 +1978,7 @@ static int add_default_events(void)
19781978
* Add TopdownL1 metrics if they exist. To minimize
19791979
* multiplexing, don't request threshold computation.
19801980
*/
1981-
if (metricgroup__has_metric(pmu, "Default")) {
1981+
if (metricgroup__has_metric_or_groups(pmu, "Default")) {
19821982
struct evlist *metric_evlist = evlist__new();
19831983

19841984
if (!metric_evlist) {

tools/perf/pmu-events/empty-pmu-events.c

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ int pmu_events_table__find_event(const struct pmu_events_table *table,
449449
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
450450
int ret;
451451

452-
if (!perf_pmu__name_wildcard_match(pmu, pmu_name))
452+
if (pmu && !perf_pmu__name_wildcard_match(pmu, pmu_name))
453453
continue;
454454

455455
ret = pmu_events_table__find_event_pmu(table, table_pmu, name, fn, data);
@@ -495,6 +495,49 @@ static int pmu_metrics_table__for_each_metric_pmu(const struct pmu_metrics_table
495495
return 0;
496496
}
497497

498+
static int pmu_metrics_table__find_metric_pmu(const struct pmu_metrics_table *table,
499+
const struct pmu_table_entry *pmu,
500+
const char *metric,
501+
pmu_metric_iter_fn fn,
502+
void *data)
503+
{
504+
struct pmu_metric pm = {
505+
.pmu = &big_c_string[pmu->pmu_name.offset],
506+
};
507+
int low = 0, high = pmu->num_entries - 1;
508+
509+
while (low <= high) {
510+
int cmp, mid = (low + high) / 2;
511+
512+
decompress_metric(pmu->entries[mid].offset, &pm);
513+
514+
if (!pm.metric_name && !metric)
515+
goto do_call;
516+
517+
if (!pm.metric_name && metric) {
518+
low = mid + 1;
519+
continue;
520+
}
521+
if (pm.metric_name && !metric) {
522+
high = mid - 1;
523+
continue;
524+
}
525+
526+
cmp = strcmp(pm.metric_name, metric);
527+
if (cmp < 0) {
528+
low = mid + 1;
529+
continue;
530+
}
531+
if (cmp > 0) {
532+
high = mid - 1;
533+
continue;
534+
}
535+
do_call:
536+
return fn ? fn(&pm, table, data) : 0;
537+
}
538+
return PMU_METRICS__NOT_FOUND;
539+
}
540+
498541
int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table,
499542
pmu_metric_iter_fn fn,
500543
void *data)
@@ -509,6 +552,27 @@ int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table,
509552
return 0;
510553
}
511554

555+
int pmu_metrics_table__find_metric(const struct pmu_metrics_table *table,
556+
struct perf_pmu *pmu,
557+
const char *metric,
558+
pmu_metric_iter_fn fn,
559+
void *data)
560+
{
561+
for (size_t i = 0; i < table->num_pmus; i++) {
562+
const struct pmu_table_entry *table_pmu = &table->pmus[i];
563+
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
564+
int ret;
565+
566+
if (pmu && !perf_pmu__name_wildcard_match(pmu, pmu_name))
567+
continue;
568+
569+
ret = pmu_metrics_table__find_metric_pmu(table, table_pmu, metric, fn, data);
570+
if (ret != PMU_METRICS__NOT_FOUND)
571+
return ret;
572+
}
573+
return PMU_METRICS__NOT_FOUND;
574+
}
575+
512576
static const struct pmu_events_map *map_for_cpu(struct perf_cpu cpu)
513577
{
514578
static struct {

tools/perf/pmu-events/jevents.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ def print_system_mapping_table() -> None:
972972
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
973973
int ret;
974974
975-
if (!perf_pmu__name_wildcard_match(pmu, pmu_name))
975+
if (pmu && !perf_pmu__name_wildcard_match(pmu, pmu_name))
976976
continue;
977977
978978
ret = pmu_events_table__find_event_pmu(table, table_pmu, name, fn, data);
@@ -1018,6 +1018,49 @@ def print_system_mapping_table() -> None:
10181018
return 0;
10191019
}
10201020
1021+
static int pmu_metrics_table__find_metric_pmu(const struct pmu_metrics_table *table,
1022+
const struct pmu_table_entry *pmu,
1023+
const char *metric,
1024+
pmu_metric_iter_fn fn,
1025+
void *data)
1026+
{
1027+
struct pmu_metric pm = {
1028+
.pmu = &big_c_string[pmu->pmu_name.offset],
1029+
};
1030+
int low = 0, high = pmu->num_entries - 1;
1031+
1032+
while (low <= high) {
1033+
int cmp, mid = (low + high) / 2;
1034+
1035+
decompress_metric(pmu->entries[mid].offset, &pm);
1036+
1037+
if (!pm.metric_name && !metric)
1038+
goto do_call;
1039+
1040+
if (!pm.metric_name && metric) {
1041+
low = mid + 1;
1042+
continue;
1043+
}
1044+
if (pm.metric_name && !metric) {
1045+
high = mid - 1;
1046+
continue;
1047+
}
1048+
1049+
cmp = strcmp(pm.metric_name, metric);
1050+
if (cmp < 0) {
1051+
low = mid + 1;
1052+
continue;
1053+
}
1054+
if (cmp > 0) {
1055+
high = mid - 1;
1056+
continue;
1057+
}
1058+
do_call:
1059+
return fn ? fn(&pm, table, data) : 0;
1060+
}
1061+
return PMU_METRICS__NOT_FOUND;
1062+
}
1063+
10211064
int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table,
10221065
pmu_metric_iter_fn fn,
10231066
void *data)
@@ -1032,6 +1075,27 @@ def print_system_mapping_table() -> None:
10321075
return 0;
10331076
}
10341077
1078+
int pmu_metrics_table__find_metric(const struct pmu_metrics_table *table,
1079+
struct perf_pmu *pmu,
1080+
const char *metric,
1081+
pmu_metric_iter_fn fn,
1082+
void *data)
1083+
{
1084+
for (size_t i = 0; i < table->num_pmus; i++) {
1085+
const struct pmu_table_entry *table_pmu = &table->pmus[i];
1086+
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
1087+
int ret;
1088+
1089+
if (pmu && !perf_pmu__name_wildcard_match(pmu, pmu_name))
1090+
continue;
1091+
1092+
ret = pmu_metrics_table__find_metric_pmu(table, table_pmu, metric, fn, data);
1093+
if (ret != PMU_METRICS__NOT_FOUND)
1094+
return ret;
1095+
}
1096+
return PMU_METRICS__NOT_FOUND;
1097+
}
1098+
10351099
static const struct pmu_events_map *map_for_cpu(struct perf_cpu cpu)
10361100
{
10371101
static struct {

tools/perf/pmu-events/pmu-events.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct pmu_events_table;
7474
struct pmu_metrics_table;
7575

7676
#define PMU_EVENTS__NOT_FOUND -1000
77+
#define PMU_METRICS__NOT_FOUND -1000
7778

7879
typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
7980
const struct pmu_events_table *table,
@@ -88,11 +89,11 @@ int pmu_events_table__for_each_event(const struct pmu_events_table *table,
8889
pmu_event_iter_fn fn,
8990
void *data);
9091
/*
91-
* Search for table and entry matching with pmu__name_match. Each matching event
92-
* has fn called on it. 0 implies to success/continue the search while non-zero
93-
* means to terminate. The special value PMU_EVENTS__NOT_FOUND is used to
94-
* indicate no event was found in one of the tables which doesn't terminate the
95-
* search of all tables.
92+
* Search for a table and entry matching with pmu__name_wildcard_match or any
93+
* tables if pmu is NULL. Each matching event has fn called on it. 0 implies to
94+
* success/continue the search while non-zero means to terminate. The special
95+
* value PMU_EVENTS__NOT_FOUND is used to indicate no event was found in one of
96+
* the tables which doesn't terminate the search of all tables.
9697
*/
9798
int pmu_events_table__find_event(const struct pmu_events_table *table,
9899
struct perf_pmu *pmu,
@@ -104,6 +105,18 @@ size_t pmu_events_table__num_events(const struct pmu_events_table *table,
104105

105106
int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
106107
void *data);
108+
/*
109+
* Search for a table and entry matching with pmu__name_wildcard_match or any
110+
* tables if pmu is NULL. Each matching metric has fn called on it. 0 implies to
111+
* success/continue the search while non-zero means to terminate. The special
112+
* value PMU_METRICS__NOT_FOUND is used to indicate no metric was found in one
113+
* of the tables which doesn't terminate the search of all tables.
114+
*/
115+
int pmu_metrics_table__find_metric(const struct pmu_metrics_table *table,
116+
struct perf_pmu *pmu,
117+
const char *metric,
118+
pmu_metric_iter_fn fn,
119+
void *data);
107120

108121
const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu);
109122
const struct pmu_metrics_table *pmu_metrics_table__find(void);

0 commit comments

Comments
 (0)