All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/17]  Compress the pmu_event tables
@ 2022-08-04 22:17 ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:17 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

jevents.py creates a number of large arrays from the json events. The
arrays contain pointers to strings that need relocating. The
relocations have file size, run time and memory costs. These changes
refactor the pmu_events API so that the storage of the pmu_event
struct isn't exposed. The format is then changed to an offset within a
combined big string, with adjacent pmu_event struct variables being
next to each other in the string separated by \0 - meaning only the
first variable of the struct needs its offset recording.

Some related fixes are contained with the patches. The architecture
jevents.py creates tables for can now be set by the JEVENTS_ARCH make
variable, with a new 'all' that generates the events and metrics for
all architectures.

An example of the improvement to the file size on x86 is:
no jevents - the same 19,788,464bytes
x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
default build options plus NO_LIBBFD=1.

I originally suggested fixing this problem in:
https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/

v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
    <john.garry@huawei.com>.
v3. Fix an ARM build issue with a missed weak symbol. Perform some
    pytype clean up.
v2. Split the substring folding optimization to its own patch and
    comment tweaks as suggested by Namhyung Kim
    <namhyung@kernel.org>. Recompute the file size savings with the
    latest json events and metrics.

Ian Rogers (17):
  perf jevents: Clean up pytype warnings
  perf jevents: Simplify generation of C-string
  perf jevents: Add JEVENTS_ARCH make option
  perf jevent: Add an 'all' architecture argument
  perf jevents: Remove the type/version variables
  perf jevents: Provide path to json file on error
  perf jevents: Sort json files entries
  perf pmu-events: Hide pmu_sys_event_tables
  perf pmu-events: Avoid passing pmu_events_map
  perf pmu-events: Hide pmu_events_map
  perf test: Use full metric resolution
  perf pmu-events: Move test events/metrics to json
  perf pmu-events: Don't assume pmu_event is an array
  perf pmu-events: Hide the pmu_events
  perf metrics: Copy entire pmu_event in find metric
  perf jevents: Compress the pmu_events_table
  perf jevents: Fold strings optimization

 tools/perf/arch/arm64/util/pmu.c              |   4 +-
 tools/perf/pmu-events/Build                   |   6 +-
 .../arch/test/test_soc/cpu/metrics.json       |  64 +++
 tools/perf/pmu-events/empty-pmu-events.c      | 204 +++++++-
 tools/perf/pmu-events/jevents.py              | 495 ++++++++++++++----
 tools/perf/pmu-events/pmu-events.h            |  40 +-
 tools/perf/tests/expand-cgroup.c              |  25 +-
 tools/perf/tests/parse-metric.c               |  77 +--
 tools/perf/tests/pmu-events.c                 | 466 +++++++----------
 tools/perf/util/metricgroup.c                 | 275 ++++++----
 tools/perf/util/metricgroup.h                 |   5 +-
 tools/perf/util/pmu.c                         | 139 ++---
 tools/perf/util/pmu.h                         |   8 +-
 tools/perf/util/s390-sample-raw.c             |  50 +-
 14 files changed, 1140 insertions(+), 718 deletions(-)
 create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json

-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH v4 00/17]  Compress the pmu_event tables
@ 2022-08-04 22:17 ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:17 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

jevents.py creates a number of large arrays from the json events. The
arrays contain pointers to strings that need relocating. The
relocations have file size, run time and memory costs. These changes
refactor the pmu_events API so that the storage of the pmu_event
struct isn't exposed. The format is then changed to an offset within a
combined big string, with adjacent pmu_event struct variables being
next to each other in the string separated by \0 - meaning only the
first variable of the struct needs its offset recording.

Some related fixes are contained with the patches. The architecture
jevents.py creates tables for can now be set by the JEVENTS_ARCH make
variable, with a new 'all' that generates the events and metrics for
all architectures.

An example of the improvement to the file size on x86 is:
no jevents - the same 19,788,464bytes
x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
default build options plus NO_LIBBFD=1.

I originally suggested fixing this problem in:
https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/

v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
    <john.garry@huawei.com>.
v3. Fix an ARM build issue with a missed weak symbol. Perform some
    pytype clean up.
v2. Split the substring folding optimization to its own patch and
    comment tweaks as suggested by Namhyung Kim
    <namhyung@kernel.org>. Recompute the file size savings with the
    latest json events and metrics.

Ian Rogers (17):
  perf jevents: Clean up pytype warnings
  perf jevents: Simplify generation of C-string
  perf jevents: Add JEVENTS_ARCH make option
  perf jevent: Add an 'all' architecture argument
  perf jevents: Remove the type/version variables
  perf jevents: Provide path to json file on error
  perf jevents: Sort json files entries
  perf pmu-events: Hide pmu_sys_event_tables
  perf pmu-events: Avoid passing pmu_events_map
  perf pmu-events: Hide pmu_events_map
  perf test: Use full metric resolution
  perf pmu-events: Move test events/metrics to json
  perf pmu-events: Don't assume pmu_event is an array
  perf pmu-events: Hide the pmu_events
  perf metrics: Copy entire pmu_event in find metric
  perf jevents: Compress the pmu_events_table
  perf jevents: Fold strings optimization

 tools/perf/arch/arm64/util/pmu.c              |   4 +-
 tools/perf/pmu-events/Build                   |   6 +-
 .../arch/test/test_soc/cpu/metrics.json       |  64 +++
 tools/perf/pmu-events/empty-pmu-events.c      | 204 +++++++-
 tools/perf/pmu-events/jevents.py              | 495 ++++++++++++++----
 tools/perf/pmu-events/pmu-events.h            |  40 +-
 tools/perf/tests/expand-cgroup.c              |  25 +-
 tools/perf/tests/parse-metric.c               |  77 +--
 tools/perf/tests/pmu-events.c                 | 466 +++++++----------
 tools/perf/util/metricgroup.c                 | 275 ++++++----
 tools/perf/util/metricgroup.h                 |   5 +-
 tools/perf/util/pmu.c                         | 139 ++---
 tools/perf/util/pmu.h                         |   8 +-
 tools/perf/util/s390-sample-raw.c             |  50 +-
 14 files changed, 1140 insertions(+), 718 deletions(-)
 create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json

-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH v4 01/17] perf jevents: Clean up pytype warnings
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Improve type hints to clean up pytype warnings.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 83e0dcbeac9a..5b72048d50da 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -6,8 +6,7 @@ import csv
 import json
 import os
 import sys
-from typing import Callable
-from typing import Sequence
+from typing import (Callable, Optional, Sequence)
 
 # Global command line arguments.
 _args = None
@@ -57,7 +56,7 @@ class JsonEvent:
                                        '. '), '.').replace('\n', '\\n').replace(
                                            '\"', '\\"').replace('\r', '\\r')
 
-    def convert_aggr_mode(aggr_mode: str) -> str:
+    def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
       """Returns the aggr_mode_class enum value associated with the JSON string."""
       if not aggr_mode:
         return None
@@ -67,7 +66,7 @@ class JsonEvent:
       }
       return aggr_mode_to_enum[aggr_mode]
 
-    def lookup_msr(num: str) -> str:
+    def lookup_msr(num: str) -> Optional[str]:
       """Converts the msr number, or first in a list to the appropriate event field."""
       if not num:
         return None
@@ -79,7 +78,7 @@ class JsonEvent:
       }
       return msrmap[int(num.split(',', 1)[0], 0)]
 
-    def real_event(name: str, event: str) -> str:
+    def real_event(name: str, event: str) -> Optional[str]:
       """Convert well known event names to an event string otherwise use the event argument."""
       fixed = {
           'inst_retired.any': 'event=0xc0,period=2000003',
@@ -95,7 +94,7 @@ class JsonEvent:
         return fixed[name.lower()]
       return event
 
-    def unit_to_pmu(unit: str) -> str:
+    def unit_to_pmu(unit: str) -> Optional[str]:
       """Convert a JSON Unit to Linux PMU name."""
       if not unit:
         return None
@@ -154,7 +153,7 @@ class JsonEvent:
     if self.metric_expr:
       self.metric_expr = self.metric_expr.replace('\\', '\\\\')
     arch_std = jd.get('ArchStdEvent')
-    if precise and self.desc and not '(Precise Event)' in self.desc:
+    if precise and self.desc and '(Precise Event)' not in self.desc:
       extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
                                                                  'event)')
     event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 01/17] perf jevents: Clean up pytype warnings
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Improve type hints to clean up pytype warnings.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 83e0dcbeac9a..5b72048d50da 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -6,8 +6,7 @@ import csv
 import json
 import os
 import sys
-from typing import Callable
-from typing import Sequence
+from typing import (Callable, Optional, Sequence)
 
 # Global command line arguments.
 _args = None
@@ -57,7 +56,7 @@ class JsonEvent:
                                        '. '), '.').replace('\n', '\\n').replace(
                                            '\"', '\\"').replace('\r', '\\r')
 
-    def convert_aggr_mode(aggr_mode: str) -> str:
+    def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
       """Returns the aggr_mode_class enum value associated with the JSON string."""
       if not aggr_mode:
         return None
@@ -67,7 +66,7 @@ class JsonEvent:
       }
       return aggr_mode_to_enum[aggr_mode]
 
-    def lookup_msr(num: str) -> str:
+    def lookup_msr(num: str) -> Optional[str]:
       """Converts the msr number, or first in a list to the appropriate event field."""
       if not num:
         return None
@@ -79,7 +78,7 @@ class JsonEvent:
       }
       return msrmap[int(num.split(',', 1)[0], 0)]
 
-    def real_event(name: str, event: str) -> str:
+    def real_event(name: str, event: str) -> Optional[str]:
       """Convert well known event names to an event string otherwise use the event argument."""
       fixed = {
           'inst_retired.any': 'event=0xc0,period=2000003',
@@ -95,7 +94,7 @@ class JsonEvent:
         return fixed[name.lower()]
       return event
 
-    def unit_to_pmu(unit: str) -> str:
+    def unit_to_pmu(unit: str) -> Optional[str]:
       """Convert a JSON Unit to Linux PMU name."""
       if not unit:
         return None
@@ -154,7 +153,7 @@ class JsonEvent:
     if self.metric_expr:
       self.metric_expr = self.metric_expr.replace('\\', '\\\\')
     arch_std = jd.get('ArchStdEvent')
-    if precise and self.desc and not '(Precise Event)' in self.desc:
+    if precise and self.desc and '(Precise Event)' not in self.desc:
       extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
                                                                  'event)')
     event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 02/17] perf jevents: Simplify generation of C-string
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Previous implementation wanted variable order and '(null)' string output
to match the C implementation. The '(null)' string output was a
quirk/bug and so there is no need to carry it forward.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 5b72048d50da..cdfa4e0e7557 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -203,7 +203,7 @@ class JsonEvent:
     """Representation of the event as a C struct initializer."""
 
     def attr_string(attr: str, value: str) -> str:
-      return '\t.%s = \"%s\",\n' % (attr, value)
+      return f'\t.{attr} = \"{value}\",\n'
 
     def str_if_present(self, attr: str) -> str:
       if not getattr(self, attr):
@@ -211,17 +211,11 @@ class JsonEvent:
       return attr_string(attr, getattr(self, attr))
 
     s = '{\n'
-    for attr in ['name', 'event']:
-      s += str_if_present(self, attr)
-    if self.desc is not None:
-      s += attr_string('desc', self.desc)
-    else:
-      s += attr_string('desc', '(null)')
-    s += str_if_present(self, 'compat')
     s += f'\t.topic = "{topic_local}",\n'
     for attr in [
-        'long_desc', 'pmu', 'unit', 'perpkg', 'aggr_mode', 'metric_expr',
-        'metric_name', 'metric_group', 'deprecated', 'metric_constraint'
+        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
+        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
+        'name', 'perpkg', 'pmu', 'unit'
     ]:
       s += str_if_present(self, attr)
     s += '},\n'
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 02/17] perf jevents: Simplify generation of C-string
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Previous implementation wanted variable order and '(null)' string output
to match the C implementation. The '(null)' string output was a
quirk/bug and so there is no need to carry it forward.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 5b72048d50da..cdfa4e0e7557 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -203,7 +203,7 @@ class JsonEvent:
     """Representation of the event as a C struct initializer."""
 
     def attr_string(attr: str, value: str) -> str:
-      return '\t.%s = \"%s\",\n' % (attr, value)
+      return f'\t.{attr} = \"{value}\",\n'
 
     def str_if_present(self, attr: str) -> str:
       if not getattr(self, attr):
@@ -211,17 +211,11 @@ class JsonEvent:
       return attr_string(attr, getattr(self, attr))
 
     s = '{\n'
-    for attr in ['name', 'event']:
-      s += str_if_present(self, attr)
-    if self.desc is not None:
-      s += attr_string('desc', self.desc)
-    else:
-      s += attr_string('desc', '(null)')
-    s += str_if_present(self, 'compat')
     s += f'\t.topic = "{topic_local}",\n'
     for attr in [
-        'long_desc', 'pmu', 'unit', 'perpkg', 'aggr_mode', 'metric_expr',
-        'metric_name', 'metric_group', 'deprecated', 'metric_constraint'
+        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
+        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
+        'name', 'perpkg', 'pmu', 'unit'
     ]:
       s += str_if_present(self, attr)
     s += '},\n'
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 03/17] perf jevents: Add JEVENTS_ARCH make option
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Allow the architecture built into pmu-events.c to be set on the make
command line with JEVENTS_ARCH.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/Build | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
index 28a9d01b08af..04ef95174660 100644
--- a/tools/perf/pmu-events/Build
+++ b/tools/perf/pmu-events/Build
@@ -7,6 +7,10 @@ JSON_TEST	=  $(shell [ -d $(JDIR_TEST) ] &&			\
 			find $(JDIR_TEST) -name '*.json')
 JEVENTS_PY	=  pmu-events/jevents.py
 
+ifeq ($(JEVENTS_ARCH),)
+JEVENTS_ARCH=$(SRCARCH)
+endif
+
 #
 # Locate/process JSON files in pmu-events/arch/
 # directory and create tables in pmu-events.c.
@@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
 else
 $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
 	$(call rule_mkdir)
-	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
+	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
 endif
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 03/17] perf jevents: Add JEVENTS_ARCH make option
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Allow the architecture built into pmu-events.c to be set on the make
command line with JEVENTS_ARCH.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/Build | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
index 28a9d01b08af..04ef95174660 100644
--- a/tools/perf/pmu-events/Build
+++ b/tools/perf/pmu-events/Build
@@ -7,6 +7,10 @@ JSON_TEST	=  $(shell [ -d $(JDIR_TEST) ] &&			\
 			find $(JDIR_TEST) -name '*.json')
 JEVENTS_PY	=  pmu-events/jevents.py
 
+ifeq ($(JEVENTS_ARCH),)
+JEVENTS_ARCH=$(SRCARCH)
+endif
+
 #
 # Locate/process JSON files in pmu-events/arch/
 # directory and create tables in pmu-events.c.
@@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
 else
 $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
 	$(call rule_mkdir)
-	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
+	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
 endif
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 04/17] perf jevent: Add an 'all' architecture argument
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

When 'all' is passed as the architecture generate a mapping table for
all architectures. This simplifies testing. To identify the table for an
architecture add an arch variable to the pmu_events_map.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c |  2 +
 tools/perf/pmu-events/jevents.py         | 70 +++++++++++++++---------
 tools/perf/pmu-events/pmu-events.h       |  1 +
 tools/perf/tests/pmu-events.c            |  3 +-
 4 files changed, 47 insertions(+), 29 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 77e655c6f116..d8cf9283e486 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -110,12 +110,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 
 const struct pmu_events_map pmu_events_map[] = {
 	{
+		.arch = "testarch",
 		.cpuid = "testcpu",
 		.version = "v1",
 		.type = "core",
 		.table = pme_test_soc_cpu,
 	},
 	{
+		.arch = 0,
 		.cpuid = 0,
 		.version = 0,
 		.type = 0,
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index cdfa4e0e7557..e6e6c42c3f8a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -304,38 +304,45 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   print_events_table_entries(item, get_topic(item.name))
 
 
-def print_mapping_table() -> None:
+def print_mapping_table(archs: Sequence[str]) -> None:
   """Read the mapfile and generate the struct from cpuid string to event table."""
-  with open(f'{_args.starting_dir}/{_args.arch}/mapfile.csv') as csvfile:
-    table = csv.reader(csvfile)
-    _args.output_file.write(
-        'const struct pmu_events_map pmu_events_map[] = {\n')
-    first = True
-    for row in table:
-      # Skip the first row or any row beginning with #.
-      if not first and len(row) > 0 and not row[0].startswith('#'):
-        tblname = file_name_to_table_name([], row[2].replace('/', '_'))
-        _args.output_file.write("""{
-\t.cpuid = \"%s\",
-\t.version = \"%s\",
-\t.type = \"%s\",
-\t.table = %s
-},
-""" % (row[0].replace('\\', '\\\\'), row[1], row[3], tblname))
-      first = False
-
-  _args.output_file.write("""{
+  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
+  for arch in archs:
+    if arch == 'test':
+      _args.output_file.write("""{
+\t.arch = "testarch",
 \t.cpuid = "testcpu",
 \t.version = "v1",
 \t.type = "core",
 \t.table = pme_test_soc_cpu,
 },
-{
+""")
+    else:
+      with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
+        table = csv.reader(csvfile)
+        first = True
+        for row in table:
+          # Skip the first row or any row beginning with #.
+          if not first and len(row) > 0 and not row[0].startswith('#'):
+            tblname = file_name_to_table_name([], row[2].replace('/', '_'))
+            cpuid = row[0].replace('\\', '\\\\')
+            _args.output_file.write(f"""{{
+\t.arch = "{arch}",
+\t.cpuid = "{cpuid}",
+\t.version = "{row[1]}",
+\t.type = "{row[3]}",
+\t.table = {tblname}
+}},
+""")
+          first = False
+
+  _args.output_file.write("""{
+\t.arch = 0,
 \t.cpuid = 0,
 \t.version = 0,
 \t.type = 0,
 \t.table = 0,
-},
+}
 };
 """)
 
@@ -386,15 +393,24 @@ def main() -> None:
   _args = ap.parse_args()
 
   _args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
-  for path in [_args.arch, 'test']:
-    arch_path = f'{_args.starting_dir}/{path}'
-    if not os.path.isdir(arch_path):
-      raise IOError(f'Missing architecture directory in \'{arch_path}\'')
+  archs = []
+  for item in os.scandir(_args.starting_dir):
+    if not item.is_dir():
+      continue
+    if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
+      archs.append(item.name)
+
+  if len(archs) < 2:
+    raise IOError(f'Missing architecture directory \'{_args.arch}\'')
+
+  archs.sort()
+  for arch in archs:
+    arch_path = f'{_args.starting_dir}/{arch}'
     preprocess_arch_std_files(arch_path)
     ftw(arch_path, [], process_one_file)
     print_events_table_suffix()
 
-  print_mapping_table()
+  print_mapping_table(archs)
   print_system_mapping_table()
 
 
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 6efe73976440..7a360792635f 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -38,6 +38,7 @@ struct pmu_event {
  * The  cpuid can contain any character other than the comma.
  */
 struct pmu_events_map {
+	const char *arch;
 	const char *cpuid;
 	const char *version;
 	const char *type;		/* core, uncore etc */
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 263cbb67c861..82192f1a7bf7 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -864,8 +864,7 @@ static void expr_failure(const char *msg,
 			 const struct pmu_events_map *map,
 			 const struct pmu_event *pe)
 {
-	pr_debug("%s for map %s %s %s\n",
-		msg, map->cpuid, map->version, map->type);
+	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
 	pr_debug("On metric %s\n", pe->metric_name);
 	pr_debug("On expression %s\n", pe->metric_expr);
 }
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 04/17] perf jevent: Add an 'all' architecture argument
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

When 'all' is passed as the architecture generate a mapping table for
all architectures. This simplifies testing. To identify the table for an
architecture add an arch variable to the pmu_events_map.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c |  2 +
 tools/perf/pmu-events/jevents.py         | 70 +++++++++++++++---------
 tools/perf/pmu-events/pmu-events.h       |  1 +
 tools/perf/tests/pmu-events.c            |  3 +-
 4 files changed, 47 insertions(+), 29 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 77e655c6f116..d8cf9283e486 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -110,12 +110,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 
 const struct pmu_events_map pmu_events_map[] = {
 	{
+		.arch = "testarch",
 		.cpuid = "testcpu",
 		.version = "v1",
 		.type = "core",
 		.table = pme_test_soc_cpu,
 	},
 	{
+		.arch = 0,
 		.cpuid = 0,
 		.version = 0,
 		.type = 0,
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index cdfa4e0e7557..e6e6c42c3f8a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -304,38 +304,45 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   print_events_table_entries(item, get_topic(item.name))
 
 
-def print_mapping_table() -> None:
+def print_mapping_table(archs: Sequence[str]) -> None:
   """Read the mapfile and generate the struct from cpuid string to event table."""
-  with open(f'{_args.starting_dir}/{_args.arch}/mapfile.csv') as csvfile:
-    table = csv.reader(csvfile)
-    _args.output_file.write(
-        'const struct pmu_events_map pmu_events_map[] = {\n')
-    first = True
-    for row in table:
-      # Skip the first row or any row beginning with #.
-      if not first and len(row) > 0 and not row[0].startswith('#'):
-        tblname = file_name_to_table_name([], row[2].replace('/', '_'))
-        _args.output_file.write("""{
-\t.cpuid = \"%s\",
-\t.version = \"%s\",
-\t.type = \"%s\",
-\t.table = %s
-},
-""" % (row[0].replace('\\', '\\\\'), row[1], row[3], tblname))
-      first = False
-
-  _args.output_file.write("""{
+  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
+  for arch in archs:
+    if arch == 'test':
+      _args.output_file.write("""{
+\t.arch = "testarch",
 \t.cpuid = "testcpu",
 \t.version = "v1",
 \t.type = "core",
 \t.table = pme_test_soc_cpu,
 },
-{
+""")
+    else:
+      with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
+        table = csv.reader(csvfile)
+        first = True
+        for row in table:
+          # Skip the first row or any row beginning with #.
+          if not first and len(row) > 0 and not row[0].startswith('#'):
+            tblname = file_name_to_table_name([], row[2].replace('/', '_'))
+            cpuid = row[0].replace('\\', '\\\\')
+            _args.output_file.write(f"""{{
+\t.arch = "{arch}",
+\t.cpuid = "{cpuid}",
+\t.version = "{row[1]}",
+\t.type = "{row[3]}",
+\t.table = {tblname}
+}},
+""")
+          first = False
+
+  _args.output_file.write("""{
+\t.arch = 0,
 \t.cpuid = 0,
 \t.version = 0,
 \t.type = 0,
 \t.table = 0,
-},
+}
 };
 """)
 
@@ -386,15 +393,24 @@ def main() -> None:
   _args = ap.parse_args()
 
   _args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
-  for path in [_args.arch, 'test']:
-    arch_path = f'{_args.starting_dir}/{path}'
-    if not os.path.isdir(arch_path):
-      raise IOError(f'Missing architecture directory in \'{arch_path}\'')
+  archs = []
+  for item in os.scandir(_args.starting_dir):
+    if not item.is_dir():
+      continue
+    if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
+      archs.append(item.name)
+
+  if len(archs) < 2:
+    raise IOError(f'Missing architecture directory \'{_args.arch}\'')
+
+  archs.sort()
+  for arch in archs:
+    arch_path = f'{_args.starting_dir}/{arch}'
     preprocess_arch_std_files(arch_path)
     ftw(arch_path, [], process_one_file)
     print_events_table_suffix()
 
-  print_mapping_table()
+  print_mapping_table(archs)
   print_system_mapping_table()
 
 
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 6efe73976440..7a360792635f 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -38,6 +38,7 @@ struct pmu_event {
  * The  cpuid can contain any character other than the comma.
  */
 struct pmu_events_map {
+	const char *arch;
 	const char *cpuid;
 	const char *version;
 	const char *type;		/* core, uncore etc */
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 263cbb67c861..82192f1a7bf7 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -864,8 +864,7 @@ static void expr_failure(const char *msg,
 			 const struct pmu_events_map *map,
 			 const struct pmu_event *pe)
 {
-	pr_debug("%s for map %s %s %s\n",
-		msg, map->cpuid, map->version, map->type);
+	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
 	pr_debug("On metric %s\n", pe->metric_name);
 	pr_debug("On expression %s\n", pe->metric_expr);
 }
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 05/17] perf jevents: Remove the type/version variables
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

pmu_events_map has a type variable that is always initialized to "core"
and a version variable that is never read. Remove these from the API as
it is straightforward to add them back when necessary.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c | 4 ----
 tools/perf/pmu-events/jevents.py         | 6 ------
 tools/perf/pmu-events/pmu-events.h       | 2 --
 tools/perf/tests/expand-cgroup.c         | 2 --
 tools/perf/tests/parse-metric.c          | 2 --
 5 files changed, 16 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index d8cf9283e486..4182a986f505 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -112,15 +112,11 @@ const struct pmu_events_map pmu_events_map[] = {
 	{
 		.arch = "testarch",
 		.cpuid = "testcpu",
-		.version = "v1",
-		.type = "core",
 		.table = pme_test_soc_cpu,
 	},
 	{
 		.arch = 0,
 		.cpuid = 0,
-		.version = 0,
-		.type = 0,
 		.table = 0,
 	},
 };
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index e6e6c42c3f8a..98d18d5c3830 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -312,8 +312,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
       _args.output_file.write("""{
 \t.arch = "testarch",
 \t.cpuid = "testcpu",
-\t.version = "v1",
-\t.type = "core",
 \t.table = pme_test_soc_cpu,
 },
 """)
@@ -329,8 +327,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
             _args.output_file.write(f"""{{
 \t.arch = "{arch}",
 \t.cpuid = "{cpuid}",
-\t.version = "{row[1]}",
-\t.type = "{row[3]}",
 \t.table = {tblname}
 }},
 """)
@@ -339,8 +335,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
   _args.output_file.write("""{
 \t.arch = 0,
 \t.cpuid = 0,
-\t.version = 0,
-\t.type = 0,
 \t.table = 0,
 }
 };
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 7a360792635f..a491b117c8ac 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -40,8 +40,6 @@ struct pmu_event {
 struct pmu_events_map {
 	const char *arch;
 	const char *cpuid;
-	const char *version;
-	const char *type;		/* core, uncore etc */
 	const struct pmu_event *table;
 };
 
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index dfefe5b60eb2..dc4038f997d7 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -197,8 +197,6 @@ static int expand_metric_events(void)
 	};
 	const struct pmu_events_map ev_map = {
 		.cpuid		= "test",
-		.version	= "1",
-		.type		= "core",
 		.table		= pme_test,
 	};
 
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 07b6f4ec024f..1b811a26f4ee 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -81,8 +81,6 @@ static struct pmu_event pme_test[] = {
 
 static const struct pmu_events_map map = {
 	.cpuid		= "test",
-	.version	= "1",
-	.type		= "core",
 	.table		= pme_test,
 };
 
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 05/17] perf jevents: Remove the type/version variables
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

pmu_events_map has a type variable that is always initialized to "core"
and a version variable that is never read. Remove these from the API as
it is straightforward to add them back when necessary.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c | 4 ----
 tools/perf/pmu-events/jevents.py         | 6 ------
 tools/perf/pmu-events/pmu-events.h       | 2 --
 tools/perf/tests/expand-cgroup.c         | 2 --
 tools/perf/tests/parse-metric.c          | 2 --
 5 files changed, 16 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index d8cf9283e486..4182a986f505 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -112,15 +112,11 @@ const struct pmu_events_map pmu_events_map[] = {
 	{
 		.arch = "testarch",
 		.cpuid = "testcpu",
-		.version = "v1",
-		.type = "core",
 		.table = pme_test_soc_cpu,
 	},
 	{
 		.arch = 0,
 		.cpuid = 0,
-		.version = 0,
-		.type = 0,
 		.table = 0,
 	},
 };
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index e6e6c42c3f8a..98d18d5c3830 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -312,8 +312,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
       _args.output_file.write("""{
 \t.arch = "testarch",
 \t.cpuid = "testcpu",
-\t.version = "v1",
-\t.type = "core",
 \t.table = pme_test_soc_cpu,
 },
 """)
@@ -329,8 +327,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
             _args.output_file.write(f"""{{
 \t.arch = "{arch}",
 \t.cpuid = "{cpuid}",
-\t.version = "{row[1]}",
-\t.type = "{row[3]}",
 \t.table = {tblname}
 }},
 """)
@@ -339,8 +335,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
   _args.output_file.write("""{
 \t.arch = 0,
 \t.cpuid = 0,
-\t.version = 0,
-\t.type = 0,
 \t.table = 0,
 }
 };
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 7a360792635f..a491b117c8ac 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -40,8 +40,6 @@ struct pmu_event {
 struct pmu_events_map {
 	const char *arch;
 	const char *cpuid;
-	const char *version;
-	const char *type;		/* core, uncore etc */
 	const struct pmu_event *table;
 };
 
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index dfefe5b60eb2..dc4038f997d7 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -197,8 +197,6 @@ static int expand_metric_events(void)
 	};
 	const struct pmu_events_map ev_map = {
 		.cpuid		= "test",
-		.version	= "1",
-		.type		= "core",
 		.table		= pme_test,
 	};
 
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 07b6f4ec024f..1b811a26f4ee 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -81,8 +81,6 @@ static struct pmu_event pme_test[] = {
 
 static const struct pmu_events_map map = {
 	.cpuid		= "test",
-	.version	= "1",
-	.type		= "core",
 	.table		= pme_test,
 };
 
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 06/17] perf jevents: Provide path to json file on error
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

If a JSONDecoderError or similar is raised then it is useful to know the
path. Print this and then raise the exception agan.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 98d18d5c3830..12d2daf3570c 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -224,7 +224,12 @@ class JsonEvent:
 
 def read_json_events(path: str) -> Sequence[JsonEvent]:
   """Read json events from the specified file."""
-  return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+
+  try:
+    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+  except BaseException as err:
+    print(f"Exception processing {path}")
+    raise
 
 
 def preprocess_arch_std_files(archpath: str) -> None:
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 06/17] perf jevents: Provide path to json file on error
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

If a JSONDecoderError or similar is raised then it is useful to know the
path. Print this and then raise the exception agan.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 98d18d5c3830..12d2daf3570c 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -224,7 +224,12 @@ class JsonEvent:
 
 def read_json_events(path: str) -> Sequence[JsonEvent]:
   """Read json events from the specified file."""
-  return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+
+  try:
+    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+  except BaseException as err:
+    print(f"Exception processing {path}")
+    raise
 
 
 def preprocess_arch_std_files(archpath: str) -> None:
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 07/17] perf jevents: Sort json files entries
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Sort the json files entries on conversion to C. The sort order tries to
replicated cmp_sevent from pmu.c so that the input there is already
sorted except for sysfs events.

Add the topic to JsonEvent on reading to simplify. Remove an unnecessary
lambda in the json reading.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 48 +++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 12d2daf3570c..30e0e792221a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -18,6 +18,8 @@ _sys_event_tables = []
 _arch_std_events = {}
 # Track whether an events table is currently being defined and needs closing.
 _close_table = False
+# Events to write out when the table is closed
+_pending_events = []
 
 
 def removesuffix(s: str, suffix: str) -> str:
@@ -127,6 +129,7 @@ class JsonEvent:
       eventcode |= int(jd['ExtSel']) << 8
     configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
     self.name = jd['EventName'].lower() if 'EventName' in jd else None
+    self.topic = ''
     self.compat = jd.get('Compat')
     self.desc = fixdesc(jd.get('BriefDescription'))
     self.long_desc = fixdesc(jd.get('PublicDescription'))
@@ -199,7 +202,7 @@ class JsonEvent:
         s += f'\t{attr} = {value},\n'
     return s + '}'
 
-  def to_c_string(self, topic_local: str) -> str:
+  def to_c_string(self) -> str:
     """Representation of the event as a C struct initializer."""
 
     def attr_string(attr: str, value: str) -> str:
@@ -211,25 +214,27 @@ class JsonEvent:
       return attr_string(attr, getattr(self, attr))
 
     s = '{\n'
-    s += f'\t.topic = "{topic_local}",\n'
     for attr in [
         'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
         'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
-        'name', 'perpkg', 'pmu', 'unit'
+        'name', 'perpkg', 'pmu', 'topic', 'unit'
     ]:
       s += str_if_present(self, attr)
     s += '},\n'
     return s
 
 
-def read_json_events(path: str) -> Sequence[JsonEvent]:
+def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
   """Read json events from the specified file."""
 
   try:
-    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+    result = json.load(open(path), object_hook=JsonEvent)
   except BaseException as err:
     print(f"Exception processing {path}")
     raise
+  for event in result:
+    event.topic = topic
+  return result
 
 
 def preprocess_arch_std_files(archpath: str) -> None:
@@ -237,7 +242,7 @@ def preprocess_arch_std_files(archpath: str) -> None:
   global _arch_std_events
   for item in os.scandir(archpath):
     if item.is_file() and item.name.endswith('.json'):
-      for event in read_json_events(item.path):
+      for event in read_json_events(item.path, topic=''):
         if event.name:
           _arch_std_events[event.name.lower()] = event
 
@@ -251,19 +256,36 @@ def print_events_table_prefix(tblname: str) -> None:
   _close_table = True
 
 
-def print_events_table_entries(item: os.DirEntry, topic: str) -> None:
-  """Create contents of an events table."""
+def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
+  """Add contents of file to _pending_events table."""
   if not _close_table:
     raise IOError('Table entries missing prefix')
-  for event in read_json_events(item.path):
-    _args.output_file.write(event.to_c_string(topic))
+  for e in read_json_events(item.path, topic):
+    _pending_events.append(e)
 
 
 def print_events_table_suffix() -> None:
   """Optionally close events table."""
+
+  def event_cmp_key(j: JsonEvent):
+    def fix_none(s: str):
+      if s is None:
+        return ''
+      return s
+
+    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
+            fix_none(j.metric_name))
+
   global _close_table
-  if _close_table:
-    _args.output_file.write("""{
+  if not _close_table:
+    return
+
+  global _pending_events
+  for event in sorted(_pending_events, key=event_cmp_key):
+    _args.output_file.write(event.to_c_string())
+    _pending_events = []
+
+  _args.output_file.write("""{
 \t.name = 0,
 \t.event = 0,
 \t.desc = 0,
@@ -306,7 +328,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   if not item.is_file() or not item.name.endswith('.json'):
     return
 
-  print_events_table_entries(item, get_topic(item.name))
+  add_events_table_entries(item, get_topic(item.name))
 
 
 def print_mapping_table(archs: Sequence[str]) -> None:
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 07/17] perf jevents: Sort json files entries
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Sort the json files entries on conversion to C. The sort order tries to
replicated cmp_sevent from pmu.c so that the input there is already
sorted except for sysfs events.

Add the topic to JsonEvent on reading to simplify. Remove an unnecessary
lambda in the json reading.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 48 +++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 12d2daf3570c..30e0e792221a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -18,6 +18,8 @@ _sys_event_tables = []
 _arch_std_events = {}
 # Track whether an events table is currently being defined and needs closing.
 _close_table = False
+# Events to write out when the table is closed
+_pending_events = []
 
 
 def removesuffix(s: str, suffix: str) -> str:
@@ -127,6 +129,7 @@ class JsonEvent:
       eventcode |= int(jd['ExtSel']) << 8
     configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
     self.name = jd['EventName'].lower() if 'EventName' in jd else None
+    self.topic = ''
     self.compat = jd.get('Compat')
     self.desc = fixdesc(jd.get('BriefDescription'))
     self.long_desc = fixdesc(jd.get('PublicDescription'))
@@ -199,7 +202,7 @@ class JsonEvent:
         s += f'\t{attr} = {value},\n'
     return s + '}'
 
-  def to_c_string(self, topic_local: str) -> str:
+  def to_c_string(self) -> str:
     """Representation of the event as a C struct initializer."""
 
     def attr_string(attr: str, value: str) -> str:
@@ -211,25 +214,27 @@ class JsonEvent:
       return attr_string(attr, getattr(self, attr))
 
     s = '{\n'
-    s += f'\t.topic = "{topic_local}",\n'
     for attr in [
         'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
         'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
-        'name', 'perpkg', 'pmu', 'unit'
+        'name', 'perpkg', 'pmu', 'topic', 'unit'
     ]:
       s += str_if_present(self, attr)
     s += '},\n'
     return s
 
 
-def read_json_events(path: str) -> Sequence[JsonEvent]:
+def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
   """Read json events from the specified file."""
 
   try:
-    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+    result = json.load(open(path), object_hook=JsonEvent)
   except BaseException as err:
     print(f"Exception processing {path}")
     raise
+  for event in result:
+    event.topic = topic
+  return result
 
 
 def preprocess_arch_std_files(archpath: str) -> None:
@@ -237,7 +242,7 @@ def preprocess_arch_std_files(archpath: str) -> None:
   global _arch_std_events
   for item in os.scandir(archpath):
     if item.is_file() and item.name.endswith('.json'):
-      for event in read_json_events(item.path):
+      for event in read_json_events(item.path, topic=''):
         if event.name:
           _arch_std_events[event.name.lower()] = event
 
@@ -251,19 +256,36 @@ def print_events_table_prefix(tblname: str) -> None:
   _close_table = True
 
 
-def print_events_table_entries(item: os.DirEntry, topic: str) -> None:
-  """Create contents of an events table."""
+def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
+  """Add contents of file to _pending_events table."""
   if not _close_table:
     raise IOError('Table entries missing prefix')
-  for event in read_json_events(item.path):
-    _args.output_file.write(event.to_c_string(topic))
+  for e in read_json_events(item.path, topic):
+    _pending_events.append(e)
 
 
 def print_events_table_suffix() -> None:
   """Optionally close events table."""
+
+  def event_cmp_key(j: JsonEvent):
+    def fix_none(s: str):
+      if s is None:
+        return ''
+      return s
+
+    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
+            fix_none(j.metric_name))
+
   global _close_table
-  if _close_table:
-    _args.output_file.write("""{
+  if not _close_table:
+    return
+
+  global _pending_events
+  for event in sorted(_pending_events, key=event_cmp_key):
+    _args.output_file.write(event.to_c_string())
+    _pending_events = []
+
+  _args.output_file.write("""{
 \t.name = 0,
 \t.event = 0,
 \t.desc = 0,
@@ -306,7 +328,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   if not item.is_file() or not item.name.endswith('.json'):
     return
 
-  print_events_table_entries(item, get_topic(item.name))
+  add_events_table_entries(item, get_topic(item.name))
 
 
 def print_mapping_table(archs: Sequence[str]) -> None:
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 08/17] perf pmu-events: Hide pmu_sys_event_tables
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Move usage of the table to pmu-events.c so it may be hidden. By
abstracting the table the implementation can later be changed.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c | 37 ++++++++++++++++++-
 tools/perf/pmu-events/jevents.py         | 45 ++++++++++++++++++++++--
 tools/perf/pmu-events/pmu-events.h       | 11 +++---
 tools/perf/tests/pmu-events.c            | 14 +-------
 tools/perf/util/pmu.c                    | 27 --------------
 tools/perf/util/pmu.h                    |  2 --
 6 files changed, 84 insertions(+), 52 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 4182a986f505..216ea0482c37 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -6,6 +6,8 @@
  * The test cpu/soc is provided for testing.
  */
 #include "pmu-events/pmu-events.h"
+#include <string.h>
+#include <stddef.h>
 
 static const struct pmu_event pme_test_soc_cpu[] = {
 	{
@@ -145,7 +147,12 @@ static const struct pmu_event pme_test_soc_sys[] = {
 	},
 };
 
-const struct pmu_sys_events pmu_sys_event_tables[] = {
+struct pmu_sys_events {
+	const char *name;
+	const struct pmu_event *table;
+};
+
+static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	{
 		.table = pme_test_soc_sys,
 		.name = "pme_test_soc_sys",
@@ -154,3 +161,31 @@ const struct pmu_sys_events pmu_sys_event_tables[] = {
 		.table = 0
 	},
 };
+
+const struct pmu_event *find_sys_events_table(const char *name)
+{
+	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+	     tables->name;
+	     tables++) {
+		if (!strcmp(tables->name, name))
+			return tables->table;
+	}
+	return NULL;
+}
+
+int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
+{
+	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+	     tables->name;
+	     tables++) {
+		for (const struct pmu_event *pe = &tables->table[0];
+		     pe->name || pe->metric_group || pe->metric_name;
+		     pe++) {
+			int ret = fn(pe, data);
+
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 30e0e792221a..dd21bc9eeeed 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -370,8 +370,14 @@ def print_mapping_table(archs: Sequence[str]) -> None:
 
 def print_system_mapping_table() -> None:
   """C struct mapping table array for tables from /sys directories."""
-  _args.output_file.write(
-      '\nconst struct pmu_sys_events pmu_sys_event_tables[] = {\n')
+  _args.output_file.write("""
+struct pmu_sys_events {
+\tconst char *name;
+\tconst struct pmu_event *table;
+};
+
+static const struct pmu_sys_events pmu_sys_event_tables[] = {
+""")
   for tblname in _sys_event_tables:
     _args.output_file.write(f"""\t{{
 \t\t.table = {tblname},
@@ -382,6 +388,34 @@ def print_system_mapping_table() -> None:
 \t\t.table = 0
 \t},
 };
+
+const struct pmu_event *find_sys_events_table(const char *name)
+{
+        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+             tables->name;
+             tables++) {
+                if (!strcmp(tables->name, name))
+                        return tables->table;
+        }
+        return NULL;
+}
+
+int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
+{
+        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+             tables->name;
+             tables++) {
+                for (const struct pmu_event *pe = &tables->table[0];
+                     pe->name || pe->metric_group || pe->metric_name;
+                     pe++) {
+                        int ret = fn(pe, data);
+
+                        if (ret)
+                                return ret;
+                }
+        }
+        return 0;
+}
 """)
 
 
@@ -413,7 +447,12 @@ def main() -> None:
       'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
   _args = ap.parse_args()
 
-  _args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
+  _args.output_file.write("""
+#include "pmu-events/pmu-events.h"
+#include <string.h>
+#include <stddef.h>
+
+""")
   archs = []
   for item in os.scandir(_args.starting_dir):
     if not item.is_dir():
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index a491b117c8ac..2386212b1df0 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -43,16 +43,15 @@ struct pmu_events_map {
 	const struct pmu_event *table;
 };
 
-struct pmu_sys_events {
-	const char *name;
-	const struct pmu_event *table;
-};
-
 /*
  * Global table mapping each known CPU for the architecture to its
  * table of PMU events.
  */
 extern const struct pmu_events_map pmu_events_map[];
-extern const struct pmu_sys_events pmu_sys_event_tables[];
+
+const struct pmu_event *find_sys_events_table(const char *name);
+
+typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe, void *data);
+int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
 
 #endif
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 82192f1a7bf7..a39a2c99ede6 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -286,18 +286,6 @@ static const struct pmu_events_map *__test_pmu_get_events_map(void)
 	return NULL;
 }
 
-static const struct pmu_event *__test_pmu_get_sys_events_table(void)
-{
-	const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
-
-	for ( ; tables->name; tables++) {
-		if (!strcmp("pme_test_soc_sys", tables->name))
-			return tables->table;
-	}
-
-	return NULL;
-}
-
 static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
 {
 	if (!is_same(e1->name, e2->name)) {
@@ -451,7 +439,7 @@ static int compare_alias_to_test_event(struct perf_pmu_alias *alias,
 static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
-	const struct pmu_event *sys_event_tables = __test_pmu_get_sys_events_table();
+	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
 	const struct pmu_events_map *map = __test_pmu_get_events_map();
 	const struct pmu_event *table;
 	int map_events = 0, expected_events;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 0112e1c36418..d8717c4548a4 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -868,33 +868,6 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 	pmu_add_cpu_aliases_map(head, pmu, map);
 }
 
-void pmu_for_each_sys_event(pmu_sys_event_iter_fn fn, void *data)
-{
-	int i = 0;
-
-	while (1) {
-		const struct pmu_sys_events *event_table;
-		int j = 0;
-
-		event_table = &pmu_sys_event_tables[i++];
-
-		if (!event_table->table)
-			break;
-
-		while (1) {
-			const struct pmu_event *pe = &event_table->table[j++];
-			int ret;
-
-			if (!pe->name && !pe->metric_group && !pe->metric_name)
-				break;
-
-			ret = fn(pe, data);
-			if (ret)
-				break;
-		}
-	}
-}
-
 struct pmu_sys_event_iter_data {
 	struct list_head *head;
 	struct perf_pmu *pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 4b45fd8da5a3..7e667eec2a01 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -133,8 +133,6 @@ const struct pmu_events_map *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
 
-typedef int (*pmu_sys_event_iter_fn)(const struct pmu_event *pe, void *data);
-void pmu_for_each_sys_event(pmu_sys_event_iter_fn fn, void *data);
 int perf_pmu__convert_scale(const char *scale, char **end, double *sval);
 
 int perf_pmu__caps_parse(struct perf_pmu *pmu);
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 08/17] perf pmu-events: Hide pmu_sys_event_tables
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Move usage of the table to pmu-events.c so it may be hidden. By
abstracting the table the implementation can later be changed.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c | 37 ++++++++++++++++++-
 tools/perf/pmu-events/jevents.py         | 45 ++++++++++++++++++++++--
 tools/perf/pmu-events/pmu-events.h       | 11 +++---
 tools/perf/tests/pmu-events.c            | 14 +-------
 tools/perf/util/pmu.c                    | 27 --------------
 tools/perf/util/pmu.h                    |  2 --
 6 files changed, 84 insertions(+), 52 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 4182a986f505..216ea0482c37 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -6,6 +6,8 @@
  * The test cpu/soc is provided for testing.
  */
 #include "pmu-events/pmu-events.h"
+#include <string.h>
+#include <stddef.h>
 
 static const struct pmu_event pme_test_soc_cpu[] = {
 	{
@@ -145,7 +147,12 @@ static const struct pmu_event pme_test_soc_sys[] = {
 	},
 };
 
-const struct pmu_sys_events pmu_sys_event_tables[] = {
+struct pmu_sys_events {
+	const char *name;
+	const struct pmu_event *table;
+};
+
+static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	{
 		.table = pme_test_soc_sys,
 		.name = "pme_test_soc_sys",
@@ -154,3 +161,31 @@ const struct pmu_sys_events pmu_sys_event_tables[] = {
 		.table = 0
 	},
 };
+
+const struct pmu_event *find_sys_events_table(const char *name)
+{
+	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+	     tables->name;
+	     tables++) {
+		if (!strcmp(tables->name, name))
+			return tables->table;
+	}
+	return NULL;
+}
+
+int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
+{
+	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+	     tables->name;
+	     tables++) {
+		for (const struct pmu_event *pe = &tables->table[0];
+		     pe->name || pe->metric_group || pe->metric_name;
+		     pe++) {
+			int ret = fn(pe, data);
+
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 30e0e792221a..dd21bc9eeeed 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -370,8 +370,14 @@ def print_mapping_table(archs: Sequence[str]) -> None:
 
 def print_system_mapping_table() -> None:
   """C struct mapping table array for tables from /sys directories."""
-  _args.output_file.write(
-      '\nconst struct pmu_sys_events pmu_sys_event_tables[] = {\n')
+  _args.output_file.write("""
+struct pmu_sys_events {
+\tconst char *name;
+\tconst struct pmu_event *table;
+};
+
+static const struct pmu_sys_events pmu_sys_event_tables[] = {
+""")
   for tblname in _sys_event_tables:
     _args.output_file.write(f"""\t{{
 \t\t.table = {tblname},
@@ -382,6 +388,34 @@ def print_system_mapping_table() -> None:
 \t\t.table = 0
 \t},
 };
+
+const struct pmu_event *find_sys_events_table(const char *name)
+{
+        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+             tables->name;
+             tables++) {
+                if (!strcmp(tables->name, name))
+                        return tables->table;
+        }
+        return NULL;
+}
+
+int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
+{
+        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
+             tables->name;
+             tables++) {
+                for (const struct pmu_event *pe = &tables->table[0];
+                     pe->name || pe->metric_group || pe->metric_name;
+                     pe++) {
+                        int ret = fn(pe, data);
+
+                        if (ret)
+                                return ret;
+                }
+        }
+        return 0;
+}
 """)
 
 
@@ -413,7 +447,12 @@ def main() -> None:
       'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
   _args = ap.parse_args()
 
-  _args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
+  _args.output_file.write("""
+#include "pmu-events/pmu-events.h"
+#include <string.h>
+#include <stddef.h>
+
+""")
   archs = []
   for item in os.scandir(_args.starting_dir):
     if not item.is_dir():
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index a491b117c8ac..2386212b1df0 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -43,16 +43,15 @@ struct pmu_events_map {
 	const struct pmu_event *table;
 };
 
-struct pmu_sys_events {
-	const char *name;
-	const struct pmu_event *table;
-};
-
 /*
  * Global table mapping each known CPU for the architecture to its
  * table of PMU events.
  */
 extern const struct pmu_events_map pmu_events_map[];
-extern const struct pmu_sys_events pmu_sys_event_tables[];
+
+const struct pmu_event *find_sys_events_table(const char *name);
+
+typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe, void *data);
+int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
 
 #endif
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 82192f1a7bf7..a39a2c99ede6 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -286,18 +286,6 @@ static const struct pmu_events_map *__test_pmu_get_events_map(void)
 	return NULL;
 }
 
-static const struct pmu_event *__test_pmu_get_sys_events_table(void)
-{
-	const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
-
-	for ( ; tables->name; tables++) {
-		if (!strcmp("pme_test_soc_sys", tables->name))
-			return tables->table;
-	}
-
-	return NULL;
-}
-
 static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
 {
 	if (!is_same(e1->name, e2->name)) {
@@ -451,7 +439,7 @@ static int compare_alias_to_test_event(struct perf_pmu_alias *alias,
 static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
-	const struct pmu_event *sys_event_tables = __test_pmu_get_sys_events_table();
+	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
 	const struct pmu_events_map *map = __test_pmu_get_events_map();
 	const struct pmu_event *table;
 	int map_events = 0, expected_events;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 0112e1c36418..d8717c4548a4 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -868,33 +868,6 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 	pmu_add_cpu_aliases_map(head, pmu, map);
 }
 
-void pmu_for_each_sys_event(pmu_sys_event_iter_fn fn, void *data)
-{
-	int i = 0;
-
-	while (1) {
-		const struct pmu_sys_events *event_table;
-		int j = 0;
-
-		event_table = &pmu_sys_event_tables[i++];
-
-		if (!event_table->table)
-			break;
-
-		while (1) {
-			const struct pmu_event *pe = &event_table->table[j++];
-			int ret;
-
-			if (!pe->name && !pe->metric_group && !pe->metric_name)
-				break;
-
-			ret = fn(pe, data);
-			if (ret)
-				break;
-		}
-	}
-}
-
 struct pmu_sys_event_iter_data {
 	struct list_head *head;
 	struct perf_pmu *pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 4b45fd8da5a3..7e667eec2a01 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -133,8 +133,6 @@ const struct pmu_events_map *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
 
-typedef int (*pmu_sys_event_iter_fn)(const struct pmu_event *pe, void *data);
-void pmu_for_each_sys_event(pmu_sys_event_iter_fn fn, void *data);
 int perf_pmu__convert_scale(const char *scale, char **end, double *sval);
 
 int perf_pmu__caps_parse(struct perf_pmu *pmu);
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 09/17] perf pmu-events: Avoid passing pmu_events_map
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Preparation for hiding pmu_events_map as an implementation detail. While
the map is passed, the table of events is all that is normally wanted.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/arm64/util/pmu.c  |  4 +-
 tools/perf/tests/expand-cgroup.c  |  6 +--
 tools/perf/tests/parse-metric.c   |  7 +--
 tools/perf/tests/pmu-events.c     | 63 +++++++++++-------------
 tools/perf/util/metricgroup.c     | 82 +++++++++++++++----------------
 tools/perf/util/metricgroup.h     |  4 +-
 tools/perf/util/pmu.c             | 33 +++++++------
 tools/perf/util/pmu.h             |  6 +--
 tools/perf/util/s390-sample-raw.c | 12 ++---
 9 files changed, 99 insertions(+), 118 deletions(-)

diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
index 79124bba713e..646af8603227 100644
--- a/tools/perf/arch/arm64/util/pmu.c
+++ b/tools/perf/arch/arm64/util/pmu.c
@@ -3,7 +3,7 @@
 #include "../../../util/cpumap.h"
 #include "../../../util/pmu.h"
 
-const struct pmu_events_map *pmu_events_map__find(void)
+const struct pmu_event *pmu_events_map__find(void)
 {
 	struct perf_pmu *pmu = NULL;
 
@@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
 		if (pmu->cpus->nr != cpu__max_cpu().cpu)
 			return NULL;
 
-		return perf_pmu__find_map(pmu);
+		return perf_pmu__find_table(pmu);
 	}
 
 	return NULL;
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index dc4038f997d7..411fc578e5a4 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -195,16 +195,12 @@ static int expand_metric_events(void)
 			.metric_name	= NULL,
 		},
 	};
-	const struct pmu_events_map ev_map = {
-		.cpuid		= "test",
-		.table		= pme_test,
-	};
 
 	evlist = evlist__new();
 	TEST_ASSERT_VAL("failed to get evlist", evlist);
 
 	rblist__init(&metric_events);
-	ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
+	ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
 					     false, false, &metric_events);
 	if (ret < 0) {
 		pr_debug("failed to parse '%s' metric\n", metric_str);
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 1b811a26f4ee..7aebde7c37ec 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
 }
 };
 
-static const struct pmu_events_map map = {
-	.cpuid		= "test",
-	.table		= pme_test,
-};
-
 struct value {
 	const char	*event;
 	u64		 val;
@@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	runtime_stat__init(&st);
 
 	/* Parse the metric into metric_events list. */
-	err = metricgroup__parse_groups_test(evlist, &map, name,
+	err = metricgroup__parse_groups_test(evlist, pme_test, name,
 					     false, false,
 					     &metric_events);
 	if (err)
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index a39a2c99ede6..b3cde5f98982 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
 	return !strcmp(reference, test);
 }
 
-static const struct pmu_events_map *__test_pmu_get_events_map(void)
+static const struct pmu_event *__test_pmu_get_events_table(void)
 {
-	const struct pmu_events_map *map;
-
-	for (map = &pmu_events_map[0]; map->cpuid; map++) {
+	for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
 		if (!strcmp(map->cpuid, "testcpu"))
-			return map;
+			return map->table;
 	}
 
 	pr_err("could not find test events map\n");
@@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
 	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_events_map *map = __test_pmu_get_events_map();
-	const struct pmu_event *table;
+	const struct pmu_event *table = __test_pmu_get_events_table();
 	int map_events = 0, expected_events;
 
 	/* ignore 3x sentinels */
@@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 			  ARRAY_SIZE(uncore_events) +
 			  ARRAY_SIZE(sys_events) - 3;
 
-	if (!map || !sys_event_tables)
+	if (!table || !sys_event_tables)
 		return -1;
 
-	for (table = map->table; table->name; table++) {
+	for (; table->name; table++) {
 		struct perf_pmu_test_event const **test_event_table;
 		bool found = false;
 
@@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 	struct perf_pmu *pmu;
 	LIST_HEAD(aliases);
 	int res = 0;
-	const struct pmu_events_map *map = __test_pmu_get_events_map();
+	const struct pmu_event *table = __test_pmu_get_events_table();
 	struct perf_pmu_alias *a, *tmp;
 
-	if (!map)
+	if (!table)
 		return -1;
 
 	test_event_table = &core_events[0];
@@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 
 	pmu->name = pmu_name;
 
-	pmu_add_cpu_aliases_map(&aliases, pmu, map);
+	pmu_add_cpu_aliases_map(&aliases, pmu, table);
 
 	for (; *test_event_table; test_event_table++) {
 		struct perf_pmu_test_event const *test_event = *test_event_table;
@@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 	struct perf_pmu *pmu = &test_pmu->pmu;
 	const char *pmu_name = pmu->name;
 	struct perf_pmu_alias *a, *tmp, *alias;
-	const struct pmu_events_map *map;
+	const struct pmu_event *events_table;
 	LIST_HEAD(aliases);
 	int res = 0;
 
-	map = __test_pmu_get_events_map();
-	if (!map)
+	events_table = __test_pmu_get_events_table();
+	if (!events_table)
 		return -1;
-	pmu_add_cpu_aliases_map(&aliases, pmu, map);
+	pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
 	pmu_add_sys_aliases(&aliases, pmu);
 
 	/* Count how many aliases we generated */
@@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
 	return ret;
 }
 
-static void expr_failure(const char *msg,
-			 const struct pmu_events_map *map,
-			 const struct pmu_event *pe)
+static void expr_failure(const char *msg, const struct pmu_event *pe)
 {
-	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
-	pr_debug("On metric %s\n", pe->metric_name);
-	pr_debug("On expression %s\n", pe->metric_expr);
+	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
 }
 
 struct metric {
@@ -864,7 +857,7 @@ struct metric {
 
 static int resolve_metric_simple(struct expr_parse_ctx *pctx,
 				 struct list_head *compound_list,
-				 const struct pmu_events_map *map,
+				 const struct pmu_event *map,
 				 const char *metric_name)
 {
 	struct hashmap_entry *cur, *cur_tmp;
@@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
 static int test__parsing(struct test_suite *test __maybe_unused,
 			 int subtest __maybe_unused)
 {
-	const struct pmu_events_map *cpus_map = pmu_events_map__find();
-	const struct pmu_events_map *map;
+	const struct pmu_event *cpus_table = pmu_events_map__find();
 	const struct pmu_event *pe;
 	int i, j, k;
 	int ret = 0;
@@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 	}
 	i = 0;
 	for (;;) {
-		map = &pmu_events_map[i++];
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
 		if (!map->table)
 			break;
 		j = 0;
@@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 				continue;
 			expr__ctx_clear(ctx);
 			if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
-				expr_failure("Parse find ids failed", map, pe);
+				expr_failure("Parse find ids failed", pe);
 				ret++;
 				continue;
 			}
 
-			if (resolve_metric_simple(ctx, &compound_list, map,
+			if (resolve_metric_simple(ctx, &compound_list, map->table,
 						  pe->metric_name)) {
-				expr_failure("Could not resolve metrics", map, pe);
+				expr_failure("Could not resolve metrics", pe);
 				ret++;
 				goto exit; /* Don't tolerate errors due to severity */
 			}
@@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 				expr__add_id_val(ctx, strdup(cur->key), k++);
 
 			hashmap__for_each_entry(ctx->ids, cur, bkt) {
-				if (check_parse_cpu(cur->key, map == cpus_map,
+				if (check_parse_cpu(cur->key, map->table == cpus_table,
 						   pe))
 					ret++;
 			}
@@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 				hashmap__for_each_entry(ctx->ids, cur, bkt)
 					expr__add_id_val(ctx, strdup(cur->key), k--);
 				if (expr__parse(&result, ctx, pe->metric_expr)) {
-					expr_failure("Parse failed", map, pe);
+					expr_failure("Parse failed", pe);
 					ret++;
 				}
 			}
@@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
 static int test__parsing_fake(struct test_suite *test __maybe_unused,
 			      int subtest __maybe_unused)
 {
-	const struct pmu_events_map *map;
-	const struct pmu_event *pe;
 	unsigned int i, j;
 	int err = 0;
 
@@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
 
 	i = 0;
 	for (;;) {
-		map = &pmu_events_map[i++];
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
 		if (!map->table)
 			break;
 		j = 0;
 		for (;;) {
-			pe = &map->table[j++];
+			const struct pmu_event *pe = &map->table[j++];
+
 			if (!pe->name && !pe->metric_group && !pe->metric_name)
 				break;
 			if (!pe->metric_expr)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8f7baeabc5cf..4d32b4fbf67d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 			bool raw, bool details, const char *pmu_name)
 {
-	const struct pmu_events_map *map = pmu_events_map__find();
-	const struct pmu_event *pe;
-	int i;
 	struct rblist groups;
 	struct rb_node *node, *next;
 	struct strlist *metriclist = NULL;
@@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 	groups.node_new = mep_new;
 	groups.node_cmp = mep_cmp;
 	groups.node_delete = mep_delete;
-	for (i = 0; map; i++) {
-		pe = &map->table[i];
+	for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
 
 		if (!pe->name && !pe->metric_group && !pe->metric_name)
 			break;
@@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
 	bool metric_no_group;
 	struct metric *root_metric;
 	const struct visited_metric *visited;
-	const struct pmu_events_map *map;
+	const struct pmu_event *table;
 };
 
 static int add_metric(struct list_head *metric_list,
@@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_events_map *map);
+		      const struct pmu_event *table);
 
 /**
  * resolve_metric - Locate metrics within the root metric and recursively add
@@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
  *               metrics. When adding a root this argument is NULL.
  * @visited: A singly linked list of metric names being added that is used to
  *           detect recursion.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int resolve_metric(struct list_head *metric_list,
@@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
 			  bool metric_no_group,
 			  struct metric *root_metric,
 			  const struct visited_metric *visited,
-			  const struct pmu_events_map *map)
+			  const struct pmu_event *table)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
 	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
 		const struct pmu_event *pe;
 
-		pe = metricgroup__find_metric(cur->key, map);
+		pe = metricgroup__find_metric(cur->key, table);
 		if (pe) {
 			pending = realloc(pending,
 					(pending_cnt + 1) * sizeof(struct to_resolve));
@@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
 	 */
 	for (i = 0; i < pending_cnt; i++) {
 		ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
-				root_metric, visited, map);
+				root_metric, visited, table);
 		if (ret)
 			break;
 	}
@@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
  *               metrics. When adding a root this argument is NULL.
  * @visited: A singly linked list of metric names being added that is used to
  *           detect recursion.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int __add_metric(struct list_head *metric_list,
@@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
 			int runtime,
 			struct metric *root_metric,
 			const struct visited_metric *visited,
-			const struct pmu_events_map *map)
+			const struct pmu_event *table)
 {
 	const struct visited_metric *vm;
 	int ret;
@@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
 	} else {
 		/* Resolve referenced metrics. */
 		ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
-				     &visited_node, map);
+				     &visited_node, table);
 	}
 
 	if (ret) {
@@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
 	return ret;
 }
 
-#define map_for_each_event(__pe, __idx, __map)					\
-	if (__map)								\
-		for (__idx = 0, __pe = &__map->table[__idx];			\
+#define table_for_each_event(__pe, __idx, __table)					\
+	if (__table)								\
+		for (__idx = 0, __pe = &__table[__idx];				\
 		     __pe->name || __pe->metric_group || __pe->metric_name;	\
-		     __pe = &__map->table[++__idx])
+		     __pe = &__table[++__idx])
 
-#define map_for_each_metric(__pe, __idx, __map, __metric)		\
-	map_for_each_event(__pe, __idx, __map)				\
+#define table_for_each_metric(__pe, __idx, __table, __metric)		\
+	table_for_each_event(__pe, __idx, __table)				\
 		if (__pe->metric_expr &&				\
 		    (match_metric(__pe->metric_group, __metric) ||	\
 		     match_metric(__pe->metric_name, __metric)))
 
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_map *map)
+						 const struct pmu_event *table)
 {
 	const struct pmu_event *pe;
 	int i;
 
-	map_for_each_event(pe, i, map) {
+	table_for_each_event(pe, i, table) {
 		if (match_metric(pe->metric_name, metric))
 			return pe;
 	}
@@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_events_map *map)
+		      const struct pmu_event *table)
 {
 	int ret = 0;
 
@@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
 
 	if (!strstr(pe->metric_expr, "?")) {
 		ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
-				   root_metric, visited, map);
+				   root_metric, visited, table);
 	} else {
 		int j, count;
 
@@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
 
 		for (j = 0; j < count && !ret; j++)
 			ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
-					root_metric, visited, map);
+					root_metric, visited, table);
 	}
 
 	return ret;
@@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
 		return 0;
 
 	ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
-			 d->root_metric, d->visited, d->map);
+			 d->root_metric, d->visited, d->table);
 	if (ret)
 		goto out;
 
@@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
  *                   global. Grouping is the default but due to multiplexing the
  *                   user may override.
  * @metric_list: The list that the metric or metric group are added to.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int metricgroup__add_metric(const char *metric_name, const char *modifier,
 				   bool metric_no_group,
 				   struct list_head *metric_list,
-				   const struct pmu_events_map *map)
+				   const struct pmu_event *table)
 {
 	const struct pmu_event *pe;
 	LIST_HEAD(list);
@@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 	 * Iterate over all metrics seeing if metric matches either the name or
 	 * group. When it does add the metric to the list.
 	 */
-	map_for_each_metric(pe, i, map, metric_name) {
+	table_for_each_metric(pe, i, table, metric_name) {
 		has_match = true;
 		ret = add_metric(&list, pe, modifier, metric_no_group,
 				 /*root_metric=*/NULL,
-				 /*visited_metrics=*/NULL, map);
+				 /*visited_metrics=*/NULL, table);
 		if (ret)
 			goto out;
 	}
@@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 				.metric_no_group = metric_no_group,
 				.has_match = &has_match,
 				.ret = &ret,
-				.map = map,
+				.table = table,
 			},
 		};
 
@@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
  *                   global. Grouping is the default but due to multiplexing the
  *                   user may override.
  * @metric_list: The list that metrics are added to.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 					struct list_head *metric_list,
-					const struct pmu_events_map *map)
+					const struct pmu_event *table)
 {
 	char *list_itr, *list_copy, *metric_name, *modifier;
 	int ret, count = 0;
@@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 
 		ret = metricgroup__add_metric(metric_name, modifier,
 					      metric_no_group, metric_list,
-					      map);
+					      table);
 		if (ret == -EINVAL)
 			pr_err("Cannot find metric or group `%s'\n", metric_name);
 
@@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 			bool metric_no_merge,
 			struct perf_pmu *fake_pmu,
 			struct rblist *metric_events_list,
-			const struct pmu_events_map *map)
+			const struct pmu_event *table)
 {
 	struct evlist *combined_evlist = NULL;
 	LIST_HEAD(metric_list);
@@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 	if (metric_events_list->nr_entries == 0)
 		metricgroup__rblist_init(metric_events_list);
 	ret = metricgroup__add_metric_list(str, metric_no_group,
-					   &metric_list, map);
+					   &metric_list, table);
 	if (ret)
 		goto out;
 
@@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
 			      struct rblist *metric_events)
 {
 	struct evlist *perf_evlist = *(struct evlist **)opt->value;
-	const struct pmu_events_map *map = pmu_events_map__find();
+	const struct pmu_event *table = pmu_events_map__find();
 
 	return parse_groups(perf_evlist, str, metric_no_group,
-			    metric_no_merge, NULL, metric_events, map);
+			    metric_no_merge, NULL, metric_events, table);
 }
 
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_events_map *map,
+				   const struct pmu_event *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
 				   struct rblist *metric_events)
 {
 	return parse_groups(evlist, str, metric_no_group,
-			    metric_no_merge, &perf_pmu__fake, metric_events, map);
+			    metric_no_merge, &perf_pmu__fake, metric_events, table);
 }
 
 bool metricgroup__has_metric(const char *metric)
 {
-	const struct pmu_events_map *map = pmu_events_map__find();
+	const struct pmu_event *table = pmu_events_map__find();
 	const struct pmu_event *pe;
 	int i;
 
-	if (!map)
+	if (!table)
 		return false;
 
 	for (i = 0; ; i++) {
-		pe = &map->table[i];
+		pe = &table[i];
 
 		if (!pe->name && !pe->metric_group && !pe->metric_name)
 			break;
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 2b42b778d1bf..5a1390e73d25 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
 			      bool metric_no_merge,
 			      struct rblist *metric_events);
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_map *map);
+						 const struct pmu_event *table);
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_events_map *map,
+				   const struct pmu_event *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index d8717c4548a4..f3e3c4a147e9 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 	return cpuid;
 }
 
-const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 {
-	const struct pmu_events_map *map;
+	const struct pmu_event *table = NULL;
 	char *cpuid = perf_pmu__getcpuid(pmu);
 	int i;
 
@@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
 
 	i = 0;
 	for (;;) {
-		map = &pmu_events_map[i++];
-		if (!map->table) {
-			map = NULL;
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
+		if (!map->table)
 			break;
-		}
 
-		if (!strcmp_cpuid_str(map->cpuid, cpuid))
+		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+			table = map->table;
 			break;
+		}
 	}
 	free(cpuid);
-	return map;
+	return table;
 }
 
-const struct pmu_events_map *__weak pmu_events_map__find(void)
+__weak const struct pmu_event *pmu_events_map__find(void)
 {
-	return perf_pmu__find_map(NULL);
+	return perf_pmu__find_table(NULL);
 }
 
 /*
@@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
  * as aliases.
  */
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_events_map *map)
+			     const struct pmu_event *table)
 {
 	int i;
 	const char *name = pmu->name;
@@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 	i = 0;
 	while (1) {
 		const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
-		const struct pmu_event *pe = &map->table[i++];
+		const struct pmu_event *pe = &table[i++];
 		const char *pname = pe->pmu ? pe->pmu : cpu_name;
 
 		if (!pe->name) {
@@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 
 static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 {
-	const struct pmu_events_map *map;
+	const struct pmu_event *table;
 
-	map = perf_pmu__find_map(pmu);
-	if (!map)
+	table = perf_pmu__find_table(pmu);
+	if (!table)
 		return;
 
-	pmu_add_cpu_aliases_map(head, pmu, map);
+	pmu_add_cpu_aliases_map(head, pmu, table);
 }
 
 struct pmu_sys_event_iter_data {
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 7e667eec2a01..015242c83698 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -126,10 +126,10 @@ int perf_pmu__test(void);
 
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_events_map *map);
+			     const struct pmu_event *map);
 
-const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
-const struct pmu_events_map *pmu_events_map__find(void);
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_event *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
 
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index cd3a34840389..1ecb718fc0eb 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
  * the name of this counter.
  * If no match is found a NULL pointer is returned.
  */
-static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
+static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
 {
 	int rc, event_nr, wanted = get_counterset_start(set) + nr;
 
-	if (map) {
-		const struct pmu_event *evp = map->table;
+	if (table) {
+		const struct pmu_event *evp = table;
 
 		for (; evp->name || evp->event || evp->desc; ++evp) {
 			if (evp->name == NULL || evp->event == NULL)
@@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
 	unsigned char *buf = sample->raw_data;
 	const char *color = PERF_COLOR_BLUE;
 	struct cf_ctrset_entry *cep, ce;
-	const struct pmu_events_map *map;
+	const struct pmu_event *table;
 	u64 *p;
 
-	map = pmu_events_map__find();
+	table = pmu_events_map__find();
 	while (offset < len) {
 		cep = (struct cf_ctrset_entry *)(buf + offset);
 
@@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
 		color_fprintf(stdout, color, "    [%#08zx] Counterset:%d"
 			      " Counters:%d\n", offset, ce.set, ce.ctr);
 		for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
-			const char *ev_name = get_counter_name(ce.set, i, map);
+			const char *ev_name = get_counter_name(ce.set, i, table);
 
 			color_fprintf(stdout, color,
 				      "\tCounter:%03d %s Value:%#018lx\n", i,
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 09/17] perf pmu-events: Avoid passing pmu_events_map
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Preparation for hiding pmu_events_map as an implementation detail. While
the map is passed, the table of events is all that is normally wanted.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/arm64/util/pmu.c  |  4 +-
 tools/perf/tests/expand-cgroup.c  |  6 +--
 tools/perf/tests/parse-metric.c   |  7 +--
 tools/perf/tests/pmu-events.c     | 63 +++++++++++-------------
 tools/perf/util/metricgroup.c     | 82 +++++++++++++++----------------
 tools/perf/util/metricgroup.h     |  4 +-
 tools/perf/util/pmu.c             | 33 +++++++------
 tools/perf/util/pmu.h             |  6 +--
 tools/perf/util/s390-sample-raw.c | 12 ++---
 9 files changed, 99 insertions(+), 118 deletions(-)

diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
index 79124bba713e..646af8603227 100644
--- a/tools/perf/arch/arm64/util/pmu.c
+++ b/tools/perf/arch/arm64/util/pmu.c
@@ -3,7 +3,7 @@
 #include "../../../util/cpumap.h"
 #include "../../../util/pmu.h"
 
-const struct pmu_events_map *pmu_events_map__find(void)
+const struct pmu_event *pmu_events_map__find(void)
 {
 	struct perf_pmu *pmu = NULL;
 
@@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
 		if (pmu->cpus->nr != cpu__max_cpu().cpu)
 			return NULL;
 
-		return perf_pmu__find_map(pmu);
+		return perf_pmu__find_table(pmu);
 	}
 
 	return NULL;
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index dc4038f997d7..411fc578e5a4 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -195,16 +195,12 @@ static int expand_metric_events(void)
 			.metric_name	= NULL,
 		},
 	};
-	const struct pmu_events_map ev_map = {
-		.cpuid		= "test",
-		.table		= pme_test,
-	};
 
 	evlist = evlist__new();
 	TEST_ASSERT_VAL("failed to get evlist", evlist);
 
 	rblist__init(&metric_events);
-	ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
+	ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
 					     false, false, &metric_events);
 	if (ret < 0) {
 		pr_debug("failed to parse '%s' metric\n", metric_str);
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 1b811a26f4ee..7aebde7c37ec 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
 }
 };
 
-static const struct pmu_events_map map = {
-	.cpuid		= "test",
-	.table		= pme_test,
-};
-
 struct value {
 	const char	*event;
 	u64		 val;
@@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	runtime_stat__init(&st);
 
 	/* Parse the metric into metric_events list. */
-	err = metricgroup__parse_groups_test(evlist, &map, name,
+	err = metricgroup__parse_groups_test(evlist, pme_test, name,
 					     false, false,
 					     &metric_events);
 	if (err)
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index a39a2c99ede6..b3cde5f98982 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
 	return !strcmp(reference, test);
 }
 
-static const struct pmu_events_map *__test_pmu_get_events_map(void)
+static const struct pmu_event *__test_pmu_get_events_table(void)
 {
-	const struct pmu_events_map *map;
-
-	for (map = &pmu_events_map[0]; map->cpuid; map++) {
+	for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
 		if (!strcmp(map->cpuid, "testcpu"))
-			return map;
+			return map->table;
 	}
 
 	pr_err("could not find test events map\n");
@@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
 	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_events_map *map = __test_pmu_get_events_map();
-	const struct pmu_event *table;
+	const struct pmu_event *table = __test_pmu_get_events_table();
 	int map_events = 0, expected_events;
 
 	/* ignore 3x sentinels */
@@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 			  ARRAY_SIZE(uncore_events) +
 			  ARRAY_SIZE(sys_events) - 3;
 
-	if (!map || !sys_event_tables)
+	if (!table || !sys_event_tables)
 		return -1;
 
-	for (table = map->table; table->name; table++) {
+	for (; table->name; table++) {
 		struct perf_pmu_test_event const **test_event_table;
 		bool found = false;
 
@@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 	struct perf_pmu *pmu;
 	LIST_HEAD(aliases);
 	int res = 0;
-	const struct pmu_events_map *map = __test_pmu_get_events_map();
+	const struct pmu_event *table = __test_pmu_get_events_table();
 	struct perf_pmu_alias *a, *tmp;
 
-	if (!map)
+	if (!table)
 		return -1;
 
 	test_event_table = &core_events[0];
@@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 
 	pmu->name = pmu_name;
 
-	pmu_add_cpu_aliases_map(&aliases, pmu, map);
+	pmu_add_cpu_aliases_map(&aliases, pmu, table);
 
 	for (; *test_event_table; test_event_table++) {
 		struct perf_pmu_test_event const *test_event = *test_event_table;
@@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 	struct perf_pmu *pmu = &test_pmu->pmu;
 	const char *pmu_name = pmu->name;
 	struct perf_pmu_alias *a, *tmp, *alias;
-	const struct pmu_events_map *map;
+	const struct pmu_event *events_table;
 	LIST_HEAD(aliases);
 	int res = 0;
 
-	map = __test_pmu_get_events_map();
-	if (!map)
+	events_table = __test_pmu_get_events_table();
+	if (!events_table)
 		return -1;
-	pmu_add_cpu_aliases_map(&aliases, pmu, map);
+	pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
 	pmu_add_sys_aliases(&aliases, pmu);
 
 	/* Count how many aliases we generated */
@@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
 	return ret;
 }
 
-static void expr_failure(const char *msg,
-			 const struct pmu_events_map *map,
-			 const struct pmu_event *pe)
+static void expr_failure(const char *msg, const struct pmu_event *pe)
 {
-	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
-	pr_debug("On metric %s\n", pe->metric_name);
-	pr_debug("On expression %s\n", pe->metric_expr);
+	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
 }
 
 struct metric {
@@ -864,7 +857,7 @@ struct metric {
 
 static int resolve_metric_simple(struct expr_parse_ctx *pctx,
 				 struct list_head *compound_list,
-				 const struct pmu_events_map *map,
+				 const struct pmu_event *map,
 				 const char *metric_name)
 {
 	struct hashmap_entry *cur, *cur_tmp;
@@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
 static int test__parsing(struct test_suite *test __maybe_unused,
 			 int subtest __maybe_unused)
 {
-	const struct pmu_events_map *cpus_map = pmu_events_map__find();
-	const struct pmu_events_map *map;
+	const struct pmu_event *cpus_table = pmu_events_map__find();
 	const struct pmu_event *pe;
 	int i, j, k;
 	int ret = 0;
@@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 	}
 	i = 0;
 	for (;;) {
-		map = &pmu_events_map[i++];
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
 		if (!map->table)
 			break;
 		j = 0;
@@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 				continue;
 			expr__ctx_clear(ctx);
 			if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
-				expr_failure("Parse find ids failed", map, pe);
+				expr_failure("Parse find ids failed", pe);
 				ret++;
 				continue;
 			}
 
-			if (resolve_metric_simple(ctx, &compound_list, map,
+			if (resolve_metric_simple(ctx, &compound_list, map->table,
 						  pe->metric_name)) {
-				expr_failure("Could not resolve metrics", map, pe);
+				expr_failure("Could not resolve metrics", pe);
 				ret++;
 				goto exit; /* Don't tolerate errors due to severity */
 			}
@@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 				expr__add_id_val(ctx, strdup(cur->key), k++);
 
 			hashmap__for_each_entry(ctx->ids, cur, bkt) {
-				if (check_parse_cpu(cur->key, map == cpus_map,
+				if (check_parse_cpu(cur->key, map->table == cpus_table,
 						   pe))
 					ret++;
 			}
@@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 				hashmap__for_each_entry(ctx->ids, cur, bkt)
 					expr__add_id_val(ctx, strdup(cur->key), k--);
 				if (expr__parse(&result, ctx, pe->metric_expr)) {
-					expr_failure("Parse failed", map, pe);
+					expr_failure("Parse failed", pe);
 					ret++;
 				}
 			}
@@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
 static int test__parsing_fake(struct test_suite *test __maybe_unused,
 			      int subtest __maybe_unused)
 {
-	const struct pmu_events_map *map;
-	const struct pmu_event *pe;
 	unsigned int i, j;
 	int err = 0;
 
@@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
 
 	i = 0;
 	for (;;) {
-		map = &pmu_events_map[i++];
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
 		if (!map->table)
 			break;
 		j = 0;
 		for (;;) {
-			pe = &map->table[j++];
+			const struct pmu_event *pe = &map->table[j++];
+
 			if (!pe->name && !pe->metric_group && !pe->metric_name)
 				break;
 			if (!pe->metric_expr)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8f7baeabc5cf..4d32b4fbf67d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 			bool raw, bool details, const char *pmu_name)
 {
-	const struct pmu_events_map *map = pmu_events_map__find();
-	const struct pmu_event *pe;
-	int i;
 	struct rblist groups;
 	struct rb_node *node, *next;
 	struct strlist *metriclist = NULL;
@@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 	groups.node_new = mep_new;
 	groups.node_cmp = mep_cmp;
 	groups.node_delete = mep_delete;
-	for (i = 0; map; i++) {
-		pe = &map->table[i];
+	for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
 
 		if (!pe->name && !pe->metric_group && !pe->metric_name)
 			break;
@@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
 	bool metric_no_group;
 	struct metric *root_metric;
 	const struct visited_metric *visited;
-	const struct pmu_events_map *map;
+	const struct pmu_event *table;
 };
 
 static int add_metric(struct list_head *metric_list,
@@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_events_map *map);
+		      const struct pmu_event *table);
 
 /**
  * resolve_metric - Locate metrics within the root metric and recursively add
@@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
  *               metrics. When adding a root this argument is NULL.
  * @visited: A singly linked list of metric names being added that is used to
  *           detect recursion.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int resolve_metric(struct list_head *metric_list,
@@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
 			  bool metric_no_group,
 			  struct metric *root_metric,
 			  const struct visited_metric *visited,
-			  const struct pmu_events_map *map)
+			  const struct pmu_event *table)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
 	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
 		const struct pmu_event *pe;
 
-		pe = metricgroup__find_metric(cur->key, map);
+		pe = metricgroup__find_metric(cur->key, table);
 		if (pe) {
 			pending = realloc(pending,
 					(pending_cnt + 1) * sizeof(struct to_resolve));
@@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
 	 */
 	for (i = 0; i < pending_cnt; i++) {
 		ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
-				root_metric, visited, map);
+				root_metric, visited, table);
 		if (ret)
 			break;
 	}
@@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
  *               metrics. When adding a root this argument is NULL.
  * @visited: A singly linked list of metric names being added that is used to
  *           detect recursion.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int __add_metric(struct list_head *metric_list,
@@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
 			int runtime,
 			struct metric *root_metric,
 			const struct visited_metric *visited,
-			const struct pmu_events_map *map)
+			const struct pmu_event *table)
 {
 	const struct visited_metric *vm;
 	int ret;
@@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
 	} else {
 		/* Resolve referenced metrics. */
 		ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
-				     &visited_node, map);
+				     &visited_node, table);
 	}
 
 	if (ret) {
@@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
 	return ret;
 }
 
-#define map_for_each_event(__pe, __idx, __map)					\
-	if (__map)								\
-		for (__idx = 0, __pe = &__map->table[__idx];			\
+#define table_for_each_event(__pe, __idx, __table)					\
+	if (__table)								\
+		for (__idx = 0, __pe = &__table[__idx];				\
 		     __pe->name || __pe->metric_group || __pe->metric_name;	\
-		     __pe = &__map->table[++__idx])
+		     __pe = &__table[++__idx])
 
-#define map_for_each_metric(__pe, __idx, __map, __metric)		\
-	map_for_each_event(__pe, __idx, __map)				\
+#define table_for_each_metric(__pe, __idx, __table, __metric)		\
+	table_for_each_event(__pe, __idx, __table)				\
 		if (__pe->metric_expr &&				\
 		    (match_metric(__pe->metric_group, __metric) ||	\
 		     match_metric(__pe->metric_name, __metric)))
 
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_map *map)
+						 const struct pmu_event *table)
 {
 	const struct pmu_event *pe;
 	int i;
 
-	map_for_each_event(pe, i, map) {
+	table_for_each_event(pe, i, table) {
 		if (match_metric(pe->metric_name, metric))
 			return pe;
 	}
@@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_events_map *map)
+		      const struct pmu_event *table)
 {
 	int ret = 0;
 
@@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
 
 	if (!strstr(pe->metric_expr, "?")) {
 		ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
-				   root_metric, visited, map);
+				   root_metric, visited, table);
 	} else {
 		int j, count;
 
@@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
 
 		for (j = 0; j < count && !ret; j++)
 			ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
-					root_metric, visited, map);
+					root_metric, visited, table);
 	}
 
 	return ret;
@@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
 		return 0;
 
 	ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
-			 d->root_metric, d->visited, d->map);
+			 d->root_metric, d->visited, d->table);
 	if (ret)
 		goto out;
 
@@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
  *                   global. Grouping is the default but due to multiplexing the
  *                   user may override.
  * @metric_list: The list that the metric or metric group are added to.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int metricgroup__add_metric(const char *metric_name, const char *modifier,
 				   bool metric_no_group,
 				   struct list_head *metric_list,
-				   const struct pmu_events_map *map)
+				   const struct pmu_event *table)
 {
 	const struct pmu_event *pe;
 	LIST_HEAD(list);
@@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 	 * Iterate over all metrics seeing if metric matches either the name or
 	 * group. When it does add the metric to the list.
 	 */
-	map_for_each_metric(pe, i, map, metric_name) {
+	table_for_each_metric(pe, i, table, metric_name) {
 		has_match = true;
 		ret = add_metric(&list, pe, modifier, metric_no_group,
 				 /*root_metric=*/NULL,
-				 /*visited_metrics=*/NULL, map);
+				 /*visited_metrics=*/NULL, table);
 		if (ret)
 			goto out;
 	}
@@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 				.metric_no_group = metric_no_group,
 				.has_match = &has_match,
 				.ret = &ret,
-				.map = map,
+				.table = table,
 			},
 		};
 
@@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
  *                   global. Grouping is the default but due to multiplexing the
  *                   user may override.
  * @metric_list: The list that metrics are added to.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
  *       architecture perf is running upon.
  */
 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 					struct list_head *metric_list,
-					const struct pmu_events_map *map)
+					const struct pmu_event *table)
 {
 	char *list_itr, *list_copy, *metric_name, *modifier;
 	int ret, count = 0;
@@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 
 		ret = metricgroup__add_metric(metric_name, modifier,
 					      metric_no_group, metric_list,
-					      map);
+					      table);
 		if (ret == -EINVAL)
 			pr_err("Cannot find metric or group `%s'\n", metric_name);
 
@@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 			bool metric_no_merge,
 			struct perf_pmu *fake_pmu,
 			struct rblist *metric_events_list,
-			const struct pmu_events_map *map)
+			const struct pmu_event *table)
 {
 	struct evlist *combined_evlist = NULL;
 	LIST_HEAD(metric_list);
@@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 	if (metric_events_list->nr_entries == 0)
 		metricgroup__rblist_init(metric_events_list);
 	ret = metricgroup__add_metric_list(str, metric_no_group,
-					   &metric_list, map);
+					   &metric_list, table);
 	if (ret)
 		goto out;
 
@@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
 			      struct rblist *metric_events)
 {
 	struct evlist *perf_evlist = *(struct evlist **)opt->value;
-	const struct pmu_events_map *map = pmu_events_map__find();
+	const struct pmu_event *table = pmu_events_map__find();
 
 	return parse_groups(perf_evlist, str, metric_no_group,
-			    metric_no_merge, NULL, metric_events, map);
+			    metric_no_merge, NULL, metric_events, table);
 }
 
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_events_map *map,
+				   const struct pmu_event *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
 				   struct rblist *metric_events)
 {
 	return parse_groups(evlist, str, metric_no_group,
-			    metric_no_merge, &perf_pmu__fake, metric_events, map);
+			    metric_no_merge, &perf_pmu__fake, metric_events, table);
 }
 
 bool metricgroup__has_metric(const char *metric)
 {
-	const struct pmu_events_map *map = pmu_events_map__find();
+	const struct pmu_event *table = pmu_events_map__find();
 	const struct pmu_event *pe;
 	int i;
 
-	if (!map)
+	if (!table)
 		return false;
 
 	for (i = 0; ; i++) {
-		pe = &map->table[i];
+		pe = &table[i];
 
 		if (!pe->name && !pe->metric_group && !pe->metric_name)
 			break;
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 2b42b778d1bf..5a1390e73d25 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
 			      bool metric_no_merge,
 			      struct rblist *metric_events);
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_map *map);
+						 const struct pmu_event *table);
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_events_map *map,
+				   const struct pmu_event *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index d8717c4548a4..f3e3c4a147e9 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 	return cpuid;
 }
 
-const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 {
-	const struct pmu_events_map *map;
+	const struct pmu_event *table = NULL;
 	char *cpuid = perf_pmu__getcpuid(pmu);
 	int i;
 
@@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
 
 	i = 0;
 	for (;;) {
-		map = &pmu_events_map[i++];
-		if (!map->table) {
-			map = NULL;
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
+		if (!map->table)
 			break;
-		}
 
-		if (!strcmp_cpuid_str(map->cpuid, cpuid))
+		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+			table = map->table;
 			break;
+		}
 	}
 	free(cpuid);
-	return map;
+	return table;
 }
 
-const struct pmu_events_map *__weak pmu_events_map__find(void)
+__weak const struct pmu_event *pmu_events_map__find(void)
 {
-	return perf_pmu__find_map(NULL);
+	return perf_pmu__find_table(NULL);
 }
 
 /*
@@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
  * as aliases.
  */
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_events_map *map)
+			     const struct pmu_event *table)
 {
 	int i;
 	const char *name = pmu->name;
@@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 	i = 0;
 	while (1) {
 		const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
-		const struct pmu_event *pe = &map->table[i++];
+		const struct pmu_event *pe = &table[i++];
 		const char *pname = pe->pmu ? pe->pmu : cpu_name;
 
 		if (!pe->name) {
@@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 
 static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 {
-	const struct pmu_events_map *map;
+	const struct pmu_event *table;
 
-	map = perf_pmu__find_map(pmu);
-	if (!map)
+	table = perf_pmu__find_table(pmu);
+	if (!table)
 		return;
 
-	pmu_add_cpu_aliases_map(head, pmu, map);
+	pmu_add_cpu_aliases_map(head, pmu, table);
 }
 
 struct pmu_sys_event_iter_data {
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 7e667eec2a01..015242c83698 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -126,10 +126,10 @@ int perf_pmu__test(void);
 
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_events_map *map);
+			     const struct pmu_event *map);
 
-const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
-const struct pmu_events_map *pmu_events_map__find(void);
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_event *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
 
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index cd3a34840389..1ecb718fc0eb 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
  * the name of this counter.
  * If no match is found a NULL pointer is returned.
  */
-static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
+static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
 {
 	int rc, event_nr, wanted = get_counterset_start(set) + nr;
 
-	if (map) {
-		const struct pmu_event *evp = map->table;
+	if (table) {
+		const struct pmu_event *evp = table;
 
 		for (; evp->name || evp->event || evp->desc; ++evp) {
 			if (evp->name == NULL || evp->event == NULL)
@@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
 	unsigned char *buf = sample->raw_data;
 	const char *color = PERF_COLOR_BLUE;
 	struct cf_ctrset_entry *cep, ce;
-	const struct pmu_events_map *map;
+	const struct pmu_event *table;
 	u64 *p;
 
-	map = pmu_events_map__find();
+	table = pmu_events_map__find();
 	while (offset < len) {
 		cep = (struct cf_ctrset_entry *)(buf + offset);
 
@@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
 		color_fprintf(stdout, color, "    [%#08zx] Counterset:%d"
 			      " Counters:%d\n", offset, ce.set, ce.ctr);
 		for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
-			const char *ev_name = get_counter_name(ce.set, i, map);
+			const char *ev_name = get_counter_name(ce.set, i, table);
 
 			color_fprintf(stdout, color,
 				      "\tCounter:%03d %s Value:%#018lx\n", i,
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Move usage of the table to pmu-events.c so it may be hidden. By
abstracting the table the implementation can later be changed.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c |  81 ++++++++-
 tools/perf/pmu-events/jevents.py         |  81 ++++++++-
 tools/perf/pmu-events/pmu-events.h       |  29 +--
 tools/perf/tests/pmu-events.c            | 218 +++++++++++------------
 tools/perf/util/metricgroup.c            |  15 +-
 tools/perf/util/pmu.c                    |  34 +---
 tools/perf/util/pmu.h                    |   2 +-
 7 files changed, 280 insertions(+), 180 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 216ea0482c37..8ef75aff996c 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -6,6 +6,8 @@
  * The test cpu/soc is provided for testing.
  */
 #include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
 #include <string.h>
 #include <stddef.h>
 
@@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 	},
 };
 
-const struct pmu_events_map pmu_events_map[] = {
+
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The  cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+	const char *arch;
+	const char *cpuid;
+	const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+static const struct pmu_events_map pmu_events_map[] = {
 	{
 		.arch = "testarch",
 		.cpuid = "testcpu",
@@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	},
 };
 
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+	const struct pmu_event *table = NULL;
+	char *cpuid = perf_pmu__getcpuid(pmu);
+	int i;
+
+	/* on some platforms which uses cpus map, cpuid can be NULL for
+	 * PMUs other than CORE PMUs.
+	 */
+	if (!cpuid)
+		return NULL;
+
+	i = 0;
+	for (;;) {
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
+		if (!map->table)
+			break;
+
+		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+			table = map->table;
+			break;
+		}
+	}
+	free(cpuid);
+	return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+	for (const struct pmu_events_map *tables = &pmu_events_map[0];
+	     tables->table;
+	     tables++) {
+		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+			return tables->table;
+	}
+	return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+	for (const struct pmu_events_map *tables = &pmu_events_map[0];
+	     tables->table;
+	     tables++) {
+		for (const struct pmu_event *pe = &tables->table[0];
+		     pe->name || pe->metric_group || pe->metric_name;
+		     pe++) {
+			int ret = fn(pe, &tables->table[0], data);
+
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
 const struct pmu_event *find_sys_events_table(const char *name)
 {
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
 		for (const struct pmu_event *pe = &tables->table[0];
 		     pe->name || pe->metric_group || pe->metric_name;
 		     pe++) {
-			int ret = fn(pe, data);
+			int ret = fn(pe, &tables->table[0], data);
 
 			if (ret)
 				return ret;
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index dd21bc9eeeed..e976c5e8e80b 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
 
 def print_mapping_table(archs: Sequence[str]) -> None:
   """Read the mapfile and generate the struct from cpuid string to event table."""
-  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
+  _args.output_file.write("""
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The  cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+        const char *arch;
+        const char *cpuid;
+        const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+const struct pmu_events_map pmu_events_map[] = {
+""")
   for arch in archs:
     if arch == 'test':
       _args.output_file.write("""{
@@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 \t},
 };
 
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+        const struct pmu_event *table = NULL;
+        char *cpuid = perf_pmu__getcpuid(pmu);
+        int i;
+
+        /* on some platforms which uses cpus map, cpuid can be NULL for
+         * PMUs other than CORE PMUs.
+         */
+        if (!cpuid)
+                return NULL;
+
+        i = 0;
+        for (;;) {
+                const struct pmu_events_map *map = &pmu_events_map[i++];
+                if (!map->table)
+                        break;
+
+                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+                        table = map->table;
+                        break;
+                }
+        }
+        free(cpuid);
+        return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->table;
+             tables++) {
+                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+                        return tables->table;
+        }
+        return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->table;
+             tables++) {
+                for (const struct pmu_event *pe = &tables->table[0];
+                     pe->name || pe->metric_group || pe->metric_name;
+                     pe++) {
+                        int ret = fn(pe, &tables->table[0], data);
+
+                        if (ret)
+                                return ret;
+                }
+        }
+        return 0;
+}
+
 const struct pmu_event *find_sys_events_table(const char *name)
 {
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -408,7 +483,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
                 for (const struct pmu_event *pe = &tables->table[0];
                      pe->name || pe->metric_group || pe->metric_name;
                      pe++) {
-                        int ret = fn(pe, data);
+                        int ret = fn(pe, &tables->table[0], data);
 
                         if (ret)
                                 return ret;
@@ -449,6 +524,8 @@ def main() -> None:
 
   _args.output_file.write("""
 #include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
 #include <string.h>
 #include <stddef.h>
 
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 2386212b1df0..485e730f9922 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -2,6 +2,8 @@
 #ifndef PMU_EVENTS_H
 #define PMU_EVENTS_H
 
+struct perf_pmu;
+
 enum aggr_mode_class {
 	PerChip = 1,
 	PerCore
@@ -28,30 +30,15 @@ struct pmu_event {
 	const char *metric_constraint;
 };
 
-/*
- *
- * Map a CPU to its table of PMU events. The CPU is identified by the
- * cpuid field, which is an arch-specific identifier for the CPU.
- * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
- * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
- *
- * The  cpuid can contain any character other than the comma.
- */
-struct pmu_events_map {
-	const char *arch;
-	const char *cpuid;
-	const struct pmu_event *table;
-};
+typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
+				 const struct pmu_event *table,
+				 void *data);
 
-/*
- * Global table mapping each known CPU for the architecture to its
- * table of PMU events.
- */
-extern const struct pmu_events_map pmu_events_map[];
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
 
 const struct pmu_event *find_sys_events_table(const char *name);
-
-typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe, void *data);
 int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
 
 #endif
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index b3cde5f98982..ea8b41b5c4e3 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -272,18 +272,6 @@ static bool is_same(const char *reference, const char *test)
 	return !strcmp(reference, test);
 }
 
-static const struct pmu_event *__test_pmu_get_events_table(void)
-{
-	for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
-		if (!strcmp(map->cpuid, "testcpu"))
-			return map->table;
-	}
-
-	pr_err("could not find test events map\n");
-
-	return NULL;
-}
-
 static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
 {
 	if (!is_same(e1->name, e2->name)) {
@@ -438,7 +426,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
 	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_event *table = __test_pmu_get_events_table();
+	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
 	int map_events = 0, expected_events;
 
 	/* ignore 3x sentinels */
@@ -534,7 +522,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 	struct perf_pmu *pmu;
 	LIST_HEAD(aliases);
 	int res = 0;
-	const struct pmu_event *table = __test_pmu_get_events_table();
+	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
 	struct perf_pmu_alias *a, *tmp;
 
 	if (!table)
@@ -591,7 +579,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 	LIST_HEAD(aliases);
 	int res = 0;
 
-	events_table = __test_pmu_get_events_table();
+	events_table = find_core_events_table("testarch", "testcpu");
 	if (!events_table)
 		return -1;
 	pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
@@ -845,11 +833,6 @@ static int check_parse_fake(const char *id)
 	return ret;
 }
 
-static void expr_failure(const char *msg, const struct pmu_event *pe)
-{
-	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
-}
-
 struct metric {
 	struct list_head list;
 	struct metric_ref metric_ref;
@@ -915,93 +898,100 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
 
 }
 
-static int test__parsing(struct test_suite *test __maybe_unused,
-			 int subtest __maybe_unused)
+static void expr_failure(const char *msg, const struct pmu_event *pe)
 {
-	const struct pmu_event *cpus_table = pmu_events_map__find();
-	const struct pmu_event *pe;
-	int i, j, k;
-	int ret = 0;
+	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
+}
+
+
+struct test__parsing_data {
+	const struct pmu_event *cpus_table;
 	struct expr_parse_ctx *ctx;
+	int failures;
+};
+
+static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
+				  void *vdata)
+{
+	struct test__parsing_data *data = vdata;
+	struct metric *metric, *tmp;
+	struct hashmap_entry *cur;
+	LIST_HEAD(compound_list);
+	size_t bkt;
+	int k;
 	double result;
 
-	ctx = expr__ctx_new();
-	if (!ctx) {
-		pr_debug("expr__ctx_new failed");
-		return TEST_FAIL;
+	if (!pe->metric_expr)
+		return 0;
+
+	pr_debug("Found metric '%s'\n", pe->metric_name);
+
+	expr__ctx_clear(data->ctx);
+	if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
+		expr_failure("Parse find ids failed", pe);
+		data->failures++;
+		return 0;
 	}
-	i = 0;
-	for (;;) {
-		const struct pmu_events_map *map = &pmu_events_map[i++];
 
-		if (!map->table)
-			break;
-		j = 0;
-		for (;;) {
-			struct metric *metric, *tmp;
-			struct hashmap_entry *cur;
-			LIST_HEAD(compound_list);
-			size_t bkt;
-
-			pe = &map->table[j++];
-			if (!pe->name && !pe->metric_group && !pe->metric_name)
-				break;
-			if (!pe->metric_expr)
-				continue;
-			expr__ctx_clear(ctx);
-			if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
-				expr_failure("Parse find ids failed", pe);
-				ret++;
-				continue;
-			}
+	if (resolve_metric_simple(data->ctx, &compound_list, table,
+				  pe->metric_name)) {
+		expr_failure("Could not resolve metrics", pe);
+		data->failures++;
+		return TEST_FAIL; /* Don't tolerate errors due to severity */
+	}
 
-			if (resolve_metric_simple(ctx, &compound_list, map->table,
-						  pe->metric_name)) {
-				expr_failure("Could not resolve metrics", pe);
-				ret++;
-				goto exit; /* Don't tolerate errors due to severity */
-			}
+	/*
+	 * Add all ids with a made up value. The value may trigger divide by
+	 * zero when subtracted and so try to make them unique.
+	 */
+	k = 1;
+	hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+		expr__add_id_val(data->ctx, strdup(cur->key), k++);
 
-			/*
-			 * Add all ids with a made up value. The value may
-			 * trigger divide by zero when subtracted and so try to
-			 * make them unique.
-			 */
-			k = 1;
-			hashmap__for_each_entry(ctx->ids, cur, bkt)
-				expr__add_id_val(ctx, strdup(cur->key), k++);
-
-			hashmap__for_each_entry(ctx->ids, cur, bkt) {
-				if (check_parse_cpu(cur->key, map->table == cpus_table,
-						   pe))
-					ret++;
-			}
+	hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
+		if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
+			data->failures++;
+	}
 
-			list_for_each_entry_safe(metric, tmp, &compound_list, list) {
-				expr__add_ref(ctx, &metric->metric_ref);
-				free(metric);
-			}
+	list_for_each_entry_safe(metric, tmp, &compound_list, list) {
+		expr__add_ref(data->ctx, &metric->metric_ref);
+		free(metric);
+	}
 
-			if (expr__parse(&result, ctx, pe->metric_expr)) {
-				/*
-				 * Parsing failed, make numbers go from large to
-				 * small which can resolve divide by zero
-				 * issues.
-				 */
-				k = 1024;
-				hashmap__for_each_entry(ctx->ids, cur, bkt)
-					expr__add_id_val(ctx, strdup(cur->key), k--);
-				if (expr__parse(&result, ctx, pe->metric_expr)) {
-					expr_failure("Parse failed", pe);
-					ret++;
-				}
-			}
+	if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+		/*
+		 * Parsing failed, make numbers go from large to small which can
+		 * resolve divide by zero issues.
+		 */
+		k = 1024;
+		hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+			expr__add_id_val(data->ctx, strdup(cur->key), k--);
+		if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+			expr_failure("Parse failed", pe);
+			data->failures++;
 		}
 	}
-	expr__ctx_free(ctx);
-	/* TODO: fail when not ok */
-exit:
-	return ret == 0 ? TEST_OK : TEST_SKIP;
+	return 0;
+}
+
+static int test__parsing(struct test_suite *test __maybe_unused,
+			 int subtest __maybe_unused)
+{
+	struct test__parsing_data data = {
+		.cpus_table = pmu_events_map__find(),
+		.ctx = expr__ctx_new(),
+		.failures = 0,
+	};
+
+	if (!data.ctx) {
+		pr_debug("expr__ctx_new failed");
+		return TEST_FAIL;
+	}
+	pmu_for_each_core_event(test__parsing_callback, &data);
+	pmu_for_each_sys_event(test__parsing_callback, &data);
+
+	expr__ctx_free(data.ctx);
+	return data.failures == 0 ? TEST_OK : TEST_FAIL;
 }
 
 struct test_metric {
@@ -1073,6 +1063,16 @@ static int metric_parse_fake(const char *str)
 	return ret;
 }
 
+static int test__parsing_fake_callback(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *data __maybe_unused)
+{
+	if (!pe->metric_expr)
+		return 0;
+
+	return metric_parse_fake(pe->metric_expr);
+}
+
 /*
  * Parse all the metrics for current architecture,
  * or all defined cpus via the 'fake_pmu'
@@ -1081,37 +1081,19 @@ static int metric_parse_fake(const char *str)
 static int test__parsing_fake(struct test_suite *test __maybe_unused,
 			      int subtest __maybe_unused)
 {
-	unsigned int i, j;
 	int err = 0;
 
-	for (i = 0; i < ARRAY_SIZE(metrics); i++) {
+	for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) {
 		err = metric_parse_fake(metrics[i].str);
 		if (err)
 			return err;
 	}
 
-	i = 0;
-	for (;;) {
-		const struct pmu_events_map *map = &pmu_events_map[i++];
+	err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
+	if (err)
+		return err;
 
-		if (!map->table)
-			break;
-		j = 0;
-		for (;;) {
-			const struct pmu_event *pe = &map->table[j++];
-
-			if (!pe->name && !pe->metric_group && !pe->metric_name)
-				break;
-			if (!pe->metric_expr)
-				continue;
-			pr_debug("Found metric '%s' for '%s'\n", pe->metric_name, map->cpuid);
-			err = metric_parse_fake(pe->metric_expr);
-			if (err)
-				return err;
-		}
-	}
-
-	return 0;
+	return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
 }
 
 static struct test_case pmu_events_tests[] = {
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 4d32b4fbf67d..680f7c63838d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -502,14 +502,14 @@ struct metricgroup_print_sys_idata {
 	bool details;
 };
 
-typedef int (*metricgroup_sys_event_iter_fn)(const struct pmu_event *pe, void *);
-
 struct metricgroup_iter_data {
-	metricgroup_sys_event_iter_fn fn;
+	pmu_event_iter_fn fn;
 	void *data;
 };
 
-static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
+static int metricgroup__sys_event_iter(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *data)
 {
 	struct metricgroup_iter_data *d = data;
 	struct perf_pmu *pmu = NULL;
@@ -522,13 +522,15 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
 		if (!pmu->id || strcmp(pmu->id, pe->compat))
 			continue;
 
-		return d->fn(pe, d->data);
+		return d->fn(pe, table, d->data);
 	}
 
 	return 0;
 }
 
-static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *data)
+static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
+					     const struct pmu_event *table __maybe_unused,
+					     void *data)
 {
 	struct metricgroup_print_sys_idata *d = data;
 
@@ -1101,6 +1103,7 @@ static int add_metric(struct list_head *metric_list,
 }
 
 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
+						  const struct pmu_event *table __maybe_unused,
 						  void *data)
 {
 	struct metricgroup_add_iter_data *d = data;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index f3e3c4a147e9..5bb03d4e52a3 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -690,7 +690,7 @@ static int is_arm_pmu_core(const char *name)
 	return file_available(path);
 }
 
-static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
+char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 {
 	char *cpuid;
 	static bool printed;
@@ -710,34 +710,6 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 	return cpuid;
 }
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
-{
-	const struct pmu_event *table = NULL;
-	char *cpuid = perf_pmu__getcpuid(pmu);
-	int i;
-
-	/* on some platforms which uses cpus map, cpuid can be NULL for
-	 * PMUs other than CORE PMUs.
-	 */
-	if (!cpuid)
-		return NULL;
-
-	i = 0;
-	for (;;) {
-		const struct pmu_events_map *map = &pmu_events_map[i++];
-
-		if (!map->table)
-			break;
-
-		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-			table = map->table;
-			break;
-		}
-	}
-	free(cpuid);
-	return table;
-}
-
 __weak const struct pmu_event *pmu_events_map__find(void)
 {
 	return perf_pmu__find_table(NULL);
@@ -874,7 +846,9 @@ struct pmu_sys_event_iter_data {
 	struct perf_pmu *pmu;
 };
 
-static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, void *data)
+static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *data)
 {
 	struct pmu_sys_event_iter_data *idata = data;
 	struct perf_pmu *pmu = idata->pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 015242c83698..06df99ba2029 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -128,7 +128,7 @@ struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 			     const struct pmu_event *map);
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+char *perf_pmu__getcpuid(struct perf_pmu *pmu);
 const struct pmu_event *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Move usage of the table to pmu-events.c so it may be hidden. By
abstracting the table the implementation can later be changed.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c |  81 ++++++++-
 tools/perf/pmu-events/jevents.py         |  81 ++++++++-
 tools/perf/pmu-events/pmu-events.h       |  29 +--
 tools/perf/tests/pmu-events.c            | 218 +++++++++++------------
 tools/perf/util/metricgroup.c            |  15 +-
 tools/perf/util/pmu.c                    |  34 +---
 tools/perf/util/pmu.h                    |   2 +-
 7 files changed, 280 insertions(+), 180 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 216ea0482c37..8ef75aff996c 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -6,6 +6,8 @@
  * The test cpu/soc is provided for testing.
  */
 #include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
 #include <string.h>
 #include <stddef.h>
 
@@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 	},
 };
 
-const struct pmu_events_map pmu_events_map[] = {
+
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The  cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+	const char *arch;
+	const char *cpuid;
+	const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+static const struct pmu_events_map pmu_events_map[] = {
 	{
 		.arch = "testarch",
 		.cpuid = "testcpu",
@@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	},
 };
 
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+	const struct pmu_event *table = NULL;
+	char *cpuid = perf_pmu__getcpuid(pmu);
+	int i;
+
+	/* on some platforms which uses cpus map, cpuid can be NULL for
+	 * PMUs other than CORE PMUs.
+	 */
+	if (!cpuid)
+		return NULL;
+
+	i = 0;
+	for (;;) {
+		const struct pmu_events_map *map = &pmu_events_map[i++];
+
+		if (!map->table)
+			break;
+
+		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+			table = map->table;
+			break;
+		}
+	}
+	free(cpuid);
+	return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+	for (const struct pmu_events_map *tables = &pmu_events_map[0];
+	     tables->table;
+	     tables++) {
+		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+			return tables->table;
+	}
+	return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+	for (const struct pmu_events_map *tables = &pmu_events_map[0];
+	     tables->table;
+	     tables++) {
+		for (const struct pmu_event *pe = &tables->table[0];
+		     pe->name || pe->metric_group || pe->metric_name;
+		     pe++) {
+			int ret = fn(pe, &tables->table[0], data);
+
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
 const struct pmu_event *find_sys_events_table(const char *name)
 {
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
 		for (const struct pmu_event *pe = &tables->table[0];
 		     pe->name || pe->metric_group || pe->metric_name;
 		     pe++) {
-			int ret = fn(pe, data);
+			int ret = fn(pe, &tables->table[0], data);
 
 			if (ret)
 				return ret;
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index dd21bc9eeeed..e976c5e8e80b 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
 
 def print_mapping_table(archs: Sequence[str]) -> None:
   """Read the mapfile and generate the struct from cpuid string to event table."""
-  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
+  _args.output_file.write("""
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The  cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+        const char *arch;
+        const char *cpuid;
+        const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+const struct pmu_events_map pmu_events_map[] = {
+""")
   for arch in archs:
     if arch == 'test':
       _args.output_file.write("""{
@@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 \t},
 };
 
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+        const struct pmu_event *table = NULL;
+        char *cpuid = perf_pmu__getcpuid(pmu);
+        int i;
+
+        /* on some platforms which uses cpus map, cpuid can be NULL for
+         * PMUs other than CORE PMUs.
+         */
+        if (!cpuid)
+                return NULL;
+
+        i = 0;
+        for (;;) {
+                const struct pmu_events_map *map = &pmu_events_map[i++];
+                if (!map->table)
+                        break;
+
+                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+                        table = map->table;
+                        break;
+                }
+        }
+        free(cpuid);
+        return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->table;
+             tables++) {
+                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+                        return tables->table;
+        }
+        return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->table;
+             tables++) {
+                for (const struct pmu_event *pe = &tables->table[0];
+                     pe->name || pe->metric_group || pe->metric_name;
+                     pe++) {
+                        int ret = fn(pe, &tables->table[0], data);
+
+                        if (ret)
+                                return ret;
+                }
+        }
+        return 0;
+}
+
 const struct pmu_event *find_sys_events_table(const char *name)
 {
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -408,7 +483,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
                 for (const struct pmu_event *pe = &tables->table[0];
                      pe->name || pe->metric_group || pe->metric_name;
                      pe++) {
-                        int ret = fn(pe, data);
+                        int ret = fn(pe, &tables->table[0], data);
 
                         if (ret)
                                 return ret;
@@ -449,6 +524,8 @@ def main() -> None:
 
   _args.output_file.write("""
 #include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
 #include <string.h>
 #include <stddef.h>
 
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 2386212b1df0..485e730f9922 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -2,6 +2,8 @@
 #ifndef PMU_EVENTS_H
 #define PMU_EVENTS_H
 
+struct perf_pmu;
+
 enum aggr_mode_class {
 	PerChip = 1,
 	PerCore
@@ -28,30 +30,15 @@ struct pmu_event {
 	const char *metric_constraint;
 };
 
-/*
- *
- * Map a CPU to its table of PMU events. The CPU is identified by the
- * cpuid field, which is an arch-specific identifier for the CPU.
- * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
- * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
- *
- * The  cpuid can contain any character other than the comma.
- */
-struct pmu_events_map {
-	const char *arch;
-	const char *cpuid;
-	const struct pmu_event *table;
-};
+typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
+				 const struct pmu_event *table,
+				 void *data);
 
-/*
- * Global table mapping each known CPU for the architecture to its
- * table of PMU events.
- */
-extern const struct pmu_events_map pmu_events_map[];
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
 
 const struct pmu_event *find_sys_events_table(const char *name);
-
-typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe, void *data);
 int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
 
 #endif
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index b3cde5f98982..ea8b41b5c4e3 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -272,18 +272,6 @@ static bool is_same(const char *reference, const char *test)
 	return !strcmp(reference, test);
 }
 
-static const struct pmu_event *__test_pmu_get_events_table(void)
-{
-	for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
-		if (!strcmp(map->cpuid, "testcpu"))
-			return map->table;
-	}
-
-	pr_err("could not find test events map\n");
-
-	return NULL;
-}
-
 static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
 {
 	if (!is_same(e1->name, e2->name)) {
@@ -438,7 +426,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
 	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_event *table = __test_pmu_get_events_table();
+	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
 	int map_events = 0, expected_events;
 
 	/* ignore 3x sentinels */
@@ -534,7 +522,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 	struct perf_pmu *pmu;
 	LIST_HEAD(aliases);
 	int res = 0;
-	const struct pmu_event *table = __test_pmu_get_events_table();
+	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
 	struct perf_pmu_alias *a, *tmp;
 
 	if (!table)
@@ -591,7 +579,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 	LIST_HEAD(aliases);
 	int res = 0;
 
-	events_table = __test_pmu_get_events_table();
+	events_table = find_core_events_table("testarch", "testcpu");
 	if (!events_table)
 		return -1;
 	pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
@@ -845,11 +833,6 @@ static int check_parse_fake(const char *id)
 	return ret;
 }
 
-static void expr_failure(const char *msg, const struct pmu_event *pe)
-{
-	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
-}
-
 struct metric {
 	struct list_head list;
 	struct metric_ref metric_ref;
@@ -915,93 +898,100 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
 
 }
 
-static int test__parsing(struct test_suite *test __maybe_unused,
-			 int subtest __maybe_unused)
+static void expr_failure(const char *msg, const struct pmu_event *pe)
 {
-	const struct pmu_event *cpus_table = pmu_events_map__find();
-	const struct pmu_event *pe;
-	int i, j, k;
-	int ret = 0;
+	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
+}
+
+
+struct test__parsing_data {
+	const struct pmu_event *cpus_table;
 	struct expr_parse_ctx *ctx;
+	int failures;
+};
+
+static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
+				  void *vdata)
+{
+	struct test__parsing_data *data = vdata;
+	struct metric *metric, *tmp;
+	struct hashmap_entry *cur;
+	LIST_HEAD(compound_list);
+	size_t bkt;
+	int k;
 	double result;
 
-	ctx = expr__ctx_new();
-	if (!ctx) {
-		pr_debug("expr__ctx_new failed");
-		return TEST_FAIL;
+	if (!pe->metric_expr)
+		return 0;
+
+	pr_debug("Found metric '%s'\n", pe->metric_name);
+
+	expr__ctx_clear(data->ctx);
+	if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
+		expr_failure("Parse find ids failed", pe);
+		data->failures++;
+		return 0;
 	}
-	i = 0;
-	for (;;) {
-		const struct pmu_events_map *map = &pmu_events_map[i++];
 
-		if (!map->table)
-			break;
-		j = 0;
-		for (;;) {
-			struct metric *metric, *tmp;
-			struct hashmap_entry *cur;
-			LIST_HEAD(compound_list);
-			size_t bkt;
-
-			pe = &map->table[j++];
-			if (!pe->name && !pe->metric_group && !pe->metric_name)
-				break;
-			if (!pe->metric_expr)
-				continue;
-			expr__ctx_clear(ctx);
-			if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
-				expr_failure("Parse find ids failed", pe);
-				ret++;
-				continue;
-			}
+	if (resolve_metric_simple(data->ctx, &compound_list, table,
+				  pe->metric_name)) {
+		expr_failure("Could not resolve metrics", pe);
+		data->failures++;
+		return TEST_FAIL; /* Don't tolerate errors due to severity */
+	}
 
-			if (resolve_metric_simple(ctx, &compound_list, map->table,
-						  pe->metric_name)) {
-				expr_failure("Could not resolve metrics", pe);
-				ret++;
-				goto exit; /* Don't tolerate errors due to severity */
-			}
+	/*
+	 * Add all ids with a made up value. The value may trigger divide by
+	 * zero when subtracted and so try to make them unique.
+	 */
+	k = 1;
+	hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+		expr__add_id_val(data->ctx, strdup(cur->key), k++);
 
-			/*
-			 * Add all ids with a made up value. The value may
-			 * trigger divide by zero when subtracted and so try to
-			 * make them unique.
-			 */
-			k = 1;
-			hashmap__for_each_entry(ctx->ids, cur, bkt)
-				expr__add_id_val(ctx, strdup(cur->key), k++);
-
-			hashmap__for_each_entry(ctx->ids, cur, bkt) {
-				if (check_parse_cpu(cur->key, map->table == cpus_table,
-						   pe))
-					ret++;
-			}
+	hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
+		if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
+			data->failures++;
+	}
 
-			list_for_each_entry_safe(metric, tmp, &compound_list, list) {
-				expr__add_ref(ctx, &metric->metric_ref);
-				free(metric);
-			}
+	list_for_each_entry_safe(metric, tmp, &compound_list, list) {
+		expr__add_ref(data->ctx, &metric->metric_ref);
+		free(metric);
+	}
 
-			if (expr__parse(&result, ctx, pe->metric_expr)) {
-				/*
-				 * Parsing failed, make numbers go from large to
-				 * small which can resolve divide by zero
-				 * issues.
-				 */
-				k = 1024;
-				hashmap__for_each_entry(ctx->ids, cur, bkt)
-					expr__add_id_val(ctx, strdup(cur->key), k--);
-				if (expr__parse(&result, ctx, pe->metric_expr)) {
-					expr_failure("Parse failed", pe);
-					ret++;
-				}
-			}
+	if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+		/*
+		 * Parsing failed, make numbers go from large to small which can
+		 * resolve divide by zero issues.
+		 */
+		k = 1024;
+		hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+			expr__add_id_val(data->ctx, strdup(cur->key), k--);
+		if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+			expr_failure("Parse failed", pe);
+			data->failures++;
 		}
 	}
-	expr__ctx_free(ctx);
-	/* TODO: fail when not ok */
-exit:
-	return ret == 0 ? TEST_OK : TEST_SKIP;
+	return 0;
+}
+
+static int test__parsing(struct test_suite *test __maybe_unused,
+			 int subtest __maybe_unused)
+{
+	struct test__parsing_data data = {
+		.cpus_table = pmu_events_map__find(),
+		.ctx = expr__ctx_new(),
+		.failures = 0,
+	};
+
+	if (!data.ctx) {
+		pr_debug("expr__ctx_new failed");
+		return TEST_FAIL;
+	}
+	pmu_for_each_core_event(test__parsing_callback, &data);
+	pmu_for_each_sys_event(test__parsing_callback, &data);
+
+	expr__ctx_free(data.ctx);
+	return data.failures == 0 ? TEST_OK : TEST_FAIL;
 }
 
 struct test_metric {
@@ -1073,6 +1063,16 @@ static int metric_parse_fake(const char *str)
 	return ret;
 }
 
+static int test__parsing_fake_callback(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *data __maybe_unused)
+{
+	if (!pe->metric_expr)
+		return 0;
+
+	return metric_parse_fake(pe->metric_expr);
+}
+
 /*
  * Parse all the metrics for current architecture,
  * or all defined cpus via the 'fake_pmu'
@@ -1081,37 +1081,19 @@ static int metric_parse_fake(const char *str)
 static int test__parsing_fake(struct test_suite *test __maybe_unused,
 			      int subtest __maybe_unused)
 {
-	unsigned int i, j;
 	int err = 0;
 
-	for (i = 0; i < ARRAY_SIZE(metrics); i++) {
+	for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) {
 		err = metric_parse_fake(metrics[i].str);
 		if (err)
 			return err;
 	}
 
-	i = 0;
-	for (;;) {
-		const struct pmu_events_map *map = &pmu_events_map[i++];
+	err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
+	if (err)
+		return err;
 
-		if (!map->table)
-			break;
-		j = 0;
-		for (;;) {
-			const struct pmu_event *pe = &map->table[j++];
-
-			if (!pe->name && !pe->metric_group && !pe->metric_name)
-				break;
-			if (!pe->metric_expr)
-				continue;
-			pr_debug("Found metric '%s' for '%s'\n", pe->metric_name, map->cpuid);
-			err = metric_parse_fake(pe->metric_expr);
-			if (err)
-				return err;
-		}
-	}
-
-	return 0;
+	return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
 }
 
 static struct test_case pmu_events_tests[] = {
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 4d32b4fbf67d..680f7c63838d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -502,14 +502,14 @@ struct metricgroup_print_sys_idata {
 	bool details;
 };
 
-typedef int (*metricgroup_sys_event_iter_fn)(const struct pmu_event *pe, void *);
-
 struct metricgroup_iter_data {
-	metricgroup_sys_event_iter_fn fn;
+	pmu_event_iter_fn fn;
 	void *data;
 };
 
-static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
+static int metricgroup__sys_event_iter(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *data)
 {
 	struct metricgroup_iter_data *d = data;
 	struct perf_pmu *pmu = NULL;
@@ -522,13 +522,15 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
 		if (!pmu->id || strcmp(pmu->id, pe->compat))
 			continue;
 
-		return d->fn(pe, d->data);
+		return d->fn(pe, table, d->data);
 	}
 
 	return 0;
 }
 
-static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *data)
+static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
+					     const struct pmu_event *table __maybe_unused,
+					     void *data)
 {
 	struct metricgroup_print_sys_idata *d = data;
 
@@ -1101,6 +1103,7 @@ static int add_metric(struct list_head *metric_list,
 }
 
 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
+						  const struct pmu_event *table __maybe_unused,
 						  void *data)
 {
 	struct metricgroup_add_iter_data *d = data;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index f3e3c4a147e9..5bb03d4e52a3 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -690,7 +690,7 @@ static int is_arm_pmu_core(const char *name)
 	return file_available(path);
 }
 
-static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
+char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 {
 	char *cpuid;
 	static bool printed;
@@ -710,34 +710,6 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 	return cpuid;
 }
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
-{
-	const struct pmu_event *table = NULL;
-	char *cpuid = perf_pmu__getcpuid(pmu);
-	int i;
-
-	/* on some platforms which uses cpus map, cpuid can be NULL for
-	 * PMUs other than CORE PMUs.
-	 */
-	if (!cpuid)
-		return NULL;
-
-	i = 0;
-	for (;;) {
-		const struct pmu_events_map *map = &pmu_events_map[i++];
-
-		if (!map->table)
-			break;
-
-		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-			table = map->table;
-			break;
-		}
-	}
-	free(cpuid);
-	return table;
-}
-
 __weak const struct pmu_event *pmu_events_map__find(void)
 {
 	return perf_pmu__find_table(NULL);
@@ -874,7 +846,9 @@ struct pmu_sys_event_iter_data {
 	struct perf_pmu *pmu;
 };
 
-static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, void *data)
+static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *data)
 {
 	struct pmu_sys_event_iter_data *idata = data;
 	struct perf_pmu *pmu = idata->pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 015242c83698..06df99ba2029 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -128,7 +128,7 @@ struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 			     const struct pmu_event *map);
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+char *perf_pmu__getcpuid(struct perf_pmu *pmu);
 const struct pmu_event *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 11/17] perf test: Use full metric resolution
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

The simple metric resolution doesn't handle recursion properly, switch
to use the full resolution as with the parse-metric tests which also
increases coverage. Don't set the values for the metric backward as
failures to generate a result are ignored.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/tests/pmu-events.c | 222 ++++++++++++----------------------
 1 file changed, 77 insertions(+), 145 deletions(-)

diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index ea8b41b5c4e3..e8df6bc26ebd 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -9,10 +9,12 @@
 #include <linux/zalloc.h>
 #include "debug.h"
 #include "../pmu-events/pmu-events.h"
+#include <perf/evlist.h>
 #include "util/evlist.h"
 #include "util/expr.h"
 #include "util/parse-events.h"
 #include "metricgroup.h"
+#include "stat.h"
 
 struct perf_pmu_test_event {
 	/* used for matching against events from generated pmu-events.c */
@@ -801,27 +803,6 @@ static int check_parse_id(const char *id, struct parse_events_error *error,
 	return ret;
 }
 
-static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event *pe)
-{
-	struct parse_events_error error;
-	int ret;
-
-	parse_events_error__init(&error);
-	ret = check_parse_id(id, &error, NULL);
-	if (ret && same_cpu) {
-		pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n",
-			pe->metric_name, id, pe->metric_expr);
-		pr_warning("Error string '%s' help '%s'\n", error.str,
-			error.help);
-	} else if (ret) {
-		pr_debug3("Parse event failed, but for an event that may not be supported by this CPU.\nid '%s' metric '%s' expr '%s'\n",
-			  id, pe->metric_name, pe->metric_expr);
-		ret = 0;
-	}
-	parse_events_error__exit(&error);
-	return ret;
-}
-
 static int check_parse_fake(const char *id)
 {
 	struct parse_events_error error;
@@ -838,160 +819,111 @@ struct metric {
 	struct metric_ref metric_ref;
 };
 
-static int resolve_metric_simple(struct expr_parse_ctx *pctx,
-				 struct list_head *compound_list,
-				 const struct pmu_event *map,
-				 const char *metric_name)
-{
-	struct hashmap_entry *cur, *cur_tmp;
-	struct metric *metric, *tmp;
-	size_t bkt;
-	bool all;
-	int rc;
-
-	do {
-		all = true;
-		hashmap__for_each_entry_safe(pctx->ids, cur, cur_tmp, bkt) {
-			struct metric_ref *ref;
-			const struct pmu_event *pe;
-
-			pe = metricgroup__find_metric(cur->key, map);
-			if (!pe)
-				continue;
-
-			if (!strcmp(metric_name, (char *)cur->key)) {
-				pr_warning("Recursion detected for metric %s\n", metric_name);
-				rc = -1;
-				goto out_err;
-			}
-
-			all = false;
-
-			/* The metric key itself needs to go out.. */
-			expr__del_id(pctx, cur->key);
-
-			metric = malloc(sizeof(*metric));
-			if (!metric) {
-				rc = -ENOMEM;
-				goto out_err;
-			}
-
-			ref = &metric->metric_ref;
-			ref->metric_name = pe->metric_name;
-			ref->metric_expr = pe->metric_expr;
-			list_add_tail(&metric->list, compound_list);
-
-			rc = expr__find_ids(pe->metric_expr, NULL, pctx);
-			if (rc)
-				goto out_err;
-			break; /* The hashmap has been modified, so restart */
-		}
-	} while (!all);
-
-	return 0;
-
-out_err:
-	list_for_each_entry_safe(metric, tmp, compound_list, list)
-		free(metric);
-
-	return rc;
-
-}
-
-static void expr_failure(const char *msg, const struct pmu_event *pe)
-{
-	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
-}
-
-
-struct test__parsing_data {
-	const struct pmu_event *cpus_table;
-	struct expr_parse_ctx *ctx;
-	int failures;
-};
-
 static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
-				  void *vdata)
+				  void *data)
 {
-	struct test__parsing_data *data = vdata;
-	struct metric *metric, *tmp;
-	struct hashmap_entry *cur;
-	LIST_HEAD(compound_list);
-	size_t bkt;
+	int *failures = data;
 	int k;
-	double result;
+	struct evlist *evlist;
+	struct perf_cpu_map *cpus;
+	struct runtime_stat st;
+	struct evsel *evsel;
+	struct rblist metric_events = {
+		.nr_entries = 0,
+	};
+	int err = 0;
 
 	if (!pe->metric_expr)
 		return 0;
 
 	pr_debug("Found metric '%s'\n", pe->metric_name);
+	(*failures)++;
 
-	expr__ctx_clear(data->ctx);
-	if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
-		expr_failure("Parse find ids failed", pe);
-		data->failures++;
-		return 0;
+	/*
+	 * We need to prepare evlist for stat mode running on CPU 0
+	 * because that's where all the stats are going to be created.
+	 */
+	evlist = evlist__new();
+	if (!evlist)
+		return -ENOMEM;
+
+	cpus = perf_cpu_map__new("0");
+	if (!cpus) {
+		evlist__delete(evlist);
+		return -ENOMEM;
 	}
 
-	if (resolve_metric_simple(data->ctx, &compound_list, table,
-				  pe->metric_name)) {
-		expr_failure("Could not resolve metrics", pe);
-		data->failures++;
-		return TEST_FAIL; /* Don't tolerate errors due to severity */
+	perf_evlist__set_maps(&evlist->core, cpus, NULL);
+	runtime_stat__init(&st);
+
+	err = metricgroup__parse_groups_test(evlist, table, pe->metric_name,
+					     false, false,
+					     &metric_events);
+	if (err) {
+		if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") ||
+		    !strcmp(pe->metric_name, "M3")) {
+			(*failures)--;
+			pr_debug("Expected broken metric %s skipping\n", pe->metric_name);
+			err = 0;
+		}
+		goto out_err;
 	}
 
+	err = evlist__alloc_stats(evlist, false);
+	if (err)
+		goto out_err;
 	/*
 	 * Add all ids with a made up value. The value may trigger divide by
 	 * zero when subtracted and so try to make them unique.
 	 */
 	k = 1;
-	hashmap__for_each_entry(data->ctx->ids, cur, bkt)
-		expr__add_id_val(data->ctx, strdup(cur->key), k++);
-
-	hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
-		if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
-			data->failures++;
+	perf_stat__reset_shadow_stats();
+	evlist__for_each_entry(evlist, evsel) {
+		perf_stat__update_shadow_stats(evsel, k, 0, &st);
+		if (!strcmp(evsel->name, "duration_time"))
+			update_stats(&walltime_nsecs_stats, k);
+		k++;
 	}
+	evlist__for_each_entry(evlist, evsel) {
+		struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false);
 
-	list_for_each_entry_safe(metric, tmp, &compound_list, list) {
-		expr__add_ref(data->ctx, &metric->metric_ref);
-		free(metric);
-	}
+		if (me != NULL) {
+			struct metric_expr *mexp;
 
-	if (expr__parse(&result, data->ctx, pe->metric_expr)) {
-		/*
-		 * Parsing failed, make numbers go from large to small which can
-		 * resolve divide by zero issues.
-		 */
-		k = 1024;
-		hashmap__for_each_entry(data->ctx->ids, cur, bkt)
-			expr__add_id_val(data->ctx, strdup(cur->key), k--);
-		if (expr__parse(&result, data->ctx, pe->metric_expr)) {
-			expr_failure("Parse failed", pe);
-			data->failures++;
+			list_for_each_entry (mexp, &me->head, nd) {
+				if (strcmp(mexp->metric_name, pe->metric_name))
+					continue;
+				pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st));
+				err = 0;
+				(*failures)--;
+				goto out_err;
+			}
 		}
 	}
-	return 0;
+	pr_debug("Didn't find parsed metric %s", pe->metric_name);
+	err = 1;
+out_err:
+	if (err)
+		pr_debug("Broken metric %s\n", pe->metric_name);
+
+	/* ... cleanup. */
+	metricgroup__rblist_exit(&metric_events);
+	runtime_stat__exit(&st);
+	evlist__free_stats(evlist);
+	perf_cpu_map__put(cpus);
+	evlist__delete(evlist);
+	return err;
 }
 
 static int test__parsing(struct test_suite *test __maybe_unused,
 			 int subtest __maybe_unused)
 {
-	struct test__parsing_data data = {
-		.cpus_table = pmu_events_map__find(),
-		.ctx = expr__ctx_new(),
-		.failures = 0,
-	};
+	int failures = 0;
 
-	if (!data.ctx) {
-		pr_debug("expr__ctx_new failed");
-		return TEST_FAIL;
-	}
-	pmu_for_each_core_event(test__parsing_callback, &data);
-	pmu_for_each_sys_event(test__parsing_callback, &data);
+	pmu_for_each_core_event(test__parsing_callback, &failures);
+	pmu_for_each_sys_event(test__parsing_callback, &failures);
 
-	expr__ctx_free(data.ctx);
-	return data.failures == 0 ? TEST_OK : TEST_FAIL;
+	return failures == 0 ? TEST_OK : TEST_FAIL;
 }
 
 struct test_metric {
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 11/17] perf test: Use full metric resolution
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

The simple metric resolution doesn't handle recursion properly, switch
to use the full resolution as with the parse-metric tests which also
increases coverage. Don't set the values for the metric backward as
failures to generate a result are ignored.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/tests/pmu-events.c | 222 ++++++++++++----------------------
 1 file changed, 77 insertions(+), 145 deletions(-)

diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index ea8b41b5c4e3..e8df6bc26ebd 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -9,10 +9,12 @@
 #include <linux/zalloc.h>
 #include "debug.h"
 #include "../pmu-events/pmu-events.h"
+#include <perf/evlist.h>
 #include "util/evlist.h"
 #include "util/expr.h"
 #include "util/parse-events.h"
 #include "metricgroup.h"
+#include "stat.h"
 
 struct perf_pmu_test_event {
 	/* used for matching against events from generated pmu-events.c */
@@ -801,27 +803,6 @@ static int check_parse_id(const char *id, struct parse_events_error *error,
 	return ret;
 }
 
-static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event *pe)
-{
-	struct parse_events_error error;
-	int ret;
-
-	parse_events_error__init(&error);
-	ret = check_parse_id(id, &error, NULL);
-	if (ret && same_cpu) {
-		pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n",
-			pe->metric_name, id, pe->metric_expr);
-		pr_warning("Error string '%s' help '%s'\n", error.str,
-			error.help);
-	} else if (ret) {
-		pr_debug3("Parse event failed, but for an event that may not be supported by this CPU.\nid '%s' metric '%s' expr '%s'\n",
-			  id, pe->metric_name, pe->metric_expr);
-		ret = 0;
-	}
-	parse_events_error__exit(&error);
-	return ret;
-}
-
 static int check_parse_fake(const char *id)
 {
 	struct parse_events_error error;
@@ -838,160 +819,111 @@ struct metric {
 	struct metric_ref metric_ref;
 };
 
-static int resolve_metric_simple(struct expr_parse_ctx *pctx,
-				 struct list_head *compound_list,
-				 const struct pmu_event *map,
-				 const char *metric_name)
-{
-	struct hashmap_entry *cur, *cur_tmp;
-	struct metric *metric, *tmp;
-	size_t bkt;
-	bool all;
-	int rc;
-
-	do {
-		all = true;
-		hashmap__for_each_entry_safe(pctx->ids, cur, cur_tmp, bkt) {
-			struct metric_ref *ref;
-			const struct pmu_event *pe;
-
-			pe = metricgroup__find_metric(cur->key, map);
-			if (!pe)
-				continue;
-
-			if (!strcmp(metric_name, (char *)cur->key)) {
-				pr_warning("Recursion detected for metric %s\n", metric_name);
-				rc = -1;
-				goto out_err;
-			}
-
-			all = false;
-
-			/* The metric key itself needs to go out.. */
-			expr__del_id(pctx, cur->key);
-
-			metric = malloc(sizeof(*metric));
-			if (!metric) {
-				rc = -ENOMEM;
-				goto out_err;
-			}
-
-			ref = &metric->metric_ref;
-			ref->metric_name = pe->metric_name;
-			ref->metric_expr = pe->metric_expr;
-			list_add_tail(&metric->list, compound_list);
-
-			rc = expr__find_ids(pe->metric_expr, NULL, pctx);
-			if (rc)
-				goto out_err;
-			break; /* The hashmap has been modified, so restart */
-		}
-	} while (!all);
-
-	return 0;
-
-out_err:
-	list_for_each_entry_safe(metric, tmp, compound_list, list)
-		free(metric);
-
-	return rc;
-
-}
-
-static void expr_failure(const char *msg, const struct pmu_event *pe)
-{
-	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
-}
-
-
-struct test__parsing_data {
-	const struct pmu_event *cpus_table;
-	struct expr_parse_ctx *ctx;
-	int failures;
-};
-
 static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
-				  void *vdata)
+				  void *data)
 {
-	struct test__parsing_data *data = vdata;
-	struct metric *metric, *tmp;
-	struct hashmap_entry *cur;
-	LIST_HEAD(compound_list);
-	size_t bkt;
+	int *failures = data;
 	int k;
-	double result;
+	struct evlist *evlist;
+	struct perf_cpu_map *cpus;
+	struct runtime_stat st;
+	struct evsel *evsel;
+	struct rblist metric_events = {
+		.nr_entries = 0,
+	};
+	int err = 0;
 
 	if (!pe->metric_expr)
 		return 0;
 
 	pr_debug("Found metric '%s'\n", pe->metric_name);
+	(*failures)++;
 
-	expr__ctx_clear(data->ctx);
-	if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
-		expr_failure("Parse find ids failed", pe);
-		data->failures++;
-		return 0;
+	/*
+	 * We need to prepare evlist for stat mode running on CPU 0
+	 * because that's where all the stats are going to be created.
+	 */
+	evlist = evlist__new();
+	if (!evlist)
+		return -ENOMEM;
+
+	cpus = perf_cpu_map__new("0");
+	if (!cpus) {
+		evlist__delete(evlist);
+		return -ENOMEM;
 	}
 
-	if (resolve_metric_simple(data->ctx, &compound_list, table,
-				  pe->metric_name)) {
-		expr_failure("Could not resolve metrics", pe);
-		data->failures++;
-		return TEST_FAIL; /* Don't tolerate errors due to severity */
+	perf_evlist__set_maps(&evlist->core, cpus, NULL);
+	runtime_stat__init(&st);
+
+	err = metricgroup__parse_groups_test(evlist, table, pe->metric_name,
+					     false, false,
+					     &metric_events);
+	if (err) {
+		if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") ||
+		    !strcmp(pe->metric_name, "M3")) {
+			(*failures)--;
+			pr_debug("Expected broken metric %s skipping\n", pe->metric_name);
+			err = 0;
+		}
+		goto out_err;
 	}
 
+	err = evlist__alloc_stats(evlist, false);
+	if (err)
+		goto out_err;
 	/*
 	 * Add all ids with a made up value. The value may trigger divide by
 	 * zero when subtracted and so try to make them unique.
 	 */
 	k = 1;
-	hashmap__for_each_entry(data->ctx->ids, cur, bkt)
-		expr__add_id_val(data->ctx, strdup(cur->key), k++);
-
-	hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
-		if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
-			data->failures++;
+	perf_stat__reset_shadow_stats();
+	evlist__for_each_entry(evlist, evsel) {
+		perf_stat__update_shadow_stats(evsel, k, 0, &st);
+		if (!strcmp(evsel->name, "duration_time"))
+			update_stats(&walltime_nsecs_stats, k);
+		k++;
 	}
+	evlist__for_each_entry(evlist, evsel) {
+		struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false);
 
-	list_for_each_entry_safe(metric, tmp, &compound_list, list) {
-		expr__add_ref(data->ctx, &metric->metric_ref);
-		free(metric);
-	}
+		if (me != NULL) {
+			struct metric_expr *mexp;
 
-	if (expr__parse(&result, data->ctx, pe->metric_expr)) {
-		/*
-		 * Parsing failed, make numbers go from large to small which can
-		 * resolve divide by zero issues.
-		 */
-		k = 1024;
-		hashmap__for_each_entry(data->ctx->ids, cur, bkt)
-			expr__add_id_val(data->ctx, strdup(cur->key), k--);
-		if (expr__parse(&result, data->ctx, pe->metric_expr)) {
-			expr_failure("Parse failed", pe);
-			data->failures++;
+			list_for_each_entry (mexp, &me->head, nd) {
+				if (strcmp(mexp->metric_name, pe->metric_name))
+					continue;
+				pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st));
+				err = 0;
+				(*failures)--;
+				goto out_err;
+			}
 		}
 	}
-	return 0;
+	pr_debug("Didn't find parsed metric %s", pe->metric_name);
+	err = 1;
+out_err:
+	if (err)
+		pr_debug("Broken metric %s\n", pe->metric_name);
+
+	/* ... cleanup. */
+	metricgroup__rblist_exit(&metric_events);
+	runtime_stat__exit(&st);
+	evlist__free_stats(evlist);
+	perf_cpu_map__put(cpus);
+	evlist__delete(evlist);
+	return err;
 }
 
 static int test__parsing(struct test_suite *test __maybe_unused,
 			 int subtest __maybe_unused)
 {
-	struct test__parsing_data data = {
-		.cpus_table = pmu_events_map__find(),
-		.ctx = expr__ctx_new(),
-		.failures = 0,
-	};
+	int failures = 0;
 
-	if (!data.ctx) {
-		pr_debug("expr__ctx_new failed");
-		return TEST_FAIL;
-	}
-	pmu_for_each_core_event(test__parsing_callback, &data);
-	pmu_for_each_sys_event(test__parsing_callback, &data);
+	pmu_for_each_core_event(test__parsing_callback, &failures);
+	pmu_for_each_sys_event(test__parsing_callback, &failures);
 
-	expr__ctx_free(data.ctx);
-	return data.failures == 0 ? TEST_OK : TEST_FAIL;
+	return failures == 0 ? TEST_OK : TEST_FAIL;
 }
 
 struct test_metric {
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 12/17] perf pmu-events: Move test events/metrics to json
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Move arrays of pmu_events into the json code so that it may be
regenerated and modified by the jevents.py script.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 .../arch/test/test_soc/cpu/metrics.json       | 64 +++++++++++++++++
 tools/perf/pmu-events/empty-pmu-events.c      | 64 +++++++++++++++++
 tools/perf/tests/expand-cgroup.c              | 17 +----
 tools/perf/tests/parse-metric.c               | 68 +------------------
 4 files changed, 132 insertions(+), 81 deletions(-)
 create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json

diff --git a/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json b/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
new file mode 100644
index 000000000000..42d9b5242fd7
--- /dev/null
+++ b/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
@@ -0,0 +1,64 @@
+[
+  {
+    "MetricExpr": "1 / IPC",
+    "MetricName": "CPI"
+  },
+  {
+    "MetricExpr": "inst_retired.any / cpu_clk_unhalted.thread",
+    "MetricName": "IPC",
+    "MetricGroup": "group1"
+  },
+  {
+    "MetricExpr": "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * ( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
+    "MetricName": "Frontend_Bound_SMT"
+  },
+  {
+    "MetricExpr": "l1d\\-loads\\-misses / inst_retired.any",
+    "MetricName": "dcache_miss_cpi"
+  },
+  {
+    "MetricExpr": "l1i\\-loads\\-misses / inst_retired.any",
+    "MetricName": "icache_miss_cycles"
+  },
+  {
+    "MetricExpr": "(dcache_miss_cpi + icache_miss_cycles)",
+    "MetricName": "cache_miss_cycles",
+    "MetricGroup": "group1"
+  },
+  {
+    "MetricExpr": "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
+    "MetricName": "DCache_L2_All_Hits"
+  },
+  {
+    "MetricExpr": "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
+    "MetricName": "DCache_L2_All_Miss"
+  },
+  {
+    "MetricExpr": "dcache_l2_all_hits + dcache_l2_all_miss",
+    "MetricName": "DCache_L2_All"
+  },
+  {
+    "MetricExpr": "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
+    "MetricName": "DCache_L2_Hits"
+  },
+  {
+    "MetricExpr": "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
+    "MetricName": "DCache_L2_Misses"
+  },
+  {
+    "MetricExpr": "ipc + M2",
+    "MetricName": "M1"
+  },
+  {
+    "MetricExpr": "ipc + M1",
+    "MetricName": "M2"
+  },
+  {
+    "MetricExpr": "1/M3",
+    "MetricName": "M3"
+  },
+  {
+    "MetricExpr": "64 * l1d.replacement / 1000000000 / duration_time",
+    "MetricName": "L1D_Cache_Fill_BW"
+  }
+]
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 8ef75aff996c..028f44efe48d 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -105,6 +105,70 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 		.desc = "L2 BTB Correction",
 		.topic = "branch",
 	},
+	{
+		.metric_expr	= "1 / IPC",
+		.metric_name	= "CPI",
+	},
+	{
+		.metric_expr	= "inst_retired.any / cpu_clk_unhalted.thread",
+		.metric_name	= "IPC",
+		.metric_group	= "group1",
+	},
+	{
+		.metric_expr	= "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
+		"( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
+		.metric_name	= "Frontend_Bound_SMT",
+	},
+	{
+		.metric_expr	= "l1d\\-loads\\-misses / inst_retired.any",
+		.metric_name	= "dcache_miss_cpi",
+	},
+	{
+		.metric_expr	= "l1i\\-loads\\-misses / inst_retired.any",
+		.metric_name	= "icache_miss_cycles",
+	},
+	{
+		.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
+		.metric_name	= "cache_miss_cycles",
+		.metric_group	= "group1",
+	},
+	{
+		.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
+		.metric_name	= "DCache_L2_All_Hits",
+	},
+	{
+		.metric_expr	= "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
+		"l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
+		.metric_name	= "DCache_L2_All_Miss",
+	},
+	{
+		.metric_expr	= "dcache_l2_all_hits + dcache_l2_all_miss",
+		.metric_name	= "DCache_L2_All",
+	},
+	{
+		.metric_expr	= "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
+		.metric_name	= "DCache_L2_Hits",
+	},
+	{
+		.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
+		.metric_name	= "DCache_L2_Misses",
+	},
+	{
+		.metric_expr	= "ipc + M2",
+		.metric_name	= "M1",
+	},
+	{
+		.metric_expr	= "ipc + M1",
+		.metric_name	= "M2",
+	},
+	{
+		.metric_expr	= "1/M3",
+		.metric_name	= "M3",
+	},
+	{
+		.metric_expr	= "64 * l1d.replacement / 1000000000 / duration_time",
+		.metric_name	= "L1D_Cache_Fill_BW",
+	},
 	{
 		.name = 0,
 		.event = 0,
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index 411fc578e5a4..e79ee8621a90 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -180,26 +180,13 @@ static int expand_metric_events(void)
 	struct evlist *evlist;
 	struct rblist metric_events;
 	const char metric_str[] = "CPI";
-
-	struct pmu_event pme_test[] = {
-		{
-			.metric_expr	= "instructions / cycles",
-			.metric_name	= "IPC",
-		},
-		{
-			.metric_expr	= "1 / IPC",
-			.metric_name	= "CPI",
-		},
-		{
-			.metric_expr	= NULL,
-			.metric_name	= NULL,
-		},
-	};
+	const struct pmu_event *pme_test;
 
 	evlist = evlist__new();
 	TEST_ASSERT_VAL("failed to get evlist", evlist);
 
 	rblist__init(&metric_events);
+	pme_test = find_core_events_table("testarch", "testcpu");
 	ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
 					     false, false, &metric_events);
 	if (ret < 0) {
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 7aebde7c37ec..30c7091857b8 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -13,72 +13,6 @@
 #include "stat.h"
 #include "pmu.h"
 
-static struct pmu_event pme_test[] = {
-{
-	.metric_expr	= "inst_retired.any / cpu_clk_unhalted.thread",
-	.metric_name	= "IPC",
-	.metric_group	= "group1",
-},
-{
-	.metric_expr	= "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
-			  "( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
-	.metric_name	= "Frontend_Bound_SMT",
-},
-{
-	.metric_expr	= "l1d\\-loads\\-misses / inst_retired.any",
-	.metric_name	= "dcache_miss_cpi",
-},
-{
-	.metric_expr	= "l1i\\-loads\\-misses / inst_retired.any",
-	.metric_name	= "icache_miss_cycles",
-},
-{
-	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
-	.metric_name	= "cache_miss_cycles",
-	.metric_group	= "group1",
-},
-{
-	.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
-	.metric_name	= "DCache_L2_All_Hits",
-},
-{
-	.metric_expr	= "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
-			  "l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
-	.metric_name	= "DCache_L2_All_Miss",
-},
-{
-	.metric_expr	= "dcache_l2_all_hits + dcache_l2_all_miss",
-	.metric_name	= "DCache_L2_All",
-},
-{
-	.metric_expr	= "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
-	.metric_name	= "DCache_L2_Hits",
-},
-{
-	.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
-	.metric_name	= "DCache_L2_Misses",
-},
-{
-	.metric_expr	= "ipc + m2",
-	.metric_name	= "M1",
-},
-{
-	.metric_expr	= "ipc + m1",
-	.metric_name	= "M2",
-},
-{
-	.metric_expr	= "1/m3",
-	.metric_name	= "M3",
-},
-{
-	.metric_expr	= "64 * l1d.replacement / 1000000000 / duration_time",
-	.metric_name	= "L1D_Cache_Fill_BW",
-},
-{
-	.name	= NULL,
-}
-};
-
 struct value {
 	const char	*event;
 	u64		 val;
@@ -138,6 +72,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	struct rblist metric_events = {
 		.nr_entries = 0,
 	};
+	const struct pmu_event *pme_test;
 	struct perf_cpu_map *cpus;
 	struct runtime_stat st;
 	struct evlist *evlist;
@@ -161,6 +96,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	runtime_stat__init(&st);
 
 	/* Parse the metric into metric_events list. */
+	pme_test = find_core_events_table("testarch", "testcpu");
 	err = metricgroup__parse_groups_test(evlist, pme_test, name,
 					     false, false,
 					     &metric_events);
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 12/17] perf pmu-events: Move test events/metrics to json
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Move arrays of pmu_events into the json code so that it may be
regenerated and modified by the jevents.py script.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 .../arch/test/test_soc/cpu/metrics.json       | 64 +++++++++++++++++
 tools/perf/pmu-events/empty-pmu-events.c      | 64 +++++++++++++++++
 tools/perf/tests/expand-cgroup.c              | 17 +----
 tools/perf/tests/parse-metric.c               | 68 +------------------
 4 files changed, 132 insertions(+), 81 deletions(-)
 create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json

diff --git a/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json b/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
new file mode 100644
index 000000000000..42d9b5242fd7
--- /dev/null
+++ b/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
@@ -0,0 +1,64 @@
+[
+  {
+    "MetricExpr": "1 / IPC",
+    "MetricName": "CPI"
+  },
+  {
+    "MetricExpr": "inst_retired.any / cpu_clk_unhalted.thread",
+    "MetricName": "IPC",
+    "MetricGroup": "group1"
+  },
+  {
+    "MetricExpr": "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * ( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
+    "MetricName": "Frontend_Bound_SMT"
+  },
+  {
+    "MetricExpr": "l1d\\-loads\\-misses / inst_retired.any",
+    "MetricName": "dcache_miss_cpi"
+  },
+  {
+    "MetricExpr": "l1i\\-loads\\-misses / inst_retired.any",
+    "MetricName": "icache_miss_cycles"
+  },
+  {
+    "MetricExpr": "(dcache_miss_cpi + icache_miss_cycles)",
+    "MetricName": "cache_miss_cycles",
+    "MetricGroup": "group1"
+  },
+  {
+    "MetricExpr": "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
+    "MetricName": "DCache_L2_All_Hits"
+  },
+  {
+    "MetricExpr": "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
+    "MetricName": "DCache_L2_All_Miss"
+  },
+  {
+    "MetricExpr": "dcache_l2_all_hits + dcache_l2_all_miss",
+    "MetricName": "DCache_L2_All"
+  },
+  {
+    "MetricExpr": "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
+    "MetricName": "DCache_L2_Hits"
+  },
+  {
+    "MetricExpr": "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
+    "MetricName": "DCache_L2_Misses"
+  },
+  {
+    "MetricExpr": "ipc + M2",
+    "MetricName": "M1"
+  },
+  {
+    "MetricExpr": "ipc + M1",
+    "MetricName": "M2"
+  },
+  {
+    "MetricExpr": "1/M3",
+    "MetricName": "M3"
+  },
+  {
+    "MetricExpr": "64 * l1d.replacement / 1000000000 / duration_time",
+    "MetricName": "L1D_Cache_Fill_BW"
+  }
+]
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 8ef75aff996c..028f44efe48d 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -105,6 +105,70 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 		.desc = "L2 BTB Correction",
 		.topic = "branch",
 	},
+	{
+		.metric_expr	= "1 / IPC",
+		.metric_name	= "CPI",
+	},
+	{
+		.metric_expr	= "inst_retired.any / cpu_clk_unhalted.thread",
+		.metric_name	= "IPC",
+		.metric_group	= "group1",
+	},
+	{
+		.metric_expr	= "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
+		"( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
+		.metric_name	= "Frontend_Bound_SMT",
+	},
+	{
+		.metric_expr	= "l1d\\-loads\\-misses / inst_retired.any",
+		.metric_name	= "dcache_miss_cpi",
+	},
+	{
+		.metric_expr	= "l1i\\-loads\\-misses / inst_retired.any",
+		.metric_name	= "icache_miss_cycles",
+	},
+	{
+		.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
+		.metric_name	= "cache_miss_cycles",
+		.metric_group	= "group1",
+	},
+	{
+		.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
+		.metric_name	= "DCache_L2_All_Hits",
+	},
+	{
+		.metric_expr	= "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
+		"l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
+		.metric_name	= "DCache_L2_All_Miss",
+	},
+	{
+		.metric_expr	= "dcache_l2_all_hits + dcache_l2_all_miss",
+		.metric_name	= "DCache_L2_All",
+	},
+	{
+		.metric_expr	= "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
+		.metric_name	= "DCache_L2_Hits",
+	},
+	{
+		.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
+		.metric_name	= "DCache_L2_Misses",
+	},
+	{
+		.metric_expr	= "ipc + M2",
+		.metric_name	= "M1",
+	},
+	{
+		.metric_expr	= "ipc + M1",
+		.metric_name	= "M2",
+	},
+	{
+		.metric_expr	= "1/M3",
+		.metric_name	= "M3",
+	},
+	{
+		.metric_expr	= "64 * l1d.replacement / 1000000000 / duration_time",
+		.metric_name	= "L1D_Cache_Fill_BW",
+	},
 	{
 		.name = 0,
 		.event = 0,
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index 411fc578e5a4..e79ee8621a90 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -180,26 +180,13 @@ static int expand_metric_events(void)
 	struct evlist *evlist;
 	struct rblist metric_events;
 	const char metric_str[] = "CPI";
-
-	struct pmu_event pme_test[] = {
-		{
-			.metric_expr	= "instructions / cycles",
-			.metric_name	= "IPC",
-		},
-		{
-			.metric_expr	= "1 / IPC",
-			.metric_name	= "CPI",
-		},
-		{
-			.metric_expr	= NULL,
-			.metric_name	= NULL,
-		},
-	};
+	const struct pmu_event *pme_test;
 
 	evlist = evlist__new();
 	TEST_ASSERT_VAL("failed to get evlist", evlist);
 
 	rblist__init(&metric_events);
+	pme_test = find_core_events_table("testarch", "testcpu");
 	ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
 					     false, false, &metric_events);
 	if (ret < 0) {
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 7aebde7c37ec..30c7091857b8 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -13,72 +13,6 @@
 #include "stat.h"
 #include "pmu.h"
 
-static struct pmu_event pme_test[] = {
-{
-	.metric_expr	= "inst_retired.any / cpu_clk_unhalted.thread",
-	.metric_name	= "IPC",
-	.metric_group	= "group1",
-},
-{
-	.metric_expr	= "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
-			  "( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
-	.metric_name	= "Frontend_Bound_SMT",
-},
-{
-	.metric_expr	= "l1d\\-loads\\-misses / inst_retired.any",
-	.metric_name	= "dcache_miss_cpi",
-},
-{
-	.metric_expr	= "l1i\\-loads\\-misses / inst_retired.any",
-	.metric_name	= "icache_miss_cycles",
-},
-{
-	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
-	.metric_name	= "cache_miss_cycles",
-	.metric_group	= "group1",
-},
-{
-	.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
-	.metric_name	= "DCache_L2_All_Hits",
-},
-{
-	.metric_expr	= "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
-			  "l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
-	.metric_name	= "DCache_L2_All_Miss",
-},
-{
-	.metric_expr	= "dcache_l2_all_hits + dcache_l2_all_miss",
-	.metric_name	= "DCache_L2_All",
-},
-{
-	.metric_expr	= "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
-	.metric_name	= "DCache_L2_Hits",
-},
-{
-	.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
-	.metric_name	= "DCache_L2_Misses",
-},
-{
-	.metric_expr	= "ipc + m2",
-	.metric_name	= "M1",
-},
-{
-	.metric_expr	= "ipc + m1",
-	.metric_name	= "M2",
-},
-{
-	.metric_expr	= "1/m3",
-	.metric_name	= "M3",
-},
-{
-	.metric_expr	= "64 * l1d.replacement / 1000000000 / duration_time",
-	.metric_name	= "L1D_Cache_Fill_BW",
-},
-{
-	.name	= NULL,
-}
-};
-
 struct value {
 	const char	*event;
 	u64		 val;
@@ -138,6 +72,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	struct rblist metric_events = {
 		.nr_entries = 0,
 	};
+	const struct pmu_event *pme_test;
 	struct perf_cpu_map *cpus;
 	struct runtime_stat st;
 	struct evlist *evlist;
@@ -161,6 +96,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	runtime_stat__init(&st);
 
 	/* Parse the metric into metric_events list. */
+	pme_test = find_core_events_table("testarch", "testcpu");
 	err = metricgroup__parse_groups_test(evlist, pme_test, name,
 					     false, false,
 					     &metric_events);
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 13/17] perf pmu-events: Don't assume pmu_event is an array
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Current code assumes that a struct pmu_event can be iterated over
forward until a NULL pmu_event is encountered. This makes it difficult
to refactor pmu_event. Add a loop function taking a callback function
that's passed the struct pmu_event. This way the pmu_event is only
needed for one element and not an entire array.

Switch existing code iterating over the pmu_event arrays to use the new
loop function pmu_events_table_for_each_event.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c |  34 +++--
 tools/perf/pmu-events/jevents.py         |  34 +++--
 tools/perf/pmu-events/pmu-events.h       |   3 +
 tools/perf/tests/pmu-events.c            | 136 +++++++++--------
 tools/perf/util/metricgroup.c            | 181 ++++++++++++++++-------
 tools/perf/util/pmu.c                    |  65 ++++----
 tools/perf/util/s390-sample-raw.c        |  42 ++++--
 7 files changed, 313 insertions(+), 182 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 028f44efe48d..bee1967baa2b 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -247,6 +247,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	},
 };
 
+int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+				    void *data)
+{
+	for (const struct pmu_event *pe = &table[0];
+	     pe->name || pe->metric_group || pe->metric_name;
+	     pe++) {
+		int ret = fn(pe, table, data);
+
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 {
 	const struct pmu_event *table = NULL;
@@ -291,14 +305,10 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 	for (const struct pmu_events_map *tables = &pmu_events_map[0];
 	     tables->table;
 	     tables++) {
-		for (const struct pmu_event *pe = &tables->table[0];
-		     pe->name || pe->metric_group || pe->metric_name;
-		     pe++) {
-			int ret = fn(pe, &tables->table[0], data);
+		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-			if (ret)
-				return ret;
-		}
+		if (ret)
+			return ret;
 	}
 	return 0;
 }
@@ -319,14 +329,10 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
 	     tables->name;
 	     tables++) {
-		for (const struct pmu_event *pe = &tables->table[0];
-		     pe->name || pe->metric_group || pe->metric_name;
-		     pe++) {
-			int ret = fn(pe, &tables->table[0], data);
+		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-			if (ret)
-				return ret;
-		}
+		if (ret)
+			return ret;
 	}
 	return 0;
 }
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index e976c5e8e80b..365c960202b0 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -409,6 +409,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 \t},
 };
 
+int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+                                    void *data)
+{
+        for (const struct pmu_event *pe = &table[0];
+             pe->name || pe->metric_group || pe->metric_name;
+             pe++) {
+                int ret = fn(pe, table, data);
+
+                if (ret)
+                        return ret;
+        }
+        return 0;
+}
+
 const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 {
         const struct pmu_event *table = NULL;
@@ -452,14 +466,10 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
              tables->table;
              tables++) {
-                for (const struct pmu_event *pe = &tables->table[0];
-                     pe->name || pe->metric_group || pe->metric_name;
-                     pe++) {
-                        int ret = fn(pe, &tables->table[0], data);
+                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-                        if (ret)
-                                return ret;
-                }
+                if (ret)
+                        return ret;
         }
         return 0;
 }
@@ -480,14 +490,10 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
              tables->name;
              tables++) {
-                for (const struct pmu_event *pe = &tables->table[0];
-                     pe->name || pe->metric_group || pe->metric_name;
-                     pe++) {
-                        int ret = fn(pe, &tables->table[0], data);
+                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-                        if (ret)
-                                return ret;
-                }
+                if (ret)
+                        return ret;
         }
         return 0;
 }
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 485e730f9922..70672842f77f 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -34,6 +34,9 @@ typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
 				 const struct pmu_event *table,
 				 void *data);
 
+int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+				    void *data);
+
 const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
 const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index e8df6bc26ebd..1c3479e5890e 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -423,84 +423,104 @@ static int compare_alias_to_test_event(struct perf_pmu_alias *alias,
 	return 0;
 }
 
-/* Verify generated events from pmu-events.c are as expected */
-static int test__pmu_event_table(struct test_suite *test __maybe_unused,
-				 int subtest __maybe_unused)
+static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
+					       const struct pmu_event *table __maybe_unused,
+					       void *data)
 {
-	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
-	int map_events = 0, expected_events;
+	int *map_events = data;
+	struct perf_pmu_test_event const **test_event_table;
+	bool found = false;
 
-	/* ignore 3x sentinels */
-	expected_events = ARRAY_SIZE(core_events) +
-			  ARRAY_SIZE(uncore_events) +
-			  ARRAY_SIZE(sys_events) - 3;
+	if (!pe->name)
+		return 0;
 
-	if (!table || !sys_event_tables)
-		return -1;
+	if (pe->pmu)
+		test_event_table = &uncore_events[0];
+	else
+		test_event_table = &core_events[0];
 
-	for (; table->name; table++) {
-		struct perf_pmu_test_event const **test_event_table;
-		bool found = false;
+	for (; *test_event_table; test_event_table++) {
+		struct perf_pmu_test_event const *test_event = *test_event_table;
+		struct pmu_event const *event = &test_event->event;
 
-		if (table->pmu)
-			test_event_table = &uncore_events[0];
-		else
-			test_event_table = &core_events[0];
+		if (strcmp(pe->name, event->name))
+			continue;
+		found = true;
+		(*map_events)++;
 
-		for (; *test_event_table; test_event_table++) {
-			struct perf_pmu_test_event const *test_event = *test_event_table;
-			struct pmu_event const *event = &test_event->event;
+		if (compare_pmu_events(pe, event))
+			return -1;
 
-			if (strcmp(table->name, event->name))
-				continue;
-			found = true;
-			map_events++;
+		pr_debug("testing event table %s: pass\n", pe->name);
+	}
+	if (!found) {
+		pr_err("testing event table: could not find event %s\n", pe->name);
+		return -1;
+	}
+	return 0;
+}
 
-			if (compare_pmu_events(table, event))
-				return -1;
+static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
+					      const struct pmu_event *table __maybe_unused,
+					      void *data)
+{
+	int *map_events = data;
+	struct perf_pmu_test_event const **test_event_table;
+	bool found = false;
 
-			pr_debug("testing event table %s: pass\n", table->name);
-		}
+	test_event_table = &sys_events[0];
 
-		if (!found) {
-			pr_err("testing event table: could not find event %s\n",
-			       table->name);
-			return -1;
-		}
-	}
+	for (; *test_event_table; test_event_table++) {
+		struct perf_pmu_test_event const *test_event = *test_event_table;
+		struct pmu_event const *event = &test_event->event;
 
-	for (table = sys_event_tables; table->name; table++) {
-		struct perf_pmu_test_event const **test_event_table;
-		bool found = false;
+		if (strcmp(pe->name, event->name))
+			continue;
+		found = true;
+		(*map_events)++;
 
-		test_event_table = &sys_events[0];
+		if (compare_pmu_events(pe, event))
+			return TEST_FAIL;
 
-		for (; *test_event_table; test_event_table++) {
-			struct perf_pmu_test_event const *test_event = *test_event_table;
-			struct pmu_event const *event = &test_event->event;
+		pr_debug("testing sys event table %s: pass\n", pe->name);
+	}
+	if (!found) {
+		pr_debug("testing sys event table: could not find event %s\n", pe->name);
+		return TEST_FAIL;
+	}
+	return TEST_OK;
+}
 
-			if (strcmp(table->name, event->name))
-				continue;
-			found = true;
-			map_events++;
+/* Verify generated events from pmu-events.c are as expected */
+static int test__pmu_event_table(struct test_suite *test __maybe_unused,
+				 int subtest __maybe_unused)
+{
+	const struct pmu_event *sys_event_table = find_sys_events_table("pme_test_soc_sys");
+	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+	int map_events = 0, expected_events, err;
 
-			if (compare_pmu_events(table, event))
-				return -1;
+	/* ignore 3x sentinels */
+	expected_events = ARRAY_SIZE(core_events) +
+			  ARRAY_SIZE(uncore_events) +
+			  ARRAY_SIZE(sys_events) - 3;
 
-			pr_debug("testing sys event table %s: pass\n", table->name);
-		}
-		if (!found) {
-			pr_debug("testing event table: could not find event %s\n",
-				   table->name);
-			return -1;
-		}
-	}
+	if (!table || !sys_event_table)
+		return -1;
+
+	err = pmu_events_table_for_each_event(table, test__pmu_event_table_core_callback,
+					      &map_events);
+	if (err)
+		return err;
+
+	err = pmu_events_table_for_each_event(sys_event_table, test__pmu_event_table_sys_callback,
+					      &map_events);
+	if (err)
+		return err;
 
 	if (map_events != expected_events) {
 		pr_err("testing event table: found %d, but expected %d\n",
 		       map_events, expected_events);
-		return -1;
+		return TEST_FAIL;
 	}
 
 	return 0;
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 680f7c63838d..f702b73a7609 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -538,12 +538,40 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
 				     d->details, d->groups, d->metriclist);
 }
 
+struct metricgroup_print_data {
+	const char *pmu_name;
+	struct strlist *metriclist;
+	char *filter;
+	struct rblist *groups;
+	bool metricgroups;
+	bool raw;
+	bool details;
+};
+
+static int metricgroup__print_callback(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *vdata)
+{
+	struct metricgroup_print_data *data = vdata;
+
+	if (!pe->metric_expr)
+		return 0;
+
+	if (data->pmu_name && perf_pmu__is_hybrid(pe->pmu) && strcmp(data->pmu_name, pe->pmu))
+		return 0;
+
+	return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter,
+					    data->raw, data->details, data->groups,
+					    data->metriclist);
+}
+
 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 			bool raw, bool details, const char *pmu_name)
 {
 	struct rblist groups;
 	struct rb_node *node, *next;
 	struct strlist *metriclist = NULL;
+	const struct pmu_event *table;
 
 	if (!metricgroups) {
 		metriclist = strlist__new(NULL, NULL);
@@ -555,22 +583,22 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 	groups.node_new = mep_new;
 	groups.node_cmp = mep_cmp;
 	groups.node_delete = mep_delete;
-	for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
+	table = pmu_events_map__find();
+	if (table) {
+		struct metricgroup_print_data data = {
+			.pmu_name = pmu_name,
+			.metriclist = metriclist,
+			.metricgroups = metricgroups,
+			.filter = filter,
+			.raw = raw,
+			.details = details,
+			.groups = &groups,
+		};
 
-		if (!pe->name && !pe->metric_group && !pe->metric_name)
-			break;
-		if (!pe->metric_expr)
-			continue;
-		if (pmu_name && perf_pmu__is_hybrid(pe->pmu) &&
-		    strcmp(pmu_name, pe->pmu)) {
-			continue;
-		}
-		if (metricgroup__print_pmu_event(pe, metricgroups, filter,
-						 raw, details, &groups,
-						 metriclist) < 0)
-			return;
+		pmu_events_table_for_each_event(table,
+						metricgroup__print_callback,
+						&data);
 	}
-
 	{
 		struct metricgroup_iter_data data = {
 			.fn = metricgroup__print_sys_event_iter,
@@ -1043,30 +1071,35 @@ static int __add_metric(struct list_head *metric_list,
 	return ret;
 }
 
-#define table_for_each_event(__pe, __idx, __table)					\
-	if (__table)								\
-		for (__idx = 0, __pe = &__table[__idx];				\
-		     __pe->name || __pe->metric_group || __pe->metric_name;	\
-		     __pe = &__table[++__idx])
+struct metricgroup__find_metric_data {
+	const char *metric;
+	const struct pmu_event *pe;
+};
+
+static int metricgroup__find_metric_callback(const struct pmu_event *pe,
+					     const struct pmu_event *table  __maybe_unused,
+					     void *vdata)
+{
+	struct metricgroup__find_metric_data *data = vdata;
+
+	if (!match_metric(pe->metric_name, data->metric))
+		return 0;
 
-#define table_for_each_metric(__pe, __idx, __table, __metric)		\
-	table_for_each_event(__pe, __idx, __table)				\
-		if (__pe->metric_expr &&				\
-		    (match_metric(__pe->metric_group, __metric) ||	\
-		     match_metric(__pe->metric_name, __metric)))
+	data->pe = pe;
+	return -1;
+}
 
 const struct pmu_event *metricgroup__find_metric(const char *metric,
 						 const struct pmu_event *table)
 {
-	const struct pmu_event *pe;
-	int i;
+	struct metricgroup__find_metric_data data = {
+		.metric = metric,
+		.pe = NULL,
+	};
 
-	table_for_each_event(pe, i, table) {
-		if (match_metric(pe->metric_name, metric))
-			return pe;
-	}
+	pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data);
 
-	return NULL;
+	return data.pe;
 }
 
 static int add_metric(struct list_head *metric_list,
@@ -1151,6 +1184,33 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
 	return right_count - left_count;
 }
 
+struct metricgroup__add_metric_data {
+	struct list_head *list;
+	const char *metric_name;
+	const char *modifier;
+	bool metric_no_group;
+	bool has_match;
+};
+
+static int metricgroup__add_metric_callback(const struct pmu_event *pe,
+					    const struct pmu_event *table,
+					    void *vdata)
+{
+	struct metricgroup__add_metric_data *data = vdata;
+	int ret = 0;
+
+	if (pe->metric_expr &&
+		(match_metric(pe->metric_group, data->metric_name) ||
+		 match_metric(pe->metric_name, data->metric_name))) {
+
+		data->has_match = true;
+		ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
+				 /*root_metric=*/NULL,
+				 /*visited_metrics=*/NULL, table);
+	}
+	return ret;
+}
+
 /**
  * metricgroup__add_metric - Find and add a metric, or a metric group.
  * @metric_name: The name of the metric or metric group. For example, "IPC"
@@ -1169,24 +1229,29 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 				   struct list_head *metric_list,
 				   const struct pmu_event *table)
 {
-	const struct pmu_event *pe;
 	LIST_HEAD(list);
-	int i, ret;
+	int ret;
 	bool has_match = false;
 
-	/*
-	 * Iterate over all metrics seeing if metric matches either the name or
-	 * group. When it does add the metric to the list.
-	 */
-	table_for_each_metric(pe, i, table, metric_name) {
-		has_match = true;
-		ret = add_metric(&list, pe, modifier, metric_no_group,
-				 /*root_metric=*/NULL,
-				 /*visited_metrics=*/NULL, table);
+	{
+		struct metricgroup__add_metric_data data = {
+			.list = &list,
+			.metric_name = metric_name,
+			.modifier = modifier,
+			.metric_no_group = metric_no_group,
+			.has_match = false,
+		};
+		/*
+		 * Iterate over all metrics seeing if metric matches either the
+		 * name or group. When it does add the metric to the list.
+		 */
+		ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
+						      &data);
 		if (ret)
 			goto out;
-	}
 
+		has_match = data.has_match;
+	}
 	{
 		struct metricgroup_iter_data data = {
 			.fn = metricgroup__add_metric_sys_event_iter,
@@ -1602,26 +1667,30 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
 			    metric_no_merge, &perf_pmu__fake, metric_events, table);
 }
 
+static int metricgroup__has_metric_callback(const struct pmu_event *pe,
+					    const struct pmu_event *table __maybe_unused,
+					    void *vdata)
+{
+	const char *metric = vdata;
+
+	if (!pe->metric_expr)
+		return 0;
+
+	if (match_metric(pe->metric_name, metric))
+		return 1;
+
+	return 0;
+}
+
 bool metricgroup__has_metric(const char *metric)
 {
 	const struct pmu_event *table = pmu_events_map__find();
-	const struct pmu_event *pe;
-	int i;
 
 	if (!table)
 		return false;
 
-	for (i = 0; ; i++) {
-		pe = &table[i];
-
-		if (!pe->name && !pe->metric_group && !pe->metric_name)
-			break;
-		if (!pe->metric_expr)
-			continue;
-		if (match_metric(pe->metric_name, metric))
-			return true;
-	}
-	return false;
+	return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
+					       (void *)metric) ? true : false;
 }
 
 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 5bb03d4e52a3..ab94d672d7bf 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -791,6 +791,36 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
 	return res;
 }
 
+struct pmu_add_cpu_aliases_map_data {
+	struct list_head *head;
+	const char *name;
+	const char *cpu_name;
+	struct perf_pmu *pmu;
+};
+
+static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
+					const struct pmu_event *table __maybe_unused,
+					void *vdata)
+{
+	struct pmu_add_cpu_aliases_map_data *data = vdata;
+	const char *pname = pe->pmu ? pe->pmu : data->cpu_name;
+
+	if (!pe->name)
+		return 0;
+
+	if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name))
+		goto new_alias;
+
+	if (strcmp(pname, data->name))
+		return 0;
+
+new_alias:
+	/* need type casts to override 'const' */
+	__perf_pmu__new_alias(data->head, NULL, (char *)pe->name, (char *)pe->desc,
+			      (char *)pe->event, pe);
+	return 0;
+}
+
 /*
  * From the pmu_events_map, find the table of PMU events that corresponds
  * to the current running CPU. Then, add all PMU events from that table
@@ -799,35 +829,14 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 			     const struct pmu_event *table)
 {
-	int i;
-	const char *name = pmu->name;
-	/*
-	 * Found a matching PMU events table. Create aliases
-	 */
-	i = 0;
-	while (1) {
-		const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
-		const struct pmu_event *pe = &table[i++];
-		const char *pname = pe->pmu ? pe->pmu : cpu_name;
-
-		if (!pe->name) {
-			if (pe->metric_group || pe->metric_name)
-				continue;
-			break;
-		}
-
-		if (pmu->is_uncore && pmu_uncore_alias_match(pname, name))
-			goto new_alias;
-
-		if (strcmp(pname, name))
-			continue;
+	struct pmu_add_cpu_aliases_map_data data = {
+		.head = head,
+		.name = pmu->name,
+		.cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu",
+		.pmu = pmu,
+	};
 
-new_alias:
-		/* need type casts to override 'const' */
-		__perf_pmu__new_alias(head, NULL, (char *)pe->name,
-				(char *)pe->desc, (char *)pe->event,
-				pe);
-	}
+	pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data);
 }
 
 static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index 1ecb718fc0eb..b1c052c176bb 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -129,6 +129,28 @@ static int get_counterset_start(int setnr)
 	}
 }
 
+struct get_counter_name_data {
+	int wanted;
+	const char *result;
+};
+
+static int get_counter_name_callback(const struct pmu_event *evp,
+				     const struct pmu_event *table __maybe_unused,
+				     void *vdata)
+{
+	struct get_counter_name_data *data = vdata;
+	int rc, event_nr;
+
+	if (evp->name == NULL || evp->event == NULL)
+		return 0;
+	rc = sscanf(evp->event, "event=%x", &event_nr);
+	if (rc == 1 && event_nr == data->wanted) {
+		data->result = evp->name;
+		return 1; /* Terminate the search. */
+	}
+	return 0;
+}
+
 /* Scan the PMU table and extract the logical name of a counter from the
  * PMU events table. Input is the counter set and counter number with in the
  * set. Construct the event number and use this as key. If they match return
@@ -137,20 +159,16 @@ static int get_counterset_start(int setnr)
  */
 static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
 {
-	int rc, event_nr, wanted = get_counterset_start(set) + nr;
+	struct get_counter_name_data data = {
+		.wanted = get_counterset_start(set) + nr,
+		.result = NULL,
+	};
 
-	if (table) {
-		const struct pmu_event *evp = table;
+	if (!table)
+		return NULL;
 
-		for (; evp->name || evp->event || evp->desc; ++evp) {
-			if (evp->name == NULL || evp->event == NULL)
-				continue;
-			rc = sscanf(evp->event, "event=%x", &event_nr);
-			if (rc == 1 && event_nr == wanted)
-				return evp->name;
-		}
-	}
-	return NULL;
+	pmu_events_table_for_each_event(table, get_counter_name_callback, &data);
+	return data.result;
 }
 
 static void s390_cpumcfdg_dump(struct perf_sample *sample)
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 13/17] perf pmu-events: Don't assume pmu_event is an array
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Current code assumes that a struct pmu_event can be iterated over
forward until a NULL pmu_event is encountered. This makes it difficult
to refactor pmu_event. Add a loop function taking a callback function
that's passed the struct pmu_event. This way the pmu_event is only
needed for one element and not an entire array.

Switch existing code iterating over the pmu_event arrays to use the new
loop function pmu_events_table_for_each_event.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/empty-pmu-events.c |  34 +++--
 tools/perf/pmu-events/jevents.py         |  34 +++--
 tools/perf/pmu-events/pmu-events.h       |   3 +
 tools/perf/tests/pmu-events.c            | 136 +++++++++--------
 tools/perf/util/metricgroup.c            | 181 ++++++++++++++++-------
 tools/perf/util/pmu.c                    |  65 ++++----
 tools/perf/util/s390-sample-raw.c        |  42 ++++--
 7 files changed, 313 insertions(+), 182 deletions(-)

diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 028f44efe48d..bee1967baa2b 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -247,6 +247,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	},
 };
 
+int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+				    void *data)
+{
+	for (const struct pmu_event *pe = &table[0];
+	     pe->name || pe->metric_group || pe->metric_name;
+	     pe++) {
+		int ret = fn(pe, table, data);
+
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 {
 	const struct pmu_event *table = NULL;
@@ -291,14 +305,10 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 	for (const struct pmu_events_map *tables = &pmu_events_map[0];
 	     tables->table;
 	     tables++) {
-		for (const struct pmu_event *pe = &tables->table[0];
-		     pe->name || pe->metric_group || pe->metric_name;
-		     pe++) {
-			int ret = fn(pe, &tables->table[0], data);
+		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-			if (ret)
-				return ret;
-		}
+		if (ret)
+			return ret;
 	}
 	return 0;
 }
@@ -319,14 +329,10 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
 	     tables->name;
 	     tables++) {
-		for (const struct pmu_event *pe = &tables->table[0];
-		     pe->name || pe->metric_group || pe->metric_name;
-		     pe++) {
-			int ret = fn(pe, &tables->table[0], data);
+		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-			if (ret)
-				return ret;
-		}
+		if (ret)
+			return ret;
 	}
 	return 0;
 }
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index e976c5e8e80b..365c960202b0 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -409,6 +409,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 \t},
 };
 
+int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+                                    void *data)
+{
+        for (const struct pmu_event *pe = &table[0];
+             pe->name || pe->metric_group || pe->metric_name;
+             pe++) {
+                int ret = fn(pe, table, data);
+
+                if (ret)
+                        return ret;
+        }
+        return 0;
+}
+
 const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 {
         const struct pmu_event *table = NULL;
@@ -452,14 +466,10 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
              tables->table;
              tables++) {
-                for (const struct pmu_event *pe = &tables->table[0];
-                     pe->name || pe->metric_group || pe->metric_name;
-                     pe++) {
-                        int ret = fn(pe, &tables->table[0], data);
+                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-                        if (ret)
-                                return ret;
-                }
+                if (ret)
+                        return ret;
         }
         return 0;
 }
@@ -480,14 +490,10 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
              tables->name;
              tables++) {
-                for (const struct pmu_event *pe = &tables->table[0];
-                     pe->name || pe->metric_group || pe->metric_name;
-                     pe++) {
-                        int ret = fn(pe, &tables->table[0], data);
+                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
 
-                        if (ret)
-                                return ret;
-                }
+                if (ret)
+                        return ret;
         }
         return 0;
 }
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 485e730f9922..70672842f77f 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -34,6 +34,9 @@ typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
 				 const struct pmu_event *table,
 				 void *data);
 
+int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+				    void *data);
+
 const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
 const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index e8df6bc26ebd..1c3479e5890e 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -423,84 +423,104 @@ static int compare_alias_to_test_event(struct perf_pmu_alias *alias,
 	return 0;
 }
 
-/* Verify generated events from pmu-events.c are as expected */
-static int test__pmu_event_table(struct test_suite *test __maybe_unused,
-				 int subtest __maybe_unused)
+static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
+					       const struct pmu_event *table __maybe_unused,
+					       void *data)
 {
-	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
-	int map_events = 0, expected_events;
+	int *map_events = data;
+	struct perf_pmu_test_event const **test_event_table;
+	bool found = false;
 
-	/* ignore 3x sentinels */
-	expected_events = ARRAY_SIZE(core_events) +
-			  ARRAY_SIZE(uncore_events) +
-			  ARRAY_SIZE(sys_events) - 3;
+	if (!pe->name)
+		return 0;
 
-	if (!table || !sys_event_tables)
-		return -1;
+	if (pe->pmu)
+		test_event_table = &uncore_events[0];
+	else
+		test_event_table = &core_events[0];
 
-	for (; table->name; table++) {
-		struct perf_pmu_test_event const **test_event_table;
-		bool found = false;
+	for (; *test_event_table; test_event_table++) {
+		struct perf_pmu_test_event const *test_event = *test_event_table;
+		struct pmu_event const *event = &test_event->event;
 
-		if (table->pmu)
-			test_event_table = &uncore_events[0];
-		else
-			test_event_table = &core_events[0];
+		if (strcmp(pe->name, event->name))
+			continue;
+		found = true;
+		(*map_events)++;
 
-		for (; *test_event_table; test_event_table++) {
-			struct perf_pmu_test_event const *test_event = *test_event_table;
-			struct pmu_event const *event = &test_event->event;
+		if (compare_pmu_events(pe, event))
+			return -1;
 
-			if (strcmp(table->name, event->name))
-				continue;
-			found = true;
-			map_events++;
+		pr_debug("testing event table %s: pass\n", pe->name);
+	}
+	if (!found) {
+		pr_err("testing event table: could not find event %s\n", pe->name);
+		return -1;
+	}
+	return 0;
+}
 
-			if (compare_pmu_events(table, event))
-				return -1;
+static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
+					      const struct pmu_event *table __maybe_unused,
+					      void *data)
+{
+	int *map_events = data;
+	struct perf_pmu_test_event const **test_event_table;
+	bool found = false;
 
-			pr_debug("testing event table %s: pass\n", table->name);
-		}
+	test_event_table = &sys_events[0];
 
-		if (!found) {
-			pr_err("testing event table: could not find event %s\n",
-			       table->name);
-			return -1;
-		}
-	}
+	for (; *test_event_table; test_event_table++) {
+		struct perf_pmu_test_event const *test_event = *test_event_table;
+		struct pmu_event const *event = &test_event->event;
 
-	for (table = sys_event_tables; table->name; table++) {
-		struct perf_pmu_test_event const **test_event_table;
-		bool found = false;
+		if (strcmp(pe->name, event->name))
+			continue;
+		found = true;
+		(*map_events)++;
 
-		test_event_table = &sys_events[0];
+		if (compare_pmu_events(pe, event))
+			return TEST_FAIL;
 
-		for (; *test_event_table; test_event_table++) {
-			struct perf_pmu_test_event const *test_event = *test_event_table;
-			struct pmu_event const *event = &test_event->event;
+		pr_debug("testing sys event table %s: pass\n", pe->name);
+	}
+	if (!found) {
+		pr_debug("testing sys event table: could not find event %s\n", pe->name);
+		return TEST_FAIL;
+	}
+	return TEST_OK;
+}
 
-			if (strcmp(table->name, event->name))
-				continue;
-			found = true;
-			map_events++;
+/* Verify generated events from pmu-events.c are as expected */
+static int test__pmu_event_table(struct test_suite *test __maybe_unused,
+				 int subtest __maybe_unused)
+{
+	const struct pmu_event *sys_event_table = find_sys_events_table("pme_test_soc_sys");
+	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+	int map_events = 0, expected_events, err;
 
-			if (compare_pmu_events(table, event))
-				return -1;
+	/* ignore 3x sentinels */
+	expected_events = ARRAY_SIZE(core_events) +
+			  ARRAY_SIZE(uncore_events) +
+			  ARRAY_SIZE(sys_events) - 3;
 
-			pr_debug("testing sys event table %s: pass\n", table->name);
-		}
-		if (!found) {
-			pr_debug("testing event table: could not find event %s\n",
-				   table->name);
-			return -1;
-		}
-	}
+	if (!table || !sys_event_table)
+		return -1;
+
+	err = pmu_events_table_for_each_event(table, test__pmu_event_table_core_callback,
+					      &map_events);
+	if (err)
+		return err;
+
+	err = pmu_events_table_for_each_event(sys_event_table, test__pmu_event_table_sys_callback,
+					      &map_events);
+	if (err)
+		return err;
 
 	if (map_events != expected_events) {
 		pr_err("testing event table: found %d, but expected %d\n",
 		       map_events, expected_events);
-		return -1;
+		return TEST_FAIL;
 	}
 
 	return 0;
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 680f7c63838d..f702b73a7609 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -538,12 +538,40 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
 				     d->details, d->groups, d->metriclist);
 }
 
+struct metricgroup_print_data {
+	const char *pmu_name;
+	struct strlist *metriclist;
+	char *filter;
+	struct rblist *groups;
+	bool metricgroups;
+	bool raw;
+	bool details;
+};
+
+static int metricgroup__print_callback(const struct pmu_event *pe,
+				       const struct pmu_event *table __maybe_unused,
+				       void *vdata)
+{
+	struct metricgroup_print_data *data = vdata;
+
+	if (!pe->metric_expr)
+		return 0;
+
+	if (data->pmu_name && perf_pmu__is_hybrid(pe->pmu) && strcmp(data->pmu_name, pe->pmu))
+		return 0;
+
+	return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter,
+					    data->raw, data->details, data->groups,
+					    data->metriclist);
+}
+
 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 			bool raw, bool details, const char *pmu_name)
 {
 	struct rblist groups;
 	struct rb_node *node, *next;
 	struct strlist *metriclist = NULL;
+	const struct pmu_event *table;
 
 	if (!metricgroups) {
 		metriclist = strlist__new(NULL, NULL);
@@ -555,22 +583,22 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 	groups.node_new = mep_new;
 	groups.node_cmp = mep_cmp;
 	groups.node_delete = mep_delete;
-	for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
+	table = pmu_events_map__find();
+	if (table) {
+		struct metricgroup_print_data data = {
+			.pmu_name = pmu_name,
+			.metriclist = metriclist,
+			.metricgroups = metricgroups,
+			.filter = filter,
+			.raw = raw,
+			.details = details,
+			.groups = &groups,
+		};
 
-		if (!pe->name && !pe->metric_group && !pe->metric_name)
-			break;
-		if (!pe->metric_expr)
-			continue;
-		if (pmu_name && perf_pmu__is_hybrid(pe->pmu) &&
-		    strcmp(pmu_name, pe->pmu)) {
-			continue;
-		}
-		if (metricgroup__print_pmu_event(pe, metricgroups, filter,
-						 raw, details, &groups,
-						 metriclist) < 0)
-			return;
+		pmu_events_table_for_each_event(table,
+						metricgroup__print_callback,
+						&data);
 	}
-
 	{
 		struct metricgroup_iter_data data = {
 			.fn = metricgroup__print_sys_event_iter,
@@ -1043,30 +1071,35 @@ static int __add_metric(struct list_head *metric_list,
 	return ret;
 }
 
-#define table_for_each_event(__pe, __idx, __table)					\
-	if (__table)								\
-		for (__idx = 0, __pe = &__table[__idx];				\
-		     __pe->name || __pe->metric_group || __pe->metric_name;	\
-		     __pe = &__table[++__idx])
+struct metricgroup__find_metric_data {
+	const char *metric;
+	const struct pmu_event *pe;
+};
+
+static int metricgroup__find_metric_callback(const struct pmu_event *pe,
+					     const struct pmu_event *table  __maybe_unused,
+					     void *vdata)
+{
+	struct metricgroup__find_metric_data *data = vdata;
+
+	if (!match_metric(pe->metric_name, data->metric))
+		return 0;
 
-#define table_for_each_metric(__pe, __idx, __table, __metric)		\
-	table_for_each_event(__pe, __idx, __table)				\
-		if (__pe->metric_expr &&				\
-		    (match_metric(__pe->metric_group, __metric) ||	\
-		     match_metric(__pe->metric_name, __metric)))
+	data->pe = pe;
+	return -1;
+}
 
 const struct pmu_event *metricgroup__find_metric(const char *metric,
 						 const struct pmu_event *table)
 {
-	const struct pmu_event *pe;
-	int i;
+	struct metricgroup__find_metric_data data = {
+		.metric = metric,
+		.pe = NULL,
+	};
 
-	table_for_each_event(pe, i, table) {
-		if (match_metric(pe->metric_name, metric))
-			return pe;
-	}
+	pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data);
 
-	return NULL;
+	return data.pe;
 }
 
 static int add_metric(struct list_head *metric_list,
@@ -1151,6 +1184,33 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
 	return right_count - left_count;
 }
 
+struct metricgroup__add_metric_data {
+	struct list_head *list;
+	const char *metric_name;
+	const char *modifier;
+	bool metric_no_group;
+	bool has_match;
+};
+
+static int metricgroup__add_metric_callback(const struct pmu_event *pe,
+					    const struct pmu_event *table,
+					    void *vdata)
+{
+	struct metricgroup__add_metric_data *data = vdata;
+	int ret = 0;
+
+	if (pe->metric_expr &&
+		(match_metric(pe->metric_group, data->metric_name) ||
+		 match_metric(pe->metric_name, data->metric_name))) {
+
+		data->has_match = true;
+		ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
+				 /*root_metric=*/NULL,
+				 /*visited_metrics=*/NULL, table);
+	}
+	return ret;
+}
+
 /**
  * metricgroup__add_metric - Find and add a metric, or a metric group.
  * @metric_name: The name of the metric or metric group. For example, "IPC"
@@ -1169,24 +1229,29 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 				   struct list_head *metric_list,
 				   const struct pmu_event *table)
 {
-	const struct pmu_event *pe;
 	LIST_HEAD(list);
-	int i, ret;
+	int ret;
 	bool has_match = false;
 
-	/*
-	 * Iterate over all metrics seeing if metric matches either the name or
-	 * group. When it does add the metric to the list.
-	 */
-	table_for_each_metric(pe, i, table, metric_name) {
-		has_match = true;
-		ret = add_metric(&list, pe, modifier, metric_no_group,
-				 /*root_metric=*/NULL,
-				 /*visited_metrics=*/NULL, table);
+	{
+		struct metricgroup__add_metric_data data = {
+			.list = &list,
+			.metric_name = metric_name,
+			.modifier = modifier,
+			.metric_no_group = metric_no_group,
+			.has_match = false,
+		};
+		/*
+		 * Iterate over all metrics seeing if metric matches either the
+		 * name or group. When it does add the metric to the list.
+		 */
+		ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
+						      &data);
 		if (ret)
 			goto out;
-	}
 
+		has_match = data.has_match;
+	}
 	{
 		struct metricgroup_iter_data data = {
 			.fn = metricgroup__add_metric_sys_event_iter,
@@ -1602,26 +1667,30 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
 			    metric_no_merge, &perf_pmu__fake, metric_events, table);
 }
 
+static int metricgroup__has_metric_callback(const struct pmu_event *pe,
+					    const struct pmu_event *table __maybe_unused,
+					    void *vdata)
+{
+	const char *metric = vdata;
+
+	if (!pe->metric_expr)
+		return 0;
+
+	if (match_metric(pe->metric_name, metric))
+		return 1;
+
+	return 0;
+}
+
 bool metricgroup__has_metric(const char *metric)
 {
 	const struct pmu_event *table = pmu_events_map__find();
-	const struct pmu_event *pe;
-	int i;
 
 	if (!table)
 		return false;
 
-	for (i = 0; ; i++) {
-		pe = &table[i];
-
-		if (!pe->name && !pe->metric_group && !pe->metric_name)
-			break;
-		if (!pe->metric_expr)
-			continue;
-		if (match_metric(pe->metric_name, metric))
-			return true;
-	}
-	return false;
+	return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
+					       (void *)metric) ? true : false;
 }
 
 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 5bb03d4e52a3..ab94d672d7bf 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -791,6 +791,36 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
 	return res;
 }
 
+struct pmu_add_cpu_aliases_map_data {
+	struct list_head *head;
+	const char *name;
+	const char *cpu_name;
+	struct perf_pmu *pmu;
+};
+
+static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
+					const struct pmu_event *table __maybe_unused,
+					void *vdata)
+{
+	struct pmu_add_cpu_aliases_map_data *data = vdata;
+	const char *pname = pe->pmu ? pe->pmu : data->cpu_name;
+
+	if (!pe->name)
+		return 0;
+
+	if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name))
+		goto new_alias;
+
+	if (strcmp(pname, data->name))
+		return 0;
+
+new_alias:
+	/* need type casts to override 'const' */
+	__perf_pmu__new_alias(data->head, NULL, (char *)pe->name, (char *)pe->desc,
+			      (char *)pe->event, pe);
+	return 0;
+}
+
 /*
  * From the pmu_events_map, find the table of PMU events that corresponds
  * to the current running CPU. Then, add all PMU events from that table
@@ -799,35 +829,14 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 			     const struct pmu_event *table)
 {
-	int i;
-	const char *name = pmu->name;
-	/*
-	 * Found a matching PMU events table. Create aliases
-	 */
-	i = 0;
-	while (1) {
-		const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
-		const struct pmu_event *pe = &table[i++];
-		const char *pname = pe->pmu ? pe->pmu : cpu_name;
-
-		if (!pe->name) {
-			if (pe->metric_group || pe->metric_name)
-				continue;
-			break;
-		}
-
-		if (pmu->is_uncore && pmu_uncore_alias_match(pname, name))
-			goto new_alias;
-
-		if (strcmp(pname, name))
-			continue;
+	struct pmu_add_cpu_aliases_map_data data = {
+		.head = head,
+		.name = pmu->name,
+		.cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu",
+		.pmu = pmu,
+	};
 
-new_alias:
-		/* need type casts to override 'const' */
-		__perf_pmu__new_alias(head, NULL, (char *)pe->name,
-				(char *)pe->desc, (char *)pe->event,
-				pe);
-	}
+	pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data);
 }
 
 static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index 1ecb718fc0eb..b1c052c176bb 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -129,6 +129,28 @@ static int get_counterset_start(int setnr)
 	}
 }
 
+struct get_counter_name_data {
+	int wanted;
+	const char *result;
+};
+
+static int get_counter_name_callback(const struct pmu_event *evp,
+				     const struct pmu_event *table __maybe_unused,
+				     void *vdata)
+{
+	struct get_counter_name_data *data = vdata;
+	int rc, event_nr;
+
+	if (evp->name == NULL || evp->event == NULL)
+		return 0;
+	rc = sscanf(evp->event, "event=%x", &event_nr);
+	if (rc == 1 && event_nr == data->wanted) {
+		data->result = evp->name;
+		return 1; /* Terminate the search. */
+	}
+	return 0;
+}
+
 /* Scan the PMU table and extract the logical name of a counter from the
  * PMU events table. Input is the counter set and counter number with in the
  * set. Construct the event number and use this as key. If they match return
@@ -137,20 +159,16 @@ static int get_counterset_start(int setnr)
  */
 static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
 {
-	int rc, event_nr, wanted = get_counterset_start(set) + nr;
+	struct get_counter_name_data data = {
+		.wanted = get_counterset_start(set) + nr,
+		.result = NULL,
+	};
 
-	if (table) {
-		const struct pmu_event *evp = table;
+	if (!table)
+		return NULL;
 
-		for (; evp->name || evp->event || evp->desc; ++evp) {
-			if (evp->name == NULL || evp->event == NULL)
-				continue;
-			rc = sscanf(evp->event, "event=%x", &event_nr);
-			if (rc == 1 && event_nr == wanted)
-				return evp->name;
-		}
-	}
-	return NULL;
+	pmu_events_table_for_each_event(table, get_counter_name_callback, &data);
+	return data.result;
 }
 
 static void s390_cpumcfdg_dump(struct perf_sample *sample)
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 14/17] perf pmu-events: Hide the pmu_events
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Hide that the pmu_event structs are an array with a new wrapper struct.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/arm64/util/pmu.c         |  2 +-
 tools/perf/pmu-events/empty-pmu-events.c | 44 ++++++++++++----------
 tools/perf/pmu-events/jevents.py         | 47 +++++++++++++-----------
 tools/perf/pmu-events/pmu-events.h       | 12 +++---
 tools/perf/tests/expand-cgroup.c         |  2 +-
 tools/perf/tests/parse-metric.c          |  2 +-
 tools/perf/tests/pmu-events.c            | 16 ++++----
 tools/perf/util/metricgroup.c            | 42 ++++++++++-----------
 tools/perf/util/metricgroup.h            |  5 +--
 tools/perf/util/pmu.c                    | 10 ++---
 tools/perf/util/pmu.h                    |  4 +-
 tools/perf/util/s390-sample-raw.c        |  6 +--
 12 files changed, 101 insertions(+), 91 deletions(-)

diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
index 646af8603227..149fb334b40b 100644
--- a/tools/perf/arch/arm64/util/pmu.c
+++ b/tools/perf/arch/arm64/util/pmu.c
@@ -3,7 +3,7 @@
 #include "../../../util/cpumap.h"
 #include "../../../util/pmu.h"
 
-const struct pmu_event *pmu_events_map__find(void)
+const struct pmu_events_table *pmu_events_map__find(void)
 {
 	struct perf_pmu *pmu = NULL;
 
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index bee1967baa2b..5ed8c0aa4817 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -176,6 +176,10 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 	},
 };
 
+/* Struct used to make the PMU event table implementation opaque to callers. */
+struct pmu_events_table {
+	const struct pmu_event *entries;
+};
 
 /*
  * Map a CPU to its table of PMU events. The CPU is identified by the
@@ -188,7 +192,7 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 struct pmu_events_map {
 	const char *arch;
 	const char *cpuid;
-	const struct pmu_event *table;
+	const struct pmu_events_table table;
 };
 
 /*
@@ -199,12 +203,12 @@ static const struct pmu_events_map pmu_events_map[] = {
 	{
 		.arch = "testarch",
 		.cpuid = "testcpu",
-		.table = pme_test_soc_cpu,
+		.table = { pme_test_soc_cpu },
 	},
 	{
 		.arch = 0,
 		.cpuid = 0,
-		.table = 0,
+		.table = { 0 },
 	},
 };
 
@@ -234,23 +238,23 @@ static const struct pmu_event pme_test_soc_sys[] = {
 
 struct pmu_sys_events {
 	const char *name;
-	const struct pmu_event *table;
+	const struct pmu_events_table table;
 };
 
 static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	{
-		.table = pme_test_soc_sys,
+		.table = { pme_test_soc_sys },
 		.name = "pme_test_soc_sys",
 	},
 	{
-		.table = 0
+		.table = { 0 }
 	},
 };
 
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
 				    void *data)
 {
-	for (const struct pmu_event *pe = &table[0];
+	for (const struct pmu_event *pe = &table->entries[0];
 	     pe->name || pe->metric_group || pe->metric_name;
 	     pe++) {
 		int ret = fn(pe, table, data);
@@ -261,9 +265,9 @@ int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_ite
 	return 0;
 }
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
 {
-	const struct pmu_event *table = NULL;
+	const struct pmu_events_table *table = NULL;
 	char *cpuid = perf_pmu__getcpuid(pmu);
 	int i;
 
@@ -277,11 +281,11 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 	for (;;) {
 		const struct pmu_events_map *map = &pmu_events_map[i++];
 
-		if (!map->table)
+		if (!map->cpuid)
 			break;
 
 		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-			table = map->table;
+			table = &map->table;
 			break;
 		}
 	}
@@ -289,13 +293,13 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 	return table;
 }
 
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
 {
 	for (const struct pmu_events_map *tables = &pmu_events_map[0];
-	     tables->table;
+	     tables->arch;
 	     tables++) {
 		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
-			return tables->table;
+			return &tables->table;
 	}
 	return NULL;
 }
@@ -303,9 +307,9 @@ const struct pmu_event *find_core_events_table(const char *arch, const char *cpu
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 {
 	for (const struct pmu_events_map *tables = &pmu_events_map[0];
-	     tables->table;
+	     tables->arch;
 	     tables++) {
-		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
 		if (ret)
 			return ret;
@@ -313,13 +317,13 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 	return 0;
 }
 
-const struct pmu_event *find_sys_events_table(const char *name)
+const struct pmu_events_table *find_sys_events_table(const char *name)
 {
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
 	     tables->name;
 	     tables++) {
 		if (!strcmp(tables->name, name))
-			return tables->table;
+			return &tables->table;
 	}
 	return NULL;
 }
@@ -329,7 +333,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
 	     tables->name;
 	     tables++) {
-		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
 		if (ret)
 			return ret;
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 365c960202b0..aa8df649025a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -334,6 +334,11 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
 def print_mapping_table(archs: Sequence[str]) -> None:
   """Read the mapfile and generate the struct from cpuid string to event table."""
   _args.output_file.write("""
+/* Struct used to make the PMU event table implementation opaque to callers. */
+struct pmu_events_table {
+        const struct pmu_event *entries;
+};
+
 /*
  * Map a CPU to its table of PMU events. The CPU is identified by the
  * cpuid field, which is an arch-specific identifier for the CPU.
@@ -345,7 +350,7 @@ def print_mapping_table(archs: Sequence[str]) -> None:
 struct pmu_events_map {
         const char *arch;
         const char *cpuid;
-        const struct pmu_event *table;
+        struct pmu_events_table table;
 };
 
 /*
@@ -359,7 +364,7 @@ const struct pmu_events_map pmu_events_map[] = {
       _args.output_file.write("""{
 \t.arch = "testarch",
 \t.cpuid = "testcpu",
-\t.table = pme_test_soc_cpu,
+\t.table = { pme_test_soc_cpu },
 },
 """)
     else:
@@ -374,7 +379,7 @@ const struct pmu_events_map pmu_events_map[] = {
             _args.output_file.write(f"""{{
 \t.arch = "{arch}",
 \t.cpuid = "{cpuid}",
-\t.table = {tblname}
+\t.table = {{ {tblname} }}
 }},
 """)
           first = False
@@ -382,7 +387,7 @@ const struct pmu_events_map pmu_events_map[] = {
   _args.output_file.write("""{
 \t.arch = 0,
 \t.cpuid = 0,
-\t.table = 0,
+\t.table = { 0 },
 }
 };
 """)
@@ -393,26 +398,26 @@ def print_system_mapping_table() -> None:
   _args.output_file.write("""
 struct pmu_sys_events {
 \tconst char *name;
-\tconst struct pmu_event *table;
+\tstruct pmu_events_table table;
 };
 
 static const struct pmu_sys_events pmu_sys_event_tables[] = {
 """)
   for tblname in _sys_event_tables:
     _args.output_file.write(f"""\t{{
-\t\t.table = {tblname},
+\t\t.table = {{ {tblname} }},
 \t\t.name = \"{tblname}\",
 \t}},
 """)
   _args.output_file.write("""\t{
-\t\t.table = 0
+\t\t.table = { 0 }
 \t},
 };
 
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
                                     void *data)
 {
-        for (const struct pmu_event *pe = &table[0];
+        for (const struct pmu_event *pe = &table->entries[0];
              pe->name || pe->metric_group || pe->metric_name;
              pe++) {
                 int ret = fn(pe, table, data);
@@ -423,9 +428,9 @@ int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_ite
         return 0;
 }
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
 {
-        const struct pmu_event *table = NULL;
+        const struct pmu_events_table *table = NULL;
         char *cpuid = perf_pmu__getcpuid(pmu);
         int i;
 
@@ -438,11 +443,11 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
         i = 0;
         for (;;) {
                 const struct pmu_events_map *map = &pmu_events_map[i++];
-                if (!map->table)
+                if (!map->arch)
                         break;
 
                 if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-                        table = map->table;
+                        table = &map->table;
                         break;
                 }
         }
@@ -450,13 +455,13 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
         return table;
 }
 
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
 {
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
-             tables->table;
+             tables->arch;
              tables++) {
                 if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
-                        return tables->table;
+                        return &tables->table;
         }
         return NULL;
 }
@@ -464,9 +469,9 @@ const struct pmu_event *find_core_events_table(const char *arch, const char *cpu
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 {
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
-             tables->table;
+             tables->arch;
              tables++) {
-                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+                int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
                 if (ret)
                         return ret;
@@ -474,13 +479,13 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
         return 0;
 }
 
-const struct pmu_event *find_sys_events_table(const char *name)
+const struct pmu_events_table *find_sys_events_table(const char *name)
 {
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
              tables->name;
              tables++) {
                 if (!strcmp(tables->name, name))
-                        return tables->table;
+                        return &tables->table;
         }
         return NULL;
 }
@@ -490,7 +495,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
              tables->name;
              tables++) {
-                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+                int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
                 if (ret)
                         return ret;
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 70672842f77f..fe343c4d8016 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -30,18 +30,20 @@ struct pmu_event {
 	const char *metric_constraint;
 };
 
+struct pmu_events_table;
+
 typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
-				 const struct pmu_event *table,
+				 const struct pmu_events_table *table,
 				 void *data);
 
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
 				    void *data);
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid);
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
 
-const struct pmu_event *find_sys_events_table(const char *name);
+const struct pmu_events_table *find_sys_events_table(const char *name);
 int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
 
 #endif
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index e79ee8621a90..51fb5f34c1dd 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -180,7 +180,7 @@ static int expand_metric_events(void)
 	struct evlist *evlist;
 	struct rblist metric_events;
 	const char metric_str[] = "CPI";
-	const struct pmu_event *pme_test;
+	const struct pmu_events_table *pme_test;
 
 	evlist = evlist__new();
 	TEST_ASSERT_VAL("failed to get evlist", evlist);
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 30c7091857b8..68f5a2a03242 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -72,7 +72,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	struct rblist metric_events = {
 		.nr_entries = 0,
 	};
-	const struct pmu_event *pme_test;
+	const struct pmu_events_table *pme_test;
 	struct perf_cpu_map *cpus;
 	struct runtime_stat st;
 	struct evlist *evlist;
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 1c3479e5890e..9111725041d0 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -424,7 +424,7 @@ static int compare_alias_to_test_event(struct perf_pmu_alias *alias,
 }
 
 static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
-					       const struct pmu_event *table __maybe_unused,
+					       const struct pmu_events_table *table __maybe_unused,
 					       void *data)
 {
 	int *map_events = data;
@@ -461,7 +461,7 @@ static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
 }
 
 static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
-					      const struct pmu_event *table __maybe_unused,
+					      const struct pmu_events_table *table __maybe_unused,
 					      void *data)
 {
 	int *map_events = data;
@@ -495,8 +495,8 @@ static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
 static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
-	const struct pmu_event *sys_event_table = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+	const struct pmu_events_table *sys_event_table = find_sys_events_table("pme_test_soc_sys");
+	const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
 	int map_events = 0, expected_events, err;
 
 	/* ignore 3x sentinels */
@@ -544,7 +544,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 	struct perf_pmu *pmu;
 	LIST_HEAD(aliases);
 	int res = 0;
-	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+	const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
 	struct perf_pmu_alias *a, *tmp;
 
 	if (!table)
@@ -597,7 +597,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 	struct perf_pmu *pmu = &test_pmu->pmu;
 	const char *pmu_name = pmu->name;
 	struct perf_pmu_alias *a, *tmp, *alias;
-	const struct pmu_event *events_table;
+	const struct pmu_events_table *events_table;
 	LIST_HEAD(aliases);
 	int res = 0;
 
@@ -839,7 +839,7 @@ struct metric {
 	struct metric_ref metric_ref;
 };
 
-static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
+static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_events_table *table,
 				  void *data)
 {
 	int *failures = data;
@@ -1016,7 +1016,7 @@ static int metric_parse_fake(const char *str)
 }
 
 static int test__parsing_fake_callback(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table __maybe_unused,
 				       void *data __maybe_unused)
 {
 	if (!pe->metric_expr)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index f702b73a7609..8ef44f4b5e9a 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -508,7 +508,7 @@ struct metricgroup_iter_data {
 };
 
 static int metricgroup__sys_event_iter(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table,
 				       void *data)
 {
 	struct metricgroup_iter_data *d = data;
@@ -529,7 +529,7 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe,
 }
 
 static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
-					     const struct pmu_event *table __maybe_unused,
+					     const struct pmu_events_table *table __maybe_unused,
 					     void *data)
 {
 	struct metricgroup_print_sys_idata *d = data;
@@ -549,7 +549,7 @@ struct metricgroup_print_data {
 };
 
 static int metricgroup__print_callback(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table __maybe_unused,
 				       void *vdata)
 {
 	struct metricgroup_print_data *data = vdata;
@@ -571,7 +571,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 	struct rblist groups;
 	struct rb_node *node, *next;
 	struct strlist *metriclist = NULL;
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 
 	if (!metricgroups) {
 		metriclist = strlist__new(NULL, NULL);
@@ -876,7 +876,7 @@ struct metricgroup_add_iter_data {
 	bool metric_no_group;
 	struct metric *root_metric;
 	const struct visited_metric *visited;
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 };
 
 static int add_metric(struct list_head *metric_list,
@@ -885,7 +885,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_event *table);
+		      const struct pmu_events_table *table);
 
 /**
  * resolve_metric - Locate metrics within the root metric and recursively add
@@ -908,7 +908,7 @@ static int resolve_metric(struct list_head *metric_list,
 			  bool metric_no_group,
 			  struct metric *root_metric,
 			  const struct visited_metric *visited,
-			  const struct pmu_event *table)
+			  const struct pmu_events_table *table)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -986,7 +986,7 @@ static int __add_metric(struct list_head *metric_list,
 			int runtime,
 			struct metric *root_metric,
 			const struct visited_metric *visited,
-			const struct pmu_event *table)
+			const struct pmu_events_table *table)
 {
 	const struct visited_metric *vm;
 	int ret;
@@ -1077,7 +1077,7 @@ struct metricgroup__find_metric_data {
 };
 
 static int metricgroup__find_metric_callback(const struct pmu_event *pe,
-					     const struct pmu_event *table  __maybe_unused,
+					     const struct pmu_events_table *table  __maybe_unused,
 					     void *vdata)
 {
 	struct metricgroup__find_metric_data *data = vdata;
@@ -1090,7 +1090,7 @@ static int metricgroup__find_metric_callback(const struct pmu_event *pe,
 }
 
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_event *table)
+						 const struct pmu_events_table *table)
 {
 	struct metricgroup__find_metric_data data = {
 		.metric = metric,
@@ -1108,7 +1108,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_event *table)
+		      const struct pmu_events_table *table)
 {
 	int ret = 0;
 
@@ -1136,8 +1136,8 @@ static int add_metric(struct list_head *metric_list,
 }
 
 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
-						  const struct pmu_event *table __maybe_unused,
-						  void *data)
+						const struct pmu_events_table *table __maybe_unused,
+						void *data)
 {
 	struct metricgroup_add_iter_data *d = data;
 	int ret;
@@ -1193,7 +1193,7 @@ struct metricgroup__add_metric_data {
 };
 
 static int metricgroup__add_metric_callback(const struct pmu_event *pe,
-					    const struct pmu_event *table,
+					    const struct pmu_events_table *table,
 					    void *vdata)
 {
 	struct metricgroup__add_metric_data *data = vdata;
@@ -1227,7 +1227,7 @@ static int metricgroup__add_metric_callback(const struct pmu_event *pe,
 static int metricgroup__add_metric(const char *metric_name, const char *modifier,
 				   bool metric_no_group,
 				   struct list_head *metric_list,
-				   const struct pmu_event *table)
+				   const struct pmu_events_table *table)
 {
 	LIST_HEAD(list);
 	int ret;
@@ -1296,7 +1296,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
  */
 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 					struct list_head *metric_list,
-					const struct pmu_event *table)
+					const struct pmu_events_table *table)
 {
 	char *list_itr, *list_copy, *metric_name, *modifier;
 	int ret, count = 0;
@@ -1504,7 +1504,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 			bool metric_no_merge,
 			struct perf_pmu *fake_pmu,
 			struct rblist *metric_events_list,
-			const struct pmu_event *table)
+			const struct pmu_events_table *table)
 {
 	struct evlist *combined_evlist = NULL;
 	LIST_HEAD(metric_list);
@@ -1650,14 +1650,14 @@ int metricgroup__parse_groups(const struct option *opt,
 			      struct rblist *metric_events)
 {
 	struct evlist *perf_evlist = *(struct evlist **)opt->value;
-	const struct pmu_event *table = pmu_events_map__find();
+	const struct pmu_events_table *table = pmu_events_map__find();
 
 	return parse_groups(perf_evlist, str, metric_no_group,
 			    metric_no_merge, NULL, metric_events, table);
 }
 
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_event *table,
+				   const struct pmu_events_table *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
@@ -1668,7 +1668,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
 }
 
 static int metricgroup__has_metric_callback(const struct pmu_event *pe,
-					    const struct pmu_event *table __maybe_unused,
+					    const struct pmu_events_table *table __maybe_unused,
 					    void *vdata)
 {
 	const char *metric = vdata;
@@ -1684,7 +1684,7 @@ static int metricgroup__has_metric_callback(const struct pmu_event *pe,
 
 bool metricgroup__has_metric(const char *metric)
 {
-	const struct pmu_event *table = pmu_events_map__find();
+	const struct pmu_events_table *table = pmu_events_map__find();
 
 	if (!table)
 		return false;
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 5a1390e73d25..f54d170043e9 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -11,7 +11,6 @@ struct evlist;
 struct evsel;
 struct option;
 struct rblist;
-struct pmu_events_map;
 struct cgroup;
 
 /**
@@ -71,9 +70,9 @@ int metricgroup__parse_groups(const struct option *opt,
 			      bool metric_no_merge,
 			      struct rblist *metric_events);
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_event *table);
+						 const struct pmu_events_table *table);
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_event *table,
+				   const struct pmu_events_table *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index ab94d672d7bf..a84fa532817f 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -710,7 +710,7 @@ char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 	return cpuid;
 }
 
-__weak const struct pmu_event *pmu_events_map__find(void)
+__weak const struct pmu_events_table *pmu_events_map__find(void)
 {
 	return perf_pmu__find_table(NULL);
 }
@@ -799,7 +799,7 @@ struct pmu_add_cpu_aliases_map_data {
 };
 
 static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
-					const struct pmu_event *table __maybe_unused,
+					const struct pmu_events_table *table __maybe_unused,
 					void *vdata)
 {
 	struct pmu_add_cpu_aliases_map_data *data = vdata;
@@ -827,7 +827,7 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
  * as aliases.
  */
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_event *table)
+			     const struct pmu_events_table *table)
 {
 	struct pmu_add_cpu_aliases_map_data data = {
 		.head = head,
@@ -841,7 +841,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 
 static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 {
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 
 	table = perf_pmu__find_table(pmu);
 	if (!table)
@@ -856,7 +856,7 @@ struct pmu_sys_event_iter_data {
 };
 
 static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table __maybe_unused,
 				       void *data)
 {
 	struct pmu_sys_event_iter_data *idata = data;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 06df99ba2029..78f87b46ddf3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -126,10 +126,10 @@ int perf_pmu__test(void);
 
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_event *map);
+			     const struct pmu_events_table *map);
 
 char *perf_pmu__getcpuid(struct perf_pmu *pmu);
-const struct pmu_event *pmu_events_map__find(void);
+const struct pmu_events_table *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
 
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index b1c052c176bb..fad1e96c74ba 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -135,7 +135,7 @@ struct get_counter_name_data {
 };
 
 static int get_counter_name_callback(const struct pmu_event *evp,
-				     const struct pmu_event *table __maybe_unused,
+				     const struct pmu_events_table *table __maybe_unused,
 				     void *vdata)
 {
 	struct get_counter_name_data *data = vdata;
@@ -157,7 +157,7 @@ static int get_counter_name_callback(const struct pmu_event *evp,
  * the name of this counter.
  * If no match is found a NULL pointer is returned.
  */
-static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
+static const char *get_counter_name(int set, int nr, const struct pmu_events_table *table)
 {
 	struct get_counter_name_data data = {
 		.wanted = get_counterset_start(set) + nr,
@@ -177,7 +177,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
 	unsigned char *buf = sample->raw_data;
 	const char *color = PERF_COLOR_BLUE;
 	struct cf_ctrset_entry *cep, ce;
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 	u64 *p;
 
 	table = pmu_events_map__find();
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 14/17] perf pmu-events: Hide the pmu_events
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

Hide that the pmu_event structs are an array with a new wrapper struct.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/arm64/util/pmu.c         |  2 +-
 tools/perf/pmu-events/empty-pmu-events.c | 44 ++++++++++++----------
 tools/perf/pmu-events/jevents.py         | 47 +++++++++++++-----------
 tools/perf/pmu-events/pmu-events.h       | 12 +++---
 tools/perf/tests/expand-cgroup.c         |  2 +-
 tools/perf/tests/parse-metric.c          |  2 +-
 tools/perf/tests/pmu-events.c            | 16 ++++----
 tools/perf/util/metricgroup.c            | 42 ++++++++++-----------
 tools/perf/util/metricgroup.h            |  5 +--
 tools/perf/util/pmu.c                    | 10 ++---
 tools/perf/util/pmu.h                    |  4 +-
 tools/perf/util/s390-sample-raw.c        |  6 +--
 12 files changed, 101 insertions(+), 91 deletions(-)

diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
index 646af8603227..149fb334b40b 100644
--- a/tools/perf/arch/arm64/util/pmu.c
+++ b/tools/perf/arch/arm64/util/pmu.c
@@ -3,7 +3,7 @@
 #include "../../../util/cpumap.h"
 #include "../../../util/pmu.h"
 
-const struct pmu_event *pmu_events_map__find(void)
+const struct pmu_events_table *pmu_events_map__find(void)
 {
 	struct perf_pmu *pmu = NULL;
 
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index bee1967baa2b..5ed8c0aa4817 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -176,6 +176,10 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 	},
 };
 
+/* Struct used to make the PMU event table implementation opaque to callers. */
+struct pmu_events_table {
+	const struct pmu_event *entries;
+};
 
 /*
  * Map a CPU to its table of PMU events. The CPU is identified by the
@@ -188,7 +192,7 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 struct pmu_events_map {
 	const char *arch;
 	const char *cpuid;
-	const struct pmu_event *table;
+	const struct pmu_events_table table;
 };
 
 /*
@@ -199,12 +203,12 @@ static const struct pmu_events_map pmu_events_map[] = {
 	{
 		.arch = "testarch",
 		.cpuid = "testcpu",
-		.table = pme_test_soc_cpu,
+		.table = { pme_test_soc_cpu },
 	},
 	{
 		.arch = 0,
 		.cpuid = 0,
-		.table = 0,
+		.table = { 0 },
 	},
 };
 
@@ -234,23 +238,23 @@ static const struct pmu_event pme_test_soc_sys[] = {
 
 struct pmu_sys_events {
 	const char *name;
-	const struct pmu_event *table;
+	const struct pmu_events_table table;
 };
 
 static const struct pmu_sys_events pmu_sys_event_tables[] = {
 	{
-		.table = pme_test_soc_sys,
+		.table = { pme_test_soc_sys },
 		.name = "pme_test_soc_sys",
 	},
 	{
-		.table = 0
+		.table = { 0 }
 	},
 };
 
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
 				    void *data)
 {
-	for (const struct pmu_event *pe = &table[0];
+	for (const struct pmu_event *pe = &table->entries[0];
 	     pe->name || pe->metric_group || pe->metric_name;
 	     pe++) {
 		int ret = fn(pe, table, data);
@@ -261,9 +265,9 @@ int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_ite
 	return 0;
 }
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
 {
-	const struct pmu_event *table = NULL;
+	const struct pmu_events_table *table = NULL;
 	char *cpuid = perf_pmu__getcpuid(pmu);
 	int i;
 
@@ -277,11 +281,11 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 	for (;;) {
 		const struct pmu_events_map *map = &pmu_events_map[i++];
 
-		if (!map->table)
+		if (!map->cpuid)
 			break;
 
 		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-			table = map->table;
+			table = &map->table;
 			break;
 		}
 	}
@@ -289,13 +293,13 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
 	return table;
 }
 
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
 {
 	for (const struct pmu_events_map *tables = &pmu_events_map[0];
-	     tables->table;
+	     tables->arch;
 	     tables++) {
 		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
-			return tables->table;
+			return &tables->table;
 	}
 	return NULL;
 }
@@ -303,9 +307,9 @@ const struct pmu_event *find_core_events_table(const char *arch, const char *cpu
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 {
 	for (const struct pmu_events_map *tables = &pmu_events_map[0];
-	     tables->table;
+	     tables->arch;
 	     tables++) {
-		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
 		if (ret)
 			return ret;
@@ -313,13 +317,13 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 	return 0;
 }
 
-const struct pmu_event *find_sys_events_table(const char *name)
+const struct pmu_events_table *find_sys_events_table(const char *name)
 {
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
 	     tables->name;
 	     tables++) {
 		if (!strcmp(tables->name, name))
-			return tables->table;
+			return &tables->table;
 	}
 	return NULL;
 }
@@ -329,7 +333,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
 	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
 	     tables->name;
 	     tables++) {
-		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
 		if (ret)
 			return ret;
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 365c960202b0..aa8df649025a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -334,6 +334,11 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
 def print_mapping_table(archs: Sequence[str]) -> None:
   """Read the mapfile and generate the struct from cpuid string to event table."""
   _args.output_file.write("""
+/* Struct used to make the PMU event table implementation opaque to callers. */
+struct pmu_events_table {
+        const struct pmu_event *entries;
+};
+
 /*
  * Map a CPU to its table of PMU events. The CPU is identified by the
  * cpuid field, which is an arch-specific identifier for the CPU.
@@ -345,7 +350,7 @@ def print_mapping_table(archs: Sequence[str]) -> None:
 struct pmu_events_map {
         const char *arch;
         const char *cpuid;
-        const struct pmu_event *table;
+        struct pmu_events_table table;
 };
 
 /*
@@ -359,7 +364,7 @@ const struct pmu_events_map pmu_events_map[] = {
       _args.output_file.write("""{
 \t.arch = "testarch",
 \t.cpuid = "testcpu",
-\t.table = pme_test_soc_cpu,
+\t.table = { pme_test_soc_cpu },
 },
 """)
     else:
@@ -374,7 +379,7 @@ const struct pmu_events_map pmu_events_map[] = {
             _args.output_file.write(f"""{{
 \t.arch = "{arch}",
 \t.cpuid = "{cpuid}",
-\t.table = {tblname}
+\t.table = {{ {tblname} }}
 }},
 """)
           first = False
@@ -382,7 +387,7 @@ const struct pmu_events_map pmu_events_map[] = {
   _args.output_file.write("""{
 \t.arch = 0,
 \t.cpuid = 0,
-\t.table = 0,
+\t.table = { 0 },
 }
 };
 """)
@@ -393,26 +398,26 @@ def print_system_mapping_table() -> None:
   _args.output_file.write("""
 struct pmu_sys_events {
 \tconst char *name;
-\tconst struct pmu_event *table;
+\tstruct pmu_events_table table;
 };
 
 static const struct pmu_sys_events pmu_sys_event_tables[] = {
 """)
   for tblname in _sys_event_tables:
     _args.output_file.write(f"""\t{{
-\t\t.table = {tblname},
+\t\t.table = {{ {tblname} }},
 \t\t.name = \"{tblname}\",
 \t}},
 """)
   _args.output_file.write("""\t{
-\t\t.table = 0
+\t\t.table = { 0 }
 \t},
 };
 
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
                                     void *data)
 {
-        for (const struct pmu_event *pe = &table[0];
+        for (const struct pmu_event *pe = &table->entries[0];
              pe->name || pe->metric_group || pe->metric_name;
              pe++) {
                 int ret = fn(pe, table, data);
@@ -423,9 +428,9 @@ int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_ite
         return 0;
 }
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
 {
-        const struct pmu_event *table = NULL;
+        const struct pmu_events_table *table = NULL;
         char *cpuid = perf_pmu__getcpuid(pmu);
         int i;
 
@@ -438,11 +443,11 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
         i = 0;
         for (;;) {
                 const struct pmu_events_map *map = &pmu_events_map[i++];
-                if (!map->table)
+                if (!map->arch)
                         break;
 
                 if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-                        table = map->table;
+                        table = &map->table;
                         break;
                 }
         }
@@ -450,13 +455,13 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
         return table;
 }
 
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
 {
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
-             tables->table;
+             tables->arch;
              tables++) {
                 if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
-                        return tables->table;
+                        return &tables->table;
         }
         return NULL;
 }
@@ -464,9 +469,9 @@ const struct pmu_event *find_core_events_table(const char *arch, const char *cpu
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 {
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
-             tables->table;
+             tables->arch;
              tables++) {
-                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+                int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
                 if (ret)
                         return ret;
@@ -474,13 +479,13 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
         return 0;
 }
 
-const struct pmu_event *find_sys_events_table(const char *name)
+const struct pmu_events_table *find_sys_events_table(const char *name)
 {
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
              tables->name;
              tables++) {
                 if (!strcmp(tables->name, name))
-                        return tables->table;
+                        return &tables->table;
         }
         return NULL;
 }
@@ -490,7 +495,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
              tables->name;
              tables++) {
-                int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+                int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
 
                 if (ret)
                         return ret;
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 70672842f77f..fe343c4d8016 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -30,18 +30,20 @@ struct pmu_event {
 	const char *metric_constraint;
 };
 
+struct pmu_events_table;
+
 typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
-				 const struct pmu_event *table,
+				 const struct pmu_events_table *table,
 				 void *data);
 
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
 				    void *data);
 
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid);
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
 
-const struct pmu_event *find_sys_events_table(const char *name);
+const struct pmu_events_table *find_sys_events_table(const char *name);
 int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
 
 #endif
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index e79ee8621a90..51fb5f34c1dd 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -180,7 +180,7 @@ static int expand_metric_events(void)
 	struct evlist *evlist;
 	struct rblist metric_events;
 	const char metric_str[] = "CPI";
-	const struct pmu_event *pme_test;
+	const struct pmu_events_table *pme_test;
 
 	evlist = evlist__new();
 	TEST_ASSERT_VAL("failed to get evlist", evlist);
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 30c7091857b8..68f5a2a03242 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -72,7 +72,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	struct rblist metric_events = {
 		.nr_entries = 0,
 	};
-	const struct pmu_event *pme_test;
+	const struct pmu_events_table *pme_test;
 	struct perf_cpu_map *cpus;
 	struct runtime_stat st;
 	struct evlist *evlist;
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 1c3479e5890e..9111725041d0 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -424,7 +424,7 @@ static int compare_alias_to_test_event(struct perf_pmu_alias *alias,
 }
 
 static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
-					       const struct pmu_event *table __maybe_unused,
+					       const struct pmu_events_table *table __maybe_unused,
 					       void *data)
 {
 	int *map_events = data;
@@ -461,7 +461,7 @@ static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
 }
 
 static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
-					      const struct pmu_event *table __maybe_unused,
+					      const struct pmu_events_table *table __maybe_unused,
 					      void *data)
 {
 	int *map_events = data;
@@ -495,8 +495,8 @@ static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
 static int test__pmu_event_table(struct test_suite *test __maybe_unused,
 				 int subtest __maybe_unused)
 {
-	const struct pmu_event *sys_event_table = find_sys_events_table("pme_test_soc_sys");
-	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+	const struct pmu_events_table *sys_event_table = find_sys_events_table("pme_test_soc_sys");
+	const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
 	int map_events = 0, expected_events, err;
 
 	/* ignore 3x sentinels */
@@ -544,7 +544,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 	struct perf_pmu *pmu;
 	LIST_HEAD(aliases);
 	int res = 0;
-	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+	const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
 	struct perf_pmu_alias *a, *tmp;
 
 	if (!table)
@@ -597,7 +597,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 	struct perf_pmu *pmu = &test_pmu->pmu;
 	const char *pmu_name = pmu->name;
 	struct perf_pmu_alias *a, *tmp, *alias;
-	const struct pmu_event *events_table;
+	const struct pmu_events_table *events_table;
 	LIST_HEAD(aliases);
 	int res = 0;
 
@@ -839,7 +839,7 @@ struct metric {
 	struct metric_ref metric_ref;
 };
 
-static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
+static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_events_table *table,
 				  void *data)
 {
 	int *failures = data;
@@ -1016,7 +1016,7 @@ static int metric_parse_fake(const char *str)
 }
 
 static int test__parsing_fake_callback(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table __maybe_unused,
 				       void *data __maybe_unused)
 {
 	if (!pe->metric_expr)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index f702b73a7609..8ef44f4b5e9a 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -508,7 +508,7 @@ struct metricgroup_iter_data {
 };
 
 static int metricgroup__sys_event_iter(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table,
 				       void *data)
 {
 	struct metricgroup_iter_data *d = data;
@@ -529,7 +529,7 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe,
 }
 
 static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
-					     const struct pmu_event *table __maybe_unused,
+					     const struct pmu_events_table *table __maybe_unused,
 					     void *data)
 {
 	struct metricgroup_print_sys_idata *d = data;
@@ -549,7 +549,7 @@ struct metricgroup_print_data {
 };
 
 static int metricgroup__print_callback(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table __maybe_unused,
 				       void *vdata)
 {
 	struct metricgroup_print_data *data = vdata;
@@ -571,7 +571,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 	struct rblist groups;
 	struct rb_node *node, *next;
 	struct strlist *metriclist = NULL;
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 
 	if (!metricgroups) {
 		metriclist = strlist__new(NULL, NULL);
@@ -876,7 +876,7 @@ struct metricgroup_add_iter_data {
 	bool metric_no_group;
 	struct metric *root_metric;
 	const struct visited_metric *visited;
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 };
 
 static int add_metric(struct list_head *metric_list,
@@ -885,7 +885,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_event *table);
+		      const struct pmu_events_table *table);
 
 /**
  * resolve_metric - Locate metrics within the root metric and recursively add
@@ -908,7 +908,7 @@ static int resolve_metric(struct list_head *metric_list,
 			  bool metric_no_group,
 			  struct metric *root_metric,
 			  const struct visited_metric *visited,
-			  const struct pmu_event *table)
+			  const struct pmu_events_table *table)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -986,7 +986,7 @@ static int __add_metric(struct list_head *metric_list,
 			int runtime,
 			struct metric *root_metric,
 			const struct visited_metric *visited,
-			const struct pmu_event *table)
+			const struct pmu_events_table *table)
 {
 	const struct visited_metric *vm;
 	int ret;
@@ -1077,7 +1077,7 @@ struct metricgroup__find_metric_data {
 };
 
 static int metricgroup__find_metric_callback(const struct pmu_event *pe,
-					     const struct pmu_event *table  __maybe_unused,
+					     const struct pmu_events_table *table  __maybe_unused,
 					     void *vdata)
 {
 	struct metricgroup__find_metric_data *data = vdata;
@@ -1090,7 +1090,7 @@ static int metricgroup__find_metric_callback(const struct pmu_event *pe,
 }
 
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_event *table)
+						 const struct pmu_events_table *table)
 {
 	struct metricgroup__find_metric_data data = {
 		.metric = metric,
@@ -1108,7 +1108,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool metric_no_group,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_event *table)
+		      const struct pmu_events_table *table)
 {
 	int ret = 0;
 
@@ -1136,8 +1136,8 @@ static int add_metric(struct list_head *metric_list,
 }
 
 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
-						  const struct pmu_event *table __maybe_unused,
-						  void *data)
+						const struct pmu_events_table *table __maybe_unused,
+						void *data)
 {
 	struct metricgroup_add_iter_data *d = data;
 	int ret;
@@ -1193,7 +1193,7 @@ struct metricgroup__add_metric_data {
 };
 
 static int metricgroup__add_metric_callback(const struct pmu_event *pe,
-					    const struct pmu_event *table,
+					    const struct pmu_events_table *table,
 					    void *vdata)
 {
 	struct metricgroup__add_metric_data *data = vdata;
@@ -1227,7 +1227,7 @@ static int metricgroup__add_metric_callback(const struct pmu_event *pe,
 static int metricgroup__add_metric(const char *metric_name, const char *modifier,
 				   bool metric_no_group,
 				   struct list_head *metric_list,
-				   const struct pmu_event *table)
+				   const struct pmu_events_table *table)
 {
 	LIST_HEAD(list);
 	int ret;
@@ -1296,7 +1296,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
  */
 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 					struct list_head *metric_list,
-					const struct pmu_event *table)
+					const struct pmu_events_table *table)
 {
 	char *list_itr, *list_copy, *metric_name, *modifier;
 	int ret, count = 0;
@@ -1504,7 +1504,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 			bool metric_no_merge,
 			struct perf_pmu *fake_pmu,
 			struct rblist *metric_events_list,
-			const struct pmu_event *table)
+			const struct pmu_events_table *table)
 {
 	struct evlist *combined_evlist = NULL;
 	LIST_HEAD(metric_list);
@@ -1650,14 +1650,14 @@ int metricgroup__parse_groups(const struct option *opt,
 			      struct rblist *metric_events)
 {
 	struct evlist *perf_evlist = *(struct evlist **)opt->value;
-	const struct pmu_event *table = pmu_events_map__find();
+	const struct pmu_events_table *table = pmu_events_map__find();
 
 	return parse_groups(perf_evlist, str, metric_no_group,
 			    metric_no_merge, NULL, metric_events, table);
 }
 
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_event *table,
+				   const struct pmu_events_table *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
@@ -1668,7 +1668,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
 }
 
 static int metricgroup__has_metric_callback(const struct pmu_event *pe,
-					    const struct pmu_event *table __maybe_unused,
+					    const struct pmu_events_table *table __maybe_unused,
 					    void *vdata)
 {
 	const char *metric = vdata;
@@ -1684,7 +1684,7 @@ static int metricgroup__has_metric_callback(const struct pmu_event *pe,
 
 bool metricgroup__has_metric(const char *metric)
 {
-	const struct pmu_event *table = pmu_events_map__find();
+	const struct pmu_events_table *table = pmu_events_map__find();
 
 	if (!table)
 		return false;
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 5a1390e73d25..f54d170043e9 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -11,7 +11,6 @@ struct evlist;
 struct evsel;
 struct option;
 struct rblist;
-struct pmu_events_map;
 struct cgroup;
 
 /**
@@ -71,9 +70,9 @@ int metricgroup__parse_groups(const struct option *opt,
 			      bool metric_no_merge,
 			      struct rblist *metric_events);
 const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_event *table);
+						 const struct pmu_events_table *table);
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_event *table,
+				   const struct pmu_events_table *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index ab94d672d7bf..a84fa532817f 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -710,7 +710,7 @@ char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 	return cpuid;
 }
 
-__weak const struct pmu_event *pmu_events_map__find(void)
+__weak const struct pmu_events_table *pmu_events_map__find(void)
 {
 	return perf_pmu__find_table(NULL);
 }
@@ -799,7 +799,7 @@ struct pmu_add_cpu_aliases_map_data {
 };
 
 static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
-					const struct pmu_event *table __maybe_unused,
+					const struct pmu_events_table *table __maybe_unused,
 					void *vdata)
 {
 	struct pmu_add_cpu_aliases_map_data *data = vdata;
@@ -827,7 +827,7 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
  * as aliases.
  */
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_event *table)
+			     const struct pmu_events_table *table)
 {
 	struct pmu_add_cpu_aliases_map_data data = {
 		.head = head,
@@ -841,7 +841,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 
 static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 {
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 
 	table = perf_pmu__find_table(pmu);
 	if (!table)
@@ -856,7 +856,7 @@ struct pmu_sys_event_iter_data {
 };
 
 static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
-				       const struct pmu_event *table __maybe_unused,
+				       const struct pmu_events_table *table __maybe_unused,
 				       void *data)
 {
 	struct pmu_sys_event_iter_data *idata = data;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 06df99ba2029..78f87b46ddf3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -126,10 +126,10 @@ int perf_pmu__test(void);
 
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
 void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
-			     const struct pmu_event *map);
+			     const struct pmu_events_table *map);
 
 char *perf_pmu__getcpuid(struct perf_pmu *pmu);
-const struct pmu_event *pmu_events_map__find(void);
+const struct pmu_events_table *pmu_events_map__find(void);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
 void perf_pmu_free_alias(struct perf_pmu_alias *alias);
 
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index b1c052c176bb..fad1e96c74ba 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -135,7 +135,7 @@ struct get_counter_name_data {
 };
 
 static int get_counter_name_callback(const struct pmu_event *evp,
-				     const struct pmu_event *table __maybe_unused,
+				     const struct pmu_events_table *table __maybe_unused,
 				     void *vdata)
 {
 	struct get_counter_name_data *data = vdata;
@@ -157,7 +157,7 @@ static int get_counter_name_callback(const struct pmu_event *evp,
  * the name of this counter.
  * If no match is found a NULL pointer is returned.
  */
-static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
+static const char *get_counter_name(int set, int nr, const struct pmu_events_table *table)
 {
 	struct get_counter_name_data data = {
 		.wanted = get_counterset_start(set) + nr,
@@ -177,7 +177,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
 	unsigned char *buf = sample->raw_data;
 	const char *color = PERF_COLOR_BLUE;
 	struct cf_ctrset_entry *cep, ce;
-	const struct pmu_event *table;
+	const struct pmu_events_table *table;
 	u64 *p;
 
 	table = pmu_events_map__find();
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 15/17] perf metrics: Copy entire pmu_event in find metric
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

The pmu_event passed to the pmu_events_table_for_each_event is invalid
after the loop. Copy the entire struct in metricgroup__find_metric.
Reduce the scope of this function to static.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/metricgroup.c | 33 ++++++++++++++++++---------------
 tools/perf/util/metricgroup.h |  2 --
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8ef44f4b5e9a..95f4b46dba09 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -879,6 +879,10 @@ struct metricgroup_add_iter_data {
 	const struct pmu_events_table *table;
 };
 
+static bool metricgroup__find_metric(const char *metric,
+				     const struct pmu_events_table *table,
+				     struct pmu_event *pe);
+
 static int add_metric(struct list_head *metric_list,
 		      const struct pmu_event *pe,
 		      const char *modifier,
@@ -914,7 +918,7 @@ static int resolve_metric(struct list_head *metric_list,
 	size_t bkt;
 	struct to_resolve {
 		/* The metric to resolve. */
-		const struct pmu_event *pe;
+		struct pmu_event pe;
 		/*
 		 * The key in the IDs map, this may differ from in case,
 		 * etc. from pe->metric_name.
@@ -928,16 +932,15 @@ static int resolve_metric(struct list_head *metric_list,
 	 * the pending array.
 	 */
 	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
-		const struct pmu_event *pe;
+		struct pmu_event pe;
 
-		pe = metricgroup__find_metric(cur->key, table);
-		if (pe) {
+		if (metricgroup__find_metric(cur->key, table, &pe)) {
 			pending = realloc(pending,
 					(pending_cnt + 1) * sizeof(struct to_resolve));
 			if (!pending)
 				return -ENOMEM;
 
-			pending[pending_cnt].pe = pe;
+			memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
 			pending[pending_cnt].key = cur->key;
 			pending_cnt++;
 		}
@@ -952,7 +955,7 @@ static int resolve_metric(struct list_head *metric_list,
 	 * context.
 	 */
 	for (i = 0; i < pending_cnt; i++) {
-		ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
+		ret = add_metric(metric_list, &pending[i].pe, modifier, metric_no_group,
 				root_metric, visited, table);
 		if (ret)
 			break;
@@ -1073,7 +1076,7 @@ static int __add_metric(struct list_head *metric_list,
 
 struct metricgroup__find_metric_data {
 	const char *metric;
-	const struct pmu_event *pe;
+	struct pmu_event *pe;
 };
 
 static int metricgroup__find_metric_callback(const struct pmu_event *pe,
@@ -1085,21 +1088,21 @@ static int metricgroup__find_metric_callback(const struct pmu_event *pe,
 	if (!match_metric(pe->metric_name, data->metric))
 		return 0;
 
-	data->pe = pe;
-	return -1;
+	memcpy(data->pe, pe, sizeof(*pe));
+	return 1;
 }
 
-const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_table *table)
+static bool metricgroup__find_metric(const char *metric,
+				     const struct pmu_events_table *table,
+				     struct pmu_event *pe)
 {
 	struct metricgroup__find_metric_data data = {
 		.metric = metric,
-		.pe = NULL,
+		.pe = pe,
 	};
 
-	pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data);
-
-	return data.pe;
+	return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
+		? true : false;
 }
 
 static int add_metric(struct list_head *metric_list,
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index f54d170043e9..016b3b1a289a 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -69,8 +69,6 @@ int metricgroup__parse_groups(const struct option *opt,
 			      bool metric_no_group,
 			      bool metric_no_merge,
 			      struct rblist *metric_events);
-const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_table *table);
 int metricgroup__parse_groups_test(struct evlist *evlist,
 				   const struct pmu_events_table *table,
 				   const char *str,
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 15/17] perf metrics: Copy entire pmu_event in find metric
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

The pmu_event passed to the pmu_events_table_for_each_event is invalid
after the loop. Copy the entire struct in metricgroup__find_metric.
Reduce the scope of this function to static.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/metricgroup.c | 33 ++++++++++++++++++---------------
 tools/perf/util/metricgroup.h |  2 --
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8ef44f4b5e9a..95f4b46dba09 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -879,6 +879,10 @@ struct metricgroup_add_iter_data {
 	const struct pmu_events_table *table;
 };
 
+static bool metricgroup__find_metric(const char *metric,
+				     const struct pmu_events_table *table,
+				     struct pmu_event *pe);
+
 static int add_metric(struct list_head *metric_list,
 		      const struct pmu_event *pe,
 		      const char *modifier,
@@ -914,7 +918,7 @@ static int resolve_metric(struct list_head *metric_list,
 	size_t bkt;
 	struct to_resolve {
 		/* The metric to resolve. */
-		const struct pmu_event *pe;
+		struct pmu_event pe;
 		/*
 		 * The key in the IDs map, this may differ from in case,
 		 * etc. from pe->metric_name.
@@ -928,16 +932,15 @@ static int resolve_metric(struct list_head *metric_list,
 	 * the pending array.
 	 */
 	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
-		const struct pmu_event *pe;
+		struct pmu_event pe;
 
-		pe = metricgroup__find_metric(cur->key, table);
-		if (pe) {
+		if (metricgroup__find_metric(cur->key, table, &pe)) {
 			pending = realloc(pending,
 					(pending_cnt + 1) * sizeof(struct to_resolve));
 			if (!pending)
 				return -ENOMEM;
 
-			pending[pending_cnt].pe = pe;
+			memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
 			pending[pending_cnt].key = cur->key;
 			pending_cnt++;
 		}
@@ -952,7 +955,7 @@ static int resolve_metric(struct list_head *metric_list,
 	 * context.
 	 */
 	for (i = 0; i < pending_cnt; i++) {
-		ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
+		ret = add_metric(metric_list, &pending[i].pe, modifier, metric_no_group,
 				root_metric, visited, table);
 		if (ret)
 			break;
@@ -1073,7 +1076,7 @@ static int __add_metric(struct list_head *metric_list,
 
 struct metricgroup__find_metric_data {
 	const char *metric;
-	const struct pmu_event *pe;
+	struct pmu_event *pe;
 };
 
 static int metricgroup__find_metric_callback(const struct pmu_event *pe,
@@ -1085,21 +1088,21 @@ static int metricgroup__find_metric_callback(const struct pmu_event *pe,
 	if (!match_metric(pe->metric_name, data->metric))
 		return 0;
 
-	data->pe = pe;
-	return -1;
+	memcpy(data->pe, pe, sizeof(*pe));
+	return 1;
 }
 
-const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_table *table)
+static bool metricgroup__find_metric(const char *metric,
+				     const struct pmu_events_table *table,
+				     struct pmu_event *pe)
 {
 	struct metricgroup__find_metric_data data = {
 		.metric = metric,
-		.pe = NULL,
+		.pe = pe,
 	};
 
-	pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data);
-
-	return data.pe;
+	return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
+		? true : false;
 }
 
 static int add_metric(struct list_head *metric_list,
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index f54d170043e9..016b3b1a289a 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -69,8 +69,6 @@ int metricgroup__parse_groups(const struct option *opt,
 			      bool metric_no_group,
 			      bool metric_no_merge,
 			      struct rblist *metric_events);
-const struct pmu_event *metricgroup__find_metric(const char *metric,
-						 const struct pmu_events_table *table);
 int metricgroup__parse_groups_test(struct evlist *evlist,
 				   const struct pmu_events_table *table,
 				   const char *str,
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 16/17] perf jevents: Compress the pmu_events_table
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

The pmu_events array requires 15 pointers per entry which in position
independent code need relocating. Change the array to be an array of
offsets within a big C string. Only the offset of the first variable is
required, subsequent variables are stored in order after the \0
terminator (requiring a byte per variable rather than 4 bytes per
offset).

The file size savings are:
no jevents - the same 19,788,464bytes
x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
default build options plus NO_LIBBFD=1.

For example, the x86 build savings come from .rela.dyn and
.data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
respectively. .rodata increases by 1,432,448bytes, giving an overall
4,766,600bytes saving.

To make metric strings more shareable, the topic is changed from say
'skx metrics' to just 'metrics'.

To try to help with the memory layout the pmu_events are ordered as used
by perf qsort comparator functions.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
 1 file changed, 162 insertions(+), 45 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index aa8df649025a..a5e162558994 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -6,7 +6,8 @@ import csv
 import json
 import os
 import sys
-from typing import (Callable, Optional, Sequence)
+from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
+import collections
 
 # Global command line arguments.
 _args = None
@@ -20,6 +21,19 @@ _arch_std_events = {}
 _close_table = False
 # Events to write out when the table is closed
 _pending_events = []
+# Global BigCString shared by all structures.
+_bcs = None
+# Order specific JsonEvent attributes will be visited.
+_json_event_attributes = [
+    # cmp_sevent related attributes.
+    'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
+    # Seems useful, put it early.
+    'event',
+    # Short things in alphabetical order.
+    'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
+    # Longer things (the last won't be iterated over during decompress).
+    'metric_constraint', 'metric_expr', 'long_desc'
+]
 
 
 def removesuffix(s: str, suffix: str) -> str:
@@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
   tblname += '_' + dirname
   return tblname.replace('-', '_')
 
+def c_len(s: str) -> int:
+  """Return the length of s a C string
+
+  This doesn't handle all escape characters properly. It first assumes
+  all \ are for escaping, it then adjusts as it will have over counted
+  \\. The code uses \000 rather than \0 as a terminator as an adjacent
+  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
+  equal a terminator followed by the number 5 but the escape of
+  \05). The code adjusts for \000 but not properly for all octal, hex
+  or unicode values.
+  """
+  try:
+    utf = s.encode(encoding='utf-8',errors='strict')
+  except:
+    print(f'broken string {s}')
+    raise
+  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
+
+class BigCString:
+  """A class to hold many strings concatenated together.
+
+  Generating a large number of stand-alone C strings creates a large
+  number of relocations in position independent code. The BigCString
+  is a helper for this case. It builds a single string which within it
+  are all the other C strings (to avoid memory issues the string
+  itself is held as a list of strings). The offsets within the big
+  string are recorded and when stored to disk these don't need
+  relocation.
+  """
+  strings: Set[str]
+  big_string: Sequence[str]
+  offsets: Dict[str, int]
+
+  def __init__(self):
+    self.strings = set()
+
+  def add(self, s: str) -> None:
+    """Called to add to the big string."""
+    self.strings.add(s)
+
+  def compute(self) -> None:
+    """Called once all strings are added to compute the string and offsets."""
+
+    # big_string_offset is the current location within the C string
+    # being appended to - comments, etc. don't count. big_string is
+    # the string contents represented as a list. Strings are immutable
+    # in Python and so appending to one causes memory issues, while
+    # lists are mutable.
+    big_string_offset = 0
+    self.big_string = []
+    self.offsets = {}
+    # Emit all strings in a sorted manner.
+    for s in sorted(self.strings):
+      self.offsets[s] = big_string_offset
+      self.big_string.append(f'/* offset={big_string_offset} */ "')
+      self.big_string.append(s)
+      self.big_string.append('"\n')
+      big_string_offset += c_len(s)
+
+_bcs = BigCString()
 
 class JsonEvent:
   """Representation of an event loaded from a json file dictionary."""
@@ -202,26 +276,18 @@ class JsonEvent:
         s += f'\t{attr} = {value},\n'
     return s + '}'
 
+  def build_c_string(self) -> str:
+    s = ''
+    for attr in _json_event_attributes:
+      x = getattr(self, attr)
+      s += f'{x}\\000' if x else '\\000'
+    return s
+
   def to_c_string(self) -> str:
     """Representation of the event as a C struct initializer."""
 
-    def attr_string(attr: str, value: str) -> str:
-      return f'\t.{attr} = \"{value}\",\n'
-
-    def str_if_present(self, attr: str) -> str:
-      if not getattr(self, attr):
-        return ''
-      return attr_string(attr, getattr(self, attr))
-
-    s = '{\n'
-    for attr in [
-        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
-        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
-        'name', 'perpkg', 'pmu', 'topic', 'unit'
-    ]:
-      s += str_if_present(self, attr)
-    s += '},\n'
-    return s
+    s = self.build_c_string()
+    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
 
 
 def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
@@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
     event.topic = topic
   return result
 
-
 def preprocess_arch_std_files(archpath: str) -> None:
   """Read in all architecture standard events."""
   global _arch_std_events
@@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
   global _close_table
   if _close_table:
     raise IOError('Printing table prefix but last table has no suffix')
-  _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
+  _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
   _close_table = True
 
 
@@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
 def print_events_table_suffix() -> None:
   """Optionally close events table."""
 
-  def event_cmp_key(j: JsonEvent):
-    def fix_none(s: str):
+  def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
+    def fix_none(s: Optional[str]) -> str:
       if s is None:
         return ''
       return s
 
-    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
+    return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
             fix_none(j.metric_name))
 
   global _close_table
@@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
     _args.output_file.write(event.to_c_string())
     _pending_events = []
 
-  _args.output_file.write("""{
-\t.name = 0,
-\t.event = 0,
-\t.desc = 0,
-},
-};
-""")
+  _args.output_file.write('};\n\n')
   _close_table = False
 
+def get_topic(topic: str) -> str:
+  if topic.endswith('metrics.json'):
+    return 'metrics'
+  return removesuffix(topic, '.json').replace('-', ' ')
+
+def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
+
+  if item.is_dir():
+    return
+
+  # base dir or too deep
+  level = len(parents)
+  if level == 0 or level > 4:
+    return
+
+  # Ignore other directories. If the file name does not have a .json
+  # extension, ignore it. It could be a readme.txt for instance.
+  if not item.is_file() or not item.name.endswith('.json'):
+    return
+
+  topic = get_topic(item.name)
+  for event in read_json_events(item.path, topic):
+    _bcs.add(event.build_c_string())
 
 def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   """Process a JSON file during the main walk."""
   global _sys_event_tables
 
-  def get_topic(topic: str) -> str:
-    return removesuffix(topic, '.json').replace('-', ' ')
-
   def is_leaf_dir(path: str) -> bool:
     for item in os.scandir(path):
       if item.is_dir():
@@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
   _args.output_file.write("""
 /* Struct used to make the PMU event table implementation opaque to callers. */
 struct pmu_events_table {
-        const struct pmu_event *entries;
+        const struct compact_pmu_event *entries;
+        size_t length;
 };
 
 /*
@@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
       _args.output_file.write("""{
 \t.arch = "testarch",
 \t.cpuid = "testcpu",
-\t.table = { pme_test_soc_cpu },
+\t.table = {
+\t.entries = pme_test_soc_cpu,
+\t.length = ARRAY_SIZE(pme_test_soc_cpu),
+\t}
 },
 """)
     else:
@@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
             _args.output_file.write(f"""{{
 \t.arch = "{arch}",
 \t.cpuid = "{cpuid}",
-\t.table = {{ {tblname} }}
+\t.table = {{
+\t\t.entries = {tblname},
+\t\t.length = ARRAY_SIZE({tblname})
+\t}}
 }},
 """)
           first = False
@@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
   _args.output_file.write("""{
 \t.arch = 0,
 \t.cpuid = 0,
-\t.table = { 0 },
+\t.table = { 0, 0 },
 }
 };
 """)
@@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 """)
   for tblname in _sys_event_tables:
     _args.output_file.write(f"""\t{{
-\t\t.table = {{ {tblname} }},
+\t\t.table = {{
+\t\t\t.entries = {tblname},
+\t\t\t.length = ARRAY_SIZE({tblname})
+\t\t}},
 \t\t.name = \"{tblname}\",
 \t}},
 """)
   _args.output_file.write("""\t{
-\t\t.table = { 0 }
+\t\t.table = { 0, 0 }
 \t},
 };
 
-int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
+static void decompress(int offset, struct pmu_event *pe)
+{
+\tconst char *p = &big_c_string[offset];
+""")
+  for attr in _json_event_attributes:
+    _args.output_file.write(f"""
+\tpe->{attr} = (*p == '\\0' ? NULL : p);
+""")
+    if attr == _json_event_attributes[-1]:
+      continue
+    _args.output_file.write('\twhile (*p++);')
+  _args.output_file.write("""}
+
+int pmu_events_table_for_each_event(const struct pmu_events_table *table,
+                                    pmu_event_iter_fn fn,
                                     void *data)
 {
-        for (const struct pmu_event *pe = &table->entries[0];
-             pe->name || pe->metric_group || pe->metric_name;
-             pe++) {
-                int ret = fn(pe, table, data);
+        for (size_t i = 0; i < table->length; i++) {
+                struct pmu_event pe;
+                int ret;
 
+                decompress(table->entries[i].offset, &pe);
+                ret = fn(&pe, table, data);
                 if (ret)
                         return ret;
         }
@@ -530,7 +634,7 @@ def main() -> None:
       help='Root of tree containing architecture directories containing json files'
   )
   ap.add_argument(
-      'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
+      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
   _args = ap.parse_args()
 
   _args.output_file.write("""
@@ -540,6 +644,10 @@ def main() -> None:
 #include <string.h>
 #include <stddef.h>
 
+struct compact_pmu_event {
+  int offset;
+};
+
 """)
   archs = []
   for item in os.scandir(_args.starting_dir):
@@ -555,6 +663,15 @@ def main() -> None:
   for arch in archs:
     arch_path = f'{_args.starting_dir}/{arch}'
     preprocess_arch_std_files(arch_path)
+    ftw(arch_path, [], preprocess_one_file)
+
+  _bcs.compute()
+  _args.output_file.write('static const char *const big_c_string =\n')
+  for s in _bcs.big_string:
+    _args.output_file.write(s)
+  _args.output_file.write(';\n\n')
+  for arch in archs:
+    arch_path = f'{_args.starting_dir}/{arch}'
     ftw(arch_path, [], process_one_file)
     print_events_table_suffix()
 
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 16/17] perf jevents: Compress the pmu_events_table
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

The pmu_events array requires 15 pointers per entry which in position
independent code need relocating. Change the array to be an array of
offsets within a big C string. Only the offset of the first variable is
required, subsequent variables are stored in order after the \0
terminator (requiring a byte per variable rather than 4 bytes per
offset).

The file size savings are:
no jevents - the same 19,788,464bytes
x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
default build options plus NO_LIBBFD=1.

For example, the x86 build savings come from .rela.dyn and
.data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
respectively. .rodata increases by 1,432,448bytes, giving an overall
4,766,600bytes saving.

To make metric strings more shareable, the topic is changed from say
'skx metrics' to just 'metrics'.

To try to help with the memory layout the pmu_events are ordered as used
by perf qsort comparator functions.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
 1 file changed, 162 insertions(+), 45 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index aa8df649025a..a5e162558994 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -6,7 +6,8 @@ import csv
 import json
 import os
 import sys
-from typing import (Callable, Optional, Sequence)
+from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
+import collections
 
 # Global command line arguments.
 _args = None
@@ -20,6 +21,19 @@ _arch_std_events = {}
 _close_table = False
 # Events to write out when the table is closed
 _pending_events = []
+# Global BigCString shared by all structures.
+_bcs = None
+# Order specific JsonEvent attributes will be visited.
+_json_event_attributes = [
+    # cmp_sevent related attributes.
+    'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
+    # Seems useful, put it early.
+    'event',
+    # Short things in alphabetical order.
+    'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
+    # Longer things (the last won't be iterated over during decompress).
+    'metric_constraint', 'metric_expr', 'long_desc'
+]
 
 
 def removesuffix(s: str, suffix: str) -> str:
@@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
   tblname += '_' + dirname
   return tblname.replace('-', '_')
 
+def c_len(s: str) -> int:
+  """Return the length of s a C string
+
+  This doesn't handle all escape characters properly. It first assumes
+  all \ are for escaping, it then adjusts as it will have over counted
+  \\. The code uses \000 rather than \0 as a terminator as an adjacent
+  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
+  equal a terminator followed by the number 5 but the escape of
+  \05). The code adjusts for \000 but not properly for all octal, hex
+  or unicode values.
+  """
+  try:
+    utf = s.encode(encoding='utf-8',errors='strict')
+  except:
+    print(f'broken string {s}')
+    raise
+  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
+
+class BigCString:
+  """A class to hold many strings concatenated together.
+
+  Generating a large number of stand-alone C strings creates a large
+  number of relocations in position independent code. The BigCString
+  is a helper for this case. It builds a single string which within it
+  are all the other C strings (to avoid memory issues the string
+  itself is held as a list of strings). The offsets within the big
+  string are recorded and when stored to disk these don't need
+  relocation.
+  """
+  strings: Set[str]
+  big_string: Sequence[str]
+  offsets: Dict[str, int]
+
+  def __init__(self):
+    self.strings = set()
+
+  def add(self, s: str) -> None:
+    """Called to add to the big string."""
+    self.strings.add(s)
+
+  def compute(self) -> None:
+    """Called once all strings are added to compute the string and offsets."""
+
+    # big_string_offset is the current location within the C string
+    # being appended to - comments, etc. don't count. big_string is
+    # the string contents represented as a list. Strings are immutable
+    # in Python and so appending to one causes memory issues, while
+    # lists are mutable.
+    big_string_offset = 0
+    self.big_string = []
+    self.offsets = {}
+    # Emit all strings in a sorted manner.
+    for s in sorted(self.strings):
+      self.offsets[s] = big_string_offset
+      self.big_string.append(f'/* offset={big_string_offset} */ "')
+      self.big_string.append(s)
+      self.big_string.append('"\n')
+      big_string_offset += c_len(s)
+
+_bcs = BigCString()
 
 class JsonEvent:
   """Representation of an event loaded from a json file dictionary."""
@@ -202,26 +276,18 @@ class JsonEvent:
         s += f'\t{attr} = {value},\n'
     return s + '}'
 
+  def build_c_string(self) -> str:
+    s = ''
+    for attr in _json_event_attributes:
+      x = getattr(self, attr)
+      s += f'{x}\\000' if x else '\\000'
+    return s
+
   def to_c_string(self) -> str:
     """Representation of the event as a C struct initializer."""
 
-    def attr_string(attr: str, value: str) -> str:
-      return f'\t.{attr} = \"{value}\",\n'
-
-    def str_if_present(self, attr: str) -> str:
-      if not getattr(self, attr):
-        return ''
-      return attr_string(attr, getattr(self, attr))
-
-    s = '{\n'
-    for attr in [
-        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
-        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
-        'name', 'perpkg', 'pmu', 'topic', 'unit'
-    ]:
-      s += str_if_present(self, attr)
-    s += '},\n'
-    return s
+    s = self.build_c_string()
+    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
 
 
 def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
@@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
     event.topic = topic
   return result
 
-
 def preprocess_arch_std_files(archpath: str) -> None:
   """Read in all architecture standard events."""
   global _arch_std_events
@@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
   global _close_table
   if _close_table:
     raise IOError('Printing table prefix but last table has no suffix')
-  _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
+  _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
   _close_table = True
 
 
@@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
 def print_events_table_suffix() -> None:
   """Optionally close events table."""
 
-  def event_cmp_key(j: JsonEvent):
-    def fix_none(s: str):
+  def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
+    def fix_none(s: Optional[str]) -> str:
       if s is None:
         return ''
       return s
 
-    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
+    return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
             fix_none(j.metric_name))
 
   global _close_table
@@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
     _args.output_file.write(event.to_c_string())
     _pending_events = []
 
-  _args.output_file.write("""{
-\t.name = 0,
-\t.event = 0,
-\t.desc = 0,
-},
-};
-""")
+  _args.output_file.write('};\n\n')
   _close_table = False
 
+def get_topic(topic: str) -> str:
+  if topic.endswith('metrics.json'):
+    return 'metrics'
+  return removesuffix(topic, '.json').replace('-', ' ')
+
+def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
+
+  if item.is_dir():
+    return
+
+  # base dir or too deep
+  level = len(parents)
+  if level == 0 or level > 4:
+    return
+
+  # Ignore other directories. If the file name does not have a .json
+  # extension, ignore it. It could be a readme.txt for instance.
+  if not item.is_file() or not item.name.endswith('.json'):
+    return
+
+  topic = get_topic(item.name)
+  for event in read_json_events(item.path, topic):
+    _bcs.add(event.build_c_string())
 
 def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   """Process a JSON file during the main walk."""
   global _sys_event_tables
 
-  def get_topic(topic: str) -> str:
-    return removesuffix(topic, '.json').replace('-', ' ')
-
   def is_leaf_dir(path: str) -> bool:
     for item in os.scandir(path):
       if item.is_dir():
@@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
   _args.output_file.write("""
 /* Struct used to make the PMU event table implementation opaque to callers. */
 struct pmu_events_table {
-        const struct pmu_event *entries;
+        const struct compact_pmu_event *entries;
+        size_t length;
 };
 
 /*
@@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
       _args.output_file.write("""{
 \t.arch = "testarch",
 \t.cpuid = "testcpu",
-\t.table = { pme_test_soc_cpu },
+\t.table = {
+\t.entries = pme_test_soc_cpu,
+\t.length = ARRAY_SIZE(pme_test_soc_cpu),
+\t}
 },
 """)
     else:
@@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
             _args.output_file.write(f"""{{
 \t.arch = "{arch}",
 \t.cpuid = "{cpuid}",
-\t.table = {{ {tblname} }}
+\t.table = {{
+\t\t.entries = {tblname},
+\t\t.length = ARRAY_SIZE({tblname})
+\t}}
 }},
 """)
           first = False
@@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
   _args.output_file.write("""{
 \t.arch = 0,
 \t.cpuid = 0,
-\t.table = { 0 },
+\t.table = { 0, 0 },
 }
 };
 """)
@@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 """)
   for tblname in _sys_event_tables:
     _args.output_file.write(f"""\t{{
-\t\t.table = {{ {tblname} }},
+\t\t.table = {{
+\t\t\t.entries = {tblname},
+\t\t\t.length = ARRAY_SIZE({tblname})
+\t\t}},
 \t\t.name = \"{tblname}\",
 \t}},
 """)
   _args.output_file.write("""\t{
-\t\t.table = { 0 }
+\t\t.table = { 0, 0 }
 \t},
 };
 
-int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
+static void decompress(int offset, struct pmu_event *pe)
+{
+\tconst char *p = &big_c_string[offset];
+""")
+  for attr in _json_event_attributes:
+    _args.output_file.write(f"""
+\tpe->{attr} = (*p == '\\0' ? NULL : p);
+""")
+    if attr == _json_event_attributes[-1]:
+      continue
+    _args.output_file.write('\twhile (*p++);')
+  _args.output_file.write("""}
+
+int pmu_events_table_for_each_event(const struct pmu_events_table *table,
+                                    pmu_event_iter_fn fn,
                                     void *data)
 {
-        for (const struct pmu_event *pe = &table->entries[0];
-             pe->name || pe->metric_group || pe->metric_name;
-             pe++) {
-                int ret = fn(pe, table, data);
+        for (size_t i = 0; i < table->length; i++) {
+                struct pmu_event pe;
+                int ret;
 
+                decompress(table->entries[i].offset, &pe);
+                ret = fn(&pe, table, data);
                 if (ret)
                         return ret;
         }
@@ -530,7 +634,7 @@ def main() -> None:
       help='Root of tree containing architecture directories containing json files'
   )
   ap.add_argument(
-      'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
+      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
   _args = ap.parse_args()
 
   _args.output_file.write("""
@@ -540,6 +644,10 @@ def main() -> None:
 #include <string.h>
 #include <stddef.h>
 
+struct compact_pmu_event {
+  int offset;
+};
+
 """)
   archs = []
   for item in os.scandir(_args.starting_dir):
@@ -555,6 +663,15 @@ def main() -> None:
   for arch in archs:
     arch_path = f'{_args.starting_dir}/{arch}'
     preprocess_arch_std_files(arch_path)
+    ftw(arch_path, [], preprocess_one_file)
+
+  _bcs.compute()
+  _args.output_file.write('static const char *const big_c_string =\n')
+  for s in _bcs.big_string:
+    _args.output_file.write(s)
+  _args.output_file.write(';\n\n')
+  for arch in archs:
+    arch_path = f'{_args.starting_dir}/{arch}'
     ftw(arch_path, [], process_one_file)
     print_events_table_suffix()
 
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 17/17] perf jevents: Fold strings optimization
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-04 22:18   ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

If a shorter string ends a longer string then the shorter string may
reuse the longer string at an offset. For example, on x86 the event
arith.cycles_div_busy and cycles_div_busy can be folded, even though
they have difference names the strings are identical after 6
characters. cycles_div_busy can reuse the arith.cycles_div_busy string
at an offset of 6.

In pmu-events.c this looks like the following where the 'also:' lists
folded strings:
/* offset=177541 */ "arith.cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000" /* also: cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000 */

As jevents.py combines multiple strings for an event into a larger
string, the amount of folding is minimal as all parts of the event must
align. Other organizations can benefit more from folding, but lose space
by say recording more offsets.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 55 ++++++++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index a5e162558994..e5545758c92d 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -80,7 +80,9 @@ class BigCString:
   are all the other C strings (to avoid memory issues the string
   itself is held as a list of strings). The offsets within the big
   string are recorded and when stored to disk these don't need
-  relocation.
+  relocation. To reduce the size of the string further, identical
+  strings are merged. If a longer string ends-with the same value as a
+  shorter string, these entries are also merged.
   """
   strings: Set[str]
   big_string: Sequence[str]
@@ -96,6 +98,33 @@ class BigCString:
   def compute(self) -> None:
     """Called once all strings are added to compute the string and offsets."""
 
+    folded_strings = {}
+    # Determine if two strings can be folded, ie. let 1 string use the
+    # end of another. First reverse all strings and sort them.
+    sorted_reversed_strings = sorted([x[::-1] for x in self.strings])
+
+    # Strings 'xyz' and 'yz' will now be [ 'zy', 'zyx' ]. Scan forward
+    # for each string to see if there is a better candidate to fold it
+    # into, in the example rather than using 'yz' we can use'xyz' at
+    # an offset of 1. We record which string can be folded into which
+    # in folded_strings, we don't need to record the offset as it is
+    # trivially computed from the string lengths.
+    for pos,s in enumerate(sorted_reversed_strings):
+      best_pos = pos
+      for check_pos in range(pos + 1, len(sorted_reversed_strings)):
+        if sorted_reversed_strings[check_pos].startswith(s):
+          best_pos = check_pos
+        else:
+          break
+      if pos != best_pos:
+        folded_strings[s[::-1]] = sorted_reversed_strings[best_pos][::-1]
+
+    # Compute reverse mappings for debugging.
+    fold_into_strings = collections.defaultdict(set)
+    for key, val in folded_strings.items():
+      if key != val:
+        fold_into_strings[val].add(key)
+
     # big_string_offset is the current location within the C string
     # being appended to - comments, etc. don't count. big_string is
     # the string contents represented as a list. Strings are immutable
@@ -104,13 +133,25 @@ class BigCString:
     big_string_offset = 0
     self.big_string = []
     self.offsets = {}
-    # Emit all strings in a sorted manner.
+
+    # Emit all strings that aren't folded in a sorted manner.
     for s in sorted(self.strings):
-      self.offsets[s] = big_string_offset
-      self.big_string.append(f'/* offset={big_string_offset} */ "')
-      self.big_string.append(s)
-      self.big_string.append('"\n')
-      big_string_offset += c_len(s)
+      if s not in folded_strings:
+        self.offsets[s] = big_string_offset
+        self.big_string.append(f'/* offset={big_string_offset} */ "')
+        self.big_string.append(s)
+        self.big_string.append('"')
+        if s in fold_into_strings:
+          self.big_string.append(' /* also: ' + ', '.join(fold_into_strings[s]) + ' */')
+        self.big_string.append('\n')
+        big_string_offset += c_len(s)
+        continue
+
+    # Compute the offsets of the folded strings.
+    for s in folded_strings.keys():
+      assert s not in self.offsets
+      folded_s = folded_strings[s]
+      self.offsets[s] = self.offsets[folded_s] + c_len(folded_s) - c_len(s)
 
 _bcs = BigCString()
 
-- 
2.37.1.559.g78731f0fdb-goog


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v4 17/17] perf jevents: Fold strings optimization
@ 2022-08-04 22:18   ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-04 22:18 UTC (permalink / raw)
  To: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian, Ian Rogers

If a shorter string ends a longer string then the shorter string may
reuse the longer string at an offset. For example, on x86 the event
arith.cycles_div_busy and cycles_div_busy can be folded, even though
they have difference names the strings are identical after 6
characters. cycles_div_busy can reuse the arith.cycles_div_busy string
at an offset of 6.

In pmu-events.c this looks like the following where the 'also:' lists
folded strings:
/* offset=177541 */ "arith.cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000" /* also: cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000 */

As jevents.py combines multiple strings for an event into a larger
string, the amount of folding is minimal as all parts of the event must
align. Other organizations can benefit more from folding, but lose space
by say recording more offsets.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 55 ++++++++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index a5e162558994..e5545758c92d 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -80,7 +80,9 @@ class BigCString:
   are all the other C strings (to avoid memory issues the string
   itself is held as a list of strings). The offsets within the big
   string are recorded and when stored to disk these don't need
-  relocation.
+  relocation. To reduce the size of the string further, identical
+  strings are merged. If a longer string ends-with the same value as a
+  shorter string, these entries are also merged.
   """
   strings: Set[str]
   big_string: Sequence[str]
@@ -96,6 +98,33 @@ class BigCString:
   def compute(self) -> None:
     """Called once all strings are added to compute the string and offsets."""
 
+    folded_strings = {}
+    # Determine if two strings can be folded, ie. let 1 string use the
+    # end of another. First reverse all strings and sort them.
+    sorted_reversed_strings = sorted([x[::-1] for x in self.strings])
+
+    # Strings 'xyz' and 'yz' will now be [ 'zy', 'zyx' ]. Scan forward
+    # for each string to see if there is a better candidate to fold it
+    # into, in the example rather than using 'yz' we can use'xyz' at
+    # an offset of 1. We record which string can be folded into which
+    # in folded_strings, we don't need to record the offset as it is
+    # trivially computed from the string lengths.
+    for pos,s in enumerate(sorted_reversed_strings):
+      best_pos = pos
+      for check_pos in range(pos + 1, len(sorted_reversed_strings)):
+        if sorted_reversed_strings[check_pos].startswith(s):
+          best_pos = check_pos
+        else:
+          break
+      if pos != best_pos:
+        folded_strings[s[::-1]] = sorted_reversed_strings[best_pos][::-1]
+
+    # Compute reverse mappings for debugging.
+    fold_into_strings = collections.defaultdict(set)
+    for key, val in folded_strings.items():
+      if key != val:
+        fold_into_strings[val].add(key)
+
     # big_string_offset is the current location within the C string
     # being appended to - comments, etc. don't count. big_string is
     # the string contents represented as a list. Strings are immutable
@@ -104,13 +133,25 @@ class BigCString:
     big_string_offset = 0
     self.big_string = []
     self.offsets = {}
-    # Emit all strings in a sorted manner.
+
+    # Emit all strings that aren't folded in a sorted manner.
     for s in sorted(self.strings):
-      self.offsets[s] = big_string_offset
-      self.big_string.append(f'/* offset={big_string_offset} */ "')
-      self.big_string.append(s)
-      self.big_string.append('"\n')
-      big_string_offset += c_len(s)
+      if s not in folded_strings:
+        self.offsets[s] = big_string_offset
+        self.big_string.append(f'/* offset={big_string_offset} */ "')
+        self.big_string.append(s)
+        self.big_string.append('"')
+        if s in fold_into_strings:
+          self.big_string.append(' /* also: ' + ', '.join(fold_into_strings[s]) + ' */')
+        self.big_string.append('\n')
+        big_string_offset += c_len(s)
+        continue
+
+    # Compute the offsets of the folded strings.
+    for s in folded_strings.keys():
+      assert s not in self.offsets
+      folded_s = folded_strings[s]
+      self.offsets[s] = self.offsets[folded_s] + c_len(folded_s) - c_len(s)
 
 _bcs = BigCString()
 
-- 
2.37.1.559.g78731f0fdb-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 03/17] perf jevents: Add JEVENTS_ARCH make option
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05  9:55     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05  9:55 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Allow the architecture built into pmu-events.c to be set on the make
> command line with JEVENTS_ARCH.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>

Seems reasonable, so:

Reviewed-by: John Garry <john.garry@huawei.com>

I assume that if we run on the wrong arch (than we build for) then it 
has same effect as if pmu-events is not supported.

> ---
>   tools/perf/pmu-events/Build | 6 +++++-
>   1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
> index 28a9d01b08af..04ef95174660 100644
> --- a/tools/perf/pmu-events/Build
> +++ b/tools/perf/pmu-events/Build
> @@ -7,6 +7,10 @@ JSON_TEST	=  $(shell [ -d $(JDIR_TEST) ] &&			\
>   			find $(JDIR_TEST) -name '*.json')
>   JEVENTS_PY	=  pmu-events/jevents.py
>   
> +ifeq ($(JEVENTS_ARCH),)
> +JEVENTS_ARCH=$(SRCARCH)
> +endif
> +
>   #
>   # Locate/process JSON files in pmu-events/arch/
>   # directory and create tables in pmu-events.c.
> @@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
>   else
>   $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
>   	$(call rule_mkdir)
> -	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
> +	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
>   endif


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 03/17] perf jevents: Add JEVENTS_ARCH make option
@ 2022-08-05  9:55     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05  9:55 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Allow the architecture built into pmu-events.c to be set on the make
> command line with JEVENTS_ARCH.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>

Seems reasonable, so:

Reviewed-by: John Garry <john.garry@huawei.com>

I assume that if we run on the wrong arch (than we build for) then it 
has same effect as if pmu-events is not supported.

> ---
>   tools/perf/pmu-events/Build | 6 +++++-
>   1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
> index 28a9d01b08af..04ef95174660 100644
> --- a/tools/perf/pmu-events/Build
> +++ b/tools/perf/pmu-events/Build
> @@ -7,6 +7,10 @@ JSON_TEST	=  $(shell [ -d $(JDIR_TEST) ] &&			\
>   			find $(JDIR_TEST) -name '*.json')
>   JEVENTS_PY	=  pmu-events/jevents.py
>   
> +ifeq ($(JEVENTS_ARCH),)
> +JEVENTS_ARCH=$(SRCARCH)
> +endif
> +
>   #
>   # Locate/process JSON files in pmu-events/arch/
>   # directory and create tables in pmu-events.c.
> @@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
>   else
>   $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
>   	$(call rule_mkdir)
> -	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
> +	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
>   endif


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 04/17] perf jevent: Add an 'all' architecture argument
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 10:34     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 10:34 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> When 'all' is passed as the architecture generate a mapping table for
> all architectures. This simplifies testing. To identify the table for an
> architecture add an arch variable to the pmu_events_map.

so could this 'all' arg ever passed for perf test? I thought maybe we 
could use to verify tables for all architectures - I didn't think that 
we did it today.

Thanks,
John

> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/empty-pmu-events.c |  2 +
>   tools/perf/pmu-events/jevents.py         | 70 +++++++++++++++---------
>   tools/perf/pmu-events/pmu-events.h       |  1 +
>   tools/perf/tests/pmu-events.c            |  3 +-
>   4 files changed, 47 insertions(+), 29 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 77e655c6f116..d8cf9283e486 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -110,12 +110,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
>   
>   const struct pmu_events_map pmu_events_map[] = {
>   	{
> +		.arch = "testarch",
>   		.cpuid = "testcpu",
>   		.version = "v1",
>   		.type = "core",
>   		.table = pme_test_soc_cpu,
>   	},
>   	{
> +		.arch = 0,
>   		.cpuid = 0,
>   		.version = 0,
>   		.type = 0,
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index cdfa4e0e7557..e6e6c42c3f8a 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -304,38 +304,45 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>     print_events_table_entries(item, get_topic(item.name))
>   
>   
> -def print_mapping_table() -> None:
> +def print_mapping_table(archs: Sequence[str]) -> None:
>     """Read the mapfile and generate the struct from cpuid string to event table."""
> -  with open(f'{_args.starting_dir}/{_args.arch}/mapfile.csv') as csvfile:
> -    table = csv.reader(csvfile)
> -    _args.output_file.write(
> -        'const struct pmu_events_map pmu_events_map[] = {\n')
> -    first = True
> -    for row in table:
> -      # Skip the first row or any row beginning with #.
> -      if not first and len(row) > 0 and not row[0].startswith('#'):
> -        tblname = file_name_to_table_name([], row[2].replace('/', '_'))
> -        _args.output_file.write("""{
> -\t.cpuid = \"%s\",
> -\t.version = \"%s\",
> -\t.type = \"%s\",
> -\t.table = %s
> -},
> -""" % (row[0].replace('\\', '\\\\'), row[1], row[3], tblname))
> -      first = False
> -
> -  _args.output_file.write("""{
> +  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> +  for arch in archs:
> +    if arch == 'test':
> +      _args.output_file.write("""{
> +\t.arch = "testarch",
>   \t.cpuid = "testcpu",
>   \t.version = "v1",
>   \t.type = "core",
>   \t.table = pme_test_soc_cpu,
>   },
> -{
> +""")
> +    else:
> +      with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
> +        table = csv.reader(csvfile)
> +        first = True
> +        for row in table:
> +          # Skip the first row or any row beginning with #.
> +          if not first and len(row) > 0 and not row[0].startswith('#'):
> +            tblname = file_name_to_table_name([], row[2].replace('/', '_'))
> +            cpuid = row[0].replace('\\', '\\\\')
> +            _args.output_file.write(f"""{{
> +\t.arch = "{arch}",
> +\t.cpuid = "{cpuid}",
> +\t.version = "{row[1]}",
> +\t.type = "{row[3]}",
> +\t.table = {tblname}
> +}},
> +""")
> +          first = False
> +
> +  _args.output_file.write("""{
> +\t.arch = 0,
>   \t.cpuid = 0,
>   \t.version = 0,
>   \t.type = 0,
>   \t.table = 0,
> -},
> +}
>   };
>   """)
>   
> @@ -386,15 +393,24 @@ def main() -> None:
>     _args = ap.parse_args()
>   
>     _args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
> -  for path in [_args.arch, 'test']:
> -    arch_path = f'{_args.starting_dir}/{path}'
> -    if not os.path.isdir(arch_path):
> -      raise IOError(f'Missing architecture directory in \'{arch_path}\'')
> +  archs = []
> +  for item in os.scandir(_args.starting_dir):
> +    if not item.is_dir():
> +      continue
> +    if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
> +      archs.append(item.name)
> +
> +  if len(archs) < 2:
> +    raise IOError(f'Missing architecture directory \'{_args.arch}\'')
> +
> +  archs.sort()
> +  for arch in archs:
> +    arch_path = f'{_args.starting_dir}/{arch}'
>       preprocess_arch_std_files(arch_path)
>       ftw(arch_path, [], process_one_file)
>       print_events_table_suffix()
>   
> -  print_mapping_table()
> +  print_mapping_table(archs)
>     print_system_mapping_table()
>   
>   
> diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
> index 6efe73976440..7a360792635f 100644
> --- a/tools/perf/pmu-events/pmu-events.h
> +++ b/tools/perf/pmu-events/pmu-events.h
> @@ -38,6 +38,7 @@ struct pmu_event {
>    * The  cpuid can contain any character other than the comma.
>    */
>   struct pmu_events_map {
> +	const char *arch;
>   	const char *cpuid;
>   	const char *version;
>   	const char *type;		/* core, uncore etc */
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index 263cbb67c861..82192f1a7bf7 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -864,8 +864,7 @@ static void expr_failure(const char *msg,
>   			 const struct pmu_events_map *map,
>   			 const struct pmu_event *pe)
>   {
> -	pr_debug("%s for map %s %s %s\n",
> -		msg, map->cpuid, map->version, map->type);
> +	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
>   	pr_debug("On metric %s\n", pe->metric_name);
>   	pr_debug("On expression %s\n", pe->metric_expr);
>   }


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 04/17] perf jevent: Add an 'all' architecture argument
@ 2022-08-05 10:34     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 10:34 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> When 'all' is passed as the architecture generate a mapping table for
> all architectures. This simplifies testing. To identify the table for an
> architecture add an arch variable to the pmu_events_map.

so could this 'all' arg ever passed for perf test? I thought maybe we 
could use to verify tables for all architectures - I didn't think that 
we did it today.

Thanks,
John

> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/empty-pmu-events.c |  2 +
>   tools/perf/pmu-events/jevents.py         | 70 +++++++++++++++---------
>   tools/perf/pmu-events/pmu-events.h       |  1 +
>   tools/perf/tests/pmu-events.c            |  3 +-
>   4 files changed, 47 insertions(+), 29 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 77e655c6f116..d8cf9283e486 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -110,12 +110,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
>   
>   const struct pmu_events_map pmu_events_map[] = {
>   	{
> +		.arch = "testarch",
>   		.cpuid = "testcpu",
>   		.version = "v1",
>   		.type = "core",
>   		.table = pme_test_soc_cpu,
>   	},
>   	{
> +		.arch = 0,
>   		.cpuid = 0,
>   		.version = 0,
>   		.type = 0,
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index cdfa4e0e7557..e6e6c42c3f8a 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -304,38 +304,45 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>     print_events_table_entries(item, get_topic(item.name))
>   
>   
> -def print_mapping_table() -> None:
> +def print_mapping_table(archs: Sequence[str]) -> None:
>     """Read the mapfile and generate the struct from cpuid string to event table."""
> -  with open(f'{_args.starting_dir}/{_args.arch}/mapfile.csv') as csvfile:
> -    table = csv.reader(csvfile)
> -    _args.output_file.write(
> -        'const struct pmu_events_map pmu_events_map[] = {\n')
> -    first = True
> -    for row in table:
> -      # Skip the first row or any row beginning with #.
> -      if not first and len(row) > 0 and not row[0].startswith('#'):
> -        tblname = file_name_to_table_name([], row[2].replace('/', '_'))
> -        _args.output_file.write("""{
> -\t.cpuid = \"%s\",
> -\t.version = \"%s\",
> -\t.type = \"%s\",
> -\t.table = %s
> -},
> -""" % (row[0].replace('\\', '\\\\'), row[1], row[3], tblname))
> -      first = False
> -
> -  _args.output_file.write("""{
> +  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> +  for arch in archs:
> +    if arch == 'test':
> +      _args.output_file.write("""{
> +\t.arch = "testarch",
>   \t.cpuid = "testcpu",
>   \t.version = "v1",
>   \t.type = "core",
>   \t.table = pme_test_soc_cpu,
>   },
> -{
> +""")
> +    else:
> +      with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
> +        table = csv.reader(csvfile)
> +        first = True
> +        for row in table:
> +          # Skip the first row or any row beginning with #.
> +          if not first and len(row) > 0 and not row[0].startswith('#'):
> +            tblname = file_name_to_table_name([], row[2].replace('/', '_'))
> +            cpuid = row[0].replace('\\', '\\\\')
> +            _args.output_file.write(f"""{{
> +\t.arch = "{arch}",
> +\t.cpuid = "{cpuid}",
> +\t.version = "{row[1]}",
> +\t.type = "{row[3]}",
> +\t.table = {tblname}
> +}},
> +""")
> +          first = False
> +
> +  _args.output_file.write("""{
> +\t.arch = 0,
>   \t.cpuid = 0,
>   \t.version = 0,
>   \t.type = 0,
>   \t.table = 0,
> -},
> +}
>   };
>   """)
>   
> @@ -386,15 +393,24 @@ def main() -> None:
>     _args = ap.parse_args()
>   
>     _args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
> -  for path in [_args.arch, 'test']:
> -    arch_path = f'{_args.starting_dir}/{path}'
> -    if not os.path.isdir(arch_path):
> -      raise IOError(f'Missing architecture directory in \'{arch_path}\'')
> +  archs = []
> +  for item in os.scandir(_args.starting_dir):
> +    if not item.is_dir():
> +      continue
> +    if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
> +      archs.append(item.name)
> +
> +  if len(archs) < 2:
> +    raise IOError(f'Missing architecture directory \'{_args.arch}\'')
> +
> +  archs.sort()
> +  for arch in archs:
> +    arch_path = f'{_args.starting_dir}/{arch}'
>       preprocess_arch_std_files(arch_path)
>       ftw(arch_path, [], process_one_file)
>       print_events_table_suffix()
>   
> -  print_mapping_table()
> +  print_mapping_table(archs)
>     print_system_mapping_table()
>   
>   
> diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
> index 6efe73976440..7a360792635f 100644
> --- a/tools/perf/pmu-events/pmu-events.h
> +++ b/tools/perf/pmu-events/pmu-events.h
> @@ -38,6 +38,7 @@ struct pmu_event {
>    * The  cpuid can contain any character other than the comma.
>    */
>   struct pmu_events_map {
> +	const char *arch;
>   	const char *cpuid;
>   	const char *version;
>   	const char *type;		/* core, uncore etc */
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index 263cbb67c861..82192f1a7bf7 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -864,8 +864,7 @@ static void expr_failure(const char *msg,
>   			 const struct pmu_events_map *map,
>   			 const struct pmu_event *pe)
>   {
> -	pr_debug("%s for map %s %s %s\n",
> -		msg, map->cpuid, map->version, map->type);
> +	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
>   	pr_debug("On metric %s\n", pe->metric_name);
>   	pr_debug("On expression %s\n", pe->metric_expr);
>   }


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 05/17] perf jevents: Remove the type/version variables
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 10:35     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 10:35 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> pmu_events_map has a type variable that is always initialized to "core"
> and a version variable that is never read. Remove these from the API as
> it is straightforward to add them back when necessary.
> 

it might be worth mentioning why we don't want the fields removed from 
the per-arch mapfile.csv

> Signed-off-by: Ian Rogers<irogers@google.com>

Reviewed-by: John Garry <john.garry@huawei.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 05/17] perf jevents: Remove the type/version variables
@ 2022-08-05 10:35     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 10:35 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> pmu_events_map has a type variable that is always initialized to "core"
> and a version variable that is never read. Remove these from the API as
> it is straightforward to add them back when necessary.
> 

it might be worth mentioning why we don't want the fields removed from 
the per-arch mapfile.csv

> Signed-off-by: Ian Rogers<irogers@google.com>

Reviewed-by: John Garry <john.garry@huawei.com>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 07/17] perf jevents: Sort json files entries
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 10:49     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 10:49 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Sort the json files entries on conversion to C. The sort order tries to
> replicated cmp_sevent from pmu.c so that the input there is already

replicate

> sorted except for sysfs events.
> 
> Add the topic to JsonEvent on reading to simplify. Remove an unnecessary
> lambda in the json reading.

We sort the attributes of the events alphabetically by attribute name, 
right? Is there any advantage in this? Do we need it for later?

thanks,
John

> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/jevents.py | 48 +++++++++++++++++++++++---------
>   1 file changed, 35 insertions(+), 13 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 12d2daf3570c..30e0e792221a 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -18,6 +18,8 @@ _sys_event_tables = []
>   _arch_std_events = {}
>   # Track whether an events table is currently being defined and needs closing.
>   _close_table = False
> +# Events to write out when the table is closed
> +_pending_events = []
>   
>   
>   def removesuffix(s: str, suffix: str) -> str:
> @@ -127,6 +129,7 @@ class JsonEvent:
>         eventcode |= int(jd['ExtSel']) << 8
>       configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
>       self.name = jd['EventName'].lower() if 'EventName' in jd else None
> +    self.topic = ''
>       self.compat = jd.get('Compat')
>       self.desc = fixdesc(jd.get('BriefDescription'))
>       self.long_desc = fixdesc(jd.get('PublicDescription'))
> @@ -199,7 +202,7 @@ class JsonEvent:
>           s += f'\t{attr} = {value},\n'
>       return s + '}'
>   
> -  def to_c_string(self, topic_local: str) -> str:
> +  def to_c_string(self) -> str:
>       """Representation of the event as a C struct initializer."""
>   
>       def attr_string(attr: str, value: str) -> str:
> @@ -211,25 +214,27 @@ class JsonEvent:
>         return attr_string(attr, getattr(self, attr))
>   
>       s = '{\n'
> -    s += f'\t.topic = "{topic_local}",\n'
>       for attr in [
>           'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
>           'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> -        'name', 'perpkg', 'pmu', 'unit'
> +        'name', 'perpkg', 'pmu', 'topic', 'unit'
>       ]:
>         s += str_if_present(self, attr)
>       s += '},\n'
>       return s
>   
>   
> -def read_json_events(path: str) -> Sequence[JsonEvent]:
> +def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
>     """Read json events from the specified file."""
>   
>     try:
> -    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
> +    result = json.load(open(path), object_hook=JsonEvent)
>     except BaseException as err:
>       print(f"Exception processing {path}")
>       raise
> +  for event in result:
> +    event.topic = topic
> +  return result
>   
>   
>   def preprocess_arch_std_files(archpath: str) -> None:
> @@ -237,7 +242,7 @@ def preprocess_arch_std_files(archpath: str) -> None:
>     global _arch_std_events
>     for item in os.scandir(archpath):
>       if item.is_file() and item.name.endswith('.json'):
> -      for event in read_json_events(item.path):
> +      for event in read_json_events(item.path, topic=''):
>           if event.name:
>             _arch_std_events[event.name.lower()] = event
>   
> @@ -251,19 +256,36 @@ def print_events_table_prefix(tblname: str) -> None:
>     _close_table = True
>   
>   
> -def print_events_table_entries(item: os.DirEntry, topic: str) -> None:
> -  """Create contents of an events table."""
> +def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> +  """Add contents of file to _pending_events table."""
>     if not _close_table:
>       raise IOError('Table entries missing prefix')
> -  for event in read_json_events(item.path):
> -    _args.output_file.write(event.to_c_string(topic))
> +  for e in read_json_events(item.path, topic):
> +    _pending_events.append(e)
>   
>   
>   def print_events_table_suffix() -> None:
>     """Optionally close events table."""
> +
> +  def event_cmp_key(j: JsonEvent):
> +    def fix_none(s: str):
> +      if s is None:
> +        return ''
> +      return s
> +
> +    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> +            fix_none(j.metric_name))
> +
>     global _close_table
> -  if _close_table:
> -    _args.output_file.write("""{
> +  if not _close_table:
> +    return
> +
> +  global _pending_events
> +  for event in sorted(_pending_events, key=event_cmp_key):
> +    _args.output_file.write(event.to_c_string())
> +    _pending_events = []
> +
> +  _args.output_file.write("""{
>   \t.name = 0,
>   \t.event = 0,
>   \t.desc = 0,
> @@ -306,7 +328,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>     if not item.is_file() or not item.name.endswith('.json'):
>       return
>   
> -  print_events_table_entries(item, get_topic(item.name))
> +  add_events_table_entries(item, get_topic(item.name))
>   
>   
>   def print_mapping_table(archs: Sequence[str]) -> None:


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 07/17] perf jevents: Sort json files entries
@ 2022-08-05 10:49     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 10:49 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Sort the json files entries on conversion to C. The sort order tries to
> replicated cmp_sevent from pmu.c so that the input there is already

replicate

> sorted except for sysfs events.
> 
> Add the topic to JsonEvent on reading to simplify. Remove an unnecessary
> lambda in the json reading.

We sort the attributes of the events alphabetically by attribute name, 
right? Is there any advantage in this? Do we need it for later?

thanks,
John

> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/jevents.py | 48 +++++++++++++++++++++++---------
>   1 file changed, 35 insertions(+), 13 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 12d2daf3570c..30e0e792221a 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -18,6 +18,8 @@ _sys_event_tables = []
>   _arch_std_events = {}
>   # Track whether an events table is currently being defined and needs closing.
>   _close_table = False
> +# Events to write out when the table is closed
> +_pending_events = []
>   
>   
>   def removesuffix(s: str, suffix: str) -> str:
> @@ -127,6 +129,7 @@ class JsonEvent:
>         eventcode |= int(jd['ExtSel']) << 8
>       configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
>       self.name = jd['EventName'].lower() if 'EventName' in jd else None
> +    self.topic = ''
>       self.compat = jd.get('Compat')
>       self.desc = fixdesc(jd.get('BriefDescription'))
>       self.long_desc = fixdesc(jd.get('PublicDescription'))
> @@ -199,7 +202,7 @@ class JsonEvent:
>           s += f'\t{attr} = {value},\n'
>       return s + '}'
>   
> -  def to_c_string(self, topic_local: str) -> str:
> +  def to_c_string(self) -> str:
>       """Representation of the event as a C struct initializer."""
>   
>       def attr_string(attr: str, value: str) -> str:
> @@ -211,25 +214,27 @@ class JsonEvent:
>         return attr_string(attr, getattr(self, attr))
>   
>       s = '{\n'
> -    s += f'\t.topic = "{topic_local}",\n'
>       for attr in [
>           'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
>           'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> -        'name', 'perpkg', 'pmu', 'unit'
> +        'name', 'perpkg', 'pmu', 'topic', 'unit'
>       ]:
>         s += str_if_present(self, attr)
>       s += '},\n'
>       return s
>   
>   
> -def read_json_events(path: str) -> Sequence[JsonEvent]:
> +def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
>     """Read json events from the specified file."""
>   
>     try:
> -    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
> +    result = json.load(open(path), object_hook=JsonEvent)
>     except BaseException as err:
>       print(f"Exception processing {path}")
>       raise
> +  for event in result:
> +    event.topic = topic
> +  return result
>   
>   
>   def preprocess_arch_std_files(archpath: str) -> None:
> @@ -237,7 +242,7 @@ def preprocess_arch_std_files(archpath: str) -> None:
>     global _arch_std_events
>     for item in os.scandir(archpath):
>       if item.is_file() and item.name.endswith('.json'):
> -      for event in read_json_events(item.path):
> +      for event in read_json_events(item.path, topic=''):
>           if event.name:
>             _arch_std_events[event.name.lower()] = event
>   
> @@ -251,19 +256,36 @@ def print_events_table_prefix(tblname: str) -> None:
>     _close_table = True
>   
>   
> -def print_events_table_entries(item: os.DirEntry, topic: str) -> None:
> -  """Create contents of an events table."""
> +def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> +  """Add contents of file to _pending_events table."""
>     if not _close_table:
>       raise IOError('Table entries missing prefix')
> -  for event in read_json_events(item.path):
> -    _args.output_file.write(event.to_c_string(topic))
> +  for e in read_json_events(item.path, topic):
> +    _pending_events.append(e)
>   
>   
>   def print_events_table_suffix() -> None:
>     """Optionally close events table."""
> +
> +  def event_cmp_key(j: JsonEvent):
> +    def fix_none(s: str):
> +      if s is None:
> +        return ''
> +      return s
> +
> +    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> +            fix_none(j.metric_name))
> +
>     global _close_table
> -  if _close_table:
> -    _args.output_file.write("""{
> +  if not _close_table:
> +    return
> +
> +  global _pending_events
> +  for event in sorted(_pending_events, key=event_cmp_key):
> +    _args.output_file.write(event.to_c_string())
> +    _pending_events = []
> +
> +  _args.output_file.write("""{
>   \t.name = 0,
>   \t.event = 0,
>   \t.desc = 0,
> @@ -306,7 +328,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>     if not item.is_file() or not item.name.endswith('.json'):
>       return
>   
> -  print_events_table_entries(item, get_topic(item.name))
> +  add_events_table_entries(item, get_topic(item.name))
>   
>   
>   def print_mapping_table(archs: Sequence[str]) -> None:


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 08/17] perf pmu-events: Hide pmu_sys_event_tables
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 11:15     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 11:15 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Move usage of the table to pmu-events.c so it may be hidden. By
> abstracting the table the implementation can later be changed.
> 
> Signed-off-by: Ian Rogers<irogers@google.com>

Reviewed-by: John Garry <john.garry@huawei.com>

> -	const struct pmu_event *sys_event_tables = __test_pmu_get_sys_events_table();
> +	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");

Maybe we can change to not need the "pme_" prefix or even some of the 
suffix, like "_sys"

>   	const struct pmu_events_map *map = __test_pmu_get_events_map();


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 08/17] perf pmu-events: Hide pmu_sys_event_tables
@ 2022-08-05 11:15     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 11:15 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Move usage of the table to pmu-events.c so it may be hidden. By
> abstracting the table the implementation can later be changed.
> 
> Signed-off-by: Ian Rogers<irogers@google.com>

Reviewed-by: John Garry <john.garry@huawei.com>

> -	const struct pmu_event *sys_event_tables = __test_pmu_get_sys_events_table();
> +	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");

Maybe we can change to not need the "pme_" prefix or even some of the 
suffix, like "_sys"

>   	const struct pmu_events_map *map = __test_pmu_get_events_map();


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 09/17] perf pmu-events: Avoid passing pmu_events_map
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 11:28     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 11:28 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Preparation for hiding pmu_events_map as an implementation detail. While
> the map is passed, the table of events is all that is normally wanted.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>

Apart from comments on naming, below:

Reviewed-by: John Garry <john.garry@huawei.com>

As an aside, I will mention that reviewing this series is not helped by 
limited description of the changes in the cover letter. A primer would 
be nice. As I go through the series, I am often assuming that the 
motivation for the change is sound.

Thanks,
John

> ---
>   tools/perf/arch/arm64/util/pmu.c  |  4 +-
>   tools/perf/tests/expand-cgroup.c  |  6 +--
>   tools/perf/tests/parse-metric.c   |  7 +--
>   tools/perf/tests/pmu-events.c     | 63 +++++++++++-------------
>   tools/perf/util/metricgroup.c     | 82 +++++++++++++++----------------
>   tools/perf/util/metricgroup.h     |  4 +-
>   tools/perf/util/pmu.c             | 33 +++++++------
>   tools/perf/util/pmu.h             |  6 +--
>   tools/perf/util/s390-sample-raw.c | 12 ++---
>   9 files changed, 99 insertions(+), 118 deletions(-)
> 
> diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> index 79124bba713e..646af8603227 100644
> --- a/tools/perf/arch/arm64/util/pmu.c
> +++ b/tools/perf/arch/arm64/util/pmu.c
> @@ -3,7 +3,7 @@
>   #include "../../../util/cpumap.h"
>   #include "../../../util/pmu.h"
>   
> -const struct pmu_events_map *pmu_events_map__find(void)
> +const struct pmu_event *pmu_events_map__find(void)

The function name is no longer appropriate


>   {
>   	struct perf_pmu *pmu = NULL;
>   
> @@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
>   		if (pmu->cpus->nr != cpu__max_cpu().cpu)
>   			return NULL;
>   
> -		return perf_pmu__find_map(pmu);
> +		return perf_pmu__find_table(pmu);
>   	}
>   
>   	return NULL;
> diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> index dc4038f997d7..411fc578e5a4 100644
> --- a/tools/perf/tests/expand-cgroup.c
> +++ b/tools/perf/tests/expand-cgroup.c
> @@ -195,16 +195,12 @@ static int expand_metric_events(void)
>   			.metric_name	= NULL,
>   		},
>   	};
> -	const struct pmu_events_map ev_map = {
> -		.cpuid		= "test",
> -		.table		= pme_test,
> -	};
>   
>   	evlist = evlist__new();
>   	TEST_ASSERT_VAL("failed to get evlist", evlist);
>   
>   	rblist__init(&metric_events);
> -	ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
> +	ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
>   					     false, false, &metric_events);
>   	if (ret < 0) {
>   		pr_debug("failed to parse '%s' metric\n", metric_str);
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 1b811a26f4ee..7aebde7c37ec 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
>   }
>   };
>   
> -static const struct pmu_events_map map = {
> -	.cpuid		= "test",
> -	.table		= pme_test,
> -};
> -
>   struct value {
>   	const char	*event;
>   	u64		 val;
> @@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
>   	runtime_stat__init(&st);
>   
>   	/* Parse the metric into metric_events list. */
> -	err = metricgroup__parse_groups_test(evlist, &map, name,
> +	err = metricgroup__parse_groups_test(evlist, pme_test, name,
>   					     false, false,
>   					     &metric_events);
>   	if (err)
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index a39a2c99ede6..b3cde5f98982 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
>   	return !strcmp(reference, test);
>   }
>   
> -static const struct pmu_events_map *__test_pmu_get_events_map(void)
> +static const struct pmu_event *__test_pmu_get_events_table(void)
>   {
> -	const struct pmu_events_map *map;
> -
> -	for (map = &pmu_events_map[0]; map->cpuid; map++) {
> +	for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
>   		if (!strcmp(map->cpuid, "testcpu"))
> -			return map;
> +			return map->table;
>   	}
>   
>   	pr_err("could not find test events map\n");
> @@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
>   				 int subtest __maybe_unused)
>   {
>   	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
> -	const struct pmu_events_map *map = __test_pmu_get_events_map();
> -	const struct pmu_event *table;
> +	const struct pmu_event *table = __test_pmu_get_events_table();
>   	int map_events = 0, expected_events;
>   
>   	/* ignore 3x sentinels */
> @@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
>   			  ARRAY_SIZE(uncore_events) +
>   			  ARRAY_SIZE(sys_events) - 3;
>   
> -	if (!map || !sys_event_tables)
> +	if (!table || !sys_event_tables)
>   		return -1;
>   
> -	for (table = map->table; table->name; table++) {
> +	for (; table->name; table++) {
>   		struct perf_pmu_test_event const **test_event_table;
>   		bool found = false;
>   
> @@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
>   	struct perf_pmu *pmu;
>   	LIST_HEAD(aliases);
>   	int res = 0;
> -	const struct pmu_events_map *map = __test_pmu_get_events_map();
> +	const struct pmu_event *table = __test_pmu_get_events_table();
>   	struct perf_pmu_alias *a, *tmp;
>   
> -	if (!map)
> +	if (!table)
>   		return -1;
>   
>   	test_event_table = &core_events[0];
> @@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
>   
>   	pmu->name = pmu_name;
>   
> -	pmu_add_cpu_aliases_map(&aliases, pmu, map);
> +	pmu_add_cpu_aliases_map(&aliases, pmu, table);
>   
>   	for (; *test_event_table; test_event_table++) {
>   		struct perf_pmu_test_event const *test_event = *test_event_table;
> @@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
>   	struct perf_pmu *pmu = &test_pmu->pmu;
>   	const char *pmu_name = pmu->name;
>   	struct perf_pmu_alias *a, *tmp, *alias;
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *events_table;
>   	LIST_HEAD(aliases);
>   	int res = 0;
>   
> -	map = __test_pmu_get_events_map();
> -	if (!map)
> +	events_table = __test_pmu_get_events_table();
> +	if (!events_table)
>   		return -1;
> -	pmu_add_cpu_aliases_map(&aliases, pmu, map);
> +	pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
>   	pmu_add_sys_aliases(&aliases, pmu);
>   
>   	/* Count how many aliases we generated */
> @@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
>   	return ret;
>   }
>   
> -static void expr_failure(const char *msg,
> -			 const struct pmu_events_map *map,
> -			 const struct pmu_event *pe)
> +static void expr_failure(const char *msg, const struct pmu_event *pe)
>   {
> -	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
> -	pr_debug("On metric %s\n", pe->metric_name);
> -	pr_debug("On expression %s\n", pe->metric_expr);
> +	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
>   }
>   
>   struct metric {
> @@ -864,7 +857,7 @@ struct metric {
>   
>   static int resolve_metric_simple(struct expr_parse_ctx *pctx,
>   				 struct list_head *compound_list,
> -				 const struct pmu_events_map *map,
> +				 const struct pmu_event *map,
>   				 const char *metric_name)
>   {
>   	struct hashmap_entry *cur, *cur_tmp;
> @@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
>   static int test__parsing(struct test_suite *test __maybe_unused,
>   			 int subtest __maybe_unused)
>   {
> -	const struct pmu_events_map *cpus_map = pmu_events_map__find();
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *cpus_table = pmu_events_map__find();
>   	const struct pmu_event *pe;
>   	int i, j, k;
>   	int ret = 0;
> @@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   	}
>   	i = 0;
>   	for (;;) {
> -		map = &pmu_events_map[i++];
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
>   		if (!map->table)
>   			break;
>   		j = 0;
> @@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   				continue;
>   			expr__ctx_clear(ctx);
>   			if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
> -				expr_failure("Parse find ids failed", map, pe);
> +				expr_failure("Parse find ids failed", pe);
>   				ret++;
>   				continue;
>   			}
>   
> -			if (resolve_metric_simple(ctx, &compound_list, map,
> +			if (resolve_metric_simple(ctx, &compound_list, map->table,
>   						  pe->metric_name)) {
> -				expr_failure("Could not resolve metrics", map, pe);
> +				expr_failure("Could not resolve metrics", pe);
>   				ret++;
>   				goto exit; /* Don't tolerate errors due to severity */
>   			}
> @@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   				expr__add_id_val(ctx, strdup(cur->key), k++);
>   
>   			hashmap__for_each_entry(ctx->ids, cur, bkt) {
> -				if (check_parse_cpu(cur->key, map == cpus_map,
> +				if (check_parse_cpu(cur->key, map->table == cpus_table,
>   						   pe))
>   					ret++;
>   			}
> @@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   				hashmap__for_each_entry(ctx->ids, cur, bkt)
>   					expr__add_id_val(ctx, strdup(cur->key), k--);
>   				if (expr__parse(&result, ctx, pe->metric_expr)) {
> -					expr_failure("Parse failed", map, pe);
> +					expr_failure("Parse failed", pe);
>   					ret++;
>   				}
>   			}
> @@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
>   static int test__parsing_fake(struct test_suite *test __maybe_unused,
>   			      int subtest __maybe_unused)
>   {
> -	const struct pmu_events_map *map;
> -	const struct pmu_event *pe;
>   	unsigned int i, j;
>   	int err = 0;
>   
> @@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
>   
>   	i = 0;
>   	for (;;) {
> -		map = &pmu_events_map[i++];
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
>   		if (!map->table)
>   			break;
>   		j = 0;
>   		for (;;) {
> -			pe = &map->table[j++];
> +			const struct pmu_event *pe = &map->table[j++];
> +
>   			if (!pe->name && !pe->metric_group && !pe->metric_name)
>   				break;
>   			if (!pe->metric_expr)
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 8f7baeabc5cf..4d32b4fbf67d 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
>   void metricgroup__print(bool metrics, bool metricgroups, char *filter,
>   			bool raw, bool details, const char *pmu_name)
>   {
> -	const struct pmu_events_map *map = pmu_events_map__find();
> -	const struct pmu_event *pe;
> -	int i;
>   	struct rblist groups;
>   	struct rb_node *node, *next;
>   	struct strlist *metriclist = NULL;
> @@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
>   	groups.node_new = mep_new;
>   	groups.node_cmp = mep_cmp;
>   	groups.node_delete = mep_delete;
> -	for (i = 0; map; i++) {
> -		pe = &map->table[i];
> +	for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
>   
>   		if (!pe->name && !pe->metric_group && !pe->metric_name)
>   			break;
> @@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
>   	bool metric_no_group;
>   	struct metric *root_metric;
>   	const struct visited_metric *visited;
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table;
>   };
>   
>   static int add_metric(struct list_head *metric_list,
> @@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
>   		      bool metric_no_group,
>   		      struct metric *root_metric,
>   		      const struct visited_metric *visited,
> -		      const struct pmu_events_map *map);
> +		      const struct pmu_event *table);
>   
>   /**
>    * resolve_metric - Locate metrics within the root metric and recursively add
> @@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
>    *               metrics. When adding a root this argument is NULL.
>    * @visited: A singly linked list of metric names being added that is used to
>    *           detect recursion.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int resolve_metric(struct list_head *metric_list,
> @@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
>   			  bool metric_no_group,
>   			  struct metric *root_metric,
>   			  const struct visited_metric *visited,
> -			  const struct pmu_events_map *map)
> +			  const struct pmu_event *table)
>   {
>   	struct hashmap_entry *cur;
>   	size_t bkt;
> @@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
>   	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
>   		const struct pmu_event *pe;
>   
> -		pe = metricgroup__find_metric(cur->key, map);
> +		pe = metricgroup__find_metric(cur->key, table);
>   		if (pe) {
>   			pending = realloc(pending,
>   					(pending_cnt + 1) * sizeof(struct to_resolve));
> @@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
>   	 */
>   	for (i = 0; i < pending_cnt; i++) {
>   		ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
> -				root_metric, visited, map);
> +				root_metric, visited, table);
>   		if (ret)
>   			break;
>   	}
> @@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
>    *               metrics. When adding a root this argument is NULL.
>    * @visited: A singly linked list of metric names being added that is used to
>    *           detect recursion.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int __add_metric(struct list_head *metric_list,
> @@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
>   			int runtime,
>   			struct metric *root_metric,
>   			const struct visited_metric *visited,
> -			const struct pmu_events_map *map)
> +			const struct pmu_event *table)
>   {
>   	const struct visited_metric *vm;
>   	int ret;
> @@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
>   	} else {
>   		/* Resolve referenced metrics. */
>   		ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
> -				     &visited_node, map);
> +				     &visited_node, table);
>   	}
>   
>   	if (ret) {
> @@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
>   	return ret;
>   }
>   
> -#define map_for_each_event(__pe, __idx, __map)					\
> -	if (__map)								\
> -		for (__idx = 0, __pe = &__map->table[__idx];			\
> +#define table_for_each_event(__pe, __idx, __table)					\
> +	if (__table)								\
> +		for (__idx = 0, __pe = &__table[__idx];				\
>   		     __pe->name || __pe->metric_group || __pe->metric_name;	\
> -		     __pe = &__map->table[++__idx])
> +		     __pe = &__table[++__idx])
>   
> -#define map_for_each_metric(__pe, __idx, __map, __metric)		\
> -	map_for_each_event(__pe, __idx, __map)				\
> +#define table_for_each_metric(__pe, __idx, __table, __metric)		\
> +	table_for_each_event(__pe, __idx, __table)				\
>   		if (__pe->metric_expr &&				\
>   		    (match_metric(__pe->metric_group, __metric) ||	\
>   		     match_metric(__pe->metric_name, __metric)))
>   
>   const struct pmu_event *metricgroup__find_metric(const char *metric,
> -						 const struct pmu_events_map *map)
> +						 const struct pmu_event *table)
>   {
>   	const struct pmu_event *pe;
>   	int i;
>   
> -	map_for_each_event(pe, i, map) {
> +	table_for_each_event(pe, i, table) {
>   		if (match_metric(pe->metric_name, metric))
>   			return pe;
>   	}
> @@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
>   		      bool metric_no_group,
>   		      struct metric *root_metric,
>   		      const struct visited_metric *visited,
> -		      const struct pmu_events_map *map)
> +		      const struct pmu_event *table)
>   {
>   	int ret = 0;
>   
> @@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
>   
>   	if (!strstr(pe->metric_expr, "?")) {
>   		ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> -				   root_metric, visited, map);
> +				   root_metric, visited, table);
>   	} else {
>   		int j, count;
>   
> @@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
>   
>   		for (j = 0; j < count && !ret; j++)
>   			ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
> -					root_metric, visited, map);
> +					root_metric, visited, table);
>   	}
>   
>   	return ret;
> @@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
>   		return 0;
>   
>   	ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> -			 d->root_metric, d->visited, d->map);
> +			 d->root_metric, d->visited, d->table);
>   	if (ret)
>   		goto out;
>   
> @@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
>    *                   global. Grouping is the default but due to multiplexing the
>    *                   user may override.
>    * @metric_list: The list that the metric or metric group are added to.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int metricgroup__add_metric(const char *metric_name, const char *modifier,
>   				   bool metric_no_group,
>   				   struct list_head *metric_list,
> -				   const struct pmu_events_map *map)
> +				   const struct pmu_event *table)
>   {
>   	const struct pmu_event *pe;
>   	LIST_HEAD(list);
> @@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
>   	 * Iterate over all metrics seeing if metric matches either the name or
>   	 * group. When it does add the metric to the list.
>   	 */
> -	map_for_each_metric(pe, i, map, metric_name) {
> +	table_for_each_metric(pe, i, table, metric_name) {
>   		has_match = true;
>   		ret = add_metric(&list, pe, modifier, metric_no_group,
>   				 /*root_metric=*/NULL,
> -				 /*visited_metrics=*/NULL, map);
> +				 /*visited_metrics=*/NULL, table);
>   		if (ret)
>   			goto out;
>   	}
> @@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
>   				.metric_no_group = metric_no_group,
>   				.has_match = &has_match,
>   				.ret = &ret,
> -				.map = map,
> +				.table = table,
>   			},
>   		};
>   
> @@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
>    *                   global. Grouping is the default but due to multiplexing the
>    *                   user may override.
>    * @metric_list: The list that metrics are added to.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>   					struct list_head *metric_list,
> -					const struct pmu_events_map *map)
> +					const struct pmu_event *table)
>   {
>   	char *list_itr, *list_copy, *metric_name, *modifier;
>   	int ret, count = 0;
> @@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>   
>   		ret = metricgroup__add_metric(metric_name, modifier,
>   					      metric_no_group, metric_list,
> -					      map);
> +					      table);
>   		if (ret == -EINVAL)
>   			pr_err("Cannot find metric or group `%s'\n", metric_name);
>   
> @@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>   			bool metric_no_merge,
>   			struct perf_pmu *fake_pmu,
>   			struct rblist *metric_events_list,
> -			const struct pmu_events_map *map)
> +			const struct pmu_event *table)
>   {
>   	struct evlist *combined_evlist = NULL;
>   	LIST_HEAD(metric_list);
> @@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>   	if (metric_events_list->nr_entries == 0)
>   		metricgroup__rblist_init(metric_events_list);
>   	ret = metricgroup__add_metric_list(str, metric_no_group,
> -					   &metric_list, map);
> +					   &metric_list, table);
>   	if (ret)
>   		goto out;
>   
> @@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
>   			      struct rblist *metric_events)
>   {
>   	struct evlist *perf_evlist = *(struct evlist **)opt->value;
> -	const struct pmu_events_map *map = pmu_events_map__find();
> +	const struct pmu_event *table = pmu_events_map__find();
>   
>   	return parse_groups(perf_evlist, str, metric_no_group,
> -			    metric_no_merge, NULL, metric_events, map);
> +			    metric_no_merge, NULL, metric_events, table);
>   }
>   
>   int metricgroup__parse_groups_test(struct evlist *evlist,
> -				   const struct pmu_events_map *map,
> +				   const struct pmu_event *table,
>   				   const char *str,
>   				   bool metric_no_group,
>   				   bool metric_no_merge,
>   				   struct rblist *metric_events)
>   {
>   	return parse_groups(evlist, str, metric_no_group,
> -			    metric_no_merge, &perf_pmu__fake, metric_events, map);
> +			    metric_no_merge, &perf_pmu__fake, metric_events, table);
>   }
>   
>   bool metricgroup__has_metric(const char *metric)
>   {
> -	const struct pmu_events_map *map = pmu_events_map__find();
> +	const struct pmu_event *table = pmu_events_map__find();
>   	const struct pmu_event *pe;
>   	int i;
>   
> -	if (!map)
> +	if (!table)
>   		return false;
>   
>   	for (i = 0; ; i++) {
> -		pe = &map->table[i];
> +		pe = &table[i];
>   
>   		if (!pe->name && !pe->metric_group && !pe->metric_name)
>   			break;
> diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
> index 2b42b778d1bf..5a1390e73d25 100644
> --- a/tools/perf/util/metricgroup.h
> +++ b/tools/perf/util/metricgroup.h
> @@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
>   			      bool metric_no_merge,
>   			      struct rblist *metric_events);
>   const struct pmu_event *metricgroup__find_metric(const char *metric,
> -						 const struct pmu_events_map *map);
> +						 const struct pmu_event *table);
>   int metricgroup__parse_groups_test(struct evlist *evlist,
> -				   const struct pmu_events_map *map,
> +				   const struct pmu_event *table,
>   				   const char *str,
>   				   bool metric_no_group,
>   				   bool metric_no_merge,
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index d8717c4548a4..f3e3c4a147e9 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
>   	return cpuid;
>   }
>   
> -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
>   {
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table = NULL;
>   	char *cpuid = perf_pmu__getcpuid(pmu);
>   	int i;
>   
> @@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
>   
>   	i = 0;
>   	for (;;) {
> -		map = &pmu_events_map[i++];
> -		if (!map->table) {
> -			map = NULL;
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> +		if (!map->table)
>   			break;
> -		}
>   
> -		if (!strcmp_cpuid_str(map->cpuid, cpuid))
> +		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> +			table = map->table;
>   			break;
> +		}
>   	}
>   	free(cpuid);
> -	return map;
> +	return table;
>   }
>   
> -const struct pmu_events_map *__weak pmu_events_map__find(void)
> +__weak const struct pmu_event *pmu_events_map__find(void)
>   {
> -	return perf_pmu__find_map(NULL);
> +	return perf_pmu__find_table(NULL);
>   }
>   
>   /*
> @@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
>    * as aliases.
>    */
>   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,

Again, it seems that this name should be changed

> -			     const struct pmu_events_map *map)
> +			     const struct pmu_event *table)
>   {
>   	int i;
>   	const char *name = pmu->name;
> @@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>   	i = 0;
>   	while (1) {
>   		const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
> -		const struct pmu_event *pe = &map->table[i++];
> +		const struct pmu_event *pe = &table[i++];
>   		const char *pname = pe->pmu ? pe->pmu : cpu_name;
>   
>   		if (!pe->name) {
> @@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>   
>   static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
>   {
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table;
>   
> -	map = perf_pmu__find_map(pmu);
> -	if (!map)
> +	table = perf_pmu__find_table(pmu);
> +	if (!table)
>   		return;
>   
> -	pmu_add_cpu_aliases_map(head, pmu, map);
> +	pmu_add_cpu_aliases_map(head, pmu, table);
>   }
>   
>   struct pmu_sys_event_iter_data {
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index 7e667eec2a01..015242c83698 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -126,10 +126,10 @@ int perf_pmu__test(void);
>   
>   struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
>   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> -			     const struct pmu_events_map *map);
> +			     const struct pmu_event *map);
>   
> -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
> -const struct pmu_events_map *pmu_events_map__find(void);
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
> +const struct pmu_event *pmu_events_map__find(void);
>   bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
>   void perf_pmu_free_alias(struct perf_pmu_alias *alias);
>   
> diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
> index cd3a34840389..1ecb718fc0eb 100644
> --- a/tools/perf/util/s390-sample-raw.c
> +++ b/tools/perf/util/s390-sample-raw.c
> @@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
>    * the name of this counter.
>    * If no match is found a NULL pointer is returned.
>    */
> -static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
> +static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
>   {
>   	int rc, event_nr, wanted = get_counterset_start(set) + nr;
>   
> -	if (map) {
> -		const struct pmu_event *evp = map->table;
> +	if (table) {
> +		const struct pmu_event *evp = table;
>   
>   		for (; evp->name || evp->event || evp->desc; ++evp) {
>   			if (evp->name == NULL || evp->event == NULL)
> @@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
>   	unsigned char *buf = sample->raw_data;
>   	const char *color = PERF_COLOR_BLUE;
>   	struct cf_ctrset_entry *cep, ce;
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table;
>   	u64 *p;
>   
> -	map = pmu_events_map__find();
> +	table = pmu_events_map__find();
>   	while (offset < len) {
>   		cep = (struct cf_ctrset_entry *)(buf + offset);
>   
> @@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
>   		color_fprintf(stdout, color, "    [%#08zx] Counterset:%d"
>   			      " Counters:%d\n", offset, ce.set, ce.ctr);
>   		for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
> -			const char *ev_name = get_counter_name(ce.set, i, map);
> +			const char *ev_name = get_counter_name(ce.set, i, table);
>   
>   			color_fprintf(stdout, color,
>   				      "\tCounter:%03d %s Value:%#018lx\n", i,


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 09/17] perf pmu-events: Avoid passing pmu_events_map
@ 2022-08-05 11:28     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 11:28 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Preparation for hiding pmu_events_map as an implementation detail. While
> the map is passed, the table of events is all that is normally wanted.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>

Apart from comments on naming, below:

Reviewed-by: John Garry <john.garry@huawei.com>

As an aside, I will mention that reviewing this series is not helped by 
limited description of the changes in the cover letter. A primer would 
be nice. As I go through the series, I am often assuming that the 
motivation for the change is sound.

Thanks,
John

> ---
>   tools/perf/arch/arm64/util/pmu.c  |  4 +-
>   tools/perf/tests/expand-cgroup.c  |  6 +--
>   tools/perf/tests/parse-metric.c   |  7 +--
>   tools/perf/tests/pmu-events.c     | 63 +++++++++++-------------
>   tools/perf/util/metricgroup.c     | 82 +++++++++++++++----------------
>   tools/perf/util/metricgroup.h     |  4 +-
>   tools/perf/util/pmu.c             | 33 +++++++------
>   tools/perf/util/pmu.h             |  6 +--
>   tools/perf/util/s390-sample-raw.c | 12 ++---
>   9 files changed, 99 insertions(+), 118 deletions(-)
> 
> diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> index 79124bba713e..646af8603227 100644
> --- a/tools/perf/arch/arm64/util/pmu.c
> +++ b/tools/perf/arch/arm64/util/pmu.c
> @@ -3,7 +3,7 @@
>   #include "../../../util/cpumap.h"
>   #include "../../../util/pmu.h"
>   
> -const struct pmu_events_map *pmu_events_map__find(void)
> +const struct pmu_event *pmu_events_map__find(void)

The function name is no longer appropriate


>   {
>   	struct perf_pmu *pmu = NULL;
>   
> @@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
>   		if (pmu->cpus->nr != cpu__max_cpu().cpu)
>   			return NULL;
>   
> -		return perf_pmu__find_map(pmu);
> +		return perf_pmu__find_table(pmu);
>   	}
>   
>   	return NULL;
> diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> index dc4038f997d7..411fc578e5a4 100644
> --- a/tools/perf/tests/expand-cgroup.c
> +++ b/tools/perf/tests/expand-cgroup.c
> @@ -195,16 +195,12 @@ static int expand_metric_events(void)
>   			.metric_name	= NULL,
>   		},
>   	};
> -	const struct pmu_events_map ev_map = {
> -		.cpuid		= "test",
> -		.table		= pme_test,
> -	};
>   
>   	evlist = evlist__new();
>   	TEST_ASSERT_VAL("failed to get evlist", evlist);
>   
>   	rblist__init(&metric_events);
> -	ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
> +	ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
>   					     false, false, &metric_events);
>   	if (ret < 0) {
>   		pr_debug("failed to parse '%s' metric\n", metric_str);
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 1b811a26f4ee..7aebde7c37ec 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
>   }
>   };
>   
> -static const struct pmu_events_map map = {
> -	.cpuid		= "test",
> -	.table		= pme_test,
> -};
> -
>   struct value {
>   	const char	*event;
>   	u64		 val;
> @@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
>   	runtime_stat__init(&st);
>   
>   	/* Parse the metric into metric_events list. */
> -	err = metricgroup__parse_groups_test(evlist, &map, name,
> +	err = metricgroup__parse_groups_test(evlist, pme_test, name,
>   					     false, false,
>   					     &metric_events);
>   	if (err)
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index a39a2c99ede6..b3cde5f98982 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
>   	return !strcmp(reference, test);
>   }
>   
> -static const struct pmu_events_map *__test_pmu_get_events_map(void)
> +static const struct pmu_event *__test_pmu_get_events_table(void)
>   {
> -	const struct pmu_events_map *map;
> -
> -	for (map = &pmu_events_map[0]; map->cpuid; map++) {
> +	for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
>   		if (!strcmp(map->cpuid, "testcpu"))
> -			return map;
> +			return map->table;
>   	}
>   
>   	pr_err("could not find test events map\n");
> @@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
>   				 int subtest __maybe_unused)
>   {
>   	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
> -	const struct pmu_events_map *map = __test_pmu_get_events_map();
> -	const struct pmu_event *table;
> +	const struct pmu_event *table = __test_pmu_get_events_table();
>   	int map_events = 0, expected_events;
>   
>   	/* ignore 3x sentinels */
> @@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
>   			  ARRAY_SIZE(uncore_events) +
>   			  ARRAY_SIZE(sys_events) - 3;
>   
> -	if (!map || !sys_event_tables)
> +	if (!table || !sys_event_tables)
>   		return -1;
>   
> -	for (table = map->table; table->name; table++) {
> +	for (; table->name; table++) {
>   		struct perf_pmu_test_event const **test_event_table;
>   		bool found = false;
>   
> @@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
>   	struct perf_pmu *pmu;
>   	LIST_HEAD(aliases);
>   	int res = 0;
> -	const struct pmu_events_map *map = __test_pmu_get_events_map();
> +	const struct pmu_event *table = __test_pmu_get_events_table();
>   	struct perf_pmu_alias *a, *tmp;
>   
> -	if (!map)
> +	if (!table)
>   		return -1;
>   
>   	test_event_table = &core_events[0];
> @@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
>   
>   	pmu->name = pmu_name;
>   
> -	pmu_add_cpu_aliases_map(&aliases, pmu, map);
> +	pmu_add_cpu_aliases_map(&aliases, pmu, table);
>   
>   	for (; *test_event_table; test_event_table++) {
>   		struct perf_pmu_test_event const *test_event = *test_event_table;
> @@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
>   	struct perf_pmu *pmu = &test_pmu->pmu;
>   	const char *pmu_name = pmu->name;
>   	struct perf_pmu_alias *a, *tmp, *alias;
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *events_table;
>   	LIST_HEAD(aliases);
>   	int res = 0;
>   
> -	map = __test_pmu_get_events_map();
> -	if (!map)
> +	events_table = __test_pmu_get_events_table();
> +	if (!events_table)
>   		return -1;
> -	pmu_add_cpu_aliases_map(&aliases, pmu, map);
> +	pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
>   	pmu_add_sys_aliases(&aliases, pmu);
>   
>   	/* Count how many aliases we generated */
> @@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
>   	return ret;
>   }
>   
> -static void expr_failure(const char *msg,
> -			 const struct pmu_events_map *map,
> -			 const struct pmu_event *pe)
> +static void expr_failure(const char *msg, const struct pmu_event *pe)
>   {
> -	pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
> -	pr_debug("On metric %s\n", pe->metric_name);
> -	pr_debug("On expression %s\n", pe->metric_expr);
> +	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
>   }
>   
>   struct metric {
> @@ -864,7 +857,7 @@ struct metric {
>   
>   static int resolve_metric_simple(struct expr_parse_ctx *pctx,
>   				 struct list_head *compound_list,
> -				 const struct pmu_events_map *map,
> +				 const struct pmu_event *map,
>   				 const char *metric_name)
>   {
>   	struct hashmap_entry *cur, *cur_tmp;
> @@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
>   static int test__parsing(struct test_suite *test __maybe_unused,
>   			 int subtest __maybe_unused)
>   {
> -	const struct pmu_events_map *cpus_map = pmu_events_map__find();
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *cpus_table = pmu_events_map__find();
>   	const struct pmu_event *pe;
>   	int i, j, k;
>   	int ret = 0;
> @@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   	}
>   	i = 0;
>   	for (;;) {
> -		map = &pmu_events_map[i++];
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
>   		if (!map->table)
>   			break;
>   		j = 0;
> @@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   				continue;
>   			expr__ctx_clear(ctx);
>   			if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
> -				expr_failure("Parse find ids failed", map, pe);
> +				expr_failure("Parse find ids failed", pe);
>   				ret++;
>   				continue;
>   			}
>   
> -			if (resolve_metric_simple(ctx, &compound_list, map,
> +			if (resolve_metric_simple(ctx, &compound_list, map->table,
>   						  pe->metric_name)) {
> -				expr_failure("Could not resolve metrics", map, pe);
> +				expr_failure("Could not resolve metrics", pe);
>   				ret++;
>   				goto exit; /* Don't tolerate errors due to severity */
>   			}
> @@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   				expr__add_id_val(ctx, strdup(cur->key), k++);
>   
>   			hashmap__for_each_entry(ctx->ids, cur, bkt) {
> -				if (check_parse_cpu(cur->key, map == cpus_map,
> +				if (check_parse_cpu(cur->key, map->table == cpus_table,
>   						   pe))
>   					ret++;
>   			}
> @@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   				hashmap__for_each_entry(ctx->ids, cur, bkt)
>   					expr__add_id_val(ctx, strdup(cur->key), k--);
>   				if (expr__parse(&result, ctx, pe->metric_expr)) {
> -					expr_failure("Parse failed", map, pe);
> +					expr_failure("Parse failed", pe);
>   					ret++;
>   				}
>   			}
> @@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
>   static int test__parsing_fake(struct test_suite *test __maybe_unused,
>   			      int subtest __maybe_unused)
>   {
> -	const struct pmu_events_map *map;
> -	const struct pmu_event *pe;
>   	unsigned int i, j;
>   	int err = 0;
>   
> @@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
>   
>   	i = 0;
>   	for (;;) {
> -		map = &pmu_events_map[i++];
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
>   		if (!map->table)
>   			break;
>   		j = 0;
>   		for (;;) {
> -			pe = &map->table[j++];
> +			const struct pmu_event *pe = &map->table[j++];
> +
>   			if (!pe->name && !pe->metric_group && !pe->metric_name)
>   				break;
>   			if (!pe->metric_expr)
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 8f7baeabc5cf..4d32b4fbf67d 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
>   void metricgroup__print(bool metrics, bool metricgroups, char *filter,
>   			bool raw, bool details, const char *pmu_name)
>   {
> -	const struct pmu_events_map *map = pmu_events_map__find();
> -	const struct pmu_event *pe;
> -	int i;
>   	struct rblist groups;
>   	struct rb_node *node, *next;
>   	struct strlist *metriclist = NULL;
> @@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
>   	groups.node_new = mep_new;
>   	groups.node_cmp = mep_cmp;
>   	groups.node_delete = mep_delete;
> -	for (i = 0; map; i++) {
> -		pe = &map->table[i];
> +	for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
>   
>   		if (!pe->name && !pe->metric_group && !pe->metric_name)
>   			break;
> @@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
>   	bool metric_no_group;
>   	struct metric *root_metric;
>   	const struct visited_metric *visited;
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table;
>   };
>   
>   static int add_metric(struct list_head *metric_list,
> @@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
>   		      bool metric_no_group,
>   		      struct metric *root_metric,
>   		      const struct visited_metric *visited,
> -		      const struct pmu_events_map *map);
> +		      const struct pmu_event *table);
>   
>   /**
>    * resolve_metric - Locate metrics within the root metric and recursively add
> @@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
>    *               metrics. When adding a root this argument is NULL.
>    * @visited: A singly linked list of metric names being added that is used to
>    *           detect recursion.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int resolve_metric(struct list_head *metric_list,
> @@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
>   			  bool metric_no_group,
>   			  struct metric *root_metric,
>   			  const struct visited_metric *visited,
> -			  const struct pmu_events_map *map)
> +			  const struct pmu_event *table)
>   {
>   	struct hashmap_entry *cur;
>   	size_t bkt;
> @@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
>   	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
>   		const struct pmu_event *pe;
>   
> -		pe = metricgroup__find_metric(cur->key, map);
> +		pe = metricgroup__find_metric(cur->key, table);
>   		if (pe) {
>   			pending = realloc(pending,
>   					(pending_cnt + 1) * sizeof(struct to_resolve));
> @@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
>   	 */
>   	for (i = 0; i < pending_cnt; i++) {
>   		ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
> -				root_metric, visited, map);
> +				root_metric, visited, table);
>   		if (ret)
>   			break;
>   	}
> @@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
>    *               metrics. When adding a root this argument is NULL.
>    * @visited: A singly linked list of metric names being added that is used to
>    *           detect recursion.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int __add_metric(struct list_head *metric_list,
> @@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
>   			int runtime,
>   			struct metric *root_metric,
>   			const struct visited_metric *visited,
> -			const struct pmu_events_map *map)
> +			const struct pmu_event *table)
>   {
>   	const struct visited_metric *vm;
>   	int ret;
> @@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
>   	} else {
>   		/* Resolve referenced metrics. */
>   		ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
> -				     &visited_node, map);
> +				     &visited_node, table);
>   	}
>   
>   	if (ret) {
> @@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
>   	return ret;
>   }
>   
> -#define map_for_each_event(__pe, __idx, __map)					\
> -	if (__map)								\
> -		for (__idx = 0, __pe = &__map->table[__idx];			\
> +#define table_for_each_event(__pe, __idx, __table)					\
> +	if (__table)								\
> +		for (__idx = 0, __pe = &__table[__idx];				\
>   		     __pe->name || __pe->metric_group || __pe->metric_name;	\
> -		     __pe = &__map->table[++__idx])
> +		     __pe = &__table[++__idx])
>   
> -#define map_for_each_metric(__pe, __idx, __map, __metric)		\
> -	map_for_each_event(__pe, __idx, __map)				\
> +#define table_for_each_metric(__pe, __idx, __table, __metric)		\
> +	table_for_each_event(__pe, __idx, __table)				\
>   		if (__pe->metric_expr &&				\
>   		    (match_metric(__pe->metric_group, __metric) ||	\
>   		     match_metric(__pe->metric_name, __metric)))
>   
>   const struct pmu_event *metricgroup__find_metric(const char *metric,
> -						 const struct pmu_events_map *map)
> +						 const struct pmu_event *table)
>   {
>   	const struct pmu_event *pe;
>   	int i;
>   
> -	map_for_each_event(pe, i, map) {
> +	table_for_each_event(pe, i, table) {
>   		if (match_metric(pe->metric_name, metric))
>   			return pe;
>   	}
> @@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
>   		      bool metric_no_group,
>   		      struct metric *root_metric,
>   		      const struct visited_metric *visited,
> -		      const struct pmu_events_map *map)
> +		      const struct pmu_event *table)
>   {
>   	int ret = 0;
>   
> @@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
>   
>   	if (!strstr(pe->metric_expr, "?")) {
>   		ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> -				   root_metric, visited, map);
> +				   root_metric, visited, table);
>   	} else {
>   		int j, count;
>   
> @@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
>   
>   		for (j = 0; j < count && !ret; j++)
>   			ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
> -					root_metric, visited, map);
> +					root_metric, visited, table);
>   	}
>   
>   	return ret;
> @@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
>   		return 0;
>   
>   	ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> -			 d->root_metric, d->visited, d->map);
> +			 d->root_metric, d->visited, d->table);
>   	if (ret)
>   		goto out;
>   
> @@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
>    *                   global. Grouping is the default but due to multiplexing the
>    *                   user may override.
>    * @metric_list: The list that the metric or metric group are added to.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int metricgroup__add_metric(const char *metric_name, const char *modifier,
>   				   bool metric_no_group,
>   				   struct list_head *metric_list,
> -				   const struct pmu_events_map *map)
> +				   const struct pmu_event *table)
>   {
>   	const struct pmu_event *pe;
>   	LIST_HEAD(list);
> @@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
>   	 * Iterate over all metrics seeing if metric matches either the name or
>   	 * group. When it does add the metric to the list.
>   	 */
> -	map_for_each_metric(pe, i, map, metric_name) {
> +	table_for_each_metric(pe, i, table, metric_name) {
>   		has_match = true;
>   		ret = add_metric(&list, pe, modifier, metric_no_group,
>   				 /*root_metric=*/NULL,
> -				 /*visited_metrics=*/NULL, map);
> +				 /*visited_metrics=*/NULL, table);
>   		if (ret)
>   			goto out;
>   	}
> @@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
>   				.metric_no_group = metric_no_group,
>   				.has_match = &has_match,
>   				.ret = &ret,
> -				.map = map,
> +				.table = table,
>   			},
>   		};
>   
> @@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
>    *                   global. Grouping is the default but due to multiplexing the
>    *                   user may override.
>    * @metric_list: The list that metrics are added to.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
>    *       architecture perf is running upon.
>    */
>   static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>   					struct list_head *metric_list,
> -					const struct pmu_events_map *map)
> +					const struct pmu_event *table)
>   {
>   	char *list_itr, *list_copy, *metric_name, *modifier;
>   	int ret, count = 0;
> @@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>   
>   		ret = metricgroup__add_metric(metric_name, modifier,
>   					      metric_no_group, metric_list,
> -					      map);
> +					      table);
>   		if (ret == -EINVAL)
>   			pr_err("Cannot find metric or group `%s'\n", metric_name);
>   
> @@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>   			bool metric_no_merge,
>   			struct perf_pmu *fake_pmu,
>   			struct rblist *metric_events_list,
> -			const struct pmu_events_map *map)
> +			const struct pmu_event *table)
>   {
>   	struct evlist *combined_evlist = NULL;
>   	LIST_HEAD(metric_list);
> @@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>   	if (metric_events_list->nr_entries == 0)
>   		metricgroup__rblist_init(metric_events_list);
>   	ret = metricgroup__add_metric_list(str, metric_no_group,
> -					   &metric_list, map);
> +					   &metric_list, table);
>   	if (ret)
>   		goto out;
>   
> @@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
>   			      struct rblist *metric_events)
>   {
>   	struct evlist *perf_evlist = *(struct evlist **)opt->value;
> -	const struct pmu_events_map *map = pmu_events_map__find();
> +	const struct pmu_event *table = pmu_events_map__find();
>   
>   	return parse_groups(perf_evlist, str, metric_no_group,
> -			    metric_no_merge, NULL, metric_events, map);
> +			    metric_no_merge, NULL, metric_events, table);
>   }
>   
>   int metricgroup__parse_groups_test(struct evlist *evlist,
> -				   const struct pmu_events_map *map,
> +				   const struct pmu_event *table,
>   				   const char *str,
>   				   bool metric_no_group,
>   				   bool metric_no_merge,
>   				   struct rblist *metric_events)
>   {
>   	return parse_groups(evlist, str, metric_no_group,
> -			    metric_no_merge, &perf_pmu__fake, metric_events, map);
> +			    metric_no_merge, &perf_pmu__fake, metric_events, table);
>   }
>   
>   bool metricgroup__has_metric(const char *metric)
>   {
> -	const struct pmu_events_map *map = pmu_events_map__find();
> +	const struct pmu_event *table = pmu_events_map__find();
>   	const struct pmu_event *pe;
>   	int i;
>   
> -	if (!map)
> +	if (!table)
>   		return false;
>   
>   	for (i = 0; ; i++) {
> -		pe = &map->table[i];
> +		pe = &table[i];
>   
>   		if (!pe->name && !pe->metric_group && !pe->metric_name)
>   			break;
> diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
> index 2b42b778d1bf..5a1390e73d25 100644
> --- a/tools/perf/util/metricgroup.h
> +++ b/tools/perf/util/metricgroup.h
> @@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
>   			      bool metric_no_merge,
>   			      struct rblist *metric_events);
>   const struct pmu_event *metricgroup__find_metric(const char *metric,
> -						 const struct pmu_events_map *map);
> +						 const struct pmu_event *table);
>   int metricgroup__parse_groups_test(struct evlist *evlist,
> -				   const struct pmu_events_map *map,
> +				   const struct pmu_event *table,
>   				   const char *str,
>   				   bool metric_no_group,
>   				   bool metric_no_merge,
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index d8717c4548a4..f3e3c4a147e9 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
>   	return cpuid;
>   }
>   
> -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
>   {
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table = NULL;
>   	char *cpuid = perf_pmu__getcpuid(pmu);
>   	int i;
>   
> @@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
>   
>   	i = 0;
>   	for (;;) {
> -		map = &pmu_events_map[i++];
> -		if (!map->table) {
> -			map = NULL;
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> +		if (!map->table)
>   			break;
> -		}
>   
> -		if (!strcmp_cpuid_str(map->cpuid, cpuid))
> +		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> +			table = map->table;
>   			break;
> +		}
>   	}
>   	free(cpuid);
> -	return map;
> +	return table;
>   }
>   
> -const struct pmu_events_map *__weak pmu_events_map__find(void)
> +__weak const struct pmu_event *pmu_events_map__find(void)
>   {
> -	return perf_pmu__find_map(NULL);
> +	return perf_pmu__find_table(NULL);
>   }
>   
>   /*
> @@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
>    * as aliases.
>    */
>   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,

Again, it seems that this name should be changed

> -			     const struct pmu_events_map *map)
> +			     const struct pmu_event *table)
>   {
>   	int i;
>   	const char *name = pmu->name;
> @@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>   	i = 0;
>   	while (1) {
>   		const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
> -		const struct pmu_event *pe = &map->table[i++];
> +		const struct pmu_event *pe = &table[i++];
>   		const char *pname = pe->pmu ? pe->pmu : cpu_name;
>   
>   		if (!pe->name) {
> @@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>   
>   static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
>   {
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table;
>   
> -	map = perf_pmu__find_map(pmu);
> -	if (!map)
> +	table = perf_pmu__find_table(pmu);
> +	if (!table)
>   		return;
>   
> -	pmu_add_cpu_aliases_map(head, pmu, map);
> +	pmu_add_cpu_aliases_map(head, pmu, table);
>   }
>   
>   struct pmu_sys_event_iter_data {
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index 7e667eec2a01..015242c83698 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -126,10 +126,10 @@ int perf_pmu__test(void);
>   
>   struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
>   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> -			     const struct pmu_events_map *map);
> +			     const struct pmu_event *map);
>   
> -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
> -const struct pmu_events_map *pmu_events_map__find(void);
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
> +const struct pmu_event *pmu_events_map__find(void);
>   bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
>   void perf_pmu_free_alias(struct perf_pmu_alias *alias);
>   
> diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
> index cd3a34840389..1ecb718fc0eb 100644
> --- a/tools/perf/util/s390-sample-raw.c
> +++ b/tools/perf/util/s390-sample-raw.c
> @@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
>    * the name of this counter.
>    * If no match is found a NULL pointer is returned.
>    */
> -static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
> +static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
>   {
>   	int rc, event_nr, wanted = get_counterset_start(set) + nr;
>   
> -	if (map) {
> -		const struct pmu_event *evp = map->table;
> +	if (table) {
> +		const struct pmu_event *evp = table;
>   
>   		for (; evp->name || evp->event || evp->desc; ++evp) {
>   			if (evp->name == NULL || evp->event == NULL)
> @@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
>   	unsigned char *buf = sample->raw_data;
>   	const char *color = PERF_COLOR_BLUE;
>   	struct cf_ctrset_entry *cep, ce;
> -	const struct pmu_events_map *map;
> +	const struct pmu_event *table;
>   	u64 *p;
>   
> -	map = pmu_events_map__find();
> +	table = pmu_events_map__find();
>   	while (offset < len) {
>   		cep = (struct cf_ctrset_entry *)(buf + offset);
>   
> @@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
>   		color_fprintf(stdout, color, "    [%#08zx] Counterset:%d"
>   			      " Counters:%d\n", offset, ce.set, ce.ctr);
>   		for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
> -			const char *ev_name = get_counter_name(ce.set, i, map);
> +			const char *ev_name = get_counter_name(ce.set, i, table);
>   
>   			color_fprintf(stdout, color,
>   				      "\tCounter:%03d %s Value:%#018lx\n", i,


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 12:31     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 12:31 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Move usage of the table to pmu-events.c so it may be hidden. By
> abstracting the table the implementation can later be changed.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/empty-pmu-events.c |  81 ++++++++-
>   tools/perf/pmu-events/jevents.py         |  81 ++++++++-
>   tools/perf/pmu-events/pmu-events.h       |  29 +--
>   tools/perf/tests/pmu-events.c            | 218 +++++++++++------------
>   tools/perf/util/metricgroup.c            |  15 +-
>   tools/perf/util/pmu.c                    |  34 +---
>   tools/perf/util/pmu.h                    |   2 +-
>   7 files changed, 280 insertions(+), 180 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 216ea0482c37..8ef75aff996c 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -6,6 +6,8 @@
>    * The test cpu/soc is provided for testing.
>    */
>   #include "pmu-events/pmu-events.h"
> +#include "util/header.h"
> +#include "util/pmu.h"
>   #include <string.h>
>   #include <stddef.h>
>   
> @@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
>   	},
>   };
>   
> -const struct pmu_events_map pmu_events_map[] = {
> +
> +/*
> + * Map a CPU to its table of PMU events. The CPU is identified by the
> + * cpuid field, which is an arch-specific identifier for the CPU.
> + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> + *
> + * The  cpuid can contain any character other than the comma.
> + */
> +struct pmu_events_map {
> +	const char *arch;
> +	const char *cpuid;
> +	const struct pmu_event *table;
> +};
> +
> +/*
> + * Global table mapping each known CPU for the architecture to its
> + * table of PMU events.
> + */
> +static const struct pmu_events_map pmu_events_map[] = {
>   	{
>   		.arch = "testarch",
>   		.cpuid = "testcpu",
> @@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   	},
>   };
>   
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> +{
> +	const struct pmu_event *table = NULL;
> +	char *cpuid = perf_pmu__getcpuid(pmu);
> +	int i;
> +
> +	/* on some platforms which uses cpus map, cpuid can be NULL for
> +	 * PMUs other than CORE PMUs.
> +	 */
> +	if (!cpuid)
> +		return NULL;
> +
> +	i = 0;
> +	for (;;) {
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> +		if (!map->table)
> +			break;
> +
> +		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> +			table = map->table;
> +			break;
> +		}
> +	}
> +	free(cpuid);
> +	return table;
> +}
> +
> +const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
> +{
> +	for (const struct pmu_events_map *tables = &pmu_events_map[0];
> +	     tables->table;
> +	     tables++) {
> +		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> +			return tables->table;
> +	}
> +	return NULL;
> +}
> +
> +int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
> +{
> +	for (const struct pmu_events_map *tables = &pmu_events_map[0];
> +	     tables->table;
> +	     tables++) {
> +		for (const struct pmu_event *pe = &tables->table[0];
> +		     pe->name || pe->metric_group || pe->metric_name;
> +		     pe++) {
> +			int ret = fn(pe, &tables->table[0], data);
> +
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +	return 0;
> +}
> +
>   const struct pmu_event *find_sys_events_table(const char *name)
>   {
>   	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> @@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
>   		for (const struct pmu_event *pe = &tables->table[0];
>   		     pe->name || pe->metric_group || pe->metric_name;
>   		     pe++) {
> -			int ret = fn(pe, data);
> +			int ret = fn(pe, &tables->table[0], data);
>   
>   			if (ret)
>   				return ret;
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index dd21bc9eeeed..e976c5e8e80b 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>   
>   def print_mapping_table(archs: Sequence[str]) -> None:
>     """Read the mapfile and generate the struct from cpuid string to event table."""
> -  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> +  _args.output_file.write("""
> +/*
> + * Map a CPU to its table of PMU events. The CPU is identified by the
> + * cpuid field, which is an arch-specific identifier for the CPU.
> + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> + *
> + * The  cpuid can contain any character other than the comma.
> + */
> +struct pmu_events_map {
> +        const char *arch;
> +        const char *cpuid;
> +        const struct pmu_event *table;
> +};
> +
> +/*
> + * Global table mapping each known CPU for the architecture to its
> + * table of PMU events.
> + */
> +const struct pmu_events_map pmu_events_map[] = {
> +""")
>     for arch in archs:
>       if arch == 'test':
>         _args.output_file.write("""{
> @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   \t},
>   };
>   
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> +{
> +        const struct pmu_event *table = NULL;
> +        char *cpuid = perf_pmu__getcpuid(pmu);

This seems an identical implementation to that in empty-pmu-events.c - 
can we reduce this duplication? Maybe a seperate common c file which can 
be linked in

The indentation seems different also - this version seems to use whitespaces

> +        int i;
> +
> +        /* on some platforms which uses cpus map, cpuid can be NULL for
> +         * PMUs other than CORE PMUs.
> +         */
> +        if (!cpuid)
> +                return NULL;
> +
> +        i = 0;
> +        for (;;) {
> +                const struct pmu_events_map *map = &pmu_events_map[i++];
> +                if (!map->table)
> +                        break;
> +
> +                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> +                        table = map->table;
> +                        break;
> +                }
> +        }
> +        free(cpuid);
> +        return table;
> +}

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
@ 2022-08-05 12:31     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 12:31 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Move usage of the table to pmu-events.c so it may be hidden. By
> abstracting the table the implementation can later be changed.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/empty-pmu-events.c |  81 ++++++++-
>   tools/perf/pmu-events/jevents.py         |  81 ++++++++-
>   tools/perf/pmu-events/pmu-events.h       |  29 +--
>   tools/perf/tests/pmu-events.c            | 218 +++++++++++------------
>   tools/perf/util/metricgroup.c            |  15 +-
>   tools/perf/util/pmu.c                    |  34 +---
>   tools/perf/util/pmu.h                    |   2 +-
>   7 files changed, 280 insertions(+), 180 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 216ea0482c37..8ef75aff996c 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -6,6 +6,8 @@
>    * The test cpu/soc is provided for testing.
>    */
>   #include "pmu-events/pmu-events.h"
> +#include "util/header.h"
> +#include "util/pmu.h"
>   #include <string.h>
>   #include <stddef.h>
>   
> @@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
>   	},
>   };
>   
> -const struct pmu_events_map pmu_events_map[] = {
> +
> +/*
> + * Map a CPU to its table of PMU events. The CPU is identified by the
> + * cpuid field, which is an arch-specific identifier for the CPU.
> + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> + *
> + * The  cpuid can contain any character other than the comma.
> + */
> +struct pmu_events_map {
> +	const char *arch;
> +	const char *cpuid;
> +	const struct pmu_event *table;
> +};
> +
> +/*
> + * Global table mapping each known CPU for the architecture to its
> + * table of PMU events.
> + */
> +static const struct pmu_events_map pmu_events_map[] = {
>   	{
>   		.arch = "testarch",
>   		.cpuid = "testcpu",
> @@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   	},
>   };
>   
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> +{
> +	const struct pmu_event *table = NULL;
> +	char *cpuid = perf_pmu__getcpuid(pmu);
> +	int i;
> +
> +	/* on some platforms which uses cpus map, cpuid can be NULL for
> +	 * PMUs other than CORE PMUs.
> +	 */
> +	if (!cpuid)
> +		return NULL;
> +
> +	i = 0;
> +	for (;;) {
> +		const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> +		if (!map->table)
> +			break;
> +
> +		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> +			table = map->table;
> +			break;
> +		}
> +	}
> +	free(cpuid);
> +	return table;
> +}
> +
> +const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
> +{
> +	for (const struct pmu_events_map *tables = &pmu_events_map[0];
> +	     tables->table;
> +	     tables++) {
> +		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> +			return tables->table;
> +	}
> +	return NULL;
> +}
> +
> +int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
> +{
> +	for (const struct pmu_events_map *tables = &pmu_events_map[0];
> +	     tables->table;
> +	     tables++) {
> +		for (const struct pmu_event *pe = &tables->table[0];
> +		     pe->name || pe->metric_group || pe->metric_name;
> +		     pe++) {
> +			int ret = fn(pe, &tables->table[0], data);
> +
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +	return 0;
> +}
> +
>   const struct pmu_event *find_sys_events_table(const char *name)
>   {
>   	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> @@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
>   		for (const struct pmu_event *pe = &tables->table[0];
>   		     pe->name || pe->metric_group || pe->metric_name;
>   		     pe++) {
> -			int ret = fn(pe, data);
> +			int ret = fn(pe, &tables->table[0], data);
>   
>   			if (ret)
>   				return ret;
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index dd21bc9eeeed..e976c5e8e80b 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>   
>   def print_mapping_table(archs: Sequence[str]) -> None:
>     """Read the mapfile and generate the struct from cpuid string to event table."""
> -  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> +  _args.output_file.write("""
> +/*
> + * Map a CPU to its table of PMU events. The CPU is identified by the
> + * cpuid field, which is an arch-specific identifier for the CPU.
> + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> + *
> + * The  cpuid can contain any character other than the comma.
> + */
> +struct pmu_events_map {
> +        const char *arch;
> +        const char *cpuid;
> +        const struct pmu_event *table;
> +};
> +
> +/*
> + * Global table mapping each known CPU for the architecture to its
> + * table of PMU events.
> + */
> +const struct pmu_events_map pmu_events_map[] = {
> +""")
>     for arch in archs:
>       if arch == 'test':
>         _args.output_file.write("""{
> @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   \t},
>   };
>   
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> +{
> +        const struct pmu_event *table = NULL;
> +        char *cpuid = perf_pmu__getcpuid(pmu);

This seems an identical implementation to that in empty-pmu-events.c - 
can we reduce this duplication? Maybe a seperate common c file which can 
be linked in

The indentation seems different also - this version seems to use whitespaces

> +        int i;
> +
> +        /* on some platforms which uses cpus map, cpuid can be NULL for
> +         * PMUs other than CORE PMUs.
> +         */
> +        if (!cpuid)
> +                return NULL;
> +
> +        i = 0;
> +        for (;;) {
> +                const struct pmu_events_map *map = &pmu_events_map[i++];
> +                if (!map->table)
> +                        break;
> +
> +                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> +                        table = map->table;
> +                        break;
> +                }
> +        }
> +        free(cpuid);
> +        return table;
> +}

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 12/17] perf pmu-events: Move test events/metrics to json
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 12:34     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 12:34 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Move arrays of pmu_events into the json code so that it may be
> regenerated and modified by the jevents.py script.
> 
> Signed-off-by: Ian Rogers<irogers@google.com>


Reviewed-by: John Garry <john.garry@huawei.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 12/17] perf pmu-events: Move test events/metrics to json
@ 2022-08-05 12:34     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 12:34 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Move arrays of pmu_events into the json code so that it may be
> regenerated and modified by the jevents.py script.
> 
> Signed-off-by: Ian Rogers<irogers@google.com>


Reviewed-by: John Garry <john.garry@huawei.com>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 13/17] perf pmu-events: Don't assume pmu_event is an array
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 12:56     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 12:56 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Current code assumes that a struct pmu_event can be iterated over
> forward until a NULL pmu_event is encountered. This makes it difficult
> to refactor pmu_event. Add a loop function taking a callback function
> that's passed the struct pmu_event. This way the pmu_event is only
> needed for one element and not an entire array.
> 
> Switch existing code iterating over the pmu_event arrays to use the new
> loop function pmu_events_table_for_each_event.


I find it hard to follow the change from the description. The title is 
"Don't assume pmu_event is an array", but that is rightly what 
pmu_events_table_for_each_event() does.

If I check - for exmaple - pmu_add_cpu_aliases_map(), you just switch it 
over to using pmu_events_table_for_each_event(), which seems resonable. 
So it just seems here that we're refactoring the code, and not changing 
the nature of how we handle pmu_events *.

> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/empty-pmu-events.c |  34 +++--
>   tools/perf/pmu-events/jevents.py         |  34 +++--
>   tools/perf/pmu-events/pmu-events.h       |   3 +
>   tools/perf/tests/pmu-events.c            | 136 +++++++++--------
>   tools/perf/util/metricgroup.c            | 181 ++++++++++++++++-------
>   tools/perf/util/pmu.c                    |  65 ++++----
>   tools/perf/util/s390-sample-raw.c        |  42 ++++--
>   7 files changed, 313 insertions(+), 182 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 028f44efe48d..bee1967baa2b 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -247,6 +247,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   	},
>   };
>   
> +int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
> +				    void *data)
> +{
> +	for (const struct pmu_event *pe = &table[0];
> +	     pe->name || pe->metric_group || pe->metric_name;
> +	     pe++) {
> +		int ret = fn(pe, table, data);
> +
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
>   const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
>   {
>   	const struct pmu_event *table = NULL;
> @@ -291,14 +305,10 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
>   	for (const struct pmu_events_map *tables = &pmu_events_map[0];
>   	     tables->table;
>   	     tables++) {
> -		for (const struct pmu_event *pe = &tables->table[0];
> -		     pe->name || pe->metric_group || pe->metric_name;
> -		     pe++) {
> -			int ret = fn(pe, &tables->table[0], data);
> +		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
>   
> -			if (ret)
> -				return ret;
> -		}
> +		if (ret)
> +			return ret;
>   	}
>   	return 0;
>   }
> @@ -319,14 +329,10 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
>   	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
>   	     tables->name;
>   	     tables++) {
> -		for (const struct pmu_event *pe = &tables->table[0];
> -		     pe->name || pe->metric_group || pe->metric_name;
> -		     pe++) {
> -			int ret = fn(pe, &tables->table[0], data);
> +		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
>   
> -			if (ret)
> -				return ret;
> -		}
> +		if (ret)
> +			return ret;
>   	}
>   	return 0;
>   }
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index e976c5e8e80b..365c960202b0 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -409,6 +409,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   \t},
>   };
>   
> +int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
> +                                    void *data)

Again we seem to be just duplicating what is in empty-pmu-events.c - can 
we avoid this? another idea (apart from linking in other c files) is for 
empty-pmu-events.c to be generated from jevents.py (like how it was done 
for jevents.c)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 13/17] perf pmu-events: Don't assume pmu_event is an array
@ 2022-08-05 12:56     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 12:56 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> Current code assumes that a struct pmu_event can be iterated over
> forward until a NULL pmu_event is encountered. This makes it difficult
> to refactor pmu_event. Add a loop function taking a callback function
> that's passed the struct pmu_event. This way the pmu_event is only
> needed for one element and not an entire array.
> 
> Switch existing code iterating over the pmu_event arrays to use the new
> loop function pmu_events_table_for_each_event.


I find it hard to follow the change from the description. The title is 
"Don't assume pmu_event is an array", but that is rightly what 
pmu_events_table_for_each_event() does.

If I check - for exmaple - pmu_add_cpu_aliases_map(), you just switch it 
over to using pmu_events_table_for_each_event(), which seems resonable. 
So it just seems here that we're refactoring the code, and not changing 
the nature of how we handle pmu_events *.

> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/empty-pmu-events.c |  34 +++--
>   tools/perf/pmu-events/jevents.py         |  34 +++--
>   tools/perf/pmu-events/pmu-events.h       |   3 +
>   tools/perf/tests/pmu-events.c            | 136 +++++++++--------
>   tools/perf/util/metricgroup.c            | 181 ++++++++++++++++-------
>   tools/perf/util/pmu.c                    |  65 ++++----
>   tools/perf/util/s390-sample-raw.c        |  42 ++++--
>   7 files changed, 313 insertions(+), 182 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 028f44efe48d..bee1967baa2b 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -247,6 +247,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   	},
>   };
>   
> +int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
> +				    void *data)
> +{
> +	for (const struct pmu_event *pe = &table[0];
> +	     pe->name || pe->metric_group || pe->metric_name;
> +	     pe++) {
> +		int ret = fn(pe, table, data);
> +
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
>   const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
>   {
>   	const struct pmu_event *table = NULL;
> @@ -291,14 +305,10 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
>   	for (const struct pmu_events_map *tables = &pmu_events_map[0];
>   	     tables->table;
>   	     tables++) {
> -		for (const struct pmu_event *pe = &tables->table[0];
> -		     pe->name || pe->metric_group || pe->metric_name;
> -		     pe++) {
> -			int ret = fn(pe, &tables->table[0], data);
> +		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
>   
> -			if (ret)
> -				return ret;
> -		}
> +		if (ret)
> +			return ret;
>   	}
>   	return 0;
>   }
> @@ -319,14 +329,10 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
>   	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
>   	     tables->name;
>   	     tables++) {
> -		for (const struct pmu_event *pe = &tables->table[0];
> -		     pe->name || pe->metric_group || pe->metric_name;
> -		     pe++) {
> -			int ret = fn(pe, &tables->table[0], data);
> +		int ret = pmu_events_table_for_each_event(tables->table, fn, data);
>   
> -			if (ret)
> -				return ret;
> -		}
> +		if (ret)
> +			return ret;
>   	}
>   	return 0;
>   }
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index e976c5e8e80b..365c960202b0 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -409,6 +409,20 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   \t},
>   };
>   
> +int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
> +                                    void *data)

Again we seem to be just duplicating what is in empty-pmu-events.c - can 
we avoid this? another idea (apart from linking in other c files) is for 
empty-pmu-events.c to be generated from jevents.py (like how it was done 
for jevents.c)

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 16/17] perf jevents: Compress the pmu_events_table
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-05 14:02     ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 14:02 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> The pmu_events array requires 15 pointers per entry which in position
> independent code need relocating. Change the array to be an array of
> offsets within a big C string. Only the offset of the first variable is
> required, subsequent variables are stored in order after the \0
> terminator (requiring a byte per variable rather than 4 bytes per
> offset).
> 
> The file size savings are:
> no jevents - the same 19,788,464bytes
> x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> default build options plus NO_LIBBFD=1.
> 
> For example, the x86 build savings come from .rela.dyn and
> .data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
> respectively. .rodata increases by 1,432,448bytes, giving an overall
> 4,766,600bytes saving.
> 
> To make metric strings more shareable, the topic is changed from say
> 'skx metrics' to just 'metrics'.
> 
> To try to help with the memory layout the pmu_events are ordered as used
> by perf qsort comparator functions.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
>   1 file changed, 162 insertions(+), 45 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index aa8df649025a..a5e162558994 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -6,7 +6,8 @@ import csv
>   import json
>   import os
>   import sys
> -from typing import (Callable, Optional, Sequence)
> +from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
> +import collections
>   
>   # Global command line arguments.
>   _args = None
> @@ -20,6 +21,19 @@ _arch_std_events = {}
>   _close_table = False
>   # Events to write out when the table is closed
>   _pending_events = []
> +# Global BigCString shared by all structures.
> +_bcs = None
> +# Order specific JsonEvent attributes will be visited.
> +_json_event_attributes = [
> +    # cmp_sevent related attributes.
> +    'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
> +    # Seems useful, put it early.
> +    'event',
> +    # Short things in alphabetical order.
> +    'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
> +    # Longer things (the last won't be iterated over during decompress).
> +    'metric_constraint', 'metric_expr', 'long_desc'
> +]
>   
>   
>   def removesuffix(s: str, suffix: str) -> str:
> @@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
>     tblname += '_' + dirname
>     return tblname.replace('-', '_')
>   
> +def c_len(s: str) -> int:
> +  """Return the length of s a C string
> +
> +  This doesn't handle all escape characters properly. It first assumes
> +  all \ are for escaping, it then adjusts as it will have over counted
> +  \\. The code uses \000 rather than \0 as a terminator as an adjacent
> +  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
> +  equal a terminator followed by the number 5 but the escape of
> +  \05). The code adjusts for \000 but not properly for all octal, hex
> +  or unicode values.
> +  """
> +  try:
> +    utf = s.encode(encoding='utf-8',errors='strict')
> +  except:
> +    print(f'broken string {s}')
> +    raise
> +  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
> +
> +class BigCString:
> +  """A class to hold many strings concatenated together.
> +
> +  Generating a large number of stand-alone C strings creates a large
> +  number of relocations in position independent code. The BigCString
> +  is a helper for this case. It builds a single string which within it
> +  are all the other C strings (to avoid memory issues the string
> +  itself is held as a list of strings). The offsets within the big
> +  string are recorded and when stored to disk these don't need
> +  relocation.
> +  """
> +  strings: Set[str]
> +  big_string: Sequence[str]
> +  offsets: Dict[str, int]
> +
> +  def __init__(self):
> +    self.strings = set()
> +
> +  def add(self, s: str) -> None:
> +    """Called to add to the big string."""
> +    self.strings.add(s)
> +
> +  def compute(self) -> None:
> +    """Called once all strings are added to compute the string and offsets."""
> +
> +    # big_string_offset is the current location within the C string
> +    # being appended to - comments, etc. don't count. big_string is
> +    # the string contents represented as a list. Strings are immutable
> +    # in Python and so appending to one causes memory issues, while
> +    # lists are mutable.
> +    big_string_offset = 0
> +    self.big_string = []
> +    self.offsets = {}
> +    # Emit all strings in a sorted manner.
> +    for s in sorted(self.strings):
> +      self.offsets[s] = big_string_offset
> +      self.big_string.append(f'/* offset={big_string_offset} */ "')
> +      self.big_string.append(s)
> +      self.big_string.append('"\n')
> +      big_string_offset += c_len(s)
> +
> +_bcs = BigCString()
>   
>   class JsonEvent:
>     """Representation of an event loaded from a json file dictionary."""
> @@ -202,26 +276,18 @@ class JsonEvent:
>           s += f'\t{attr} = {value},\n'
>       return s + '}'
>   
> +  def build_c_string(self) -> str:
> +    s = ''
> +    for attr in _json_event_attributes:
> +      x = getattr(self, attr)
> +      s += f'{x}\\000' if x else '\\000'
> +    return s
> +
>     def to_c_string(self) -> str:
>       """Representation of the event as a C struct initializer."""
>   
> -    def attr_string(attr: str, value: str) -> str:
> -      return f'\t.{attr} = \"{value}\",\n'
> -
> -    def str_if_present(self, attr: str) -> str:
> -      if not getattr(self, attr):
> -        return ''
> -      return attr_string(attr, getattr(self, attr))
> -
> -    s = '{\n'
> -    for attr in [
> -        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> -        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> -        'name', 'perpkg', 'pmu', 'topic', 'unit'
> -    ]:
> -      s += str_if_present(self, attr)
> -    s += '},\n'
> -    return s
> +    s = self.build_c_string()
> +    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
>   
>   
>   def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> @@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
>       event.topic = topic
>     return result
>   
> -
>   def preprocess_arch_std_files(archpath: str) -> None:
>     """Read in all architecture standard events."""
>     global _arch_std_events
> @@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
>     global _close_table
>     if _close_table:
>       raise IOError('Printing table prefix but last table has no suffix')
> -  _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
> +  _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
>     _close_table = True
>   
>   
> @@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
>   def print_events_table_suffix() -> None:
>     """Optionally close events table."""
>   
> -  def event_cmp_key(j: JsonEvent):
> -    def fix_none(s: str):
> +  def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
> +    def fix_none(s: Optional[str]) -> str:
>         if s is None:
>           return ''
>         return s
>   
> -    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> +    return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
>               fix_none(j.metric_name))
>   
>     global _close_table
> @@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
>       _args.output_file.write(event.to_c_string())
>       _pending_events = []
>   
> -  _args.output_file.write("""{
> -\t.name = 0,
> -\t.event = 0,
> -\t.desc = 0,
> -},
> -};
> -""")
> +  _args.output_file.write('};\n\n')
>     _close_table = False
>   
> +def get_topic(topic: str) -> str:
> +  if topic.endswith('metrics.json'):
> +    return 'metrics'
> +  return removesuffix(topic, '.json').replace('-', ' ')
> +
> +def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> +
> +  if item.is_dir():
> +    return
> +
> +  # base dir or too deep
> +  level = len(parents)
> +  if level == 0 or level > 4:
> +    return
> +
> +  # Ignore other directories. If the file name does not have a .json
> +  # extension, ignore it. It could be a readme.txt for instance.
> +  if not item.is_file() or not item.name.endswith('.json'):
> +    return
> +
> +  topic = get_topic(item.name)
> +  for event in read_json_events(item.path, topic):
> +    _bcs.add(event.build_c_string())
>   
>   def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>     """Process a JSON file during the main walk."""
>     global _sys_event_tables
>   
> -  def get_topic(topic: str) -> str:
> -    return removesuffix(topic, '.json').replace('-', ' ')
> -
>     def is_leaf_dir(path: str) -> bool:
>       for item in os.scandir(path):
>         if item.is_dir():
> @@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
>     _args.output_file.write("""
>   /* Struct used to make the PMU event table implementation opaque to callers. */
>   struct pmu_events_table {
> -        const struct pmu_event *entries;
> +        const struct compact_pmu_event *entries;
> +        size_t length;
>   };
>   
>   /*
> @@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
>         _args.output_file.write("""{
>   \t.arch = "testarch",
>   \t.cpuid = "testcpu",
> -\t.table = { pme_test_soc_cpu },
> +\t.table = {
> +\t.entries = pme_test_soc_cpu,
> +\t.length = ARRAY_SIZE(pme_test_soc_cpu),
> +\t}
>   },
>   """)
>       else:
> @@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
>               _args.output_file.write(f"""{{
>   \t.arch = "{arch}",
>   \t.cpuid = "{cpuid}",
> -\t.table = {{ {tblname} }}
> +\t.table = {{
> +\t\t.entries = {tblname},
> +\t\t.length = ARRAY_SIZE({tblname})
> +\t}}
>   }},
>   """)
>             first = False
> @@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
>     _args.output_file.write("""{
>   \t.arch = 0,
>   \t.cpuid = 0,
> -\t.table = { 0 },
> +\t.table = { 0, 0 },
>   }
>   };
>   """)
> @@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   """)
>     for tblname in _sys_event_tables:
>       _args.output_file.write(f"""\t{{
> -\t\t.table = {{ {tblname} }},
> +\t\t.table = {{
> +\t\t\t.entries = {tblname},
> +\t\t\t.length = ARRAY_SIZE({tblname})
> +\t\t}},
>   \t\t.name = \"{tblname}\",
>   \t}},
>   """)
>     _args.output_file.write("""\t{
> -\t\t.table = { 0 }
> +\t\t.table = { 0, 0 }
>   \t},
>   };
>   
> -int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
> +static void decompress(int offset, struct pmu_event *pe)
> +{
> +\tconst char *p = &big_c_string[offset];
> +""")
> +  for attr in _json_event_attributes:
> +    _args.output_file.write(f"""
> +\tpe->{attr} = (*p == '\\0' ? NULL : p);
> +""")
> +    if attr == _json_event_attributes[-1]:
> +      continue
> +    _args.output_file.write('\twhile (*p++);')
> +  _args.output_file.write("""}


I get this in generated pmu-events.c:

static void decompress(int offset, struct pmu_event *pe)
{
const char *p = &big_c_string[offset];

pe->name = (*p == '\0' ? NULL : p);
while (*p++);
pe->pmu = (*p == '\0' ? NULL : p);
while (*p++);
pe->topic = (*p == '\0' ? NULL : p);
while (*p++);
pe->desc = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_name = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_group = (*p == '\0' ? NULL : p);
while (*p++);
pe->event = (*p == '\0' ? NULL : p);
while (*p++);
pe->aggr_mode = (*p == '\0' ? NULL : p);
while (*p++);
pe->compat = (*p == '\0' ? NULL : p);
while (*p++);
pe->deprecated = (*p == '\0' ? NULL : p);
while (*p++);
pe->perpkg = (*p == '\0' ? NULL : p);
while (*p++);
pe->unit = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_constraint = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_expr = (*p == '\0' ? NULL : p);
while (*p++);
pe->long_desc = (*p == '\0' ? NULL : p);
}

int pmu_events_table_for_each_event(const struct pmu_events_table *table,
                                     pmu_event_iter_fn fn,
                                     void *data)
{
         for (size_t i = 0; i < table->length; i++) {
                 struct pmu_event pe;
                 int ret;

                 decompress(table->entries[i].offset, &pe);
                 ret = fn(&pe, table, data);
                 if (ret)
                         return ret;
         }
         return 0;
}

--->8---

This seems a bit inefficient in terms of performance - if that really is 
a requirement, but I figure that it isn't really.

Another observation is that although we compress and reduce size in this 
method, we are now losing out on some sharing of strings. For example, 
this is an extract from big_string:

/* offset=3342573 */ 
"unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core 0 C 
State Transition Cycles. Unit: uncore_pcu 
\000\000\000event=0x70\000\000\000\0001\000\000\000\000Number of cycles 
spent performing core C state transitions.  There is one event per core\000"
/* offset=3342789 */ 
"unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core C 
State Transition Cycles. Unit: uncore_pcu 
\000\000\000event=0x103\000\000\000\0001\000\000\000\000Number of cycles 
spent performing core C state transitions.  There is one event per core\000"

These super-strings are not identical, but many sub-strings are, like
"Number of cycles spent performing core C state transitions.  There is 
one event per core", so we are losing out there on sharing strings there.

Thanks,
John
> +
> +int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> +                                    pmu_event_iter_fn fn,
>                                       void *data)
>   {
> -        for (const struct pmu_event *pe = &table->entries[0];
> -             pe->name || pe->metric_group || pe->metric_name;
> -             pe++) {
> -                int ret = fn(pe, table, data);
> +        for (size_t i = 0; i < table->length; i++) {
> +                struct pmu_event pe;
> +                int ret;
>   
> +                decompress(table->entries[i].offset, &pe);
> +                ret = fn(&pe, table, data);
>                   if (ret)
>                           return ret;
>           }
> @@ -530,7 +634,7 @@ def main() -> None:
>         help='Root of tree containing architecture directories containing json files'
>     )
>     ap.add_argument(
> -      'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
> +      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
>     _args = ap.parse_args()
>   
>     _args.output_file.write("""
> @@ -540,6 +644,10 @@ def main() -> None:
>   #include <string.h>
>   #include <stddef.h>
>   
> +struct compact_pmu_event {
> +  int offset;
> +};
> +
>   """)
>     archs = []
>     for item in os.scandir(_args.starting_dir):
> @@ -555,6 +663,15 @@ def main() -> None:
>     for arch in archs:
>       arch_path = f'{_args.starting_dir}/{arch}'
>       preprocess_arch_std_files(arch_path)
> +    ftw(arch_path, [], preprocess_one_file)
> +
> +  _bcs.compute()
> +  _args.output_file.write('static const char *const big_c_string =\n')
> +  for s in _bcs.big_string:
> +    _args.output_file.write(s)
> +  _args.output_file.write(';\n\n')
> +  for arch in archs:
> +    arch_path = f'{_args.starting_dir}/{arch}'
>       ftw(arch_path, [], process_one_file)
>       print_events_table_suffix()
>   


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 16/17] perf jevents: Compress the pmu_events_table
@ 2022-08-05 14:02     ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-05 14:02 UTC (permalink / raw)
  To: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Andi Kleen, Zhengjun Xing, Ravi Bangoria, Kan Liang,
	Adrian Hunter, linux-kernel, linux-arm-kernel, linux-perf-users
  Cc: Stephane Eranian

On 04/08/2022 23:18, Ian Rogers wrote:
> The pmu_events array requires 15 pointers per entry which in position
> independent code need relocating. Change the array to be an array of
> offsets within a big C string. Only the offset of the first variable is
> required, subsequent variables are stored in order after the \0
> terminator (requiring a byte per variable rather than 4 bytes per
> offset).
> 
> The file size savings are:
> no jevents - the same 19,788,464bytes
> x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> default build options plus NO_LIBBFD=1.
> 
> For example, the x86 build savings come from .rela.dyn and
> .data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
> respectively. .rodata increases by 1,432,448bytes, giving an overall
> 4,766,600bytes saving.
> 
> To make metric strings more shareable, the topic is changed from say
> 'skx metrics' to just 'metrics'.
> 
> To try to help with the memory layout the pmu_events are ordered as used
> by perf qsort comparator functions.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
>   1 file changed, 162 insertions(+), 45 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index aa8df649025a..a5e162558994 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -6,7 +6,8 @@ import csv
>   import json
>   import os
>   import sys
> -from typing import (Callable, Optional, Sequence)
> +from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
> +import collections
>   
>   # Global command line arguments.
>   _args = None
> @@ -20,6 +21,19 @@ _arch_std_events = {}
>   _close_table = False
>   # Events to write out when the table is closed
>   _pending_events = []
> +# Global BigCString shared by all structures.
> +_bcs = None
> +# Order specific JsonEvent attributes will be visited.
> +_json_event_attributes = [
> +    # cmp_sevent related attributes.
> +    'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
> +    # Seems useful, put it early.
> +    'event',
> +    # Short things in alphabetical order.
> +    'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
> +    # Longer things (the last won't be iterated over during decompress).
> +    'metric_constraint', 'metric_expr', 'long_desc'
> +]
>   
>   
>   def removesuffix(s: str, suffix: str) -> str:
> @@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
>     tblname += '_' + dirname
>     return tblname.replace('-', '_')
>   
> +def c_len(s: str) -> int:
> +  """Return the length of s a C string
> +
> +  This doesn't handle all escape characters properly. It first assumes
> +  all \ are for escaping, it then adjusts as it will have over counted
> +  \\. The code uses \000 rather than \0 as a terminator as an adjacent
> +  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
> +  equal a terminator followed by the number 5 but the escape of
> +  \05). The code adjusts for \000 but not properly for all octal, hex
> +  or unicode values.
> +  """
> +  try:
> +    utf = s.encode(encoding='utf-8',errors='strict')
> +  except:
> +    print(f'broken string {s}')
> +    raise
> +  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
> +
> +class BigCString:
> +  """A class to hold many strings concatenated together.
> +
> +  Generating a large number of stand-alone C strings creates a large
> +  number of relocations in position independent code. The BigCString
> +  is a helper for this case. It builds a single string which within it
> +  are all the other C strings (to avoid memory issues the string
> +  itself is held as a list of strings). The offsets within the big
> +  string are recorded and when stored to disk these don't need
> +  relocation.
> +  """
> +  strings: Set[str]
> +  big_string: Sequence[str]
> +  offsets: Dict[str, int]
> +
> +  def __init__(self):
> +    self.strings = set()
> +
> +  def add(self, s: str) -> None:
> +    """Called to add to the big string."""
> +    self.strings.add(s)
> +
> +  def compute(self) -> None:
> +    """Called once all strings are added to compute the string and offsets."""
> +
> +    # big_string_offset is the current location within the C string
> +    # being appended to - comments, etc. don't count. big_string is
> +    # the string contents represented as a list. Strings are immutable
> +    # in Python and so appending to one causes memory issues, while
> +    # lists are mutable.
> +    big_string_offset = 0
> +    self.big_string = []
> +    self.offsets = {}
> +    # Emit all strings in a sorted manner.
> +    for s in sorted(self.strings):
> +      self.offsets[s] = big_string_offset
> +      self.big_string.append(f'/* offset={big_string_offset} */ "')
> +      self.big_string.append(s)
> +      self.big_string.append('"\n')
> +      big_string_offset += c_len(s)
> +
> +_bcs = BigCString()
>   
>   class JsonEvent:
>     """Representation of an event loaded from a json file dictionary."""
> @@ -202,26 +276,18 @@ class JsonEvent:
>           s += f'\t{attr} = {value},\n'
>       return s + '}'
>   
> +  def build_c_string(self) -> str:
> +    s = ''
> +    for attr in _json_event_attributes:
> +      x = getattr(self, attr)
> +      s += f'{x}\\000' if x else '\\000'
> +    return s
> +
>     def to_c_string(self) -> str:
>       """Representation of the event as a C struct initializer."""
>   
> -    def attr_string(attr: str, value: str) -> str:
> -      return f'\t.{attr} = \"{value}\",\n'
> -
> -    def str_if_present(self, attr: str) -> str:
> -      if not getattr(self, attr):
> -        return ''
> -      return attr_string(attr, getattr(self, attr))
> -
> -    s = '{\n'
> -    for attr in [
> -        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> -        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> -        'name', 'perpkg', 'pmu', 'topic', 'unit'
> -    ]:
> -      s += str_if_present(self, attr)
> -    s += '},\n'
> -    return s
> +    s = self.build_c_string()
> +    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
>   
>   
>   def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> @@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
>       event.topic = topic
>     return result
>   
> -
>   def preprocess_arch_std_files(archpath: str) -> None:
>     """Read in all architecture standard events."""
>     global _arch_std_events
> @@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
>     global _close_table
>     if _close_table:
>       raise IOError('Printing table prefix but last table has no suffix')
> -  _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
> +  _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
>     _close_table = True
>   
>   
> @@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
>   def print_events_table_suffix() -> None:
>     """Optionally close events table."""
>   
> -  def event_cmp_key(j: JsonEvent):
> -    def fix_none(s: str):
> +  def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
> +    def fix_none(s: Optional[str]) -> str:
>         if s is None:
>           return ''
>         return s
>   
> -    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> +    return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
>               fix_none(j.metric_name))
>   
>     global _close_table
> @@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
>       _args.output_file.write(event.to_c_string())
>       _pending_events = []
>   
> -  _args.output_file.write("""{
> -\t.name = 0,
> -\t.event = 0,
> -\t.desc = 0,
> -},
> -};
> -""")
> +  _args.output_file.write('};\n\n')
>     _close_table = False
>   
> +def get_topic(topic: str) -> str:
> +  if topic.endswith('metrics.json'):
> +    return 'metrics'
> +  return removesuffix(topic, '.json').replace('-', ' ')
> +
> +def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> +
> +  if item.is_dir():
> +    return
> +
> +  # base dir or too deep
> +  level = len(parents)
> +  if level == 0 or level > 4:
> +    return
> +
> +  # Ignore other directories. If the file name does not have a .json
> +  # extension, ignore it. It could be a readme.txt for instance.
> +  if not item.is_file() or not item.name.endswith('.json'):
> +    return
> +
> +  topic = get_topic(item.name)
> +  for event in read_json_events(item.path, topic):
> +    _bcs.add(event.build_c_string())
>   
>   def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>     """Process a JSON file during the main walk."""
>     global _sys_event_tables
>   
> -  def get_topic(topic: str) -> str:
> -    return removesuffix(topic, '.json').replace('-', ' ')
> -
>     def is_leaf_dir(path: str) -> bool:
>       for item in os.scandir(path):
>         if item.is_dir():
> @@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
>     _args.output_file.write("""
>   /* Struct used to make the PMU event table implementation opaque to callers. */
>   struct pmu_events_table {
> -        const struct pmu_event *entries;
> +        const struct compact_pmu_event *entries;
> +        size_t length;
>   };
>   
>   /*
> @@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
>         _args.output_file.write("""{
>   \t.arch = "testarch",
>   \t.cpuid = "testcpu",
> -\t.table = { pme_test_soc_cpu },
> +\t.table = {
> +\t.entries = pme_test_soc_cpu,
> +\t.length = ARRAY_SIZE(pme_test_soc_cpu),
> +\t}
>   },
>   """)
>       else:
> @@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
>               _args.output_file.write(f"""{{
>   \t.arch = "{arch}",
>   \t.cpuid = "{cpuid}",
> -\t.table = {{ {tblname} }}
> +\t.table = {{
> +\t\t.entries = {tblname},
> +\t\t.length = ARRAY_SIZE({tblname})
> +\t}}
>   }},
>   """)
>             first = False
> @@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
>     _args.output_file.write("""{
>   \t.arch = 0,
>   \t.cpuid = 0,
> -\t.table = { 0 },
> +\t.table = { 0, 0 },
>   }
>   };
>   """)
> @@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   """)
>     for tblname in _sys_event_tables:
>       _args.output_file.write(f"""\t{{
> -\t\t.table = {{ {tblname} }},
> +\t\t.table = {{
> +\t\t\t.entries = {tblname},
> +\t\t\t.length = ARRAY_SIZE({tblname})
> +\t\t}},
>   \t\t.name = \"{tblname}\",
>   \t}},
>   """)
>     _args.output_file.write("""\t{
> -\t\t.table = { 0 }
> +\t\t.table = { 0, 0 }
>   \t},
>   };
>   
> -int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
> +static void decompress(int offset, struct pmu_event *pe)
> +{
> +\tconst char *p = &big_c_string[offset];
> +""")
> +  for attr in _json_event_attributes:
> +    _args.output_file.write(f"""
> +\tpe->{attr} = (*p == '\\0' ? NULL : p);
> +""")
> +    if attr == _json_event_attributes[-1]:
> +      continue
> +    _args.output_file.write('\twhile (*p++);')
> +  _args.output_file.write("""}


I get this in generated pmu-events.c:

static void decompress(int offset, struct pmu_event *pe)
{
const char *p = &big_c_string[offset];

pe->name = (*p == '\0' ? NULL : p);
while (*p++);
pe->pmu = (*p == '\0' ? NULL : p);
while (*p++);
pe->topic = (*p == '\0' ? NULL : p);
while (*p++);
pe->desc = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_name = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_group = (*p == '\0' ? NULL : p);
while (*p++);
pe->event = (*p == '\0' ? NULL : p);
while (*p++);
pe->aggr_mode = (*p == '\0' ? NULL : p);
while (*p++);
pe->compat = (*p == '\0' ? NULL : p);
while (*p++);
pe->deprecated = (*p == '\0' ? NULL : p);
while (*p++);
pe->perpkg = (*p == '\0' ? NULL : p);
while (*p++);
pe->unit = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_constraint = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_expr = (*p == '\0' ? NULL : p);
while (*p++);
pe->long_desc = (*p == '\0' ? NULL : p);
}

int pmu_events_table_for_each_event(const struct pmu_events_table *table,
                                     pmu_event_iter_fn fn,
                                     void *data)
{
         for (size_t i = 0; i < table->length; i++) {
                 struct pmu_event pe;
                 int ret;

                 decompress(table->entries[i].offset, &pe);
                 ret = fn(&pe, table, data);
                 if (ret)
                         return ret;
         }
         return 0;
}

--->8---

This seems a bit inefficient in terms of performance - if that really is 
a requirement, but I figure that it isn't really.

Another observation is that although we compress and reduce size in this 
method, we are now losing out on some sharing of strings. For example, 
this is an extract from big_string:

/* offset=3342573 */ 
"unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core 0 C 
State Transition Cycles. Unit: uncore_pcu 
\000\000\000event=0x70\000\000\000\0001\000\000\000\000Number of cycles 
spent performing core C state transitions.  There is one event per core\000"
/* offset=3342789 */ 
"unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core C 
State Transition Cycles. Unit: uncore_pcu 
\000\000\000event=0x103\000\000\000\0001\000\000\000\000Number of cycles 
spent performing core C state transitions.  There is one event per core\000"

These super-strings are not identical, but many sub-strings are, like
"Number of cycles spent performing core C state transitions.  There is 
one event per core", so we are losing out there on sharing strings there.

Thanks,
John
> +
> +int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> +                                    pmu_event_iter_fn fn,
>                                       void *data)
>   {
> -        for (const struct pmu_event *pe = &table->entries[0];
> -             pe->name || pe->metric_group || pe->metric_name;
> -             pe++) {
> -                int ret = fn(pe, table, data);
> +        for (size_t i = 0; i < table->length; i++) {
> +                struct pmu_event pe;
> +                int ret;
>   
> +                decompress(table->entries[i].offset, &pe);
> +                ret = fn(&pe, table, data);
>                   if (ret)
>                           return ret;
>           }
> @@ -530,7 +634,7 @@ def main() -> None:
>         help='Root of tree containing architecture directories containing json files'
>     )
>     ap.add_argument(
> -      'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
> +      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
>     _args = ap.parse_args()
>   
>     _args.output_file.write("""
> @@ -540,6 +644,10 @@ def main() -> None:
>   #include <string.h>
>   #include <stddef.h>
>   
> +struct compact_pmu_event {
> +  int offset;
> +};
> +
>   """)
>     archs = []
>     for item in os.scandir(_args.starting_dir):
> @@ -555,6 +663,15 @@ def main() -> None:
>     for arch in archs:
>       arch_path = f'{_args.starting_dir}/{arch}'
>       preprocess_arch_std_files(arch_path)
> +    ftw(arch_path, [], preprocess_one_file)
> +
> +  _bcs.compute()
> +  _args.output_file.write('static const char *const big_c_string =\n')
> +  for s in _bcs.big_string:
> +    _args.output_file.write(s)
> +  _args.output_file.write(';\n\n')
> +  for arch in archs:
> +    arch_path = f'{_args.starting_dir}/{arch}'
>       ftw(arch_path, [], process_one_file)
>       print_events_table_suffix()
>   


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 01/17] perf jevents: Clean up pytype warnings
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-09 19:36     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:36 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Thu, Aug 04, 2022 at 03:18:00PM -0700, Ian Rogers escreveu:
> Improve type hints to clean up pytype warnings.

Thanks, applied.

- Arnaldo

 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/pmu-events/jevents.py | 13 ++++++-------
>  1 file changed, 6 insertions(+), 7 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 83e0dcbeac9a..5b72048d50da 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -6,8 +6,7 @@ import csv
>  import json
>  import os
>  import sys
> -from typing import Callable
> -from typing import Sequence
> +from typing import (Callable, Optional, Sequence)
>  
>  # Global command line arguments.
>  _args = None
> @@ -57,7 +56,7 @@ class JsonEvent:
>                                         '. '), '.').replace('\n', '\\n').replace(
>                                             '\"', '\\"').replace('\r', '\\r')
>  
> -    def convert_aggr_mode(aggr_mode: str) -> str:
> +    def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
>        """Returns the aggr_mode_class enum value associated with the JSON string."""
>        if not aggr_mode:
>          return None
> @@ -67,7 +66,7 @@ class JsonEvent:
>        }
>        return aggr_mode_to_enum[aggr_mode]
>  
> -    def lookup_msr(num: str) -> str:
> +    def lookup_msr(num: str) -> Optional[str]:
>        """Converts the msr number, or first in a list to the appropriate event field."""
>        if not num:
>          return None
> @@ -79,7 +78,7 @@ class JsonEvent:
>        }
>        return msrmap[int(num.split(',', 1)[0], 0)]
>  
> -    def real_event(name: str, event: str) -> str:
> +    def real_event(name: str, event: str) -> Optional[str]:
>        """Convert well known event names to an event string otherwise use the event argument."""
>        fixed = {
>            'inst_retired.any': 'event=0xc0,period=2000003',
> @@ -95,7 +94,7 @@ class JsonEvent:
>          return fixed[name.lower()]
>        return event
>  
> -    def unit_to_pmu(unit: str) -> str:
> +    def unit_to_pmu(unit: str) -> Optional[str]:
>        """Convert a JSON Unit to Linux PMU name."""
>        if not unit:
>          return None
> @@ -154,7 +153,7 @@ class JsonEvent:
>      if self.metric_expr:
>        self.metric_expr = self.metric_expr.replace('\\', '\\\\')
>      arch_std = jd.get('ArchStdEvent')
> -    if precise and self.desc and not '(Precise Event)' in self.desc:
> +    if precise and self.desc and '(Precise Event)' not in self.desc:
>        extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
>                                                                   'event)')
>      event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
> -- 
> 2.37.1.559.g78731f0fdb-goog

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 01/17] perf jevents: Clean up pytype warnings
@ 2022-08-09 19:36     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:36 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Thu, Aug 04, 2022 at 03:18:00PM -0700, Ian Rogers escreveu:
> Improve type hints to clean up pytype warnings.

Thanks, applied.

- Arnaldo

 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/pmu-events/jevents.py | 13 ++++++-------
>  1 file changed, 6 insertions(+), 7 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 83e0dcbeac9a..5b72048d50da 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -6,8 +6,7 @@ import csv
>  import json
>  import os
>  import sys
> -from typing import Callable
> -from typing import Sequence
> +from typing import (Callable, Optional, Sequence)
>  
>  # Global command line arguments.
>  _args = None
> @@ -57,7 +56,7 @@ class JsonEvent:
>                                         '. '), '.').replace('\n', '\\n').replace(
>                                             '\"', '\\"').replace('\r', '\\r')
>  
> -    def convert_aggr_mode(aggr_mode: str) -> str:
> +    def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
>        """Returns the aggr_mode_class enum value associated with the JSON string."""
>        if not aggr_mode:
>          return None
> @@ -67,7 +66,7 @@ class JsonEvent:
>        }
>        return aggr_mode_to_enum[aggr_mode]
>  
> -    def lookup_msr(num: str) -> str:
> +    def lookup_msr(num: str) -> Optional[str]:
>        """Converts the msr number, or first in a list to the appropriate event field."""
>        if not num:
>          return None
> @@ -79,7 +78,7 @@ class JsonEvent:
>        }
>        return msrmap[int(num.split(',', 1)[0], 0)]
>  
> -    def real_event(name: str, event: str) -> str:
> +    def real_event(name: str, event: str) -> Optional[str]:
>        """Convert well known event names to an event string otherwise use the event argument."""
>        fixed = {
>            'inst_retired.any': 'event=0xc0,period=2000003',
> @@ -95,7 +94,7 @@ class JsonEvent:
>          return fixed[name.lower()]
>        return event
>  
> -    def unit_to_pmu(unit: str) -> str:
> +    def unit_to_pmu(unit: str) -> Optional[str]:
>        """Convert a JSON Unit to Linux PMU name."""
>        if not unit:
>          return None
> @@ -154,7 +153,7 @@ class JsonEvent:
>      if self.metric_expr:
>        self.metric_expr = self.metric_expr.replace('\\', '\\\\')
>      arch_std = jd.get('ArchStdEvent')
> -    if precise and self.desc and not '(Precise Event)' in self.desc:
> +    if precise and self.desc and '(Precise Event)' not in self.desc:
>        extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
>                                                                   'event)')
>      event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
> -- 
> 2.37.1.559.g78731f0fdb-goog

-- 

- Arnaldo

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 02/17] perf jevents: Simplify generation of C-string
  2022-08-04 22:18   ` Ian Rogers
@ 2022-08-09 19:37     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:37 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Thu, Aug 04, 2022 at 03:18:01PM -0700, Ian Rogers escreveu:
> Previous implementation wanted variable order and '(null)' string output
> to match the C implementation. The '(null)' string output was a
> quirk/bug and so there is no need to carry it forward.

Thanks, applied.

- Arnaldo

 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/pmu-events/jevents.py | 14 ++++----------
>  1 file changed, 4 insertions(+), 10 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 5b72048d50da..cdfa4e0e7557 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -203,7 +203,7 @@ class JsonEvent:
>      """Representation of the event as a C struct initializer."""
>  
>      def attr_string(attr: str, value: str) -> str:
> -      return '\t.%s = \"%s\",\n' % (attr, value)
> +      return f'\t.{attr} = \"{value}\",\n'
>  
>      def str_if_present(self, attr: str) -> str:
>        if not getattr(self, attr):
> @@ -211,17 +211,11 @@ class JsonEvent:
>        return attr_string(attr, getattr(self, attr))
>  
>      s = '{\n'
> -    for attr in ['name', 'event']:
> -      s += str_if_present(self, attr)
> -    if self.desc is not None:
> -      s += attr_string('desc', self.desc)
> -    else:
> -      s += attr_string('desc', '(null)')
> -    s += str_if_present(self, 'compat')
>      s += f'\t.topic = "{topic_local}",\n'
>      for attr in [
> -        'long_desc', 'pmu', 'unit', 'perpkg', 'aggr_mode', 'metric_expr',
> -        'metric_name', 'metric_group', 'deprecated', 'metric_constraint'
> +        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> +        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> +        'name', 'perpkg', 'pmu', 'unit'
>      ]:
>        s += str_if_present(self, attr)
>      s += '},\n'
> -- 
> 2.37.1.559.g78731f0fdb-goog

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 02/17] perf jevents: Simplify generation of C-string
@ 2022-08-09 19:37     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:37 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Thu, Aug 04, 2022 at 03:18:01PM -0700, Ian Rogers escreveu:
> Previous implementation wanted variable order and '(null)' string output
> to match the C implementation. The '(null)' string output was a
> quirk/bug and so there is no need to carry it forward.

Thanks, applied.

- Arnaldo

 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/pmu-events/jevents.py | 14 ++++----------
>  1 file changed, 4 insertions(+), 10 deletions(-)
> 
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 5b72048d50da..cdfa4e0e7557 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -203,7 +203,7 @@ class JsonEvent:
>      """Representation of the event as a C struct initializer."""
>  
>      def attr_string(attr: str, value: str) -> str:
> -      return '\t.%s = \"%s\",\n' % (attr, value)
> +      return f'\t.{attr} = \"{value}\",\n'
>  
>      def str_if_present(self, attr: str) -> str:
>        if not getattr(self, attr):
> @@ -211,17 +211,11 @@ class JsonEvent:
>        return attr_string(attr, getattr(self, attr))
>  
>      s = '{\n'
> -    for attr in ['name', 'event']:
> -      s += str_if_present(self, attr)
> -    if self.desc is not None:
> -      s += attr_string('desc', self.desc)
> -    else:
> -      s += attr_string('desc', '(null)')
> -    s += str_if_present(self, 'compat')
>      s += f'\t.topic = "{topic_local}",\n'
>      for attr in [
> -        'long_desc', 'pmu', 'unit', 'perpkg', 'aggr_mode', 'metric_expr',
> -        'metric_name', 'metric_group', 'deprecated', 'metric_constraint'
> +        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> +        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> +        'name', 'perpkg', 'pmu', 'unit'
>      ]:
>        s += str_if_present(self, attr)
>      s += '},\n'
> -- 
> 2.37.1.559.g78731f0fdb-goog

-- 

- Arnaldo

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 03/17] perf jevents: Add JEVENTS_ARCH make option
  2022-08-05  9:55     ` John Garry
@ 2022-08-09 19:38       ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:38 UTC (permalink / raw)
  To: John Garry
  Cc: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Fri, Aug 05, 2022 at 10:55:50AM +0100, John Garry escreveu:
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Allow the architecture built into pmu-events.c to be set on the make
> > command line with JEVENTS_ARCH.
> > 
> > Signed-off-by: Ian Rogers <irogers@google.com>
> 
> Seems reasonable, so:
> 
> Reviewed-by: John Garry <john.garry@huawei.com>

Thanks, applied.

- Arnaldo

 
> I assume that if we run on the wrong arch (than we build for) then it has
> same effect as if pmu-events is not supported.
> 
> > ---
> >   tools/perf/pmu-events/Build | 6 +++++-
> >   1 file changed, 5 insertions(+), 1 deletion(-)
> > 
> > diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
> > index 28a9d01b08af..04ef95174660 100644
> > --- a/tools/perf/pmu-events/Build
> > +++ b/tools/perf/pmu-events/Build
> > @@ -7,6 +7,10 @@ JSON_TEST	=  $(shell [ -d $(JDIR_TEST) ] &&			\
> >   			find $(JDIR_TEST) -name '*.json')
> >   JEVENTS_PY	=  pmu-events/jevents.py
> > +ifeq ($(JEVENTS_ARCH),)
> > +JEVENTS_ARCH=$(SRCARCH)
> > +endif
> > +
> >   #
> >   # Locate/process JSON files in pmu-events/arch/
> >   # directory and create tables in pmu-events.c.
> > @@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
> >   else
> >   $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
> >   	$(call rule_mkdir)
> > -	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
> > +	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
> >   endif

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 03/17] perf jevents: Add JEVENTS_ARCH make option
@ 2022-08-09 19:38       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:38 UTC (permalink / raw)
  To: John Garry
  Cc: Ian Rogers, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Fri, Aug 05, 2022 at 10:55:50AM +0100, John Garry escreveu:
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Allow the architecture built into pmu-events.c to be set on the make
> > command line with JEVENTS_ARCH.
> > 
> > Signed-off-by: Ian Rogers <irogers@google.com>
> 
> Seems reasonable, so:
> 
> Reviewed-by: John Garry <john.garry@huawei.com>

Thanks, applied.

- Arnaldo

 
> I assume that if we run on the wrong arch (than we build for) then it has
> same effect as if pmu-events is not supported.
> 
> > ---
> >   tools/perf/pmu-events/Build | 6 +++++-
> >   1 file changed, 5 insertions(+), 1 deletion(-)
> > 
> > diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
> > index 28a9d01b08af..04ef95174660 100644
> > --- a/tools/perf/pmu-events/Build
> > +++ b/tools/perf/pmu-events/Build
> > @@ -7,6 +7,10 @@ JSON_TEST	=  $(shell [ -d $(JDIR_TEST) ] &&			\
> >   			find $(JDIR_TEST) -name '*.json')
> >   JEVENTS_PY	=  pmu-events/jevents.py
> > +ifeq ($(JEVENTS_ARCH),)
> > +JEVENTS_ARCH=$(SRCARCH)
> > +endif
> > +
> >   #
> >   # Locate/process JSON files in pmu-events/arch/
> >   # directory and create tables in pmu-events.c.
> > @@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
> >   else
> >   $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
> >   	$(call rule_mkdir)
> > -	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
> > +	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
> >   endif

-- 

- Arnaldo

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 00/17]  Compress the pmu_event tables
  2022-08-04 22:17 ` Ian Rogers
@ 2022-08-09 19:40   ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:40 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Thu, Aug 04, 2022 at 03:17:59PM -0700, Ian Rogers escreveu:
> jevents.py creates a number of large arrays from the json events. The
> arrays contain pointers to strings that need relocating. The
> relocations have file size, run time and memory costs. These changes
> refactor the pmu_events API so that the storage of the pmu_event
> struct isn't exposed. The format is then changed to an offset within a
> combined big string, with adjacent pmu_event struct variables being
> next to each other in the string separated by \0 - meaning only the
> first variable of the struct needs its offset recording.
> 
> Some related fixes are contained with the patches. The architecture
> jevents.py creates tables for can now be set by the JEVENTS_ARCH make
> variable, with a new 'all' that generates the events and metrics for
> all architectures.
> 
> An example of the improvement to the file size on x86 is:
> no jevents - the same 19,788,464bytes
> x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> default build options plus NO_LIBBFD=1.

Applied the first four patches, waiting for the review comments to be
discussed.

- Arnaldo
 
> I originally suggested fixing this problem in:
> https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/
> 
> v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
>     <john.garry@huawei.com>.
> v3. Fix an ARM build issue with a missed weak symbol. Perform some
>     pytype clean up.
> v2. Split the substring folding optimization to its own patch and
>     comment tweaks as suggested by Namhyung Kim
>     <namhyung@kernel.org>. Recompute the file size savings with the
>     latest json events and metrics.
> 
> Ian Rogers (17):
>   perf jevents: Clean up pytype warnings
>   perf jevents: Simplify generation of C-string
>   perf jevents: Add JEVENTS_ARCH make option
>   perf jevent: Add an 'all' architecture argument
>   perf jevents: Remove the type/version variables
>   perf jevents: Provide path to json file on error
>   perf jevents: Sort json files entries
>   perf pmu-events: Hide pmu_sys_event_tables
>   perf pmu-events: Avoid passing pmu_events_map
>   perf pmu-events: Hide pmu_events_map
>   perf test: Use full metric resolution
>   perf pmu-events: Move test events/metrics to json
>   perf pmu-events: Don't assume pmu_event is an array
>   perf pmu-events: Hide the pmu_events
>   perf metrics: Copy entire pmu_event in find metric
>   perf jevents: Compress the pmu_events_table
>   perf jevents: Fold strings optimization
> 
>  tools/perf/arch/arm64/util/pmu.c              |   4 +-
>  tools/perf/pmu-events/Build                   |   6 +-
>  .../arch/test/test_soc/cpu/metrics.json       |  64 +++
>  tools/perf/pmu-events/empty-pmu-events.c      | 204 +++++++-
>  tools/perf/pmu-events/jevents.py              | 495 ++++++++++++++----
>  tools/perf/pmu-events/pmu-events.h            |  40 +-
>  tools/perf/tests/expand-cgroup.c              |  25 +-
>  tools/perf/tests/parse-metric.c               |  77 +--
>  tools/perf/tests/pmu-events.c                 | 466 +++++++----------
>  tools/perf/util/metricgroup.c                 | 275 ++++++----
>  tools/perf/util/metricgroup.h                 |   5 +-
>  tools/perf/util/pmu.c                         | 139 ++---
>  tools/perf/util/pmu.h                         |   8 +-
>  tools/perf/util/s390-sample-raw.c             |  50 +-
>  14 files changed, 1140 insertions(+), 718 deletions(-)
>  create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
> 
> -- 
> 2.37.1.559.g78731f0fdb-goog

-- 

- Arnaldo

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 00/17]  Compress the pmu_event tables
@ 2022-08-09 19:40   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:40 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Thu, Aug 04, 2022 at 03:17:59PM -0700, Ian Rogers escreveu:
> jevents.py creates a number of large arrays from the json events. The
> arrays contain pointers to strings that need relocating. The
> relocations have file size, run time and memory costs. These changes
> refactor the pmu_events API so that the storage of the pmu_event
> struct isn't exposed. The format is then changed to an offset within a
> combined big string, with adjacent pmu_event struct variables being
> next to each other in the string separated by \0 - meaning only the
> first variable of the struct needs its offset recording.
> 
> Some related fixes are contained with the patches. The architecture
> jevents.py creates tables for can now be set by the JEVENTS_ARCH make
> variable, with a new 'all' that generates the events and metrics for
> all architectures.
> 
> An example of the improvement to the file size on x86 is:
> no jevents - the same 19,788,464bytes
> x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> default build options plus NO_LIBBFD=1.

Applied the first four patches, waiting for the review comments to be
discussed.

- Arnaldo
 
> I originally suggested fixing this problem in:
> https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/
> 
> v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
>     <john.garry@huawei.com>.
> v3. Fix an ARM build issue with a missed weak symbol. Perform some
>     pytype clean up.
> v2. Split the substring folding optimization to its own patch and
>     comment tweaks as suggested by Namhyung Kim
>     <namhyung@kernel.org>. Recompute the file size savings with the
>     latest json events and metrics.
> 
> Ian Rogers (17):
>   perf jevents: Clean up pytype warnings
>   perf jevents: Simplify generation of C-string
>   perf jevents: Add JEVENTS_ARCH make option
>   perf jevent: Add an 'all' architecture argument
>   perf jevents: Remove the type/version variables
>   perf jevents: Provide path to json file on error
>   perf jevents: Sort json files entries
>   perf pmu-events: Hide pmu_sys_event_tables
>   perf pmu-events: Avoid passing pmu_events_map
>   perf pmu-events: Hide pmu_events_map
>   perf test: Use full metric resolution
>   perf pmu-events: Move test events/metrics to json
>   perf pmu-events: Don't assume pmu_event is an array
>   perf pmu-events: Hide the pmu_events
>   perf metrics: Copy entire pmu_event in find metric
>   perf jevents: Compress the pmu_events_table
>   perf jevents: Fold strings optimization
> 
>  tools/perf/arch/arm64/util/pmu.c              |   4 +-
>  tools/perf/pmu-events/Build                   |   6 +-
>  .../arch/test/test_soc/cpu/metrics.json       |  64 +++
>  tools/perf/pmu-events/empty-pmu-events.c      | 204 +++++++-
>  tools/perf/pmu-events/jevents.py              | 495 ++++++++++++++----
>  tools/perf/pmu-events/pmu-events.h            |  40 +-
>  tools/perf/tests/expand-cgroup.c              |  25 +-
>  tools/perf/tests/parse-metric.c               |  77 +--
>  tools/perf/tests/pmu-events.c                 | 466 +++++++----------
>  tools/perf/util/metricgroup.c                 | 275 ++++++----
>  tools/perf/util/metricgroup.h                 |   5 +-
>  tools/perf/util/pmu.c                         | 139 ++---
>  tools/perf/util/pmu.h                         |   8 +-
>  tools/perf/util/s390-sample-raw.c             |  50 +-
>  14 files changed, 1140 insertions(+), 718 deletions(-)
>  create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
> 
> -- 
> 2.37.1.559.g78731f0fdb-goog

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 00/17]  Compress the pmu_event tables
  2022-08-09 19:40   ` Arnaldo Carvalho de Melo
@ 2022-08-09 19:41     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:41 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Tue, Aug 09, 2022 at 04:40:43PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Thu, Aug 04, 2022 at 03:17:59PM -0700, Ian Rogers escreveu:
> > jevents.py creates a number of large arrays from the json events. The
> > arrays contain pointers to strings that need relocating. The
> > relocations have file size, run time and memory costs. These changes
> > refactor the pmu_events API so that the storage of the pmu_event
> > struct isn't exposed. The format is then changed to an offset within a
> > combined big string, with adjacent pmu_event struct variables being
> > next to each other in the string separated by \0 - meaning only the
> > first variable of the struct needs its offset recording.
> > 
> > Some related fixes are contained with the patches. The architecture
> > jevents.py creates tables for can now be set by the JEVENTS_ARCH make
> > variable, with a new 'all' that generates the events and metrics for
> > all architectures.
> > 
> > An example of the improvement to the file size on x86 is:
> > no jevents - the same 19,788,464bytes
> > x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> > all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> > default build options plus NO_LIBBFD=1.
> 
> Applied the first four patches, waiting for the review comments to be

Sorry, three.

> discussed.
> 
> - Arnaldo
>  
> > I originally suggested fixing this problem in:
> > https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/
> > 
> > v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
> >     <john.garry@huawei.com>.
> > v3. Fix an ARM build issue with a missed weak symbol. Perform some
> >     pytype clean up.
> > v2. Split the substring folding optimization to its own patch and
> >     comment tweaks as suggested by Namhyung Kim
> >     <namhyung@kernel.org>. Recompute the file size savings with the
> >     latest json events and metrics.
> > 
> > Ian Rogers (17):
> >   perf jevents: Clean up pytype warnings
> >   perf jevents: Simplify generation of C-string
> >   perf jevents: Add JEVENTS_ARCH make option
> >   perf jevent: Add an 'all' architecture argument
> >   perf jevents: Remove the type/version variables
> >   perf jevents: Provide path to json file on error
> >   perf jevents: Sort json files entries
> >   perf pmu-events: Hide pmu_sys_event_tables
> >   perf pmu-events: Avoid passing pmu_events_map
> >   perf pmu-events: Hide pmu_events_map
> >   perf test: Use full metric resolution
> >   perf pmu-events: Move test events/metrics to json
> >   perf pmu-events: Don't assume pmu_event is an array
> >   perf pmu-events: Hide the pmu_events
> >   perf metrics: Copy entire pmu_event in find metric
> >   perf jevents: Compress the pmu_events_table
> >   perf jevents: Fold strings optimization
> > 
> >  tools/perf/arch/arm64/util/pmu.c              |   4 +-
> >  tools/perf/pmu-events/Build                   |   6 +-
> >  .../arch/test/test_soc/cpu/metrics.json       |  64 +++
> >  tools/perf/pmu-events/empty-pmu-events.c      | 204 +++++++-
> >  tools/perf/pmu-events/jevents.py              | 495 ++++++++++++++----
> >  tools/perf/pmu-events/pmu-events.h            |  40 +-
> >  tools/perf/tests/expand-cgroup.c              |  25 +-
> >  tools/perf/tests/parse-metric.c               |  77 +--
> >  tools/perf/tests/pmu-events.c                 | 466 +++++++----------
> >  tools/perf/util/metricgroup.c                 | 275 ++++++----
> >  tools/perf/util/metricgroup.h                 |   5 +-
> >  tools/perf/util/pmu.c                         | 139 ++---
> >  tools/perf/util/pmu.h                         |   8 +-
> >  tools/perf/util/s390-sample-raw.c             |  50 +-
> >  14 files changed, 1140 insertions(+), 718 deletions(-)
> >  create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
> > 
> > -- 
> > 2.37.1.559.g78731f0fdb-goog
> 
> -- 
> 
> - Arnaldo

-- 

- Arnaldo

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 00/17]  Compress the pmu_event tables
@ 2022-08-09 19:41     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 80+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-09 19:41 UTC (permalink / raw)
  To: Ian Rogers
  Cc: John Garry, Will Deacon, James Clark, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Andi Kleen, Zhengjun Xing,
	Ravi Bangoria, Kan Liang, Adrian Hunter, linux-kernel,
	linux-arm-kernel, linux-perf-users, Stephane Eranian

Em Tue, Aug 09, 2022 at 04:40:43PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Thu, Aug 04, 2022 at 03:17:59PM -0700, Ian Rogers escreveu:
> > jevents.py creates a number of large arrays from the json events. The
> > arrays contain pointers to strings that need relocating. The
> > relocations have file size, run time and memory costs. These changes
> > refactor the pmu_events API so that the storage of the pmu_event
> > struct isn't exposed. The format is then changed to an offset within a
> > combined big string, with adjacent pmu_event struct variables being
> > next to each other in the string separated by \0 - meaning only the
> > first variable of the struct needs its offset recording.
> > 
> > Some related fixes are contained with the patches. The architecture
> > jevents.py creates tables for can now be set by the JEVENTS_ARCH make
> > variable, with a new 'all' that generates the events and metrics for
> > all architectures.
> > 
> > An example of the improvement to the file size on x86 is:
> > no jevents - the same 19,788,464bytes
> > x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> > all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> > default build options plus NO_LIBBFD=1.
> 
> Applied the first four patches, waiting for the review comments to be

Sorry, three.

> discussed.
> 
> - Arnaldo
>  
> > I originally suggested fixing this problem in:
> > https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/
> > 
> > v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
> >     <john.garry@huawei.com>.
> > v3. Fix an ARM build issue with a missed weak symbol. Perform some
> >     pytype clean up.
> > v2. Split the substring folding optimization to its own patch and
> >     comment tweaks as suggested by Namhyung Kim
> >     <namhyung@kernel.org>. Recompute the file size savings with the
> >     latest json events and metrics.
> > 
> > Ian Rogers (17):
> >   perf jevents: Clean up pytype warnings
> >   perf jevents: Simplify generation of C-string
> >   perf jevents: Add JEVENTS_ARCH make option
> >   perf jevent: Add an 'all' architecture argument
> >   perf jevents: Remove the type/version variables
> >   perf jevents: Provide path to json file on error
> >   perf jevents: Sort json files entries
> >   perf pmu-events: Hide pmu_sys_event_tables
> >   perf pmu-events: Avoid passing pmu_events_map
> >   perf pmu-events: Hide pmu_events_map
> >   perf test: Use full metric resolution
> >   perf pmu-events: Move test events/metrics to json
> >   perf pmu-events: Don't assume pmu_event is an array
> >   perf pmu-events: Hide the pmu_events
> >   perf metrics: Copy entire pmu_event in find metric
> >   perf jevents: Compress the pmu_events_table
> >   perf jevents: Fold strings optimization
> > 
> >  tools/perf/arch/arm64/util/pmu.c              |   4 +-
> >  tools/perf/pmu-events/Build                   |   6 +-
> >  .../arch/test/test_soc/cpu/metrics.json       |  64 +++
> >  tools/perf/pmu-events/empty-pmu-events.c      | 204 +++++++-
> >  tools/perf/pmu-events/jevents.py              | 495 ++++++++++++++----
> >  tools/perf/pmu-events/pmu-events.h            |  40 +-
> >  tools/perf/tests/expand-cgroup.c              |  25 +-
> >  tools/perf/tests/parse-metric.c               |  77 +--
> >  tools/perf/tests/pmu-events.c                 | 466 +++++++----------
> >  tools/perf/util/metricgroup.c                 | 275 ++++++----
> >  tools/perf/util/metricgroup.h                 |   5 +-
> >  tools/perf/util/pmu.c                         | 139 ++---
> >  tools/perf/util/pmu.h                         |   8 +-
> >  tools/perf/util/s390-sample-raw.c             |  50 +-
> >  14 files changed, 1140 insertions(+), 718 deletions(-)
> >  create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
> > 
> > -- 
> > 2.37.1.559.g78731f0fdb-goog
> 
> -- 
> 
> - Arnaldo

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 07/17] perf jevents: Sort json files entries
  2022-08-05 10:49     ` John Garry
@ 2022-08-10 14:23       ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:23 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 3:49 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Sort the json files entries on conversion to C. The sort order tries to
> > replicated cmp_sevent from pmu.c so that the input there is already
>
> replicate

Ack.

> > sorted except for sysfs events.
> >
> > Add the topic to JsonEvent on reading to simplify. Remove an unnecessary
> > lambda in the json reading.
>
> We sort the attributes of the events alphabetically by attribute name,
> right? Is there any advantage in this? Do we need it for later?


The sort order is given by the tuple:
(not j.desc is None, fix_none(j.topic), fix_none(j.name),
fix_none(j.pmu), fix_none(j.metric_name))
which is putting events with descriptions and topics before those
without, then sorting by name, then pmu and finally metric_name. The
advantage is that when we qsort alias events:
https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/perf/util/pmu.c?h=perf/core#n1759
the events are already in the sorted format, which should make the
code faster - it still has to qsort the sysfs events.

Longer term I'd like to make the searching for an event, or metric, by
name a binary rather than a linear search.

Thanks,
Ian

> thanks,
> John
>
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/pmu-events/jevents.py | 48 +++++++++++++++++++++++---------
> >   1 file changed, 35 insertions(+), 13 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index 12d2daf3570c..30e0e792221a 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -18,6 +18,8 @@ _sys_event_tables = []
> >   _arch_std_events = {}
> >   # Track whether an events table is currently being defined and needs closing.
> >   _close_table = False
> > +# Events to write out when the table is closed
> > +_pending_events = []
> >
> >
> >   def removesuffix(s: str, suffix: str) -> str:
> > @@ -127,6 +129,7 @@ class JsonEvent:
> >         eventcode |= int(jd['ExtSel']) << 8
> >       configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
> >       self.name = jd['EventName'].lower() if 'EventName' in jd else None
> > +    self.topic = ''
> >       self.compat = jd.get('Compat')
> >       self.desc = fixdesc(jd.get('BriefDescription'))
> >       self.long_desc = fixdesc(jd.get('PublicDescription'))
> > @@ -199,7 +202,7 @@ class JsonEvent:
> >           s += f'\t{attr} = {value},\n'
> >       return s + '}'
> >
> > -  def to_c_string(self, topic_local: str) -> str:
> > +  def to_c_string(self) -> str:
> >       """Representation of the event as a C struct initializer."""
> >
> >       def attr_string(attr: str, value: str) -> str:
> > @@ -211,25 +214,27 @@ class JsonEvent:
> >         return attr_string(attr, getattr(self, attr))
> >
> >       s = '{\n'
> > -    s += f'\t.topic = "{topic_local}",\n'
> >       for attr in [
> >           'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> >           'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> > -        'name', 'perpkg', 'pmu', 'unit'
> > +        'name', 'perpkg', 'pmu', 'topic', 'unit'
> >       ]:
> >         s += str_if_present(self, attr)
> >       s += '},\n'
> >       return s
> >
> >
> > -def read_json_events(path: str) -> Sequence[JsonEvent]:
> > +def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> >     """Read json events from the specified file."""
> >
> >     try:
> > -    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
> > +    result = json.load(open(path), object_hook=JsonEvent)
> >     except BaseException as err:
> >       print(f"Exception processing {path}")
> >       raise
> > +  for event in result:
> > +    event.topic = topic
> > +  return result
> >
> >
> >   def preprocess_arch_std_files(archpath: str) -> None:
> > @@ -237,7 +242,7 @@ def preprocess_arch_std_files(archpath: str) -> None:
> >     global _arch_std_events
> >     for item in os.scandir(archpath):
> >       if item.is_file() and item.name.endswith('.json'):
> > -      for event in read_json_events(item.path):
> > +      for event in read_json_events(item.path, topic=''):
> >           if event.name:
> >             _arch_std_events[event.name.lower()] = event
> >
> > @@ -251,19 +256,36 @@ def print_events_table_prefix(tblname: str) -> None:
> >     _close_table = True
> >
> >
> > -def print_events_table_entries(item: os.DirEntry, topic: str) -> None:
> > -  """Create contents of an events table."""
> > +def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> > +  """Add contents of file to _pending_events table."""
> >     if not _close_table:
> >       raise IOError('Table entries missing prefix')
> > -  for event in read_json_events(item.path):
> > -    _args.output_file.write(event.to_c_string(topic))
> > +  for e in read_json_events(item.path, topic):
> > +    _pending_events.append(e)
> >
> >
> >   def print_events_table_suffix() -> None:
> >     """Optionally close events table."""
> > +
> > +  def event_cmp_key(j: JsonEvent):
> > +    def fix_none(s: str):
> > +      if s is None:
> > +        return ''
> > +      return s
> > +
> > +    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> > +            fix_none(j.metric_name))
> > +
> >     global _close_table
> > -  if _close_table:
> > -    _args.output_file.write("""{
> > +  if not _close_table:
> > +    return
> > +
> > +  global _pending_events
> > +  for event in sorted(_pending_events, key=event_cmp_key):
> > +    _args.output_file.write(event.to_c_string())
> > +    _pending_events = []
> > +
> > +  _args.output_file.write("""{
> >   \t.name = 0,
> >   \t.event = 0,
> >   \t.desc = 0,
> > @@ -306,7 +328,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> >     if not item.is_file() or not item.name.endswith('.json'):
> >       return
> >
> > -  print_events_table_entries(item, get_topic(item.name))
> > +  add_events_table_entries(item, get_topic(item.name))
> >
> >
> >   def print_mapping_table(archs: Sequence[str]) -> None:
>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 07/17] perf jevents: Sort json files entries
@ 2022-08-10 14:23       ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:23 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 3:49 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Sort the json files entries on conversion to C. The sort order tries to
> > replicated cmp_sevent from pmu.c so that the input there is already
>
> replicate

Ack.

> > sorted except for sysfs events.
> >
> > Add the topic to JsonEvent on reading to simplify. Remove an unnecessary
> > lambda in the json reading.
>
> We sort the attributes of the events alphabetically by attribute name,
> right? Is there any advantage in this? Do we need it for later?


The sort order is given by the tuple:
(not j.desc is None, fix_none(j.topic), fix_none(j.name),
fix_none(j.pmu), fix_none(j.metric_name))
which is putting events with descriptions and topics before those
without, then sorting by name, then pmu and finally metric_name. The
advantage is that when we qsort alias events:
https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/perf/util/pmu.c?h=perf/core#n1759
the events are already in the sorted format, which should make the
code faster - it still has to qsort the sysfs events.

Longer term I'd like to make the searching for an event, or metric, by
name a binary rather than a linear search.

Thanks,
Ian

> thanks,
> John
>
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/pmu-events/jevents.py | 48 +++++++++++++++++++++++---------
> >   1 file changed, 35 insertions(+), 13 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index 12d2daf3570c..30e0e792221a 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -18,6 +18,8 @@ _sys_event_tables = []
> >   _arch_std_events = {}
> >   # Track whether an events table is currently being defined and needs closing.
> >   _close_table = False
> > +# Events to write out when the table is closed
> > +_pending_events = []
> >
> >
> >   def removesuffix(s: str, suffix: str) -> str:
> > @@ -127,6 +129,7 @@ class JsonEvent:
> >         eventcode |= int(jd['ExtSel']) << 8
> >       configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
> >       self.name = jd['EventName'].lower() if 'EventName' in jd else None
> > +    self.topic = ''
> >       self.compat = jd.get('Compat')
> >       self.desc = fixdesc(jd.get('BriefDescription'))
> >       self.long_desc = fixdesc(jd.get('PublicDescription'))
> > @@ -199,7 +202,7 @@ class JsonEvent:
> >           s += f'\t{attr} = {value},\n'
> >       return s + '}'
> >
> > -  def to_c_string(self, topic_local: str) -> str:
> > +  def to_c_string(self) -> str:
> >       """Representation of the event as a C struct initializer."""
> >
> >       def attr_string(attr: str, value: str) -> str:
> > @@ -211,25 +214,27 @@ class JsonEvent:
> >         return attr_string(attr, getattr(self, attr))
> >
> >       s = '{\n'
> > -    s += f'\t.topic = "{topic_local}",\n'
> >       for attr in [
> >           'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> >           'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> > -        'name', 'perpkg', 'pmu', 'unit'
> > +        'name', 'perpkg', 'pmu', 'topic', 'unit'
> >       ]:
> >         s += str_if_present(self, attr)
> >       s += '},\n'
> >       return s
> >
> >
> > -def read_json_events(path: str) -> Sequence[JsonEvent]:
> > +def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> >     """Read json events from the specified file."""
> >
> >     try:
> > -    return json.load(open(path), object_hook=lambda d: JsonEvent(d))
> > +    result = json.load(open(path), object_hook=JsonEvent)
> >     except BaseException as err:
> >       print(f"Exception processing {path}")
> >       raise
> > +  for event in result:
> > +    event.topic = topic
> > +  return result
> >
> >
> >   def preprocess_arch_std_files(archpath: str) -> None:
> > @@ -237,7 +242,7 @@ def preprocess_arch_std_files(archpath: str) -> None:
> >     global _arch_std_events
> >     for item in os.scandir(archpath):
> >       if item.is_file() and item.name.endswith('.json'):
> > -      for event in read_json_events(item.path):
> > +      for event in read_json_events(item.path, topic=''):
> >           if event.name:
> >             _arch_std_events[event.name.lower()] = event
> >
> > @@ -251,19 +256,36 @@ def print_events_table_prefix(tblname: str) -> None:
> >     _close_table = True
> >
> >
> > -def print_events_table_entries(item: os.DirEntry, topic: str) -> None:
> > -  """Create contents of an events table."""
> > +def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> > +  """Add contents of file to _pending_events table."""
> >     if not _close_table:
> >       raise IOError('Table entries missing prefix')
> > -  for event in read_json_events(item.path):
> > -    _args.output_file.write(event.to_c_string(topic))
> > +  for e in read_json_events(item.path, topic):
> > +    _pending_events.append(e)
> >
> >
> >   def print_events_table_suffix() -> None:
> >     """Optionally close events table."""
> > +
> > +  def event_cmp_key(j: JsonEvent):
> > +    def fix_none(s: str):
> > +      if s is None:
> > +        return ''
> > +      return s
> > +
> > +    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> > +            fix_none(j.metric_name))
> > +
> >     global _close_table
> > -  if _close_table:
> > -    _args.output_file.write("""{
> > +  if not _close_table:
> > +    return
> > +
> > +  global _pending_events
> > +  for event in sorted(_pending_events, key=event_cmp_key):
> > +    _args.output_file.write(event.to_c_string())
> > +    _pending_events = []
> > +
> > +  _args.output_file.write("""{
> >   \t.name = 0,
> >   \t.event = 0,
> >   \t.desc = 0,
> > @@ -306,7 +328,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> >     if not item.is_file() or not item.name.endswith('.json'):
> >       return
> >
> > -  print_events_table_entries(item, get_topic(item.name))
> > +  add_events_table_entries(item, get_topic(item.name))
> >
> >
> >   def print_mapping_table(archs: Sequence[str]) -> None:
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 08/17] perf pmu-events: Hide pmu_sys_event_tables
  2022-08-05 11:15     ` John Garry
@ 2022-08-10 14:25       ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:25 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 4:15 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Move usage of the table to pmu-events.c so it may be hidden. By
> > abstracting the table the implementation can later be changed.
> >
> > Signed-off-by: Ian Rogers<irogers@google.com>
>
> Reviewed-by: John Garry <john.garry@huawei.com>
>
> > -     const struct pmu_event *sys_event_tables = __test_pmu_get_sys_events_table();
> > +     const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
>
> Maybe we can change to not need the "pme_" prefix or even some of the
> suffix, like "_sys"

Ack. Not done here so the change is the smallest possible.

Thanks,
Ian

> >       const struct pmu_events_map *map = __test_pmu_get_events_map();
>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 08/17] perf pmu-events: Hide pmu_sys_event_tables
@ 2022-08-10 14:25       ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:25 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 4:15 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Move usage of the table to pmu-events.c so it may be hidden. By
> > abstracting the table the implementation can later be changed.
> >
> > Signed-off-by: Ian Rogers<irogers@google.com>
>
> Reviewed-by: John Garry <john.garry@huawei.com>
>
> > -     const struct pmu_event *sys_event_tables = __test_pmu_get_sys_events_table();
> > +     const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
>
> Maybe we can change to not need the "pme_" prefix or even some of the
> suffix, like "_sys"

Ack. Not done here so the change is the smallest possible.

Thanks,
Ian

> >       const struct pmu_events_map *map = __test_pmu_get_events_map();
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
  2022-08-05 12:31     ` John Garry
@ 2022-08-10 14:29       ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:29 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 5:31 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Move usage of the table to pmu-events.c so it may be hidden. By
> > abstracting the table the implementation can later be changed.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/pmu-events/empty-pmu-events.c |  81 ++++++++-
> >   tools/perf/pmu-events/jevents.py         |  81 ++++++++-
> >   tools/perf/pmu-events/pmu-events.h       |  29 +--
> >   tools/perf/tests/pmu-events.c            | 218 +++++++++++------------
> >   tools/perf/util/metricgroup.c            |  15 +-
> >   tools/perf/util/pmu.c                    |  34 +---
> >   tools/perf/util/pmu.h                    |   2 +-
> >   7 files changed, 280 insertions(+), 180 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> > index 216ea0482c37..8ef75aff996c 100644
> > --- a/tools/perf/pmu-events/empty-pmu-events.c
> > +++ b/tools/perf/pmu-events/empty-pmu-events.c
> > @@ -6,6 +6,8 @@
> >    * The test cpu/soc is provided for testing.
> >    */
> >   #include "pmu-events/pmu-events.h"
> > +#include "util/header.h"
> > +#include "util/pmu.h"
> >   #include <string.h>
> >   #include <stddef.h>
> >
> > @@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
> >       },
> >   };
> >
> > -const struct pmu_events_map pmu_events_map[] = {
> > +
> > +/*
> > + * Map a CPU to its table of PMU events. The CPU is identified by the
> > + * cpuid field, which is an arch-specific identifier for the CPU.
> > + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> > + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> > + *
> > + * The  cpuid can contain any character other than the comma.
> > + */
> > +struct pmu_events_map {
> > +     const char *arch;
> > +     const char *cpuid;
> > +     const struct pmu_event *table;
> > +};
> > +
> > +/*
> > + * Global table mapping each known CPU for the architecture to its
> > + * table of PMU events.
> > + */
> > +static const struct pmu_events_map pmu_events_map[] = {
> >       {
> >               .arch = "testarch",
> >               .cpuid = "testcpu",
> > @@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >       },
> >   };
> >
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> > +{
> > +     const struct pmu_event *table = NULL;
> > +     char *cpuid = perf_pmu__getcpuid(pmu);
> > +     int i;
> > +
> > +     /* on some platforms which uses cpus map, cpuid can be NULL for
> > +      * PMUs other than CORE PMUs.
> > +      */
> > +     if (!cpuid)
> > +             return NULL;
> > +
> > +     i = 0;
> > +     for (;;) {
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > +             if (!map->table)
> > +                     break;
> > +
> > +             if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > +                     table = map->table;
> > +                     break;
> > +             }
> > +     }
> > +     free(cpuid);
> > +     return table;
> > +}
> > +
> > +const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
> > +{
> > +     for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > +          tables->table;
> > +          tables++) {
> > +             if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> > +                     return tables->table;
> > +     }
> > +     return NULL;
> > +}
> > +
> > +int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
> > +{
> > +     for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > +          tables->table;
> > +          tables++) {
> > +             for (const struct pmu_event *pe = &tables->table[0];
> > +                  pe->name || pe->metric_group || pe->metric_name;
> > +                  pe++) {
> > +                     int ret = fn(pe, &tables->table[0], data);
> > +
> > +                     if (ret)
> > +                             return ret;
> > +             }
> > +     }
> > +     return 0;
> > +}
> > +
> >   const struct pmu_event *find_sys_events_table(const char *name)
> >   {
> >       for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> > @@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
> >               for (const struct pmu_event *pe = &tables->table[0];
> >                    pe->name || pe->metric_group || pe->metric_name;
> >                    pe++) {
> > -                     int ret = fn(pe, data);
> > +                     int ret = fn(pe, &tables->table[0], data);
> >
> >                       if (ret)
> >                               return ret;
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index dd21bc9eeeed..e976c5e8e80b 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> >
> >   def print_mapping_table(archs: Sequence[str]) -> None:
> >     """Read the mapfile and generate the struct from cpuid string to event table."""
> > -  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> > +  _args.output_file.write("""
> > +/*
> > + * Map a CPU to its table of PMU events. The CPU is identified by the
> > + * cpuid field, which is an arch-specific identifier for the CPU.
> > + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> > + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> > + *
> > + * The  cpuid can contain any character other than the comma.
> > + */
> > +struct pmu_events_map {
> > +        const char *arch;
> > +        const char *cpuid;
> > +        const struct pmu_event *table;
> > +};
> > +
> > +/*
> > + * Global table mapping each known CPU for the architecture to its
> > + * table of PMU events.
> > + */
> > +const struct pmu_events_map pmu_events_map[] = {
> > +""")
> >     for arch in archs:
> >       if arch == 'test':
> >         _args.output_file.write("""{
> > @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >   \t},
> >   };
> >
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> > +{
> > +        const struct pmu_event *table = NULL;
> > +        char *cpuid = perf_pmu__getcpuid(pmu);
>
> This seems an identical implementation to that in empty-pmu-events.c -
> can we reduce this duplication? Maybe a seperate common c file which can
> be linked in
>
> The indentation seems different also - this version seems to use whitespaces

Agreed. Later on this will change, the empty version isn't compressed
and the jevents.py one is. Having a common C file would defeat the
goal of hiding the API, but ultimately we'd need to get rid of it in
later changes when the empty/compressed implementations diverge.

Thanks,
Ian

> > +        int i;
> > +
> > +        /* on some platforms which uses cpus map, cpuid can be NULL for
> > +         * PMUs other than CORE PMUs.
> > +         */
> > +        if (!cpuid)
> > +                return NULL;
> > +
> > +        i = 0;
> > +        for (;;) {
> > +                const struct pmu_events_map *map = &pmu_events_map[i++];
> > +                if (!map->table)
> > +                        break;
> > +
> > +                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > +                        table = map->table;
> > +                        break;
> > +                }
> > +        }
> > +        free(cpuid);
> > +        return table;
> > +}

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
@ 2022-08-10 14:29       ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:29 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 5:31 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Move usage of the table to pmu-events.c so it may be hidden. By
> > abstracting the table the implementation can later be changed.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/pmu-events/empty-pmu-events.c |  81 ++++++++-
> >   tools/perf/pmu-events/jevents.py         |  81 ++++++++-
> >   tools/perf/pmu-events/pmu-events.h       |  29 +--
> >   tools/perf/tests/pmu-events.c            | 218 +++++++++++------------
> >   tools/perf/util/metricgroup.c            |  15 +-
> >   tools/perf/util/pmu.c                    |  34 +---
> >   tools/perf/util/pmu.h                    |   2 +-
> >   7 files changed, 280 insertions(+), 180 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> > index 216ea0482c37..8ef75aff996c 100644
> > --- a/tools/perf/pmu-events/empty-pmu-events.c
> > +++ b/tools/perf/pmu-events/empty-pmu-events.c
> > @@ -6,6 +6,8 @@
> >    * The test cpu/soc is provided for testing.
> >    */
> >   #include "pmu-events/pmu-events.h"
> > +#include "util/header.h"
> > +#include "util/pmu.h"
> >   #include <string.h>
> >   #include <stddef.h>
> >
> > @@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
> >       },
> >   };
> >
> > -const struct pmu_events_map pmu_events_map[] = {
> > +
> > +/*
> > + * Map a CPU to its table of PMU events. The CPU is identified by the
> > + * cpuid field, which is an arch-specific identifier for the CPU.
> > + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> > + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> > + *
> > + * The  cpuid can contain any character other than the comma.
> > + */
> > +struct pmu_events_map {
> > +     const char *arch;
> > +     const char *cpuid;
> > +     const struct pmu_event *table;
> > +};
> > +
> > +/*
> > + * Global table mapping each known CPU for the architecture to its
> > + * table of PMU events.
> > + */
> > +static const struct pmu_events_map pmu_events_map[] = {
> >       {
> >               .arch = "testarch",
> >               .cpuid = "testcpu",
> > @@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >       },
> >   };
> >
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> > +{
> > +     const struct pmu_event *table = NULL;
> > +     char *cpuid = perf_pmu__getcpuid(pmu);
> > +     int i;
> > +
> > +     /* on some platforms which uses cpus map, cpuid can be NULL for
> > +      * PMUs other than CORE PMUs.
> > +      */
> > +     if (!cpuid)
> > +             return NULL;
> > +
> > +     i = 0;
> > +     for (;;) {
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > +             if (!map->table)
> > +                     break;
> > +
> > +             if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > +                     table = map->table;
> > +                     break;
> > +             }
> > +     }
> > +     free(cpuid);
> > +     return table;
> > +}
> > +
> > +const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
> > +{
> > +     for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > +          tables->table;
> > +          tables++) {
> > +             if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> > +                     return tables->table;
> > +     }
> > +     return NULL;
> > +}
> > +
> > +int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
> > +{
> > +     for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > +          tables->table;
> > +          tables++) {
> > +             for (const struct pmu_event *pe = &tables->table[0];
> > +                  pe->name || pe->metric_group || pe->metric_name;
> > +                  pe++) {
> > +                     int ret = fn(pe, &tables->table[0], data);
> > +
> > +                     if (ret)
> > +                             return ret;
> > +             }
> > +     }
> > +     return 0;
> > +}
> > +
> >   const struct pmu_event *find_sys_events_table(const char *name)
> >   {
> >       for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> > @@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
> >               for (const struct pmu_event *pe = &tables->table[0];
> >                    pe->name || pe->metric_group || pe->metric_name;
> >                    pe++) {
> > -                     int ret = fn(pe, data);
> > +                     int ret = fn(pe, &tables->table[0], data);
> >
> >                       if (ret)
> >                               return ret;
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index dd21bc9eeeed..e976c5e8e80b 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> >
> >   def print_mapping_table(archs: Sequence[str]) -> None:
> >     """Read the mapfile and generate the struct from cpuid string to event table."""
> > -  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> > +  _args.output_file.write("""
> > +/*
> > + * Map a CPU to its table of PMU events. The CPU is identified by the
> > + * cpuid field, which is an arch-specific identifier for the CPU.
> > + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> > + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> > + *
> > + * The  cpuid can contain any character other than the comma.
> > + */
> > +struct pmu_events_map {
> > +        const char *arch;
> > +        const char *cpuid;
> > +        const struct pmu_event *table;
> > +};
> > +
> > +/*
> > + * Global table mapping each known CPU for the architecture to its
> > + * table of PMU events.
> > + */
> > +const struct pmu_events_map pmu_events_map[] = {
> > +""")
> >     for arch in archs:
> >       if arch == 'test':
> >         _args.output_file.write("""{
> > @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >   \t},
> >   };
> >
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> > +{
> > +        const struct pmu_event *table = NULL;
> > +        char *cpuid = perf_pmu__getcpuid(pmu);
>
> This seems an identical implementation to that in empty-pmu-events.c -
> can we reduce this duplication? Maybe a seperate common c file which can
> be linked in
>
> The indentation seems different also - this version seems to use whitespaces

Agreed. Later on this will change, the empty version isn't compressed
and the jevents.py one is. Having a common C file would defeat the
goal of hiding the API, but ultimately we'd need to get rid of it in
later changes when the empty/compressed implementations diverge.

Thanks,
Ian

> > +        int i;
> > +
> > +        /* on some platforms which uses cpus map, cpuid can be NULL for
> > +         * PMUs other than CORE PMUs.
> > +         */
> > +        if (!cpuid)
> > +                return NULL;
> > +
> > +        i = 0;
> > +        for (;;) {
> > +                const struct pmu_events_map *map = &pmu_events_map[i++];
> > +                if (!map->table)
> > +                        break;
> > +
> > +                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > +                        table = map->table;
> > +                        break;
> > +                }
> > +        }
> > +        free(cpuid);
> > +        return table;
> > +}

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 16/17] perf jevents: Compress the pmu_events_table
  2022-08-05 14:02     ` John Garry
@ 2022-08-10 14:35       ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:35 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 7:02 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > The pmu_events array requires 15 pointers per entry which in position
> > independent code need relocating. Change the array to be an array of
> > offsets within a big C string. Only the offset of the first variable is
> > required, subsequent variables are stored in order after the \0
> > terminator (requiring a byte per variable rather than 4 bytes per
> > offset).
> >
> > The file size savings are:
> > no jevents - the same 19,788,464bytes
> > x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> > all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> > default build options plus NO_LIBBFD=1.
> >
> > For example, the x86 build savings come from .rela.dyn and
> > .data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
> > respectively. .rodata increases by 1,432,448bytes, giving an overall
> > 4,766,600bytes saving.
> >
> > To make metric strings more shareable, the topic is changed from say
> > 'skx metrics' to just 'metrics'.
> >
> > To try to help with the memory layout the pmu_events are ordered as used
> > by perf qsort comparator functions.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
> >   1 file changed, 162 insertions(+), 45 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index aa8df649025a..a5e162558994 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -6,7 +6,8 @@ import csv
> >   import json
> >   import os
> >   import sys
> > -from typing import (Callable, Optional, Sequence)
> > +from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
> > +import collections
> >
> >   # Global command line arguments.
> >   _args = None
> > @@ -20,6 +21,19 @@ _arch_std_events = {}
> >   _close_table = False
> >   # Events to write out when the table is closed
> >   _pending_events = []
> > +# Global BigCString shared by all structures.
> > +_bcs = None
> > +# Order specific JsonEvent attributes will be visited.
> > +_json_event_attributes = [
> > +    # cmp_sevent related attributes.
> > +    'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
> > +    # Seems useful, put it early.
> > +    'event',
> > +    # Short things in alphabetical order.
> > +    'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
> > +    # Longer things (the last won't be iterated over during decompress).
> > +    'metric_constraint', 'metric_expr', 'long_desc'
> > +]
> >
> >
> >   def removesuffix(s: str, suffix: str) -> str:
> > @@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
> >     tblname += '_' + dirname
> >     return tblname.replace('-', '_')
> >
> > +def c_len(s: str) -> int:
> > +  """Return the length of s a C string
> > +
> > +  This doesn't handle all escape characters properly. It first assumes
> > +  all \ are for escaping, it then adjusts as it will have over counted
> > +  \\. The code uses \000 rather than \0 as a terminator as an adjacent
> > +  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
> > +  equal a terminator followed by the number 5 but the escape of
> > +  \05). The code adjusts for \000 but not properly for all octal, hex
> > +  or unicode values.
> > +  """
> > +  try:
> > +    utf = s.encode(encoding='utf-8',errors='strict')
> > +  except:
> > +    print(f'broken string {s}')
> > +    raise
> > +  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
> > +
> > +class BigCString:
> > +  """A class to hold many strings concatenated together.
> > +
> > +  Generating a large number of stand-alone C strings creates a large
> > +  number of relocations in position independent code. The BigCString
> > +  is a helper for this case. It builds a single string which within it
> > +  are all the other C strings (to avoid memory issues the string
> > +  itself is held as a list of strings). The offsets within the big
> > +  string are recorded and when stored to disk these don't need
> > +  relocation.
> > +  """
> > +  strings: Set[str]
> > +  big_string: Sequence[str]
> > +  offsets: Dict[str, int]
> > +
> > +  def __init__(self):
> > +    self.strings = set()
> > +
> > +  def add(self, s: str) -> None:
> > +    """Called to add to the big string."""
> > +    self.strings.add(s)
> > +
> > +  def compute(self) -> None:
> > +    """Called once all strings are added to compute the string and offsets."""
> > +
> > +    # big_string_offset is the current location within the C string
> > +    # being appended to - comments, etc. don't count. big_string is
> > +    # the string contents represented as a list. Strings are immutable
> > +    # in Python and so appending to one causes memory issues, while
> > +    # lists are mutable.
> > +    big_string_offset = 0
> > +    self.big_string = []
> > +    self.offsets = {}
> > +    # Emit all strings in a sorted manner.
> > +    for s in sorted(self.strings):
> > +      self.offsets[s] = big_string_offset
> > +      self.big_string.append(f'/* offset={big_string_offset} */ "')
> > +      self.big_string.append(s)
> > +      self.big_string.append('"\n')
> > +      big_string_offset += c_len(s)
> > +
> > +_bcs = BigCString()
> >
> >   class JsonEvent:
> >     """Representation of an event loaded from a json file dictionary."""
> > @@ -202,26 +276,18 @@ class JsonEvent:
> >           s += f'\t{attr} = {value},\n'
> >       return s + '}'
> >
> > +  def build_c_string(self) -> str:
> > +    s = ''
> > +    for attr in _json_event_attributes:
> > +      x = getattr(self, attr)
> > +      s += f'{x}\\000' if x else '\\000'
> > +    return s
> > +
> >     def to_c_string(self) -> str:
> >       """Representation of the event as a C struct initializer."""
> >
> > -    def attr_string(attr: str, value: str) -> str:
> > -      return f'\t.{attr} = \"{value}\",\n'
> > -
> > -    def str_if_present(self, attr: str) -> str:
> > -      if not getattr(self, attr):
> > -        return ''
> > -      return attr_string(attr, getattr(self, attr))
> > -
> > -    s = '{\n'
> > -    for attr in [
> > -        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> > -        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> > -        'name', 'perpkg', 'pmu', 'topic', 'unit'
> > -    ]:
> > -      s += str_if_present(self, attr)
> > -    s += '},\n'
> > -    return s
> > +    s = self.build_c_string()
> > +    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
> >
> >
> >   def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> > @@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> >       event.topic = topic
> >     return result
> >
> > -
> >   def preprocess_arch_std_files(archpath: str) -> None:
> >     """Read in all architecture standard events."""
> >     global _arch_std_events
> > @@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
> >     global _close_table
> >     if _close_table:
> >       raise IOError('Printing table prefix but last table has no suffix')
> > -  _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
> > +  _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
> >     _close_table = True
> >
> >
> > @@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> >   def print_events_table_suffix() -> None:
> >     """Optionally close events table."""
> >
> > -  def event_cmp_key(j: JsonEvent):
> > -    def fix_none(s: str):
> > +  def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
> > +    def fix_none(s: Optional[str]) -> str:
> >         if s is None:
> >           return ''
> >         return s
> >
> > -    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> > +    return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> >               fix_none(j.metric_name))
> >
> >     global _close_table
> > @@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
> >       _args.output_file.write(event.to_c_string())
> >       _pending_events = []
> >
> > -  _args.output_file.write("""{
> > -\t.name = 0,
> > -\t.event = 0,
> > -\t.desc = 0,
> > -},
> > -};
> > -""")
> > +  _args.output_file.write('};\n\n')
> >     _close_table = False
> >
> > +def get_topic(topic: str) -> str:
> > +  if topic.endswith('metrics.json'):
> > +    return 'metrics'
> > +  return removesuffix(topic, '.json').replace('-', ' ')
> > +
> > +def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> > +
> > +  if item.is_dir():
> > +    return
> > +
> > +  # base dir or too deep
> > +  level = len(parents)
> > +  if level == 0 or level > 4:
> > +    return
> > +
> > +  # Ignore other directories. If the file name does not have a .json
> > +  # extension, ignore it. It could be a readme.txt for instance.
> > +  if not item.is_file() or not item.name.endswith('.json'):
> > +    return
> > +
> > +  topic = get_topic(item.name)
> > +  for event in read_json_events(item.path, topic):
> > +    _bcs.add(event.build_c_string())
> >
> >   def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> >     """Process a JSON file during the main walk."""
> >     global _sys_event_tables
> >
> > -  def get_topic(topic: str) -> str:
> > -    return removesuffix(topic, '.json').replace('-', ' ')
> > -
> >     def is_leaf_dir(path: str) -> bool:
> >       for item in os.scandir(path):
> >         if item.is_dir():
> > @@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
> >     _args.output_file.write("""
> >   /* Struct used to make the PMU event table implementation opaque to callers. */
> >   struct pmu_events_table {
> > -        const struct pmu_event *entries;
> > +        const struct compact_pmu_event *entries;
> > +        size_t length;
> >   };
> >
> >   /*
> > @@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
> >         _args.output_file.write("""{
> >   \t.arch = "testarch",
> >   \t.cpuid = "testcpu",
> > -\t.table = { pme_test_soc_cpu },
> > +\t.table = {
> > +\t.entries = pme_test_soc_cpu,
> > +\t.length = ARRAY_SIZE(pme_test_soc_cpu),
> > +\t}
> >   },
> >   """)
> >       else:
> > @@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
> >               _args.output_file.write(f"""{{
> >   \t.arch = "{arch}",
> >   \t.cpuid = "{cpuid}",
> > -\t.table = {{ {tblname} }}
> > +\t.table = {{
> > +\t\t.entries = {tblname},
> > +\t\t.length = ARRAY_SIZE({tblname})
> > +\t}}
> >   }},
> >   """)
> >             first = False
> > @@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
> >     _args.output_file.write("""{
> >   \t.arch = 0,
> >   \t.cpuid = 0,
> > -\t.table = { 0 },
> > +\t.table = { 0, 0 },
> >   }
> >   };
> >   """)
> > @@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >   """)
> >     for tblname in _sys_event_tables:
> >       _args.output_file.write(f"""\t{{
> > -\t\t.table = {{ {tblname} }},
> > +\t\t.table = {{
> > +\t\t\t.entries = {tblname},
> > +\t\t\t.length = ARRAY_SIZE({tblname})
> > +\t\t}},
> >   \t\t.name = \"{tblname}\",
> >   \t}},
> >   """)
> >     _args.output_file.write("""\t{
> > -\t\t.table = { 0 }
> > +\t\t.table = { 0, 0 }
> >   \t},
> >   };
> >
> > -int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
> > +static void decompress(int offset, struct pmu_event *pe)
> > +{
> > +\tconst char *p = &big_c_string[offset];
> > +""")
> > +  for attr in _json_event_attributes:
> > +    _args.output_file.write(f"""
> > +\tpe->{attr} = (*p == '\\0' ? NULL : p);
> > +""")
> > +    if attr == _json_event_attributes[-1]:
> > +      continue
> > +    _args.output_file.write('\twhile (*p++);')
> > +  _args.output_file.write("""}
>
>
> I get this in generated pmu-events.c:
>
> static void decompress(int offset, struct pmu_event *pe)
> {
> const char *p = &big_c_string[offset];
>
> pe->name = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->pmu = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->topic = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->desc = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_name = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_group = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->event = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->aggr_mode = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->compat = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->deprecated = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->perpkg = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->unit = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_constraint = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_expr = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->long_desc = (*p == '\0' ? NULL : p);
> }
>
> int pmu_events_table_for_each_event(const struct pmu_events_table *table,
>                                      pmu_event_iter_fn fn,
>                                      void *data)
> {
>          for (size_t i = 0; i < table->length; i++) {
>                  struct pmu_event pe;
>                  int ret;
>
>                  decompress(table->entries[i].offset, &pe);
>                  ret = fn(&pe, table, data);
>                  if (ret)
>                          return ret;
>          }
>          return 0;
> }
>
> --->8---
>
> This seems a bit inefficient in terms of performance - if that really is
> a requirement, but I figure that it isn't really.

I think the main inefficiency is coming from the struct pmu_event
containing so many variables. I think we can modify that later, say by
separating metrics from events, I did look at performance and the
decompress function is hot but overall the performance was similar to
before the change for some hand crafted examples.

> Another observation is that although we compress and reduce size in this
> method, we are now losing out on some sharing of strings. For example,
> this is an extract from big_string:
>
> /* offset=3342573 */
> "unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core 0 C
> State Transition Cycles. Unit: uncore_pcu
> \000\000\000event=0x70\000\000\000\0001\000\000\000\000Number of cycles
> spent performing core C state transitions.  There is one event per core\000"
> /* offset=3342789 */
> "unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core C
> State Transition Cycles. Unit: uncore_pcu
> \000\000\000event=0x103\000\000\000\0001\000\000\000\000Number of cycles
> spent performing core C state transitions.  There is one event per core\000"
>
> These super-strings are not identical, but many sub-strings are, like
> "Number of cycles spent performing core C state transitions.  There is
> one event per core", so we are losing out there on sharing strings there.

Agreed. I found that the savings by having a single offset were in
O(100kbs) and so had to give up string sharing for this.

Thanks,
Ian

> Thanks,
> John
> > +
> > +int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> > +                                    pmu_event_iter_fn fn,
> >                                       void *data)
> >   {
> > -        for (const struct pmu_event *pe = &table->entries[0];
> > -             pe->name || pe->metric_group || pe->metric_name;
> > -             pe++) {
> > -                int ret = fn(pe, table, data);
> > +        for (size_t i = 0; i < table->length; i++) {
> > +                struct pmu_event pe;
> > +                int ret;
> >
> > +                decompress(table->entries[i].offset, &pe);
> > +                ret = fn(&pe, table, data);
> >                   if (ret)
> >                           return ret;
> >           }
> > @@ -530,7 +634,7 @@ def main() -> None:
> >         help='Root of tree containing architecture directories containing json files'
> >     )
> >     ap.add_argument(
> > -      'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
> > +      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
> >     _args = ap.parse_args()
> >
> >     _args.output_file.write("""
> > @@ -540,6 +644,10 @@ def main() -> None:
> >   #include <string.h>
> >   #include <stddef.h>
> >
> > +struct compact_pmu_event {
> > +  int offset;
> > +};
> > +
> >   """)
> >     archs = []
> >     for item in os.scandir(_args.starting_dir):
> > @@ -555,6 +663,15 @@ def main() -> None:
> >     for arch in archs:
> >       arch_path = f'{_args.starting_dir}/{arch}'
> >       preprocess_arch_std_files(arch_path)
> > +    ftw(arch_path, [], preprocess_one_file)
> > +
> > +  _bcs.compute()
> > +  _args.output_file.write('static const char *const big_c_string =\n')
> > +  for s in _bcs.big_string:
> > +    _args.output_file.write(s)
> > +  _args.output_file.write(';\n\n')
> > +  for arch in archs:
> > +    arch_path = f'{_args.starting_dir}/{arch}'
> >       ftw(arch_path, [], process_one_file)
> >       print_events_table_suffix()
> >
>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 16/17] perf jevents: Compress the pmu_events_table
@ 2022-08-10 14:35       ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 14:35 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 7:02 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > The pmu_events array requires 15 pointers per entry which in position
> > independent code need relocating. Change the array to be an array of
> > offsets within a big C string. Only the offset of the first variable is
> > required, subsequent variables are stored in order after the \0
> > terminator (requiring a byte per variable rather than 4 bytes per
> > offset).
> >
> > The file size savings are:
> > no jevents - the same 19,788,464bytes
> > x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> > all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> > default build options plus NO_LIBBFD=1.
> >
> > For example, the x86 build savings come from .rela.dyn and
> > .data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
> > respectively. .rodata increases by 1,432,448bytes, giving an overall
> > 4,766,600bytes saving.
> >
> > To make metric strings more shareable, the topic is changed from say
> > 'skx metrics' to just 'metrics'.
> >
> > To try to help with the memory layout the pmu_events are ordered as used
> > by perf qsort comparator functions.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
> >   1 file changed, 162 insertions(+), 45 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index aa8df649025a..a5e162558994 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -6,7 +6,8 @@ import csv
> >   import json
> >   import os
> >   import sys
> > -from typing import (Callable, Optional, Sequence)
> > +from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
> > +import collections
> >
> >   # Global command line arguments.
> >   _args = None
> > @@ -20,6 +21,19 @@ _arch_std_events = {}
> >   _close_table = False
> >   # Events to write out when the table is closed
> >   _pending_events = []
> > +# Global BigCString shared by all structures.
> > +_bcs = None
> > +# Order specific JsonEvent attributes will be visited.
> > +_json_event_attributes = [
> > +    # cmp_sevent related attributes.
> > +    'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
> > +    # Seems useful, put it early.
> > +    'event',
> > +    # Short things in alphabetical order.
> > +    'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
> > +    # Longer things (the last won't be iterated over during decompress).
> > +    'metric_constraint', 'metric_expr', 'long_desc'
> > +]
> >
> >
> >   def removesuffix(s: str, suffix: str) -> str:
> > @@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
> >     tblname += '_' + dirname
> >     return tblname.replace('-', '_')
> >
> > +def c_len(s: str) -> int:
> > +  """Return the length of s a C string
> > +
> > +  This doesn't handle all escape characters properly. It first assumes
> > +  all \ are for escaping, it then adjusts as it will have over counted
> > +  \\. The code uses \000 rather than \0 as a terminator as an adjacent
> > +  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
> > +  equal a terminator followed by the number 5 but the escape of
> > +  \05). The code adjusts for \000 but not properly for all octal, hex
> > +  or unicode values.
> > +  """
> > +  try:
> > +    utf = s.encode(encoding='utf-8',errors='strict')
> > +  except:
> > +    print(f'broken string {s}')
> > +    raise
> > +  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
> > +
> > +class BigCString:
> > +  """A class to hold many strings concatenated together.
> > +
> > +  Generating a large number of stand-alone C strings creates a large
> > +  number of relocations in position independent code. The BigCString
> > +  is a helper for this case. It builds a single string which within it
> > +  are all the other C strings (to avoid memory issues the string
> > +  itself is held as a list of strings). The offsets within the big
> > +  string are recorded and when stored to disk these don't need
> > +  relocation.
> > +  """
> > +  strings: Set[str]
> > +  big_string: Sequence[str]
> > +  offsets: Dict[str, int]
> > +
> > +  def __init__(self):
> > +    self.strings = set()
> > +
> > +  def add(self, s: str) -> None:
> > +    """Called to add to the big string."""
> > +    self.strings.add(s)
> > +
> > +  def compute(self) -> None:
> > +    """Called once all strings are added to compute the string and offsets."""
> > +
> > +    # big_string_offset is the current location within the C string
> > +    # being appended to - comments, etc. don't count. big_string is
> > +    # the string contents represented as a list. Strings are immutable
> > +    # in Python and so appending to one causes memory issues, while
> > +    # lists are mutable.
> > +    big_string_offset = 0
> > +    self.big_string = []
> > +    self.offsets = {}
> > +    # Emit all strings in a sorted manner.
> > +    for s in sorted(self.strings):
> > +      self.offsets[s] = big_string_offset
> > +      self.big_string.append(f'/* offset={big_string_offset} */ "')
> > +      self.big_string.append(s)
> > +      self.big_string.append('"\n')
> > +      big_string_offset += c_len(s)
> > +
> > +_bcs = BigCString()
> >
> >   class JsonEvent:
> >     """Representation of an event loaded from a json file dictionary."""
> > @@ -202,26 +276,18 @@ class JsonEvent:
> >           s += f'\t{attr} = {value},\n'
> >       return s + '}'
> >
> > +  def build_c_string(self) -> str:
> > +    s = ''
> > +    for attr in _json_event_attributes:
> > +      x = getattr(self, attr)
> > +      s += f'{x}\\000' if x else '\\000'
> > +    return s
> > +
> >     def to_c_string(self) -> str:
> >       """Representation of the event as a C struct initializer."""
> >
> > -    def attr_string(attr: str, value: str) -> str:
> > -      return f'\t.{attr} = \"{value}\",\n'
> > -
> > -    def str_if_present(self, attr: str) -> str:
> > -      if not getattr(self, attr):
> > -        return ''
> > -      return attr_string(attr, getattr(self, attr))
> > -
> > -    s = '{\n'
> > -    for attr in [
> > -        'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> > -        'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> > -        'name', 'perpkg', 'pmu', 'topic', 'unit'
> > -    ]:
> > -      s += str_if_present(self, attr)
> > -    s += '},\n'
> > -    return s
> > +    s = self.build_c_string()
> > +    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
> >
> >
> >   def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> > @@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> >       event.topic = topic
> >     return result
> >
> > -
> >   def preprocess_arch_std_files(archpath: str) -> None:
> >     """Read in all architecture standard events."""
> >     global _arch_std_events
> > @@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
> >     global _close_table
> >     if _close_table:
> >       raise IOError('Printing table prefix but last table has no suffix')
> > -  _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
> > +  _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
> >     _close_table = True
> >
> >
> > @@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> >   def print_events_table_suffix() -> None:
> >     """Optionally close events table."""
> >
> > -  def event_cmp_key(j: JsonEvent):
> > -    def fix_none(s: str):
> > +  def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
> > +    def fix_none(s: Optional[str]) -> str:
> >         if s is None:
> >           return ''
> >         return s
> >
> > -    return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> > +    return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> >               fix_none(j.metric_name))
> >
> >     global _close_table
> > @@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
> >       _args.output_file.write(event.to_c_string())
> >       _pending_events = []
> >
> > -  _args.output_file.write("""{
> > -\t.name = 0,
> > -\t.event = 0,
> > -\t.desc = 0,
> > -},
> > -};
> > -""")
> > +  _args.output_file.write('};\n\n')
> >     _close_table = False
> >
> > +def get_topic(topic: str) -> str:
> > +  if topic.endswith('metrics.json'):
> > +    return 'metrics'
> > +  return removesuffix(topic, '.json').replace('-', ' ')
> > +
> > +def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> > +
> > +  if item.is_dir():
> > +    return
> > +
> > +  # base dir or too deep
> > +  level = len(parents)
> > +  if level == 0 or level > 4:
> > +    return
> > +
> > +  # Ignore other directories. If the file name does not have a .json
> > +  # extension, ignore it. It could be a readme.txt for instance.
> > +  if not item.is_file() or not item.name.endswith('.json'):
> > +    return
> > +
> > +  topic = get_topic(item.name)
> > +  for event in read_json_events(item.path, topic):
> > +    _bcs.add(event.build_c_string())
> >
> >   def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> >     """Process a JSON file during the main walk."""
> >     global _sys_event_tables
> >
> > -  def get_topic(topic: str) -> str:
> > -    return removesuffix(topic, '.json').replace('-', ' ')
> > -
> >     def is_leaf_dir(path: str) -> bool:
> >       for item in os.scandir(path):
> >         if item.is_dir():
> > @@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
> >     _args.output_file.write("""
> >   /* Struct used to make the PMU event table implementation opaque to callers. */
> >   struct pmu_events_table {
> > -        const struct pmu_event *entries;
> > +        const struct compact_pmu_event *entries;
> > +        size_t length;
> >   };
> >
> >   /*
> > @@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
> >         _args.output_file.write("""{
> >   \t.arch = "testarch",
> >   \t.cpuid = "testcpu",
> > -\t.table = { pme_test_soc_cpu },
> > +\t.table = {
> > +\t.entries = pme_test_soc_cpu,
> > +\t.length = ARRAY_SIZE(pme_test_soc_cpu),
> > +\t}
> >   },
> >   """)
> >       else:
> > @@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
> >               _args.output_file.write(f"""{{
> >   \t.arch = "{arch}",
> >   \t.cpuid = "{cpuid}",
> > -\t.table = {{ {tblname} }}
> > +\t.table = {{
> > +\t\t.entries = {tblname},
> > +\t\t.length = ARRAY_SIZE({tblname})
> > +\t}}
> >   }},
> >   """)
> >             first = False
> > @@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
> >     _args.output_file.write("""{
> >   \t.arch = 0,
> >   \t.cpuid = 0,
> > -\t.table = { 0 },
> > +\t.table = { 0, 0 },
> >   }
> >   };
> >   """)
> > @@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >   """)
> >     for tblname in _sys_event_tables:
> >       _args.output_file.write(f"""\t{{
> > -\t\t.table = {{ {tblname} }},
> > +\t\t.table = {{
> > +\t\t\t.entries = {tblname},
> > +\t\t\t.length = ARRAY_SIZE({tblname})
> > +\t\t}},
> >   \t\t.name = \"{tblname}\",
> >   \t}},
> >   """)
> >     _args.output_file.write("""\t{
> > -\t\t.table = { 0 }
> > +\t\t.table = { 0, 0 }
> >   \t},
> >   };
> >
> > -int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
> > +static void decompress(int offset, struct pmu_event *pe)
> > +{
> > +\tconst char *p = &big_c_string[offset];
> > +""")
> > +  for attr in _json_event_attributes:
> > +    _args.output_file.write(f"""
> > +\tpe->{attr} = (*p == '\\0' ? NULL : p);
> > +""")
> > +    if attr == _json_event_attributes[-1]:
> > +      continue
> > +    _args.output_file.write('\twhile (*p++);')
> > +  _args.output_file.write("""}
>
>
> I get this in generated pmu-events.c:
>
> static void decompress(int offset, struct pmu_event *pe)
> {
> const char *p = &big_c_string[offset];
>
> pe->name = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->pmu = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->topic = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->desc = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_name = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_group = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->event = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->aggr_mode = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->compat = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->deprecated = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->perpkg = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->unit = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_constraint = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_expr = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->long_desc = (*p == '\0' ? NULL : p);
> }
>
> int pmu_events_table_for_each_event(const struct pmu_events_table *table,
>                                      pmu_event_iter_fn fn,
>                                      void *data)
> {
>          for (size_t i = 0; i < table->length; i++) {
>                  struct pmu_event pe;
>                  int ret;
>
>                  decompress(table->entries[i].offset, &pe);
>                  ret = fn(&pe, table, data);
>                  if (ret)
>                          return ret;
>          }
>          return 0;
> }
>
> --->8---
>
> This seems a bit inefficient in terms of performance - if that really is
> a requirement, but I figure that it isn't really.

I think the main inefficiency is coming from the struct pmu_event
containing so many variables. I think we can modify that later, say by
separating metrics from events, I did look at performance and the
decompress function is hot but overall the performance was similar to
before the change for some hand crafted examples.

> Another observation is that although we compress and reduce size in this
> method, we are now losing out on some sharing of strings. For example,
> this is an extract from big_string:
>
> /* offset=3342573 */
> "unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core 0 C
> State Transition Cycles. Unit: uncore_pcu
> \000\000\000event=0x70\000\000\000\0001\000\000\000\000Number of cycles
> spent performing core C state transitions.  There is one event per core\000"
> /* offset=3342789 */
> "unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core C
> State Transition Cycles. Unit: uncore_pcu
> \000\000\000event=0x103\000\000\000\0001\000\000\000\000Number of cycles
> spent performing core C state transitions.  There is one event per core\000"
>
> These super-strings are not identical, but many sub-strings are, like
> "Number of cycles spent performing core C state transitions.  There is
> one event per core", so we are losing out there on sharing strings there.

Agreed. I found that the savings by having a single offset were in
O(100kbs) and so had to give up string sharing for this.

Thanks,
Ian

> Thanks,
> John
> > +
> > +int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> > +                                    pmu_event_iter_fn fn,
> >                                       void *data)
> >   {
> > -        for (const struct pmu_event *pe = &table->entries[0];
> > -             pe->name || pe->metric_group || pe->metric_name;
> > -             pe++) {
> > -                int ret = fn(pe, table, data);
> > +        for (size_t i = 0; i < table->length; i++) {
> > +                struct pmu_event pe;
> > +                int ret;
> >
> > +                decompress(table->entries[i].offset, &pe);
> > +                ret = fn(&pe, table, data);
> >                   if (ret)
> >                           return ret;
> >           }
> > @@ -530,7 +634,7 @@ def main() -> None:
> >         help='Root of tree containing architecture directories containing json files'
> >     )
> >     ap.add_argument(
> > -      'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
> > +      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
> >     _args = ap.parse_args()
> >
> >     _args.output_file.write("""
> > @@ -540,6 +644,10 @@ def main() -> None:
> >   #include <string.h>
> >   #include <stddef.h>
> >
> > +struct compact_pmu_event {
> > +  int offset;
> > +};
> > +
> >   """)
> >     archs = []
> >     for item in os.scandir(_args.starting_dir):
> > @@ -555,6 +663,15 @@ def main() -> None:
> >     for arch in archs:
> >       arch_path = f'{_args.starting_dir}/{arch}'
> >       preprocess_arch_std_files(arch_path)
> > +    ftw(arch_path, [], preprocess_one_file)
> > +
> > +  _bcs.compute()
> > +  _args.output_file.write('static const char *const big_c_string =\n')
> > +  for s in _bcs.big_string:
> > +    _args.output_file.write(s)
> > +  _args.output_file.write(';\n\n')
> > +  for arch in archs:
> > +    arch_path = f'{_args.starting_dir}/{arch}'
> >       ftw(arch_path, [], process_one_file)
> >       print_events_table_suffix()
> >
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 09/17] perf pmu-events: Avoid passing pmu_events_map
  2022-08-05 11:28     ` John Garry
@ 2022-08-10 15:23       ` Ian Rogers
  -1 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 15:23 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 4:28 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Preparation for hiding pmu_events_map as an implementation detail. While
> > the map is passed, the table of events is all that is normally wanted.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
>
> Apart from comments on naming, below:
>
> Reviewed-by: John Garry <john.garry@huawei.com>
>
> As an aside, I will mention that reviewing this series is not helped by
> limited description of the changes in the cover letter. A primer would
> be nice. As I go through the series, I am often assuming that the
> motivation for the change is sound.

Ack. I was hoping the compression motivation would be enough in the
cover letter, but yeah the refactoring to get to that is painful and
could do with more explaining. Thanks for the reviews!

> Thanks,
> John
>
> > ---
> >   tools/perf/arch/arm64/util/pmu.c  |  4 +-
> >   tools/perf/tests/expand-cgroup.c  |  6 +--
> >   tools/perf/tests/parse-metric.c   |  7 +--
> >   tools/perf/tests/pmu-events.c     | 63 +++++++++++-------------
> >   tools/perf/util/metricgroup.c     | 82 +++++++++++++++----------------
> >   tools/perf/util/metricgroup.h     |  4 +-
> >   tools/perf/util/pmu.c             | 33 +++++++------
> >   tools/perf/util/pmu.h             |  6 +--
> >   tools/perf/util/s390-sample-raw.c | 12 ++---
> >   9 files changed, 99 insertions(+), 118 deletions(-)
> >
> > diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> > index 79124bba713e..646af8603227 100644
> > --- a/tools/perf/arch/arm64/util/pmu.c
> > +++ b/tools/perf/arch/arm64/util/pmu.c
> > @@ -3,7 +3,7 @@
> >   #include "../../../util/cpumap.h"
> >   #include "../../../util/pmu.h"
> >
> > -const struct pmu_events_map *pmu_events_map__find(void)
> > +const struct pmu_event *pmu_events_map__find(void)
>
> The function name is no longer appropriate
>
>
> >   {
> >       struct perf_pmu *pmu = NULL;
> >
> > @@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
> >               if (pmu->cpus->nr != cpu__max_cpu().cpu)
> >                       return NULL;
> >
> > -             return perf_pmu__find_map(pmu);
> > +             return perf_pmu__find_table(pmu);
> >       }
> >
> >       return NULL;
> > diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> > index dc4038f997d7..411fc578e5a4 100644
> > --- a/tools/perf/tests/expand-cgroup.c
> > +++ b/tools/perf/tests/expand-cgroup.c
> > @@ -195,16 +195,12 @@ static int expand_metric_events(void)
> >                       .metric_name    = NULL,
> >               },
> >       };
> > -     const struct pmu_events_map ev_map = {
> > -             .cpuid          = "test",
> > -             .table          = pme_test,
> > -     };
> >
> >       evlist = evlist__new();
> >       TEST_ASSERT_VAL("failed to get evlist", evlist);
> >
> >       rblist__init(&metric_events);
> > -     ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
> > +     ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
> >                                            false, false, &metric_events);
> >       if (ret < 0) {
> >               pr_debug("failed to parse '%s' metric\n", metric_str);
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 1b811a26f4ee..7aebde7c37ec 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
> >   }
> >   };
> >
> > -static const struct pmu_events_map map = {
> > -     .cpuid          = "test",
> > -     .table          = pme_test,
> > -};
> > -
> >   struct value {
> >       const char      *event;
> >       u64              val;
> > @@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
> >       runtime_stat__init(&st);
> >
> >       /* Parse the metric into metric_events list. */
> > -     err = metricgroup__parse_groups_test(evlist, &map, name,
> > +     err = metricgroup__parse_groups_test(evlist, pme_test, name,
> >                                            false, false,
> >                                            &metric_events);
> >       if (err)
> > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> > index a39a2c99ede6..b3cde5f98982 100644
> > --- a/tools/perf/tests/pmu-events.c
> > +++ b/tools/perf/tests/pmu-events.c
> > @@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
> >       return !strcmp(reference, test);
> >   }
> >
> > -static const struct pmu_events_map *__test_pmu_get_events_map(void)
> > +static const struct pmu_event *__test_pmu_get_events_table(void)
> >   {
> > -     const struct pmu_events_map *map;
> > -
> > -     for (map = &pmu_events_map[0]; map->cpuid; map++) {
> > +     for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
> >               if (!strcmp(map->cpuid, "testcpu"))
> > -                     return map;
> > +                     return map->table;
> >       }
> >
> >       pr_err("could not find test events map\n");
> > @@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> >                                int subtest __maybe_unused)
> >   {
> >       const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
> > -     const struct pmu_events_map *map = __test_pmu_get_events_map();
> > -     const struct pmu_event *table;
> > +     const struct pmu_event *table = __test_pmu_get_events_table();
> >       int map_events = 0, expected_events;
> >
> >       /* ignore 3x sentinels */
> > @@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> >                         ARRAY_SIZE(uncore_events) +
> >                         ARRAY_SIZE(sys_events) - 3;
> >
> > -     if (!map || !sys_event_tables)
> > +     if (!table || !sys_event_tables)
> >               return -1;
> >
> > -     for (table = map->table; table->name; table++) {
> > +     for (; table->name; table++) {
> >               struct perf_pmu_test_event const **test_event_table;
> >               bool found = false;
> >
> > @@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
> >       struct perf_pmu *pmu;
> >       LIST_HEAD(aliases);
> >       int res = 0;
> > -     const struct pmu_events_map *map = __test_pmu_get_events_map();
> > +     const struct pmu_event *table = __test_pmu_get_events_table();
> >       struct perf_pmu_alias *a, *tmp;
> >
> > -     if (!map)
> > +     if (!table)
> >               return -1;
> >
> >       test_event_table = &core_events[0];
> > @@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
> >
> >       pmu->name = pmu_name;
> >
> > -     pmu_add_cpu_aliases_map(&aliases, pmu, map);
> > +     pmu_add_cpu_aliases_map(&aliases, pmu, table);
> >
> >       for (; *test_event_table; test_event_table++) {
> >               struct perf_pmu_test_event const *test_event = *test_event_table;
> > @@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
> >       struct perf_pmu *pmu = &test_pmu->pmu;
> >       const char *pmu_name = pmu->name;
> >       struct perf_pmu_alias *a, *tmp, *alias;
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *events_table;
> >       LIST_HEAD(aliases);
> >       int res = 0;
> >
> > -     map = __test_pmu_get_events_map();
> > -     if (!map)
> > +     events_table = __test_pmu_get_events_table();
> > +     if (!events_table)
> >               return -1;
> > -     pmu_add_cpu_aliases_map(&aliases, pmu, map);
> > +     pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
> >       pmu_add_sys_aliases(&aliases, pmu);
> >
> >       /* Count how many aliases we generated */
> > @@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
> >       return ret;
> >   }
> >
> > -static void expr_failure(const char *msg,
> > -                      const struct pmu_events_map *map,
> > -                      const struct pmu_event *pe)
> > +static void expr_failure(const char *msg, const struct pmu_event *pe)
> >   {
> > -     pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
> > -     pr_debug("On metric %s\n", pe->metric_name);
> > -     pr_debug("On expression %s\n", pe->metric_expr);
> > +     pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
> >   }
> >
> >   struct metric {
> > @@ -864,7 +857,7 @@ struct metric {
> >
> >   static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> >                                struct list_head *compound_list,
> > -                              const struct pmu_events_map *map,
> > +                              const struct pmu_event *map,
> >                                const char *metric_name)
> >   {
> >       struct hashmap_entry *cur, *cur_tmp;
> > @@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> >   static int test__parsing(struct test_suite *test __maybe_unused,
> >                        int subtest __maybe_unused)
> >   {
> > -     const struct pmu_events_map *cpus_map = pmu_events_map__find();
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *cpus_table = pmu_events_map__find();
> >       const struct pmu_event *pe;
> >       int i, j, k;
> >       int ret = 0;
> > @@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >       }
> >       i = 0;
> >       for (;;) {
> > -             map = &pmu_events_map[i++];
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> >               if (!map->table)
> >                       break;
> >               j = 0;
> > @@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >                               continue;
> >                       expr__ctx_clear(ctx);
> >                       if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
> > -                             expr_failure("Parse find ids failed", map, pe);
> > +                             expr_failure("Parse find ids failed", pe);
> >                               ret++;
> >                               continue;
> >                       }
> >
> > -                     if (resolve_metric_simple(ctx, &compound_list, map,
> > +                     if (resolve_metric_simple(ctx, &compound_list, map->table,
> >                                                 pe->metric_name)) {
> > -                             expr_failure("Could not resolve metrics", map, pe);
> > +                             expr_failure("Could not resolve metrics", pe);
> >                               ret++;
> >                               goto exit; /* Don't tolerate errors due to severity */
> >                       }
> > @@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >                               expr__add_id_val(ctx, strdup(cur->key), k++);
> >
> >                       hashmap__for_each_entry(ctx->ids, cur, bkt) {
> > -                             if (check_parse_cpu(cur->key, map == cpus_map,
> > +                             if (check_parse_cpu(cur->key, map->table == cpus_table,
> >                                                  pe))
> >                                       ret++;
> >                       }
> > @@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >                               hashmap__for_each_entry(ctx->ids, cur, bkt)
> >                                       expr__add_id_val(ctx, strdup(cur->key), k--);
> >                               if (expr__parse(&result, ctx, pe->metric_expr)) {
> > -                                     expr_failure("Parse failed", map, pe);
> > +                                     expr_failure("Parse failed", pe);
> >                                       ret++;
> >                               }
> >                       }
> > @@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
> >   static int test__parsing_fake(struct test_suite *test __maybe_unused,
> >                             int subtest __maybe_unused)
> >   {
> > -     const struct pmu_events_map *map;
> > -     const struct pmu_event *pe;
> >       unsigned int i, j;
> >       int err = 0;
> >
> > @@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
> >
> >       i = 0;
> >       for (;;) {
> > -             map = &pmu_events_map[i++];
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> >               if (!map->table)
> >                       break;
> >               j = 0;
> >               for (;;) {
> > -                     pe = &map->table[j++];
> > +                     const struct pmu_event *pe = &map->table[j++];
> > +
> >                       if (!pe->name && !pe->metric_group && !pe->metric_name)
> >                               break;
> >                       if (!pe->metric_expr)
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index 8f7baeabc5cf..4d32b4fbf67d 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
> >   void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> >                       bool raw, bool details, const char *pmu_name)
> >   {
> > -     const struct pmu_events_map *map = pmu_events_map__find();
> > -     const struct pmu_event *pe;
> > -     int i;
> >       struct rblist groups;
> >       struct rb_node *node, *next;
> >       struct strlist *metriclist = NULL;
> > @@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> >       groups.node_new = mep_new;
> >       groups.node_cmp = mep_cmp;
> >       groups.node_delete = mep_delete;
> > -     for (i = 0; map; i++) {
> > -             pe = &map->table[i];
> > +     for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
> >
> >               if (!pe->name && !pe->metric_group && !pe->metric_name)
> >                       break;
> > @@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
> >       bool metric_no_group;
> >       struct metric *root_metric;
> >       const struct visited_metric *visited;
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table;
> >   };
> >
> >   static int add_metric(struct list_head *metric_list,
> > @@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
> >                     bool metric_no_group,
> >                     struct metric *root_metric,
> >                     const struct visited_metric *visited,
> > -                   const struct pmu_events_map *map);
> > +                   const struct pmu_event *table);
> >
> >   /**
> >    * resolve_metric - Locate metrics within the root metric and recursively add
> > @@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
> >    *               metrics. When adding a root this argument is NULL.
> >    * @visited: A singly linked list of metric names being added that is used to
> >    *           detect recursion.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int resolve_metric(struct list_head *metric_list,
> > @@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
> >                         bool metric_no_group,
> >                         struct metric *root_metric,
> >                         const struct visited_metric *visited,
> > -                       const struct pmu_events_map *map)
> > +                       const struct pmu_event *table)
> >   {
> >       struct hashmap_entry *cur;
> >       size_t bkt;
> > @@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
> >       hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
> >               const struct pmu_event *pe;
> >
> > -             pe = metricgroup__find_metric(cur->key, map);
> > +             pe = metricgroup__find_metric(cur->key, table);
> >               if (pe) {
> >                       pending = realloc(pending,
> >                                       (pending_cnt + 1) * sizeof(struct to_resolve));
> > @@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
> >        */
> >       for (i = 0; i < pending_cnt; i++) {
> >               ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
> > -                             root_metric, visited, map);
> > +                             root_metric, visited, table);
> >               if (ret)
> >                       break;
> >       }
> > @@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
> >    *               metrics. When adding a root this argument is NULL.
> >    * @visited: A singly linked list of metric names being added that is used to
> >    *           detect recursion.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int __add_metric(struct list_head *metric_list,
> > @@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
> >                       int runtime,
> >                       struct metric *root_metric,
> >                       const struct visited_metric *visited,
> > -                     const struct pmu_events_map *map)
> > +                     const struct pmu_event *table)
> >   {
> >       const struct visited_metric *vm;
> >       int ret;
> > @@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
> >       } else {
> >               /* Resolve referenced metrics. */
> >               ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
> > -                                  &visited_node, map);
> > +                                  &visited_node, table);
> >       }
> >
> >       if (ret) {
> > @@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
> >       return ret;
> >   }
> >
> > -#define map_for_each_event(__pe, __idx, __map)                                       \
> > -     if (__map)                                                              \
> > -             for (__idx = 0, __pe = &__map->table[__idx];                    \
> > +#define table_for_each_event(__pe, __idx, __table)                                   \
> > +     if (__table)                                                            \
> > +             for (__idx = 0, __pe = &__table[__idx];                         \
> >                    __pe->name || __pe->metric_group || __pe->metric_name;     \
> > -                  __pe = &__map->table[++__idx])
> > +                  __pe = &__table[++__idx])
> >
> > -#define map_for_each_metric(__pe, __idx, __map, __metric)            \
> > -     map_for_each_event(__pe, __idx, __map)                          \
> > +#define table_for_each_metric(__pe, __idx, __table, __metric)                \
> > +     table_for_each_event(__pe, __idx, __table)                              \
> >               if (__pe->metric_expr &&                                \
> >                   (match_metric(__pe->metric_group, __metric) ||      \
> >                    match_metric(__pe->metric_name, __metric)))
> >
> >   const struct pmu_event *metricgroup__find_metric(const char *metric,
> > -                                              const struct pmu_events_map *map)
> > +                                              const struct pmu_event *table)
> >   {
> >       const struct pmu_event *pe;
> >       int i;
> >
> > -     map_for_each_event(pe, i, map) {
> > +     table_for_each_event(pe, i, table) {
> >               if (match_metric(pe->metric_name, metric))
> >                       return pe;
> >       }
> > @@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
> >                     bool metric_no_group,
> >                     struct metric *root_metric,
> >                     const struct visited_metric *visited,
> > -                   const struct pmu_events_map *map)
> > +                   const struct pmu_event *table)
> >   {
> >       int ret = 0;
> >
> > @@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
> >
> >       if (!strstr(pe->metric_expr, "?")) {
> >               ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> > -                                root_metric, visited, map);
> > +                                root_metric, visited, table);
> >       } else {
> >               int j, count;
> >
> > @@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
> >
> >               for (j = 0; j < count && !ret; j++)
> >                       ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
> > -                                     root_metric, visited, map);
> > +                                     root_metric, visited, table);
> >       }
> >
> >       return ret;
> > @@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
> >               return 0;
> >
> >       ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> > -                      d->root_metric, d->visited, d->map);
> > +                      d->root_metric, d->visited, d->table);
> >       if (ret)
> >               goto out;
> >
> > @@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
> >    *                   global. Grouping is the default but due to multiplexing the
> >    *                   user may override.
> >    * @metric_list: The list that the metric or metric group are added to.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int metricgroup__add_metric(const char *metric_name, const char *modifier,
> >                                  bool metric_no_group,
> >                                  struct list_head *metric_list,
> > -                                const struct pmu_events_map *map)
> > +                                const struct pmu_event *table)
> >   {
> >       const struct pmu_event *pe;
> >       LIST_HEAD(list);
> > @@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> >        * Iterate over all metrics seeing if metric matches either the name or
> >        * group. When it does add the metric to the list.
> >        */
> > -     map_for_each_metric(pe, i, map, metric_name) {
> > +     table_for_each_metric(pe, i, table, metric_name) {
> >               has_match = true;
> >               ret = add_metric(&list, pe, modifier, metric_no_group,
> >                                /*root_metric=*/NULL,
> > -                              /*visited_metrics=*/NULL, map);
> > +                              /*visited_metrics=*/NULL, table);
> >               if (ret)
> >                       goto out;
> >       }
> > @@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> >                               .metric_no_group = metric_no_group,
> >                               .has_match = &has_match,
> >                               .ret = &ret,
> > -                             .map = map,
> > +                             .table = table,
> >                       },
> >               };
> >
> > @@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> >    *                   global. Grouping is the default but due to multiplexing the
> >    *                   user may override.
> >    * @metric_list: The list that metrics are added to.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> >                                       struct list_head *metric_list,
> > -                                     const struct pmu_events_map *map)
> > +                                     const struct pmu_event *table)
> >   {
> >       char *list_itr, *list_copy, *metric_name, *modifier;
> >       int ret, count = 0;
> > @@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> >
> >               ret = metricgroup__add_metric(metric_name, modifier,
> >                                             metric_no_group, metric_list,
> > -                                           map);
> > +                                           table);
> >               if (ret == -EINVAL)
> >                       pr_err("Cannot find metric or group `%s'\n", metric_name);
> >
> > @@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> >                       bool metric_no_merge,
> >                       struct perf_pmu *fake_pmu,
> >                       struct rblist *metric_events_list,
> > -                     const struct pmu_events_map *map)
> > +                     const struct pmu_event *table)
> >   {
> >       struct evlist *combined_evlist = NULL;
> >       LIST_HEAD(metric_list);
> > @@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> >       if (metric_events_list->nr_entries == 0)
> >               metricgroup__rblist_init(metric_events_list);
> >       ret = metricgroup__add_metric_list(str, metric_no_group,
> > -                                        &metric_list, map);
> > +                                        &metric_list, table);
> >       if (ret)
> >               goto out;
> >
> > @@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
> >                             struct rblist *metric_events)
> >   {
> >       struct evlist *perf_evlist = *(struct evlist **)opt->value;
> > -     const struct pmu_events_map *map = pmu_events_map__find();
> > +     const struct pmu_event *table = pmu_events_map__find();
> >
> >       return parse_groups(perf_evlist, str, metric_no_group,
> > -                         metric_no_merge, NULL, metric_events, map);
> > +                         metric_no_merge, NULL, metric_events, table);
> >   }
> >
> >   int metricgroup__parse_groups_test(struct evlist *evlist,
> > -                                const struct pmu_events_map *map,
> > +                                const struct pmu_event *table,
> >                                  const char *str,
> >                                  bool metric_no_group,
> >                                  bool metric_no_merge,
> >                                  struct rblist *metric_events)
> >   {
> >       return parse_groups(evlist, str, metric_no_group,
> > -                         metric_no_merge, &perf_pmu__fake, metric_events, map);
> > +                         metric_no_merge, &perf_pmu__fake, metric_events, table);
> >   }
> >
> >   bool metricgroup__has_metric(const char *metric)
> >   {
> > -     const struct pmu_events_map *map = pmu_events_map__find();
> > +     const struct pmu_event *table = pmu_events_map__find();
> >       const struct pmu_event *pe;
> >       int i;
> >
> > -     if (!map)
> > +     if (!table)
> >               return false;
> >
> >       for (i = 0; ; i++) {
> > -             pe = &map->table[i];
> > +             pe = &table[i];
> >
> >               if (!pe->name && !pe->metric_group && !pe->metric_name)
> >                       break;
> > diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
> > index 2b42b778d1bf..5a1390e73d25 100644
> > --- a/tools/perf/util/metricgroup.h
> > +++ b/tools/perf/util/metricgroup.h
> > @@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
> >                             bool metric_no_merge,
> >                             struct rblist *metric_events);
> >   const struct pmu_event *metricgroup__find_metric(const char *metric,
> > -                                              const struct pmu_events_map *map);
> > +                                              const struct pmu_event *table);
> >   int metricgroup__parse_groups_test(struct evlist *evlist,
> > -                                const struct pmu_events_map *map,
> > +                                const struct pmu_event *table,
> >                                  const char *str,
> >                                  bool metric_no_group,
> >                                  bool metric_no_merge,
> > diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> > index d8717c4548a4..f3e3c4a147e9 100644
> > --- a/tools/perf/util/pmu.c
> > +++ b/tools/perf/util/pmu.c
> > @@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
> >       return cpuid;
> >   }
> >
> > -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> >   {
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table = NULL;
> >       char *cpuid = perf_pmu__getcpuid(pmu);
> >       int i;
> >
> > @@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> >
> >       i = 0;
> >       for (;;) {
> > -             map = &pmu_events_map[i++];
> > -             if (!map->table) {
> > -                     map = NULL;
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > +             if (!map->table)
> >                       break;
> > -             }
> >
> > -             if (!strcmp_cpuid_str(map->cpuid, cpuid))
> > +             if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > +                     table = map->table;
> >                       break;
> > +             }
> >       }
> >       free(cpuid);
> > -     return map;
> > +     return table;
> >   }
> >
> > -const struct pmu_events_map *__weak pmu_events_map__find(void)
> > +__weak const struct pmu_event *pmu_events_map__find(void)
> >   {
> > -     return perf_pmu__find_map(NULL);
> > +     return perf_pmu__find_table(NULL);
> >   }
> >
> >   /*
> > @@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
> >    * as aliases.
> >    */
> >   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>
> Again, it seems that this name should be changed

Ack. I'll put this into the next version. The next patch (number 10
"perf pmu-events: Hide the pmu_events") changes things slightly:

-const struct pmu_event *pmu_events_map__find(void)
+const struct pmu_events_table *pmu_events_map__find(void)

So I'll try to minimize the churn in renaming.

Thanks,
Ian

> > -                          const struct pmu_events_map *map)
> > +                          const struct pmu_event *table)
> >   {
> >       int i;
> >       const char *name = pmu->name;
> > @@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> >       i = 0;
> >       while (1) {
> >               const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
> > -             const struct pmu_event *pe = &map->table[i++];
> > +             const struct pmu_event *pe = &table[i++];
> >               const char *pname = pe->pmu ? pe->pmu : cpu_name;
> >
> >               if (!pe->name) {
> > @@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> >
> >   static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
> >   {
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table;
> >
> > -     map = perf_pmu__find_map(pmu);
> > -     if (!map)
> > +     table = perf_pmu__find_table(pmu);
> > +     if (!table)
> >               return;
> >
> > -     pmu_add_cpu_aliases_map(head, pmu, map);
> > +     pmu_add_cpu_aliases_map(head, pmu, table);
> >   }
> >
> >   struct pmu_sys_event_iter_data {
> > diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> > index 7e667eec2a01..015242c83698 100644
> > --- a/tools/perf/util/pmu.h
> > +++ b/tools/perf/util/pmu.h
> > @@ -126,10 +126,10 @@ int perf_pmu__test(void);
> >
> >   struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
> >   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> > -                          const struct pmu_events_map *map);
> > +                          const struct pmu_event *map);
> >
> > -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
> > -const struct pmu_events_map *pmu_events_map__find(void);
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
> > +const struct pmu_event *pmu_events_map__find(void);
> >   bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
> >   void perf_pmu_free_alias(struct perf_pmu_alias *alias);
> >
> > diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
> > index cd3a34840389..1ecb718fc0eb 100644
> > --- a/tools/perf/util/s390-sample-raw.c
> > +++ b/tools/perf/util/s390-sample-raw.c
> > @@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
> >    * the name of this counter.
> >    * If no match is found a NULL pointer is returned.
> >    */
> > -static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
> > +static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
> >   {
> >       int rc, event_nr, wanted = get_counterset_start(set) + nr;
> >
> > -     if (map) {
> > -             const struct pmu_event *evp = map->table;
> > +     if (table) {
> > +             const struct pmu_event *evp = table;
> >
> >               for (; evp->name || evp->event || evp->desc; ++evp) {
> >                       if (evp->name == NULL || evp->event == NULL)
> > @@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> >       unsigned char *buf = sample->raw_data;
> >       const char *color = PERF_COLOR_BLUE;
> >       struct cf_ctrset_entry *cep, ce;
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table;
> >       u64 *p;
> >
> > -     map = pmu_events_map__find();
> > +     table = pmu_events_map__find();
> >       while (offset < len) {
> >               cep = (struct cf_ctrset_entry *)(buf + offset);
> >
> > @@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> >               color_fprintf(stdout, color, "    [%#08zx] Counterset:%d"
> >                             " Counters:%d\n", offset, ce.set, ce.ctr);
> >               for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
> > -                     const char *ev_name = get_counter_name(ce.set, i, map);
> > +                     const char *ev_name = get_counter_name(ce.set, i, table);
> >
> >                       color_fprintf(stdout, color,
> >                                     "\tCounter:%03d %s Value:%#018lx\n", i,
>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 09/17] perf pmu-events: Avoid passing pmu_events_map
@ 2022-08-10 15:23       ` Ian Rogers
  0 siblings, 0 replies; 80+ messages in thread
From: Ian Rogers @ 2022-08-10 15:23 UTC (permalink / raw)
  To: John Garry
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On Fri, Aug 5, 2022 at 4:28 AM John Garry <john.garry@huawei.com> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Preparation for hiding pmu_events_map as an implementation detail. While
> > the map is passed, the table of events is all that is normally wanted.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
>
> Apart from comments on naming, below:
>
> Reviewed-by: John Garry <john.garry@huawei.com>
>
> As an aside, I will mention that reviewing this series is not helped by
> limited description of the changes in the cover letter. A primer would
> be nice. As I go through the series, I am often assuming that the
> motivation for the change is sound.

Ack. I was hoping the compression motivation would be enough in the
cover letter, but yeah the refactoring to get to that is painful and
could do with more explaining. Thanks for the reviews!

> Thanks,
> John
>
> > ---
> >   tools/perf/arch/arm64/util/pmu.c  |  4 +-
> >   tools/perf/tests/expand-cgroup.c  |  6 +--
> >   tools/perf/tests/parse-metric.c   |  7 +--
> >   tools/perf/tests/pmu-events.c     | 63 +++++++++++-------------
> >   tools/perf/util/metricgroup.c     | 82 +++++++++++++++----------------
> >   tools/perf/util/metricgroup.h     |  4 +-
> >   tools/perf/util/pmu.c             | 33 +++++++------
> >   tools/perf/util/pmu.h             |  6 +--
> >   tools/perf/util/s390-sample-raw.c | 12 ++---
> >   9 files changed, 99 insertions(+), 118 deletions(-)
> >
> > diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> > index 79124bba713e..646af8603227 100644
> > --- a/tools/perf/arch/arm64/util/pmu.c
> > +++ b/tools/perf/arch/arm64/util/pmu.c
> > @@ -3,7 +3,7 @@
> >   #include "../../../util/cpumap.h"
> >   #include "../../../util/pmu.h"
> >
> > -const struct pmu_events_map *pmu_events_map__find(void)
> > +const struct pmu_event *pmu_events_map__find(void)
>
> The function name is no longer appropriate
>
>
> >   {
> >       struct perf_pmu *pmu = NULL;
> >
> > @@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
> >               if (pmu->cpus->nr != cpu__max_cpu().cpu)
> >                       return NULL;
> >
> > -             return perf_pmu__find_map(pmu);
> > +             return perf_pmu__find_table(pmu);
> >       }
> >
> >       return NULL;
> > diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> > index dc4038f997d7..411fc578e5a4 100644
> > --- a/tools/perf/tests/expand-cgroup.c
> > +++ b/tools/perf/tests/expand-cgroup.c
> > @@ -195,16 +195,12 @@ static int expand_metric_events(void)
> >                       .metric_name    = NULL,
> >               },
> >       };
> > -     const struct pmu_events_map ev_map = {
> > -             .cpuid          = "test",
> > -             .table          = pme_test,
> > -     };
> >
> >       evlist = evlist__new();
> >       TEST_ASSERT_VAL("failed to get evlist", evlist);
> >
> >       rblist__init(&metric_events);
> > -     ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
> > +     ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
> >                                            false, false, &metric_events);
> >       if (ret < 0) {
> >               pr_debug("failed to parse '%s' metric\n", metric_str);
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 1b811a26f4ee..7aebde7c37ec 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
> >   }
> >   };
> >
> > -static const struct pmu_events_map map = {
> > -     .cpuid          = "test",
> > -     .table          = pme_test,
> > -};
> > -
> >   struct value {
> >       const char      *event;
> >       u64              val;
> > @@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
> >       runtime_stat__init(&st);
> >
> >       /* Parse the metric into metric_events list. */
> > -     err = metricgroup__parse_groups_test(evlist, &map, name,
> > +     err = metricgroup__parse_groups_test(evlist, pme_test, name,
> >                                            false, false,
> >                                            &metric_events);
> >       if (err)
> > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> > index a39a2c99ede6..b3cde5f98982 100644
> > --- a/tools/perf/tests/pmu-events.c
> > +++ b/tools/perf/tests/pmu-events.c
> > @@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
> >       return !strcmp(reference, test);
> >   }
> >
> > -static const struct pmu_events_map *__test_pmu_get_events_map(void)
> > +static const struct pmu_event *__test_pmu_get_events_table(void)
> >   {
> > -     const struct pmu_events_map *map;
> > -
> > -     for (map = &pmu_events_map[0]; map->cpuid; map++) {
> > +     for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
> >               if (!strcmp(map->cpuid, "testcpu"))
> > -                     return map;
> > +                     return map->table;
> >       }
> >
> >       pr_err("could not find test events map\n");
> > @@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> >                                int subtest __maybe_unused)
> >   {
> >       const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
> > -     const struct pmu_events_map *map = __test_pmu_get_events_map();
> > -     const struct pmu_event *table;
> > +     const struct pmu_event *table = __test_pmu_get_events_table();
> >       int map_events = 0, expected_events;
> >
> >       /* ignore 3x sentinels */
> > @@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> >                         ARRAY_SIZE(uncore_events) +
> >                         ARRAY_SIZE(sys_events) - 3;
> >
> > -     if (!map || !sys_event_tables)
> > +     if (!table || !sys_event_tables)
> >               return -1;
> >
> > -     for (table = map->table; table->name; table++) {
> > +     for (; table->name; table++) {
> >               struct perf_pmu_test_event const **test_event_table;
> >               bool found = false;
> >
> > @@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
> >       struct perf_pmu *pmu;
> >       LIST_HEAD(aliases);
> >       int res = 0;
> > -     const struct pmu_events_map *map = __test_pmu_get_events_map();
> > +     const struct pmu_event *table = __test_pmu_get_events_table();
> >       struct perf_pmu_alias *a, *tmp;
> >
> > -     if (!map)
> > +     if (!table)
> >               return -1;
> >
> >       test_event_table = &core_events[0];
> > @@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
> >
> >       pmu->name = pmu_name;
> >
> > -     pmu_add_cpu_aliases_map(&aliases, pmu, map);
> > +     pmu_add_cpu_aliases_map(&aliases, pmu, table);
> >
> >       for (; *test_event_table; test_event_table++) {
> >               struct perf_pmu_test_event const *test_event = *test_event_table;
> > @@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
> >       struct perf_pmu *pmu = &test_pmu->pmu;
> >       const char *pmu_name = pmu->name;
> >       struct perf_pmu_alias *a, *tmp, *alias;
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *events_table;
> >       LIST_HEAD(aliases);
> >       int res = 0;
> >
> > -     map = __test_pmu_get_events_map();
> > -     if (!map)
> > +     events_table = __test_pmu_get_events_table();
> > +     if (!events_table)
> >               return -1;
> > -     pmu_add_cpu_aliases_map(&aliases, pmu, map);
> > +     pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
> >       pmu_add_sys_aliases(&aliases, pmu);
> >
> >       /* Count how many aliases we generated */
> > @@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
> >       return ret;
> >   }
> >
> > -static void expr_failure(const char *msg,
> > -                      const struct pmu_events_map *map,
> > -                      const struct pmu_event *pe)
> > +static void expr_failure(const char *msg, const struct pmu_event *pe)
> >   {
> > -     pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
> > -     pr_debug("On metric %s\n", pe->metric_name);
> > -     pr_debug("On expression %s\n", pe->metric_expr);
> > +     pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
> >   }
> >
> >   struct metric {
> > @@ -864,7 +857,7 @@ struct metric {
> >
> >   static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> >                                struct list_head *compound_list,
> > -                              const struct pmu_events_map *map,
> > +                              const struct pmu_event *map,
> >                                const char *metric_name)
> >   {
> >       struct hashmap_entry *cur, *cur_tmp;
> > @@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> >   static int test__parsing(struct test_suite *test __maybe_unused,
> >                        int subtest __maybe_unused)
> >   {
> > -     const struct pmu_events_map *cpus_map = pmu_events_map__find();
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *cpus_table = pmu_events_map__find();
> >       const struct pmu_event *pe;
> >       int i, j, k;
> >       int ret = 0;
> > @@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >       }
> >       i = 0;
> >       for (;;) {
> > -             map = &pmu_events_map[i++];
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> >               if (!map->table)
> >                       break;
> >               j = 0;
> > @@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >                               continue;
> >                       expr__ctx_clear(ctx);
> >                       if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
> > -                             expr_failure("Parse find ids failed", map, pe);
> > +                             expr_failure("Parse find ids failed", pe);
> >                               ret++;
> >                               continue;
> >                       }
> >
> > -                     if (resolve_metric_simple(ctx, &compound_list, map,
> > +                     if (resolve_metric_simple(ctx, &compound_list, map->table,
> >                                                 pe->metric_name)) {
> > -                             expr_failure("Could not resolve metrics", map, pe);
> > +                             expr_failure("Could not resolve metrics", pe);
> >                               ret++;
> >                               goto exit; /* Don't tolerate errors due to severity */
> >                       }
> > @@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >                               expr__add_id_val(ctx, strdup(cur->key), k++);
> >
> >                       hashmap__for_each_entry(ctx->ids, cur, bkt) {
> > -                             if (check_parse_cpu(cur->key, map == cpus_map,
> > +                             if (check_parse_cpu(cur->key, map->table == cpus_table,
> >                                                  pe))
> >                                       ret++;
> >                       }
> > @@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >                               hashmap__for_each_entry(ctx->ids, cur, bkt)
> >                                       expr__add_id_val(ctx, strdup(cur->key), k--);
> >                               if (expr__parse(&result, ctx, pe->metric_expr)) {
> > -                                     expr_failure("Parse failed", map, pe);
> > +                                     expr_failure("Parse failed", pe);
> >                                       ret++;
> >                               }
> >                       }
> > @@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
> >   static int test__parsing_fake(struct test_suite *test __maybe_unused,
> >                             int subtest __maybe_unused)
> >   {
> > -     const struct pmu_events_map *map;
> > -     const struct pmu_event *pe;
> >       unsigned int i, j;
> >       int err = 0;
> >
> > @@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
> >
> >       i = 0;
> >       for (;;) {
> > -             map = &pmu_events_map[i++];
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> >               if (!map->table)
> >                       break;
> >               j = 0;
> >               for (;;) {
> > -                     pe = &map->table[j++];
> > +                     const struct pmu_event *pe = &map->table[j++];
> > +
> >                       if (!pe->name && !pe->metric_group && !pe->metric_name)
> >                               break;
> >                       if (!pe->metric_expr)
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index 8f7baeabc5cf..4d32b4fbf67d 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
> >   void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> >                       bool raw, bool details, const char *pmu_name)
> >   {
> > -     const struct pmu_events_map *map = pmu_events_map__find();
> > -     const struct pmu_event *pe;
> > -     int i;
> >       struct rblist groups;
> >       struct rb_node *node, *next;
> >       struct strlist *metriclist = NULL;
> > @@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> >       groups.node_new = mep_new;
> >       groups.node_cmp = mep_cmp;
> >       groups.node_delete = mep_delete;
> > -     for (i = 0; map; i++) {
> > -             pe = &map->table[i];
> > +     for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
> >
> >               if (!pe->name && !pe->metric_group && !pe->metric_name)
> >                       break;
> > @@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
> >       bool metric_no_group;
> >       struct metric *root_metric;
> >       const struct visited_metric *visited;
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table;
> >   };
> >
> >   static int add_metric(struct list_head *metric_list,
> > @@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
> >                     bool metric_no_group,
> >                     struct metric *root_metric,
> >                     const struct visited_metric *visited,
> > -                   const struct pmu_events_map *map);
> > +                   const struct pmu_event *table);
> >
> >   /**
> >    * resolve_metric - Locate metrics within the root metric and recursively add
> > @@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
> >    *               metrics. When adding a root this argument is NULL.
> >    * @visited: A singly linked list of metric names being added that is used to
> >    *           detect recursion.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int resolve_metric(struct list_head *metric_list,
> > @@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
> >                         bool metric_no_group,
> >                         struct metric *root_metric,
> >                         const struct visited_metric *visited,
> > -                       const struct pmu_events_map *map)
> > +                       const struct pmu_event *table)
> >   {
> >       struct hashmap_entry *cur;
> >       size_t bkt;
> > @@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
> >       hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
> >               const struct pmu_event *pe;
> >
> > -             pe = metricgroup__find_metric(cur->key, map);
> > +             pe = metricgroup__find_metric(cur->key, table);
> >               if (pe) {
> >                       pending = realloc(pending,
> >                                       (pending_cnt + 1) * sizeof(struct to_resolve));
> > @@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
> >        */
> >       for (i = 0; i < pending_cnt; i++) {
> >               ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
> > -                             root_metric, visited, map);
> > +                             root_metric, visited, table);
> >               if (ret)
> >                       break;
> >       }
> > @@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
> >    *               metrics. When adding a root this argument is NULL.
> >    * @visited: A singly linked list of metric names being added that is used to
> >    *           detect recursion.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int __add_metric(struct list_head *metric_list,
> > @@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
> >                       int runtime,
> >                       struct metric *root_metric,
> >                       const struct visited_metric *visited,
> > -                     const struct pmu_events_map *map)
> > +                     const struct pmu_event *table)
> >   {
> >       const struct visited_metric *vm;
> >       int ret;
> > @@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
> >       } else {
> >               /* Resolve referenced metrics. */
> >               ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
> > -                                  &visited_node, map);
> > +                                  &visited_node, table);
> >       }
> >
> >       if (ret) {
> > @@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
> >       return ret;
> >   }
> >
> > -#define map_for_each_event(__pe, __idx, __map)                                       \
> > -     if (__map)                                                              \
> > -             for (__idx = 0, __pe = &__map->table[__idx];                    \
> > +#define table_for_each_event(__pe, __idx, __table)                                   \
> > +     if (__table)                                                            \
> > +             for (__idx = 0, __pe = &__table[__idx];                         \
> >                    __pe->name || __pe->metric_group || __pe->metric_name;     \
> > -                  __pe = &__map->table[++__idx])
> > +                  __pe = &__table[++__idx])
> >
> > -#define map_for_each_metric(__pe, __idx, __map, __metric)            \
> > -     map_for_each_event(__pe, __idx, __map)                          \
> > +#define table_for_each_metric(__pe, __idx, __table, __metric)                \
> > +     table_for_each_event(__pe, __idx, __table)                              \
> >               if (__pe->metric_expr &&                                \
> >                   (match_metric(__pe->metric_group, __metric) ||      \
> >                    match_metric(__pe->metric_name, __metric)))
> >
> >   const struct pmu_event *metricgroup__find_metric(const char *metric,
> > -                                              const struct pmu_events_map *map)
> > +                                              const struct pmu_event *table)
> >   {
> >       const struct pmu_event *pe;
> >       int i;
> >
> > -     map_for_each_event(pe, i, map) {
> > +     table_for_each_event(pe, i, table) {
> >               if (match_metric(pe->metric_name, metric))
> >                       return pe;
> >       }
> > @@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
> >                     bool metric_no_group,
> >                     struct metric *root_metric,
> >                     const struct visited_metric *visited,
> > -                   const struct pmu_events_map *map)
> > +                   const struct pmu_event *table)
> >   {
> >       int ret = 0;
> >
> > @@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
> >
> >       if (!strstr(pe->metric_expr, "?")) {
> >               ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> > -                                root_metric, visited, map);
> > +                                root_metric, visited, table);
> >       } else {
> >               int j, count;
> >
> > @@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
> >
> >               for (j = 0; j < count && !ret; j++)
> >                       ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
> > -                                     root_metric, visited, map);
> > +                                     root_metric, visited, table);
> >       }
> >
> >       return ret;
> > @@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
> >               return 0;
> >
> >       ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> > -                      d->root_metric, d->visited, d->map);
> > +                      d->root_metric, d->visited, d->table);
> >       if (ret)
> >               goto out;
> >
> > @@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
> >    *                   global. Grouping is the default but due to multiplexing the
> >    *                   user may override.
> >    * @metric_list: The list that the metric or metric group are added to.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int metricgroup__add_metric(const char *metric_name, const char *modifier,
> >                                  bool metric_no_group,
> >                                  struct list_head *metric_list,
> > -                                const struct pmu_events_map *map)
> > +                                const struct pmu_event *table)
> >   {
> >       const struct pmu_event *pe;
> >       LIST_HEAD(list);
> > @@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> >        * Iterate over all metrics seeing if metric matches either the name or
> >        * group. When it does add the metric to the list.
> >        */
> > -     map_for_each_metric(pe, i, map, metric_name) {
> > +     table_for_each_metric(pe, i, table, metric_name) {
> >               has_match = true;
> >               ret = add_metric(&list, pe, modifier, metric_no_group,
> >                                /*root_metric=*/NULL,
> > -                              /*visited_metrics=*/NULL, map);
> > +                              /*visited_metrics=*/NULL, table);
> >               if (ret)
> >                       goto out;
> >       }
> > @@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> >                               .metric_no_group = metric_no_group,
> >                               .has_match = &has_match,
> >                               .ret = &ret,
> > -                             .map = map,
> > +                             .table = table,
> >                       },
> >               };
> >
> > @@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> >    *                   global. Grouping is the default but due to multiplexing the
> >    *                   user may override.
> >    * @metric_list: The list that metrics are added to.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> >    *       architecture perf is running upon.
> >    */
> >   static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> >                                       struct list_head *metric_list,
> > -                                     const struct pmu_events_map *map)
> > +                                     const struct pmu_event *table)
> >   {
> >       char *list_itr, *list_copy, *metric_name, *modifier;
> >       int ret, count = 0;
> > @@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> >
> >               ret = metricgroup__add_metric(metric_name, modifier,
> >                                             metric_no_group, metric_list,
> > -                                           map);
> > +                                           table);
> >               if (ret == -EINVAL)
> >                       pr_err("Cannot find metric or group `%s'\n", metric_name);
> >
> > @@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> >                       bool metric_no_merge,
> >                       struct perf_pmu *fake_pmu,
> >                       struct rblist *metric_events_list,
> > -                     const struct pmu_events_map *map)
> > +                     const struct pmu_event *table)
> >   {
> >       struct evlist *combined_evlist = NULL;
> >       LIST_HEAD(metric_list);
> > @@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> >       if (metric_events_list->nr_entries == 0)
> >               metricgroup__rblist_init(metric_events_list);
> >       ret = metricgroup__add_metric_list(str, metric_no_group,
> > -                                        &metric_list, map);
> > +                                        &metric_list, table);
> >       if (ret)
> >               goto out;
> >
> > @@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
> >                             struct rblist *metric_events)
> >   {
> >       struct evlist *perf_evlist = *(struct evlist **)opt->value;
> > -     const struct pmu_events_map *map = pmu_events_map__find();
> > +     const struct pmu_event *table = pmu_events_map__find();
> >
> >       return parse_groups(perf_evlist, str, metric_no_group,
> > -                         metric_no_merge, NULL, metric_events, map);
> > +                         metric_no_merge, NULL, metric_events, table);
> >   }
> >
> >   int metricgroup__parse_groups_test(struct evlist *evlist,
> > -                                const struct pmu_events_map *map,
> > +                                const struct pmu_event *table,
> >                                  const char *str,
> >                                  bool metric_no_group,
> >                                  bool metric_no_merge,
> >                                  struct rblist *metric_events)
> >   {
> >       return parse_groups(evlist, str, metric_no_group,
> > -                         metric_no_merge, &perf_pmu__fake, metric_events, map);
> > +                         metric_no_merge, &perf_pmu__fake, metric_events, table);
> >   }
> >
> >   bool metricgroup__has_metric(const char *metric)
> >   {
> > -     const struct pmu_events_map *map = pmu_events_map__find();
> > +     const struct pmu_event *table = pmu_events_map__find();
> >       const struct pmu_event *pe;
> >       int i;
> >
> > -     if (!map)
> > +     if (!table)
> >               return false;
> >
> >       for (i = 0; ; i++) {
> > -             pe = &map->table[i];
> > +             pe = &table[i];
> >
> >               if (!pe->name && !pe->metric_group && !pe->metric_name)
> >                       break;
> > diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
> > index 2b42b778d1bf..5a1390e73d25 100644
> > --- a/tools/perf/util/metricgroup.h
> > +++ b/tools/perf/util/metricgroup.h
> > @@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
> >                             bool metric_no_merge,
> >                             struct rblist *metric_events);
> >   const struct pmu_event *metricgroup__find_metric(const char *metric,
> > -                                              const struct pmu_events_map *map);
> > +                                              const struct pmu_event *table);
> >   int metricgroup__parse_groups_test(struct evlist *evlist,
> > -                                const struct pmu_events_map *map,
> > +                                const struct pmu_event *table,
> >                                  const char *str,
> >                                  bool metric_no_group,
> >                                  bool metric_no_merge,
> > diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> > index d8717c4548a4..f3e3c4a147e9 100644
> > --- a/tools/perf/util/pmu.c
> > +++ b/tools/perf/util/pmu.c
> > @@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
> >       return cpuid;
> >   }
> >
> > -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> >   {
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table = NULL;
> >       char *cpuid = perf_pmu__getcpuid(pmu);
> >       int i;
> >
> > @@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> >
> >       i = 0;
> >       for (;;) {
> > -             map = &pmu_events_map[i++];
> > -             if (!map->table) {
> > -                     map = NULL;
> > +             const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > +             if (!map->table)
> >                       break;
> > -             }
> >
> > -             if (!strcmp_cpuid_str(map->cpuid, cpuid))
> > +             if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > +                     table = map->table;
> >                       break;
> > +             }
> >       }
> >       free(cpuid);
> > -     return map;
> > +     return table;
> >   }
> >
> > -const struct pmu_events_map *__weak pmu_events_map__find(void)
> > +__weak const struct pmu_event *pmu_events_map__find(void)
> >   {
> > -     return perf_pmu__find_map(NULL);
> > +     return perf_pmu__find_table(NULL);
> >   }
> >
> >   /*
> > @@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
> >    * as aliases.
> >    */
> >   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>
> Again, it seems that this name should be changed

Ack. I'll put this into the next version. The next patch (number 10
"perf pmu-events: Hide the pmu_events") changes things slightly:

-const struct pmu_event *pmu_events_map__find(void)
+const struct pmu_events_table *pmu_events_map__find(void)

So I'll try to minimize the churn in renaming.

Thanks,
Ian

> > -                          const struct pmu_events_map *map)
> > +                          const struct pmu_event *table)
> >   {
> >       int i;
> >       const char *name = pmu->name;
> > @@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> >       i = 0;
> >       while (1) {
> >               const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
> > -             const struct pmu_event *pe = &map->table[i++];
> > +             const struct pmu_event *pe = &table[i++];
> >               const char *pname = pe->pmu ? pe->pmu : cpu_name;
> >
> >               if (!pe->name) {
> > @@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> >
> >   static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
> >   {
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table;
> >
> > -     map = perf_pmu__find_map(pmu);
> > -     if (!map)
> > +     table = perf_pmu__find_table(pmu);
> > +     if (!table)
> >               return;
> >
> > -     pmu_add_cpu_aliases_map(head, pmu, map);
> > +     pmu_add_cpu_aliases_map(head, pmu, table);
> >   }
> >
> >   struct pmu_sys_event_iter_data {
> > diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> > index 7e667eec2a01..015242c83698 100644
> > --- a/tools/perf/util/pmu.h
> > +++ b/tools/perf/util/pmu.h
> > @@ -126,10 +126,10 @@ int perf_pmu__test(void);
> >
> >   struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
> >   void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> > -                          const struct pmu_events_map *map);
> > +                          const struct pmu_event *map);
> >
> > -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
> > -const struct pmu_events_map *pmu_events_map__find(void);
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
> > +const struct pmu_event *pmu_events_map__find(void);
> >   bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
> >   void perf_pmu_free_alias(struct perf_pmu_alias *alias);
> >
> > diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
> > index cd3a34840389..1ecb718fc0eb 100644
> > --- a/tools/perf/util/s390-sample-raw.c
> > +++ b/tools/perf/util/s390-sample-raw.c
> > @@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
> >    * the name of this counter.
> >    * If no match is found a NULL pointer is returned.
> >    */
> > -static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
> > +static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
> >   {
> >       int rc, event_nr, wanted = get_counterset_start(set) + nr;
> >
> > -     if (map) {
> > -             const struct pmu_event *evp = map->table;
> > +     if (table) {
> > +             const struct pmu_event *evp = table;
> >
> >               for (; evp->name || evp->event || evp->desc; ++evp) {
> >                       if (evp->name == NULL || evp->event == NULL)
> > @@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> >       unsigned char *buf = sample->raw_data;
> >       const char *color = PERF_COLOR_BLUE;
> >       struct cf_ctrset_entry *cep, ce;
> > -     const struct pmu_events_map *map;
> > +     const struct pmu_event *table;
> >       u64 *p;
> >
> > -     map = pmu_events_map__find();
> > +     table = pmu_events_map__find();
> >       while (offset < len) {
> >               cep = (struct cf_ctrset_entry *)(buf + offset);
> >
> > @@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> >               color_fprintf(stdout, color, "    [%#08zx] Counterset:%d"
> >                             " Counters:%d\n", offset, ce.set, ce.ctr);
> >               for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
> > -                     const char *ev_name = get_counter_name(ce.set, i, map);
> > +                     const char *ev_name = get_counter_name(ce.set, i, table);
> >
> >                       color_fprintf(stdout, color,
> >                                     "\tCounter:%03d %s Value:%#018lx\n", i,
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 07/17] perf jevents: Sort json files entries
  2022-08-10 14:23       ` Ian Rogers
@ 2022-08-10 15:53         ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-10 15:53 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On 10/08/2022 15:23, Ian Rogers wrote:
>> We sort the attributes of the events alphabetically by attribute name,
>> right? Is there any advantage in this? Do we need it for later?
> 
> The sort order is given by the tuple:
> (not j.desc is None, fix_none(j.topic), fix_none(j.name),
> fix_none(j.pmu), fix_none(j.metric_name))
> which is putting events with descriptions and topics before those
> without, then sorting by name, then pmu and finally metric_name. The
> advantage is that when we qsort alias events:
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/perf/util/pmu.c?h=perf/core#n1759
> the events are already in the sorted format, which should make the
> code faster -

ok, so can you mention that in the commit message? Just writing that you 
want to replicate cmp_sevent from pmu.c does not tell us this clearly.

 > it still has to qsort the sysfs events.

thanks,
John


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 07/17] perf jevents: Sort json files entries
@ 2022-08-10 15:53         ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-10 15:53 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On 10/08/2022 15:23, Ian Rogers wrote:
>> We sort the attributes of the events alphabetically by attribute name,
>> right? Is there any advantage in this? Do we need it for later?
> 
> The sort order is given by the tuple:
> (not j.desc is None, fix_none(j.topic), fix_none(j.name),
> fix_none(j.pmu), fix_none(j.metric_name))
> which is putting events with descriptions and topics before those
> without, then sorting by name, then pmu and finally metric_name. The
> advantage is that when we qsort alias events:
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/perf/util/pmu.c?h=perf/core#n1759
> the events are already in the sorted format, which should make the
> code faster -

ok, so can you mention that in the commit message? Just writing that you 
want to replicate cmp_sevent from pmu.c does not tell us this clearly.

 > it still has to qsort the sysfs events.

thanks,
John


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
  2022-08-10 14:29       ` Ian Rogers
@ 2022-08-11 14:47         ` John Garry
  -1 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-11 14:47 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On 10/08/2022 15:29, Ian Rogers wrote:
>>>          _args.output_file.write("""{
>>> @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>>>    \t},
>>>    };
>>>
>>> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
>>> +{
>>> +        const struct pmu_event *table = NULL;
>>> +        char *cpuid = perf_pmu__getcpuid(pmu);
>> This seems an identical implementation to that in empty-pmu-events.c -
>> can we reduce this duplication? Maybe a seperate common c file which can
>> be linked in
>>
>> The indentation seems different also - this version seems to use whitespaces
> Agreed. Later on this will change, the empty version isn't compressed
> and the jevents.py one is. Having a common C file would defeat the
> goal of hiding the API, but ultimately we'd need to get rid of it in
> later changes when the empty/compressed implementations diverge.

ok, I suppose.. I have to say that this divergence is less then ideal 
and I don't so like much all the difference in pmu-events/pmu-events.c 
and pmu-events/empty-pmu-events.c

thanks,
John

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map
@ 2022-08-11 14:47         ` John Garry
  0 siblings, 0 replies; 80+ messages in thread
From: John Garry @ 2022-08-11 14:47 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Will Deacon, James Clark, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Andi Kleen,
	Zhengjun Xing, Ravi Bangoria, Kan Liang, Adrian Hunter,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	Stephane Eranian

On 10/08/2022 15:29, Ian Rogers wrote:
>>>          _args.output_file.write("""{
>>> @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>>>    \t},
>>>    };
>>>
>>> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
>>> +{
>>> +        const struct pmu_event *table = NULL;
>>> +        char *cpuid = perf_pmu__getcpuid(pmu);
>> This seems an identical implementation to that in empty-pmu-events.c -
>> can we reduce this duplication? Maybe a seperate common c file which can
>> be linked in
>>
>> The indentation seems different also - this version seems to use whitespaces
> Agreed. Later on this will change, the empty version isn't compressed
> and the jevents.py one is. Having a common C file would defeat the
> goal of hiding the API, but ultimately we'd need to get rid of it in
> later changes when the empty/compressed implementations diverge.

ok, I suppose.. I have to say that this divergence is less then ideal 
and I don't so like much all the difference in pmu-events/pmu-events.c 
and pmu-events/empty-pmu-events.c

thanks,
John

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 80+ messages in thread

end of thread, other threads:[~2022-08-11 14:49 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-04 22:17 [PATCH v4 00/17] Compress the pmu_event tables Ian Rogers
2022-08-04 22:17 ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 01/17] perf jevents: Clean up pytype warnings Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-09 19:36   ` Arnaldo Carvalho de Melo
2022-08-09 19:36     ` Arnaldo Carvalho de Melo
2022-08-04 22:18 ` [PATCH v4 02/17] perf jevents: Simplify generation of C-string Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-09 19:37   ` Arnaldo Carvalho de Melo
2022-08-09 19:37     ` Arnaldo Carvalho de Melo
2022-08-04 22:18 ` [PATCH v4 03/17] perf jevents: Add JEVENTS_ARCH make option Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05  9:55   ` John Garry
2022-08-05  9:55     ` John Garry
2022-08-09 19:38     ` Arnaldo Carvalho de Melo
2022-08-09 19:38       ` Arnaldo Carvalho de Melo
2022-08-04 22:18 ` [PATCH v4 04/17] perf jevent: Add an 'all' architecture argument Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 10:34   ` John Garry
2022-08-05 10:34     ` John Garry
2022-08-04 22:18 ` [PATCH v4 05/17] perf jevents: Remove the type/version variables Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 10:35   ` John Garry
2022-08-05 10:35     ` John Garry
2022-08-04 22:18 ` [PATCH v4 06/17] perf jevents: Provide path to json file on error Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 07/17] perf jevents: Sort json files entries Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 10:49   ` John Garry
2022-08-05 10:49     ` John Garry
2022-08-10 14:23     ` Ian Rogers
2022-08-10 14:23       ` Ian Rogers
2022-08-10 15:53       ` John Garry
2022-08-10 15:53         ` John Garry
2022-08-04 22:18 ` [PATCH v4 08/17] perf pmu-events: Hide pmu_sys_event_tables Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 11:15   ` John Garry
2022-08-05 11:15     ` John Garry
2022-08-10 14:25     ` Ian Rogers
2022-08-10 14:25       ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 09/17] perf pmu-events: Avoid passing pmu_events_map Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 11:28   ` John Garry
2022-08-05 11:28     ` John Garry
2022-08-10 15:23     ` Ian Rogers
2022-08-10 15:23       ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 10/17] perf pmu-events: Hide pmu_events_map Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 12:31   ` John Garry
2022-08-05 12:31     ` John Garry
2022-08-10 14:29     ` Ian Rogers
2022-08-10 14:29       ` Ian Rogers
2022-08-11 14:47       ` John Garry
2022-08-11 14:47         ` John Garry
2022-08-04 22:18 ` [PATCH v4 11/17] perf test: Use full metric resolution Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 12/17] perf pmu-events: Move test events/metrics to json Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 12:34   ` John Garry
2022-08-05 12:34     ` John Garry
2022-08-04 22:18 ` [PATCH v4 13/17] perf pmu-events: Don't assume pmu_event is an array Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 12:56   ` John Garry
2022-08-05 12:56     ` John Garry
2022-08-04 22:18 ` [PATCH v4 14/17] perf pmu-events: Hide the pmu_events Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 15/17] perf metrics: Copy entire pmu_event in find metric Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 16/17] perf jevents: Compress the pmu_events_table Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-05 14:02   ` John Garry
2022-08-05 14:02     ` John Garry
2022-08-10 14:35     ` Ian Rogers
2022-08-10 14:35       ` Ian Rogers
2022-08-04 22:18 ` [PATCH v4 17/17] perf jevents: Fold strings optimization Ian Rogers
2022-08-04 22:18   ` Ian Rogers
2022-08-09 19:40 ` [PATCH v4 00/17] Compress the pmu_event tables Arnaldo Carvalho de Melo
2022-08-09 19:40   ` Arnaldo Carvalho de Melo
2022-08-09 19:41   ` Arnaldo Carvalho de Melo
2022-08-09 19:41     ` Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.