linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/9] jevents/pmu-events improvements
@ 2022-12-21 22:34 Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 1/9] perf jevents metric: Correct Function equality Ian Rogers
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Add an optimization to jevents using the metric code, rewrite metrics
in terms of each other in order to minimize size and improve
readability. For example, on Power8
other_stall_cpi is rewritten from:
"PM_CMPLU_STALL / PM_RUN_INST_CMPL - PM_CMPLU_STALL_BRU_CRU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_FXU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_VSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_LSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NTCG_FLUSH / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NO_NTF / PM_RUN_INST_CMPL"
to:
"stall_cpi - bru_cru_stall_cpi - fxu_stall_cpi - vsu_stall_cpi - lsu_stall_cpi - ntcg_flush_cpi - no_ntf_stall_cpi"
Which more closely matches the definition on Power9.

A limitation of the substitutions are that they depend on strict
equality and the shape of the tree. This means that for "a + b + c"
then a substitution of "a + b" will succeed while "b + c" will fail
(the LHS for "+ c" is "a + b" not just "b").

Separate out the events and metrics in the pmu-events tables saving
14.8% in the table size while making it that metrics no longer need to
iterate over all events and vice versa. These changes remove evsel's
direct metric support as the pmu_event no longer has a metric to
populate it. This is a minor issue as the code wasn't working
properly, metrics for this are rare and can still be properly ran
using '-M'.

Add an ability to just build certain models into the jevents generated
pmu-metrics.c code. This functionality is appropriate for operating
systems like ChromeOS, that aim to minimize binary size and know all
the target CPU models.

v2. Rebase. Modify the code that skips rewriting a metric with the
    same name with itself, to make the name check case insensitive.

Ian Rogers (9):
  perf jevents metric: Correct Function equality
  perf jevents metric: Add ability to rewrite metrics in terms of others
  perf jevents: Rewrite metrics in the same file with each other
  perf pmu-events: Separate metric out of pmu_event
  perf stat: Remove evsel metric_name/expr
  perf jevents: Combine table prefix and suffix writing
  perf pmu-events: Introduce pmu_metrics_table
  perf jevents: Generate metrics and events as separate tables
  perf jevents: Add model list option

 tools/perf/arch/arm64/util/pmu.c         |  23 +-
 tools/perf/arch/powerpc/util/header.c    |   4 +-
 tools/perf/builtin-list.c                |  20 +-
 tools/perf/builtin-stat.c                |   1 -
 tools/perf/pmu-events/Build              |   3 +-
 tools/perf/pmu-events/empty-pmu-events.c | 111 ++++++-
 tools/perf/pmu-events/jevents.py         | 353 ++++++++++++++++++-----
 tools/perf/pmu-events/metric.py          |  79 ++++-
 tools/perf/pmu-events/metric_test.py     |  10 +
 tools/perf/pmu-events/pmu-events.h       |  26 +-
 tools/perf/tests/expand-cgroup.c         |   4 +-
 tools/perf/tests/parse-metric.c          |   4 +-
 tools/perf/tests/pmu-events.c            |  68 ++---
 tools/perf/util/cgroup.c                 |   1 -
 tools/perf/util/evsel.c                  |   2 -
 tools/perf/util/evsel.h                  |   2 -
 tools/perf/util/metricgroup.c            | 203 +++++++------
 tools/perf/util/metricgroup.h            |   4 +-
 tools/perf/util/parse-events.c           |   2 -
 tools/perf/util/pmu.c                    |  44 +--
 tools/perf/util/pmu.h                    |  10 +-
 tools/perf/util/print-events.c           |  32 +-
 tools/perf/util/print-events.h           |   3 +-
 tools/perf/util/python.c                 |   7 -
 tools/perf/util/stat-shadow.c            | 112 -------
 tools/perf/util/stat.h                   |   1 -
 26 files changed, 666 insertions(+), 463 deletions(-)

-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 1/9] perf jevents metric: Correct Function equality
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 2/9] perf jevents metric: Add ability to rewrite metrics in terms of others Ian Rogers
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

rhs may not be defined, say for source_count, so add a guard.

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

diff --git a/tools/perf/pmu-events/metric.py b/tools/perf/pmu-events/metric.py
index 4797ed4fd817..2f2fd220e843 100644
--- a/tools/perf/pmu-events/metric.py
+++ b/tools/perf/pmu-events/metric.py
@@ -261,8 +261,10 @@ class Function(Expression):
 
   def Equals(self, other: Expression) -> bool:
     if isinstance(other, Function):
-      return self.fn == other.fn and self.lhs.Equals(
-          other.lhs) and self.rhs.Equals(other.rhs)
+      result = self.fn == other.fn and self.lhs.Equals(other.lhs)
+      if self.rhs:
+        result = result and self.rhs.Equals(other.rhs)
+      return result
     return False
 
 
-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 2/9] perf jevents metric: Add ability to rewrite metrics in terms of others
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 1/9] perf jevents metric: Correct Function equality Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 3/9] perf jevents: Rewrite metrics in the same file with each other Ian Rogers
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Add RewriteMetricsInTermsOfOthers that iterates over pairs of names
and expressions trying to replace an expression, within the current
expression, with its name.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/metric.py      | 73 +++++++++++++++++++++++++++-
 tools/perf/pmu-events/metric_test.py | 10 ++++
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/tools/perf/pmu-events/metric.py b/tools/perf/pmu-events/metric.py
index 2f2fd220e843..ed13efac7389 100644
--- a/tools/perf/pmu-events/metric.py
+++ b/tools/perf/pmu-events/metric.py
@@ -4,7 +4,7 @@ import ast
 import decimal
 import json
 import re
-from typing import Dict, List, Optional, Set, Union
+from typing import Dict, List, Optional, Set, Tuple, Union
 
 
 class Expression:
@@ -26,6 +26,9 @@ class Expression:
     """Returns true when two expressions are the same."""
     raise NotImplementedError()
 
+  def Substitute(self, name: str, expression: 'Expression') -> 'Expression':
+    raise NotImplementedError()
+
   def __str__(self) -> str:
     return self.ToPerfJson()
 
@@ -186,6 +189,15 @@ class Operator(Expression):
           other.lhs) and self.rhs.Equals(other.rhs)
     return False
 
+  def Substitute(self, name: str, expression: Expression) -> Expression:
+    if self.Equals(expression):
+      return Event(name)
+    lhs = self.lhs.Substitute(name, expression)
+    rhs = None
+    if self.rhs:
+      rhs = self.rhs.Substitute(name, expression)
+    return Operator(self.operator, lhs, rhs)
+
 
 class Select(Expression):
   """Represents a select ternary in the parse tree."""
@@ -225,6 +237,14 @@ class Select(Expression):
           other.false_val) and self.true_val.Equals(other.true_val)
     return False
 
+  def Substitute(self, name: str, expression: Expression) -> Expression:
+    if self.Equals(expression):
+      return Event(name)
+    true_val = self.true_val.Substitute(name, expression)
+    cond = self.cond.Substitute(name, expression)
+    false_val = self.false_val.Substitute(name, expression)
+    return Select(true_val, cond, false_val)
+
 
 class Function(Expression):
   """A function in an expression like min, max, d_ratio."""
@@ -267,6 +287,15 @@ class Function(Expression):
       return result
     return False
 
+  def Substitute(self, name: str, expression: Expression) -> Expression:
+    if self.Equals(expression):
+      return Event(name)
+    lhs = self.lhs.Substitute(name, expression)
+    rhs = None
+    if self.rhs:
+      rhs = self.rhs.Substitute(name, expression)
+    return Function(self.fn, lhs, rhs)
+
 
 def _FixEscapes(s: str) -> str:
   s = re.sub(r'([^\\]),', r'\1\\,', s)
@@ -293,6 +322,9 @@ class Event(Expression):
   def Equals(self, other: Expression) -> bool:
     return isinstance(other, Event) and self.name == other.name
 
+  def Substitute(self, name: str, expression: Expression) -> Expression:
+    return self
+
 
 class Constant(Expression):
   """A constant within the expression tree."""
@@ -317,6 +349,9 @@ class Constant(Expression):
   def Equals(self, other: Expression) -> bool:
     return isinstance(other, Constant) and self.value == other.value
 
+  def Substitute(self, name: str, expression: Expression) -> Expression:
+    return self
+
 
 class Literal(Expression):
   """A runtime literal within the expression tree."""
@@ -336,6 +371,9 @@ class Literal(Expression):
   def Equals(self, other: Expression) -> bool:
     return isinstance(other, Literal) and self.value == other.value
 
+  def Substitute(self, name: str, expression: Expression) -> Expression:
+    return self
+
 
 def min(lhs: Union[int, float, Expression], rhs: Union[int, float,
                                                        Expression]) -> Function:
@@ -461,6 +499,7 @@ class MetricGroup:
 
 
 class _RewriteIfExpToSelect(ast.NodeTransformer):
+  """Transformer to convert if-else nodes to Select expressions."""
 
   def visit_IfExp(self, node):
     # pylint: disable=invalid-name
@@ -498,7 +537,37 @@ def ParsePerfJson(orig: str) -> Expression:
   for kw in keywords:
     py = re.sub(rf'Event\(r"{kw}"\)', kw, py)
 
-  parsed = ast.parse(py, mode='eval')
+  try:
+    parsed = ast.parse(py, mode='eval')
+  except SyntaxError as e:
+    raise SyntaxError(f'Parsing expression:\n{orig}') from e
   _RewriteIfExpToSelect().visit(parsed)
   parsed = ast.fix_missing_locations(parsed)
   return _Constify(eval(compile(parsed, orig, 'eval')))
+
+
+def RewriteMetricsInTermsOfOthers(metrics: list[Tuple[str, Expression]]
+                                  )-> Dict[str, Expression]:
+  """Shorten metrics by rewriting in terms of others.
+
+  Args:
+    metrics (list): pairs of metric names and their expressions.
+  Returns:
+    Dict: mapping from a metric name to a shortened expression.
+  """
+  updates: Dict[str, Expression] = dict()
+  for outer_name, outer_expression in metrics:
+    updated = outer_expression
+    while True:
+      for inner_name, inner_expression in metrics:
+        if inner_name.lower() == outer_name.lower():
+          continue
+        if inner_name in updates:
+          inner_expression = updates[inner_name]
+        updated = updated.Substitute(inner_name, inner_expression)
+      if updated.Equals(outer_expression):
+        break
+      if outer_name in updates and updated.Equals(updates[outer_name]):
+        break
+      updates[outer_name] = updated
+  return updates
diff --git a/tools/perf/pmu-events/metric_test.py b/tools/perf/pmu-events/metric_test.py
index 15315d0f716c..ced5998bd827 100644
--- a/tools/perf/pmu-events/metric_test.py
+++ b/tools/perf/pmu-events/metric_test.py
@@ -2,7 +2,9 @@
 import unittest
 from metric import Constant
 from metric import Event
+from metric import Expression
 from metric import ParsePerfJson
+from metric import RewriteMetricsInTermsOfOthers
 
 
 class TestMetricExpressions(unittest.TestCase):
@@ -153,5 +155,13 @@ class TestMetricExpressions(unittest.TestCase):
     after = '0 * SLOTS'
     self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
 
+  def test_RewriteMetricsInTermsOfOthers(self):
+    Expression.__eq__ = lambda e1, e2: e1.Equals(e2)
+    before = [('m1', ParsePerfJson('a + b + c + d')),
+              ('m2', ParsePerfJson('a + b + c'))]
+    after = {'m1': ParsePerfJson('m2 + d')}
+    self.assertEqual(RewriteMetricsInTermsOfOthers(before), after)
+    Expression.__eq__ = None
+
 if __name__ == '__main__':
   unittest.main()
-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 3/9] perf jevents: Rewrite metrics in the same file with each other
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 1/9] perf jevents metric: Correct Function equality Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 2/9] perf jevents metric: Add ability to rewrite metrics in terms of others Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 4/9] perf pmu-events: Separate metric out of pmu_event Ian Rogers
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Rewrite metrics within the same file in terms of each other. For example, on Power8
other_stall_cpi is rewritten from:
"PM_CMPLU_STALL / PM_RUN_INST_CMPL - PM_CMPLU_STALL_BRU_CRU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_FXU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_VSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_LSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NTCG_FLUSH / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NO_NTF / PM_RUN_INST_CMPL"
to:
"stall_cpi - bru_cru_stall_cpi - fxu_stall_cpi - vsu_stall_cpi - lsu_stall_cpi - ntcg_flush_cpi - no_ntf_stall_cpi"
Which more closely matches the definition on Power9.

To avoid recomputation decorate the function with a cache.

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

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 4c398e0eeb2f..229402565425 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -3,6 +3,7 @@
 """Convert directories of JSON events to C code."""
 import argparse
 import csv
+from functools import lru_cache
 import json
 import metric
 import os
@@ -337,18 +338,28 @@ class JsonEvent:
     s = self.build_c_string()
     return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
 
-
+@lru_cache(maxsize=None)
 def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
   """Read json events from the specified file."""
-
   try:
-    result = json.load(open(path), object_hook=JsonEvent)
+    events = json.load(open(path), object_hook=JsonEvent)
   except BaseException as err:
     print(f"Exception processing {path}")
     raise
-  for event in result:
+  metrics: list[Tuple[str, metric.Expression]] = []
+  for event in events:
     event.topic = topic
-  return result
+    if event.metric_name and '-' not in event.metric_name:
+      metrics.append((event.metric_name, event.metric_expr))
+  updates = metric.RewriteMetricsInTermsOfOthers(metrics)
+  if updates:
+    for event in events:
+      if event.metric_name in updates:
+        # print(f'Updated {event.metric_name} from\n"{event.metric_expr}"\n'
+        #       f'to\n"{updates[event.metric_name]}"')
+        event.metric_expr = updates[event.metric_name]
+
+  return events
 
 def preprocess_arch_std_files(archpath: str) -> None:
   """Read in all architecture standard events."""
-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 4/9] perf pmu-events: Separate metric out of pmu_event
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (2 preceding siblings ...)
  2022-12-21 22:34 ` [PATCH v2 3/9] perf jevents: Rewrite metrics in the same file with each other Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2023-01-23 15:15   ` John Garry
  2022-12-21 22:34 ` [PATCH v2 5/9] perf stat: Remove evsel metric_name/expr Ian Rogers
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Previously both events and metrics were encoded in struct
pmu_event. Create a new pmu_metric that has the metric related
variables and remove these from pmu_event. Add iterators for
pmu_metric and use in places that metrics are desired rather than
events.

Note, this change removes the setting of evsel's metric_name/expr as
these fields are no longer part of struct pmu_event. The metric
remains but is no longer implicitly requested when the event is. This
impacts a few Intel uncore events, however, as the ScaleUnit is shared
by the event and the metric this utility is questionable. Also the
MetricNames look broken (contain spaces) in some cases and when trying
to use the functionality with '-e' the metrics fail but regular
metrics with '-M' work. For example, on SkylakeX '-M' works:

```
$ perf stat -M LLC_MISSES.PCIE_WRITE -a sleep 1

 Performance counter stats for 'system wide':

                 0      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 #  57896.0 Bytes  LLC_MISSES.PCIE_WRITE  (49.84%)
             7,174      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1                                        (49.85%)
                 0      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3                                        (50.16%)
                63      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0                                        (50.15%)

       1.004576381 seconds time elapsed
```

whilst the event '-e' version is broken even with --group/-g (fwiw, we should also remove -g [1]):

```
$ perf stat -g -e LLC_MISSES.PCIE_WRITE -g -a sleep 1
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE

 Performance counter stats for 'system wide':

            27,316 Bytes LLC_MISSES.PCIE_WRITE

       1.004505469 seconds time elapsed
```

The code also carries warnings where the user is supposed to select
events for metrics [2] but given the lack of use of such a feature,
let's clean the code and just remove.

With NO_JEVENTS=1 the empty-pmu-events.c is used and the separation to
use metrics causes "Parse and process metrics" and "Event expansion
for cgroups" to fail as they fail to find necessary metrics. This is
fixed in a later change.

[1] https://lore.kernel.org/lkml/20220707195610.303254-1-irogers@google.com/
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/util/stat-shadow.c?id=01b8957b738f42f96a130079bc951b3cc78c5b8a#n425

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/powerpc/util/header.c    |   4 +-
 tools/perf/builtin-list.c                |  20 +--
 tools/perf/pmu-events/empty-pmu-events.c |  73 ++++++++--
 tools/perf/pmu-events/jevents.py         |  82 +++++++++++-
 tools/perf/pmu-events/pmu-events.h       |  20 ++-
 tools/perf/tests/pmu-events.c            |  62 +++------
 tools/perf/util/metricgroup.c            | 161 +++++++++++------------
 tools/perf/util/metricgroup.h            |   2 +-
 tools/perf/util/parse-events.c           |   2 -
 tools/perf/util/pmu.c                    |  35 +----
 tools/perf/util/pmu.h                    |   9 --
 tools/perf/util/print-events.c           |  32 ++---
 tools/perf/util/print-events.h           |   3 +-
 13 files changed, 266 insertions(+), 239 deletions(-)

diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index e8fe36b10d20..78eef77d8a8d 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -40,11 +40,11 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
 	return bufp;
 }
 
-int arch_get_runtimeparam(const struct pmu_event *pe)
+int arch_get_runtimeparam(const struct pmu_metric *pm)
 {
 	int count;
 	char path[PATH_MAX] = "/devices/hv_24x7/interface/";
 
-	atoi(pe->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
+	atoi(pm->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
 	return sysfs__read_int(path, &count) < 0 ? 1 : count;
 }
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 137d73edb541..791f513ae5b4 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -99,8 +99,7 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
 				const char *scale_unit __maybe_unused,
 				bool deprecated, const char *event_type_desc,
 				const char *desc, const char *long_desc,
-				const char *encoding_desc,
-				const char *metric_name, const char *metric_expr)
+				const char *encoding_desc)
 {
 	struct print_state *print_state = ps;
 	int pos;
@@ -159,10 +158,6 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
 	if (print_state->detailed && encoding_desc) {
 		printf("%*s", 8, "");
 		wordwrap(encoding_desc, 8, pager_get_columns(), 0);
-		if (metric_name)
-			printf(" MetricName: %s", metric_name);
-		if (metric_expr)
-			printf(" MetricExpr: %s", metric_expr);
 		putchar('\n');
 	}
 }
@@ -308,8 +303,7 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic,
 			     const char *scale_unit,
 			     bool deprecated, const char *event_type_desc,
 			     const char *desc, const char *long_desc,
-			     const char *encoding_desc,
-			     const char *metric_name, const char *metric_expr)
+			     const char *encoding_desc)
 {
 	struct json_print_state *print_state = ps;
 	bool need_sep = false;
@@ -366,16 +360,6 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic,
 				  encoding_desc);
 		need_sep = true;
 	}
-	if (metric_name) {
-		fix_escape_printf(&buf, "%s\t\"MetricName\": \"%S\"", need_sep ? ",\n" : "",
-				  metric_name);
-		need_sep = true;
-	}
-	if (metric_expr) {
-		fix_escape_printf(&buf, "%s\t\"MetricExpr\": \"%S\"", need_sep ? ",\n" : "",
-				  metric_expr);
-		need_sep = true;
-	}
 	printf("%s}", need_sep ? "\n" : "");
 	strbuf_release(&buf);
 }
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 480e8f0d30c8..5572a4d1eddb 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -11,7 +11,7 @@
 #include <string.h>
 #include <stddef.h>
 
-static const struct pmu_event pme_test_soc_cpu[] = {
+static const struct pmu_event pmu_events__test_soc_cpu[] = {
 	{
 		.name = "l3_cache_rd",
 		.event = "event=0x40",
@@ -105,6 +105,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 		.desc = "L2 BTB Correction",
 		.topic = "branch",
 	},
+	{
+		.name = 0,
+		.event = 0,
+		.desc = 0,
+	},
+};
+
+static const struct pmu_metric pmu_metrics__test_soc_cpu[] = {
 	{
 		.metric_expr	= "1 / IPC",
 		.metric_name	= "CPI",
@@ -170,9 +178,8 @@ static const struct pmu_event pme_test_soc_cpu[] = {
 		.metric_name	= "L1D_Cache_Fill_BW",
 	},
 	{
-		.name = 0,
-		.event = 0,
-		.desc = 0,
+		.metric_expr = 0,
+		.metric_name = 0,
 	},
 };
 
@@ -181,6 +188,11 @@ struct pmu_events_table {
 	const struct pmu_event *entries;
 };
 
+/* Struct used to make the PMU metric table implementation opaque to callers. */
+struct pmu_metrics_table {
+	const struct pmu_metric *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.
@@ -192,7 +204,8 @@ struct pmu_events_table {
 struct pmu_events_map {
 	const char *arch;
 	const char *cpuid;
-	const struct pmu_events_table table;
+	const struct pmu_events_table event_table;
+	const struct pmu_metrics_table metric_table;
 };
 
 /*
@@ -203,12 +216,14 @@ static const struct pmu_events_map pmu_events_map[] = {
 	{
 		.arch = "testarch",
 		.cpuid = "testcpu",
-		.table = { pme_test_soc_cpu },
+		.event_table = { pmu_events__test_soc_cpu },
+		.metric_table = { pmu_metrics__test_soc_cpu },
 	},
 	{
 		.arch = 0,
 		.cpuid = 0,
-		.table = { 0 },
+		.event_table = { 0 },
+		.metric_table = { 0 },
 	},
 };
 
@@ -254,9 +269,7 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 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++) {
+	for (const struct pmu_event *pe = &table->entries[0]; pe->name; pe++) {
 		int ret = fn(pe, table, data);
 
 		if (ret)
@@ -265,6 +278,21 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_ev
 	return 0;
 }
 
+int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_metric_iter_fn fn,
+				     void *data)
+{
+	struct pmu_metrics_table *table = (struct pmu_metrics_table *)etable;
+
+	for (const struct pmu_metric *pm = &table->entries[0]; pm->metric_group || pm->metric_name;
+	     pm++) {
+		int ret = fn(pm, etable, data);
+
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
 {
 	const struct pmu_events_table *table = NULL;
@@ -285,7 +313,7 @@ const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
 			break;
 
 		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-			table = &map->table;
+			table = &map->event_table;
 			break;
 		}
 	}
@@ -299,7 +327,7 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
 	     tables->arch;
 	     tables++) {
 		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
-			return &tables->table;
+			return &tables->event_table;
 	}
 	return NULL;
 }
@@ -309,7 +337,21 @@ 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->arch;
 	     tables++) {
-		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
+		int ret = pmu_events_table_for_each_event(&tables->event_table, fn, data);
+
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
+{
+	for (const struct pmu_events_map *tables = &pmu_events_map[0];
+	     tables->arch;
+	     tables++) {
+		int ret = pmu_events_table_for_each_metric(
+			(const struct pmu_events_table *)&tables->metric_table, fn, data);
 
 		if (ret)
 			return ret;
@@ -340,3 +382,8 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
 	}
 	return 0;
 }
+
+int pmu_for_each_sys_metric(pmu_metric_iter_fn fn __maybe_unused, void *data __maybe_unused)
+{
+	return 0;
+}
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 229402565425..ee3d4cdf01be 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -37,6 +37,11 @@ _json_event_attributes = [
     'metric_constraint', 'metric_expr', 'long_desc'
 ]
 
+# Attributes that are in pmu_metric rather than pmu_event.
+_json_metric_attributes = [
+    'metric_name', 'metric_group', 'metric_constraint', 'metric_expr', 'desc',
+    'long_desc', 'unit', 'compat', 'aggr_mode'
+]
 
 def removesuffix(s: str, suffix: str) -> str:
   """Remove the suffix from a string
@@ -562,12 +567,15 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 \t},
 };
 
-static void decompress(int offset, struct pmu_event *pe)
+static void decompress_event(int offset, struct pmu_event *pe)
 {
 \tconst char *p = &big_c_string[offset];
 """)
   for attr in _json_event_attributes:
-    _args.output_file.write(f"""
+    if attr in _json_metric_attributes and 'metric_' in attr:
+      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
+    else:
+      _args.output_file.write(f"""
 \tpe->{attr} = (*p == '\\0' ? NULL : p);
 """)
     if attr == _json_event_attributes[-1]:
@@ -575,6 +583,22 @@ static void decompress(int offset, struct pmu_event *pe)
     _args.output_file.write('\twhile (*p++);')
   _args.output_file.write("""}
 
+static void decompress_metric(int offset, struct pmu_metric *pm)
+{
+\tconst char *p = &big_c_string[offset];
+""")
+  for attr in _json_event_attributes:
+    if attr in _json_metric_attributes:
+      _args.output_file.write(f"""
+\tpm->{attr} = (*p == '\\0' ? NULL : p);
+""")
+    else:
+      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
+    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)
@@ -583,10 +607,30 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
                 struct pmu_event pe;
                 int ret;
 
-                decompress(table->entries[i].offset, &pe);
-                ret = fn(&pe, table, data);
-                if (ret)
-                        return ret;
+                decompress_event(table->entries[i].offset, &pe);
+                if (pe.name) {
+                        ret = fn(&pe, table, data);
+                        if (ret)
+                                return ret;
+                }
+        }
+        return 0;
+}
+
+int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
+                                     pmu_metric_iter_fn fn,
+                                     void *data)
+{
+        for (size_t i = 0; i < table->length; i++) {
+                struct pmu_metric pm;
+                int ret;
+
+                decompress_metric(table->entries[i].offset, &pm);
+                if (pm.metric_name) {
+                        ret = fn(&pm, table, data);
+                        if (ret)
+                                return ret;
+                }
         }
         return 0;
 }
@@ -642,6 +686,19 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
         return 0;
 }
 
+int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
+{
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->arch;
+             tables++) {
+                int ret = pmu_events_table_for_each_metric(&tables->table, fn, data);
+
+                if (ret)
+                        return ret;
+        }
+        return 0;
+}
+
 const struct pmu_events_table *find_sys_events_table(const char *name)
 {
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -665,6 +722,19 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
         }
         return 0;
 }
+
+int pmu_for_each_sys_metric(pmu_metric_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_metric(&tables->table, fn, data);
+
+                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 fe343c4d8016..e137f3857c03 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -23,11 +23,19 @@ struct pmu_event {
 	const char *unit;
 	const char *perpkg;
 	const char *aggr_mode;
-	const char *metric_expr;
+	const char *deprecated;
+};
+
+struct pmu_metric {
 	const char *metric_name;
 	const char *metric_group;
-	const char *deprecated;
+	const char *metric_expr;
+	const char *unit;
+	const char *compat;
+	const char *aggr_mode;
 	const char *metric_constraint;
+	const char *desc;
+	const char *long_desc;
 };
 
 struct pmu_events_table;
@@ -36,14 +44,22 @@ typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
 				 const struct pmu_events_table *table,
 				 void *data);
 
+typedef int (*pmu_metric_iter_fn)(const struct pmu_metric *pm,
+				  const struct pmu_events_table *table,
+				  void *data);
+
 int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
 				    void *data);
+int pmu_events_table_for_each_metric(const struct pmu_events_table *table, pmu_metric_iter_fn fn,
+				     void *data);
 
 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);
+int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data);
 
 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);
+int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data);
 
 #endif
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index a9f2330f6257..c2b3ada57cbc 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -337,36 +337,12 @@ static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event
 		return -1;
 	}
 
-	if (!is_same(e1->metric_expr, e2->metric_expr)) {
-		pr_debug2("testing event e1 %s: mismatched metric_expr, %s vs %s\n",
-			  e1->name, e1->metric_expr, e2->metric_expr);
-		return -1;
-	}
-
-	if (!is_same(e1->metric_name, e2->metric_name)) {
-		pr_debug2("testing event e1 %s: mismatched metric_name, %s vs %s\n",
-			  e1->name,	e1->metric_name, e2->metric_name);
-		return -1;
-	}
-
-	if (!is_same(e1->metric_group, e2->metric_group)) {
-		pr_debug2("testing event e1 %s: mismatched metric_group, %s vs %s\n",
-			  e1->name, e1->metric_group, e2->metric_group);
-		return -1;
-	}
-
 	if (!is_same(e1->deprecated, e2->deprecated)) {
 		pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n",
 			  e1->name, e1->deprecated, e2->deprecated);
 		return -1;
 	}
 
-	if (!is_same(e1->metric_constraint, e2->metric_constraint)) {
-		pr_debug2("testing event e1 %s: mismatched metric_constant, %s vs %s\n",
-			  e1->name, e1->metric_constraint, e2->metric_constraint);
-		return -1;
-	}
-
 	return 0;
 }
 
@@ -432,9 +408,6 @@ static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
 	struct perf_pmu_test_event const **test_event_table;
 	bool found = false;
 
-	if (!pe->name)
-		return 0;
-
 	if (pe->pmu)
 		test_event_table = &uncore_events[0];
 	else
@@ -840,7 +813,7 @@ struct metric {
 	struct metric_ref metric_ref;
 };
 
-static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_events_table *table,
+static int test__parsing_callback(const struct pmu_metric *pm, const struct pmu_events_table *table,
 				  void *data)
 {
 	int *failures = data;
@@ -854,10 +827,10 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
 	};
 	int err = 0;
 
-	if (!pe->metric_expr)
+	if (!pm->metric_expr)
 		return 0;
 
-	pr_debug("Found metric '%s'\n", pe->metric_name);
+	pr_debug("Found metric '%s'\n", pm->metric_name);
 	(*failures)++;
 
 	/*
@@ -877,14 +850,14 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
 	perf_evlist__set_maps(&evlist->core, cpus, NULL);
 	runtime_stat__init(&st);
 
-	err = metricgroup__parse_groups_test(evlist, table, pe->metric_name,
+	err = metricgroup__parse_groups_test(evlist, table, pm->metric_name,
 					     false, false,
 					     &metric_events);
 	if (err) {
-		if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") ||
-		    !strcmp(pe->metric_name, "M3")) {
+		if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
+		    !strcmp(pm->metric_name, "M3")) {
 			(*failures)--;
-			pr_debug("Expected broken metric %s skipping\n", pe->metric_name);
+			pr_debug("Expected broken metric %s skipping\n", pm->metric_name);
 			err = 0;
 		}
 		goto out_err;
@@ -912,7 +885,7 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
 			struct metric_expr *mexp;
 
 			list_for_each_entry (mexp, &me->head, nd) {
-				if (strcmp(mexp->metric_name, pe->metric_name))
+				if (strcmp(mexp->metric_name, pm->metric_name))
 					continue;
 				pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st));
 				err = 0;
@@ -921,11 +894,11 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
 			}
 		}
 	}
-	pr_debug("Didn't find parsed metric %s", pe->metric_name);
+	pr_debug("Didn't find parsed metric %s", pm->metric_name);
 	err = 1;
 out_err:
 	if (err)
-		pr_debug("Broken metric %s\n", pe->metric_name);
+		pr_debug("Broken metric %s\n", pm->metric_name);
 
 	/* ... cleanup. */
 	metricgroup__rblist_exit(&metric_events);
@@ -941,8 +914,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
 {
 	int failures = 0;
 
-	pmu_for_each_core_event(test__parsing_callback, &failures);
-	pmu_for_each_sys_event(test__parsing_callback, &failures);
+	pmu_for_each_core_metric(test__parsing_callback, &failures);
+	pmu_for_each_sys_metric(test__parsing_callback, &failures);
 
 	return failures == 0 ? TEST_OK : TEST_FAIL;
 }
@@ -1021,14 +994,11 @@ static int metric_parse_fake(const char *metric_name, const char *str)
 	return ret;
 }
 
-static int test__parsing_fake_callback(const struct pmu_event *pe,
+static int test__parsing_fake_callback(const struct pmu_metric *pm,
 				       const struct pmu_events_table *table __maybe_unused,
 				       void *data __maybe_unused)
 {
-	if (!pe->metric_expr)
-		return 0;
-
-	return metric_parse_fake(pe->metric_name, pe->metric_expr);
+	return metric_parse_fake(pm->metric_name, pm->metric_expr);
 }
 
 /*
@@ -1047,11 +1017,11 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
 			return err;
 	}
 
-	err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
+	err = pmu_for_each_core_metric(test__parsing_fake_callback, NULL);
 	if (err)
 		return err;
 
-	return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
+	return pmu_for_each_sys_metric(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 b9c273ed080a..47fd02af66f1 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -167,14 +167,14 @@ static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
 		   "    echo 1 > /proc/sys/kernel/nmi_watchdog\n");
 }
 
-static bool metricgroup__has_constraint(const struct pmu_event *pe)
+static bool metricgroup__has_constraint(const struct pmu_metric *pm)
 {
-	if (!pe->metric_constraint)
+	if (!pm->metric_constraint)
 		return false;
 
-	if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") &&
+	if (!strcmp(pm->metric_constraint, "NO_NMI_WATCHDOG") &&
 	    sysctl__nmi_watchdog_enabled()) {
-		metricgroup___watchdog_constraint_hint(pe->metric_name, false);
+		metricgroup___watchdog_constraint_hint(pm->metric_name, false);
 		return true;
 	}
 
@@ -193,7 +193,7 @@ static void metric__free(struct metric *m)
 	free(m);
 }
 
-static struct metric *metric__new(const struct pmu_event *pe,
+static struct metric *metric__new(const struct pmu_metric *pm,
 				  const char *modifier,
 				  bool metric_no_group,
 				  int runtime,
@@ -210,15 +210,15 @@ static struct metric *metric__new(const struct pmu_event *pe,
 	if (!m->pctx)
 		goto out_err;
 
-	m->metric_name = pe->metric_name;
+	m->metric_name = pm->metric_name;
 	m->modifier = NULL;
 	if (modifier) {
 		m->modifier = strdup(modifier);
 		if (!m->modifier)
 			goto out_err;
 	}
-	m->metric_expr = pe->metric_expr;
-	m->metric_unit = pe->unit;
+	m->metric_expr = pm->metric_expr;
+	m->metric_unit = pm->unit;
 	m->pctx->sctx.user_requested_cpu_list = NULL;
 	if (user_requested_cpu_list) {
 		m->pctx->sctx.user_requested_cpu_list = strdup(user_requested_cpu_list);
@@ -227,7 +227,7 @@ static struct metric *metric__new(const struct pmu_event *pe,
 	}
 	m->pctx->sctx.runtime = runtime;
 	m->pctx->sctx.system_wide = system_wide;
-	m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
+	m->has_constraint = metric_no_group || metricgroup__has_constraint(pm);
 	m->metric_refs = NULL;
 	m->evlist = NULL;
 
@@ -348,10 +348,10 @@ static bool match_metric(const char *n, const char *list)
 	return false;
 }
 
-static bool match_pe_metric(const struct pmu_event *pe, const char *metric)
+static bool match_pm_metric(const struct pmu_metric *pm, const char *metric)
 {
-	return match_metric(pe->metric_group, metric) ||
-	       match_metric(pe->metric_name, metric);
+	return match_metric(pm->metric_group, metric) ||
+	       match_metric(pm->metric_name, metric);
 }
 
 /** struct mep - RB-tree node for building printing information. */
@@ -420,13 +420,13 @@ static struct mep *mep_lookup(struct rblist *groups, const char *metric_group,
 	return NULL;
 }
 
-static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
+static int metricgroup__add_to_mep_groups(const struct pmu_metric *pm,
 					struct rblist *groups)
 {
 	const char *g;
 	char *omg, *mg;
 
-	mg = strdup(pe->metric_group ?: "No_group");
+	mg = strdup(pm->metric_group ?: "No_group");
 	if (!mg)
 		return -ENOMEM;
 	omg = mg;
@@ -435,15 +435,15 @@ static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
 
 		g = skip_spaces(g);
 		if (strlen(g))
-			me = mep_lookup(groups, g, pe->metric_name);
+			me = mep_lookup(groups, g, pm->metric_name);
 		else
-			me = mep_lookup(groups, "No_group", pe->metric_name);
+			me = mep_lookup(groups, "No_group", pm->metric_name);
 
 		if (me) {
-			me->metric_desc = pe->desc;
-			me->metric_long_desc = pe->long_desc;
-			me->metric_expr = pe->metric_expr;
-			me->metric_unit = pe->unit;
+			me->metric_desc = pm->desc;
+			me->metric_long_desc = pm->long_desc;
+			me->metric_expr = pm->metric_expr;
+			me->metric_unit = pm->unit;
 		}
 	}
 	free(omg);
@@ -452,40 +452,37 @@ static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
 }
 
 struct metricgroup_iter_data {
-	pmu_event_iter_fn fn;
+	pmu_metric_iter_fn fn;
 	void *data;
 };
 
-static int metricgroup__sys_event_iter(const struct pmu_event *pe,
+static int metricgroup__sys_event_iter(const struct pmu_metric *pm,
 				       const struct pmu_events_table *table,
 				       void *data)
 {
 	struct metricgroup_iter_data *d = data;
 	struct perf_pmu *pmu = NULL;
 
-	if (!pe->metric_expr || !pe->compat)
+	if (!pm->metric_expr || !pm->compat)
 		return 0;
 
 	while ((pmu = perf_pmu__scan(pmu))) {
 
-		if (!pmu->id || strcmp(pmu->id, pe->compat))
+		if (!pmu->id || strcmp(pmu->id, pm->compat))
 			continue;
 
-		return d->fn(pe, table, d->data);
+		return d->fn(pm, table, d->data);
 	}
 	return 0;
 }
 
-static int metricgroup__add_to_mep_groups_callback(const struct pmu_event *pe,
+static int metricgroup__add_to_mep_groups_callback(const struct pmu_metric *pm,
 						const struct pmu_events_table *table __maybe_unused,
 						void *vdata)
 {
 	struct rblist *groups = vdata;
 
-	if (!pe->metric_name)
-		return 0;
-
-	return metricgroup__add_to_mep_groups(pe, groups);
+	return metricgroup__add_to_mep_groups(pm, groups);
 }
 
 void metricgroup__print(const struct print_callbacks *print_cb, void *print_state)
@@ -500,16 +497,16 @@ void metricgroup__print(const struct print_callbacks *print_cb, void *print_stat
 	groups.node_delete = mep_delete;
 	table = pmu_events_table__find();
 	if (table) {
-		pmu_events_table_for_each_event(table,
-						metricgroup__add_to_mep_groups_callback,
-						&groups);
+		pmu_events_table_for_each_metric(table,
+						 metricgroup__add_to_mep_groups_callback,
+						 &groups);
 	}
 	{
 		struct metricgroup_iter_data data = {
 			.fn = metricgroup__add_to_mep_groups_callback,
 			.data = &groups,
 		};
-		pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
+		pmu_for_each_sys_metric(metricgroup__sys_event_iter, &data);
 	}
 
 	for (node = rb_first_cached(&groups.entries); node; node = next) {
@@ -743,7 +740,7 @@ static int metricgroup__build_event_string(struct strbuf *events,
 #undef RETURN_IF_NON_ZERO
 }
 
-int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused)
+int __weak arch_get_runtimeparam(const struct pmu_metric *pm __maybe_unused)
 {
 	return 1;
 }
@@ -773,10 +770,10 @@ struct metricgroup_add_iter_data {
 
 static bool metricgroup__find_metric(const char *metric,
 				     const struct pmu_events_table *table,
-				     struct pmu_event *pe);
+				     struct pmu_metric *pm);
 
 static int add_metric(struct list_head *metric_list,
-		      const struct pmu_event *pe,
+		      const struct pmu_metric *pm,
 		      const char *modifier,
 		      bool metric_no_group,
 		      const char *user_requested_cpu_list,
@@ -816,10 +813,10 @@ static int resolve_metric(struct list_head *metric_list,
 	size_t bkt;
 	struct to_resolve {
 		/* The metric to resolve. */
-		struct pmu_event pe;
+		struct pmu_metric pm;
 		/*
 		 * The key in the IDs map, this may differ from in case,
-		 * etc. from pe->metric_name.
+		 * etc. from pm->metric_name.
 		 */
 		const char *key;
 	} *pending = NULL;
@@ -830,15 +827,15 @@ static int resolve_metric(struct list_head *metric_list,
 	 * the pending array.
 	 */
 	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
-		struct pmu_event pe;
+		struct pmu_metric pm;
 
-		if (metricgroup__find_metric(cur->pkey, table, &pe)) {
+		if (metricgroup__find_metric(cur->pkey, table, &pm)) {
 			pending = realloc(pending,
 					(pending_cnt + 1) * sizeof(struct to_resolve));
 			if (!pending)
 				return -ENOMEM;
 
-			memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
+			memcpy(&pending[pending_cnt].pm, &pm, sizeof(pm));
 			pending[pending_cnt].key = cur->pkey;
 			pending_cnt++;
 		}
@@ -853,7 +850,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].pm, modifier, metric_no_group,
 				 user_requested_cpu_list, system_wide, root_metric, visited,
 				 table);
 		if (ret)
@@ -867,7 +864,7 @@ static int resolve_metric(struct list_head *metric_list,
 /**
  * __add_metric - Add a metric to metric_list.
  * @metric_list: The list the metric is added to.
- * @pe: The pmu_event containing the metric to be added.
+ * @pm: The pmu_metric containing the metric to be added.
  * @modifier: if non-null event modifiers like "u".
  * @metric_no_group: Should events written to events be grouped "{}" or
  *                   global. Grouping is the default but due to multiplexing the
@@ -884,7 +881,7 @@ static int resolve_metric(struct list_head *metric_list,
  *       architecture perf is running upon.
  */
 static int __add_metric(struct list_head *metric_list,
-			const struct pmu_event *pe,
+			const struct pmu_metric *pm,
 			const char *modifier,
 			bool metric_no_group,
 			int runtime,
@@ -898,13 +895,13 @@ static int __add_metric(struct list_head *metric_list,
 	int ret;
 	bool is_root = !root_metric;
 	struct visited_metric visited_node = {
-		.name = pe->metric_name,
+		.name = pm->metric_name,
 		.parent = visited,
 	};
 
 	for (vm = visited; vm; vm = vm->parent) {
-		if (!strcmp(pe->metric_name, vm->name)) {
-			pr_err("failed: recursion detected for %s\n", pe->metric_name);
+		if (!strcmp(pm->metric_name, vm->name)) {
+			pr_err("failed: recursion detected for %s\n", pm->metric_name);
 			return -1;
 		}
 	}
@@ -914,7 +911,7 @@ static int __add_metric(struct list_head *metric_list,
 		 * This metric is the root of a tree and may reference other
 		 * metrics that are added recursively.
 		 */
-		root_metric = metric__new(pe, modifier, metric_no_group, runtime,
+		root_metric = metric__new(pm, modifier, metric_no_group, runtime,
 					  user_requested_cpu_list, system_wide);
 		if (!root_metric)
 			return -ENOMEM;
@@ -929,7 +926,7 @@ static int __add_metric(struct list_head *metric_list,
 		 */
 		if (root_metric->metric_refs) {
 			for (; root_metric->metric_refs[cnt].metric_name; cnt++) {
-				if (!strcmp(pe->metric_name,
+				if (!strcmp(pm->metric_name,
 					    root_metric->metric_refs[cnt].metric_name))
 					return 0;
 			}
@@ -947,8 +944,8 @@ static int __add_metric(struct list_head *metric_list,
 		 * need to change them, so there's no need to create
 		 * our own copy.
 		 */
-		root_metric->metric_refs[cnt].metric_name = pe->metric_name;
-		root_metric->metric_refs[cnt].metric_expr = pe->metric_expr;
+		root_metric->metric_refs[cnt].metric_name = pm->metric_name;
+		root_metric->metric_refs[cnt].metric_expr = pm->metric_expr;
 
 		/* Null terminate array. */
 		root_metric->metric_refs[cnt+1].metric_name = NULL;
@@ -959,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
 	 * For both the parent and referenced metrics, we parse
 	 * all the metric's IDs and add it to the root context.
 	 */
-	if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) {
+	if (expr__find_ids(pm->metric_expr, NULL, root_metric->pctx) < 0) {
 		/* Broken metric. */
 		ret = -EINVAL;
 	} else {
@@ -981,37 +978,37 @@ static int __add_metric(struct list_head *metric_list,
 
 struct metricgroup__find_metric_data {
 	const char *metric;
-	struct pmu_event *pe;
+	struct pmu_metric *pm;
 };
 
-static int metricgroup__find_metric_callback(const struct pmu_event *pe,
+static int metricgroup__find_metric_callback(const struct pmu_metric *pm,
 					     const struct pmu_events_table *table  __maybe_unused,
 					     void *vdata)
 {
 	struct metricgroup__find_metric_data *data = vdata;
 
-	if (!match_metric(pe->metric_name, data->metric))
+	if (!match_metric(pm->metric_name, data->metric))
 		return 0;
 
-	memcpy(data->pe, pe, sizeof(*pe));
+	memcpy(data->pm, pm, sizeof(*pm));
 	return 1;
 }
 
 static bool metricgroup__find_metric(const char *metric,
 				     const struct pmu_events_table *table,
-				     struct pmu_event *pe)
+				     struct pmu_metric *pm)
 {
 	struct metricgroup__find_metric_data data = {
 		.metric = metric,
-		.pe = pe,
+		.pm = pm,
 	};
 
-	return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
+	return pmu_events_table_for_each_metric(table, metricgroup__find_metric_callback, &data)
 		? true : false;
 }
 
 static int add_metric(struct list_head *metric_list,
-		      const struct pmu_event *pe,
+		      const struct pmu_metric *pm,
 		      const char *modifier,
 		      bool metric_no_group,
 		      const char *user_requested_cpu_list,
@@ -1022,16 +1019,16 @@ static int add_metric(struct list_head *metric_list,
 {
 	int ret = 0;
 
-	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
+	pr_debug("metric expr %s for %s\n", pm->metric_expr, pm->metric_name);
 
-	if (!strstr(pe->metric_expr, "?")) {
-		ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
+	if (!strstr(pm->metric_expr, "?")) {
+		ret = __add_metric(metric_list, pm, modifier, metric_no_group, 0,
 				   user_requested_cpu_list, system_wide, root_metric,
 				   visited, table);
 	} else {
 		int j, count;
 
-		count = arch_get_runtimeparam(pe);
+		count = arch_get_runtimeparam(pm);
 
 		/* This loop is added to create multiple
 		 * events depend on count value and add
@@ -1039,7 +1036,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,
+			ret = __add_metric(metric_list, pm, modifier, metric_no_group, j,
 					   user_requested_cpu_list, system_wide,
 					   root_metric, visited, table);
 	}
@@ -1047,17 +1044,17 @@ static int add_metric(struct list_head *metric_list,
 	return ret;
 }
 
-static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
+static int metricgroup__add_metric_sys_event_iter(const struct pmu_metric *pm,
 						const struct pmu_events_table *table __maybe_unused,
 						void *data)
 {
 	struct metricgroup_add_iter_data *d = data;
 	int ret;
 
-	if (!match_pe_metric(pe, d->metric_name))
+	if (!match_pm_metric(pm, d->metric_name))
 		return 0;
 
-	ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
+	ret = add_metric(d->metric_list, pm, d->modifier, d->metric_no_group,
 			 d->user_requested_cpu_list, d->system_wide,
 			 d->root_metric, d->visited, d->table);
 	if (ret)
@@ -1107,19 +1104,19 @@ struct metricgroup__add_metric_data {
 	bool has_match;
 };
 
-static int metricgroup__add_metric_callback(const struct pmu_event *pe,
+static int metricgroup__add_metric_callback(const struct pmu_metric *pm,
 					    const struct pmu_events_table *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))) {
+	if (pm->metric_expr &&
+		(match_metric(pm->metric_group, data->metric_name) ||
+		 match_metric(pm->metric_name, data->metric_name))) {
 
 		data->has_match = true;
-		ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
+		ret = add_metric(data->list, pm, data->modifier, data->metric_no_group,
 				 data->user_requested_cpu_list, data->system_wide,
 				 /*root_metric=*/NULL, /*visited_metrics=*/NULL, table);
 	}
@@ -1166,8 +1163,8 @@ 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.
 		 */
-		ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
-						      &data);
+		ret = pmu_events_table_for_each_metric(table, metricgroup__add_metric_callback,
+						       &data);
 		if (ret)
 			goto out;
 
@@ -1189,7 +1186,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 			},
 		};
 
-		pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
+		pmu_for_each_sys_metric(metricgroup__sys_event_iter, &data);
 	}
 	/* End of pmu events. */
 	if (!has_match)
@@ -1603,16 +1600,16 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
 			    &perf_pmu__fake, metric_events, table);
 }
 
-static int metricgroup__has_metric_callback(const struct pmu_event *pe,
+static int metricgroup__has_metric_callback(const struct pmu_metric *pm,
 					    const struct pmu_events_table *table __maybe_unused,
 					    void *vdata)
 {
 	const char *metric = vdata;
 
-	if (!pe->metric_expr)
+	if (!pm->metric_expr)
 		return 0;
 
-	if (match_metric(pe->metric_name, metric))
+	if (match_metric(pm->metric_name, metric))
 		return 1;
 
 	return 0;
@@ -1625,8 +1622,8 @@ bool metricgroup__has_metric(const char *metric)
 	if (!table)
 		return false;
 
-	return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
-					       (void *)metric) ? true : false;
+	return pmu_events_table_for_each_metric(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/metricgroup.h b/tools/perf/util/metricgroup.h
index 0013cf582173..b1f186d0f514 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -81,7 +81,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
 
 void metricgroup__print(const struct print_callbacks *print_cb, void *print_state);
 bool metricgroup__has_metric(const char *metric);
-int arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused);
+int arch_get_runtimeparam(const struct pmu_metric *pm);
 void metricgroup__rblist_exit(struct rblist *metric_events);
 
 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 21cce83462b3..0336ff27c15f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1570,8 +1570,6 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
 	evsel->scale = info.scale;
 	evsel->per_pkg = info.per_pkg;
 	evsel->snapshot = info.snapshot;
-	evsel->metric_expr = info.metric_expr;
-	evsel->metric_name = info.metric_name;
 	return 0;
 }
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2bdeb89352e7..d627f99b5a63 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -283,10 +283,6 @@ static void perf_pmu_update_alias(struct perf_pmu_alias *old,
 	perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
 			    &newalias->long_desc);
 	perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
-	perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
-			    &newalias->metric_expr);
-	perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
-			    &newalias->metric_name);
 	perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
 	old->scale = newalias->scale;
 	old->per_pkg = newalias->per_pkg;
@@ -302,8 +298,6 @@ void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
 	zfree(&newalias->long_desc);
 	zfree(&newalias->topic);
 	zfree(&newalias->str);
-	zfree(&newalias->metric_expr);
-	zfree(&newalias->metric_name);
 	zfree(&newalias->pmu_name);
 	parse_events_terms__purge(&newalias->terms);
 	free(newalias);
@@ -340,16 +334,13 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
 	int num;
 	char newval[256];
 	char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL,
-	     *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL,
-	     *pmu_name = NULL;
+	     *deprecated = NULL, *pmu_name = NULL;
 
 	if (pe) {
 		long_desc = (char *)pe->long_desc;
 		topic = (char *)pe->topic;
 		unit = (char *)pe->unit;
 		perpkg = (char *)pe->perpkg;
-		metric_expr = (char *)pe->metric_expr;
-		metric_name = (char *)pe->metric_name;
 		deprecated = (char *)pe->deprecated;
 		pmu_name = (char *)pe->pmu;
 	}
@@ -404,8 +395,6 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
 		perf_pmu__parse_snapshot(alias, dir, name);
 	}
 
-	alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
-	alias->metric_name = metric_name ? strdup(metric_name): NULL;
 	alias->desc = desc ? strdup(desc) : NULL;
 	alias->long_desc = long_desc ? strdup(long_desc) :
 				desc ? strdup(desc) : NULL;
@@ -822,9 +811,6 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
 	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;
 
@@ -879,12 +865,6 @@ static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
 	struct pmu_sys_event_iter_data *idata = data;
 	struct perf_pmu *pmu = idata->pmu;
 
-	if (!pe->name) {
-		if (pe->metric_group || pe->metric_name)
-			return 0;
-		return -EINVAL;
-	}
-
 	if (!pe->compat || !pe->pmu)
 		return 0;
 
@@ -1469,8 +1449,6 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
 	info->unit     = NULL;
 	info->scale    = 0.0;
 	info->snapshot = false;
-	info->metric_expr = NULL;
-	info->metric_name = NULL;
 
 	list_for_each_entry_safe(term, h, head_terms, list) {
 		alias = pmu_find_alias(pmu, term);
@@ -1486,8 +1464,6 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
 
 		if (alias->per_pkg)
 			info->per_pkg = true;
-		info->metric_expr = alias->metric_expr;
-		info->metric_name = alias->metric_name;
 
 		list_del_init(&term->list);
 		parse_events_term__delete(term);
@@ -1703,8 +1679,7 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
 	for (j = 0; j < len; j++) {
 		const char *name, *alias = NULL, *scale_unit = NULL,
 			*desc = NULL, *long_desc = NULL,
-			*encoding_desc = NULL, *topic = NULL,
-			*metric_name = NULL, *metric_expr = NULL;
+			*encoding_desc = NULL, *topic = NULL;
 		bool deprecated = false;
 		size_t buf_used;
 
@@ -1742,8 +1717,6 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
 			buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
 					"%s/%s/", aliases[j].pmu->name,
 					aliases[j].event->str) + 1;
-			metric_name = aliases[j].event->metric_name;
-			metric_expr = aliases[j].event->metric_expr;
 			deprecated = aliases[j].event->deprecated;
 		}
 		print_cb->print_event(print_state,
@@ -1756,9 +1729,7 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
 				"Kernel PMU event",
 				desc,
 				long_desc,
-				encoding_desc,
-				metric_name,
-				metric_expr);
+				encoding_desc);
 	}
 	if (printed && pager_in_use())
 		printf("\n");
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 69ca0004f94f..4d8d64209b4b 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -133,8 +133,6 @@ extern struct perf_pmu perf_pmu__fake;
 
 struct perf_pmu_info {
 	const char *unit;
-	const char *metric_expr;
-	const char *metric_name;
 	double scale;
 	bool per_pkg;
 	bool snapshot;
@@ -188,13 +186,6 @@ struct perf_pmu_alias {
 	 * default.
 	 */
 	bool deprecated;
-	/**
-	 * @metric_expr: A metric expression associated with an event. Doing
-	 * this makes little sense due to scale and unit applying to both.
-	 */
-	char *metric_expr;
-	/** @metric_name: A name for the metric. unit applying to both. */
-	char *metric_name;
 	/** @pmu_name: The name copied from struct perf_pmu. */
 	char *pmu_name;
 };
diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c
index 2646ae18d9f9..62e9ea7dcf40 100644
--- a/tools/perf/util/print-events.c
+++ b/tools/perf/util/print-events.c
@@ -101,9 +101,7 @@ void print_tracepoint_events(const struct print_callbacks *print_cb, void *print
 					"Tracepoint event",
 					/*desc=*/NULL,
 					/*long_desc=*/NULL,
-					/*encoding_desc=*/NULL,
-					/*metric_name=*/NULL,
-					/*metric_expr=*/NULL);
+					/*encoding_desc=*/NULL);
 		}
 		free(dir_path);
 		free(evt_namelist);
@@ -195,9 +193,7 @@ void print_sdt_events(const struct print_callbacks *print_cb, void *print_state)
 				"SDT event",
 				/*desc=*/NULL,
 				/*long_desc=*/NULL,
-				/*encoding_desc=*/NULL,
-				/*metric_name=*/NULL,
-				/*metric_expr=*/NULL);
+				/*encoding_desc=*/NULL);
 
 		free(evt_name);
 	}
@@ -255,9 +251,7 @@ int print_hwcache_events(const struct print_callbacks *print_cb, void *print_sta
 				event_type_descriptors[PERF_TYPE_HW_CACHE],
 				/*desc=*/NULL,
 				/*long_desc=*/NULL,
-				/*encoding_desc=*/NULL,
-				/*metric_name=*/NULL,
-				/*metric_expr=*/NULL);
+				/*encoding_desc=*/NULL);
 	}
 	strlist__delete(evt_name_list);
 	return 0;
@@ -277,9 +271,7 @@ void print_tool_events(const struct print_callbacks *print_cb, void *print_state
 				"Tool event",
 				/*desc=*/NULL,
 				/*long_desc=*/NULL,
-				/*encoding_desc=*/NULL,
-				/*metric_name=*/NULL,
-				/*metric_expr=*/NULL);
+				/*encoding_desc=*/NULL);
 	}
 }
 
@@ -331,9 +323,7 @@ void print_symbol_events(const struct print_callbacks *print_cb, void *print_sta
 				event_type_descriptors[type],
 				/*desc=*/NULL,
 				/*long_desc=*/NULL,
-				/*encoding_desc=*/NULL,
-				/*metric_name=*/NULL,
-				/*metric_expr=*/NULL);
+				/*encoding_desc=*/NULL);
 	}
 	strlist__delete(evt_name_list);
 }
@@ -364,9 +354,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
 			event_type_descriptors[PERF_TYPE_RAW],
 			/*desc=*/NULL,
 			/*long_desc=*/NULL,
-			/*encoding_desc=*/NULL,
-			/*metric_name=*/NULL,
-			/*metric_expr=*/NULL);
+			/*encoding_desc=*/NULL);
 
 	print_cb->print_event(print_state,
 			/*topic=*/NULL,
@@ -378,9 +366,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
 			event_type_descriptors[PERF_TYPE_RAW],
 			"(see 'man perf-list' on how to encode it)",
 			/*long_desc=*/NULL,
-			/*encoding_desc=*/NULL,
-			/*metric_name=*/NULL,
-			/*metric_expr=*/NULL);
+			/*encoding_desc=*/NULL);
 
 	print_cb->print_event(print_state,
 			/*topic=*/NULL,
@@ -392,9 +378,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
 			event_type_descriptors[PERF_TYPE_BREAKPOINT],
 			/*desc=*/NULL,
 			/*long_desc=*/NULL,
-			/*encoding_desc=*/NULL,
-			/*metric_name=*/NULL,
-			/*metric_expr=*/NULL);
+			/*encoding_desc=*/NULL);
 
 	print_tracepoint_events(print_cb, print_state);
 
diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h
index c237e53c4487..716dcf4b4859 100644
--- a/tools/perf/util/print-events.h
+++ b/tools/perf/util/print-events.h
@@ -16,8 +16,7 @@ struct print_callbacks {
 			const char *scale_unit,
 			bool deprecated, const char *event_type_desc,
 			const char *desc, const char *long_desc,
-			const char *encoding_desc,
-			const char *metric_name, const char *metric_expr);
+			const char *encoding_desc);
 	void (*print_metric)(void *print_state,
 			const char *group,
 			const char *name,
-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 5/9] perf stat: Remove evsel metric_name/expr
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (3 preceding siblings ...)
  2022-12-21 22:34 ` [PATCH v2 4/9] perf pmu-events: Separate metric out of pmu_event Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2023-01-23 14:42   ` John Garry
  2022-12-21 22:34 ` [PATCH v2 6/9] perf jevents: Combine table prefix and suffix writing Ian Rogers
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Metrics are their own unit and these variables held broken metrics
previously and now just hold the value NULL. Remove code that used
these variables.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/builtin-stat.c     |   1 -
 tools/perf/util/cgroup.c      |   1 -
 tools/perf/util/evsel.c       |   2 -
 tools/perf/util/evsel.h       |   2 -
 tools/perf/util/python.c      |   7 ---
 tools/perf/util/stat-shadow.c | 112 ----------------------------------
 tools/perf/util/stat.h        |   1 -
 7 files changed, 126 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 9f3e4b257516..5d18a5a6f662 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -2524,7 +2524,6 @@ int cmd_stat(int argc, const char **argv)
 					&stat_config.metric_events);
 		zfree(&metrics);
 	}
-	perf_stat__collect_metric_expr(evsel_list);
 	perf_stat__init_shadow_stats();
 
 	if (add_default_attributes())
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index e99b41f9be45..dc2db0ff7ab4 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -468,7 +468,6 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str,
 		nr_cgroups++;
 
 		if (metric_events) {
-			perf_stat__collect_metric_expr(tmp_list);
 			if (metricgroup__copy_metric_events(tmp_list, cgrp,
 							    metric_events,
 							    &orig_metric_events) < 0)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 999dd1700502..4d198529911a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -285,8 +285,6 @@ void evsel__init(struct evsel *evsel,
 	evsel->sample_size = __evsel__sample_size(attr->sample_type);
 	evsel__calc_id_pos(evsel);
 	evsel->cmdline_group_boundary = false;
-	evsel->metric_expr   = NULL;
-	evsel->metric_name   = NULL;
 	evsel->metric_events = NULL;
 	evsel->per_pkg_mask  = NULL;
 	evsel->collect_stat  = false;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index d572be41b960..24cb807ef6ce 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -105,8 +105,6 @@ struct evsel {
 	 * metric fields are similar, but needs more care as they can have
 	 * references to other metric (evsel).
 	 */
-	const char *		metric_expr;
-	const char *		metric_name;
 	struct evsel		**metric_events;
 	struct evsel		*metric_leader;
 
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 212031b97910..8c450b3d0080 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -75,13 +75,6 @@ const char *perf_env__arch(struct perf_env *env __maybe_unused)
 	return NULL;
 }
 
-/*
- * Add this one here not to drag util/stat-shadow.c
- */
-void perf_stat__collect_metric_expr(struct evlist *evsel_list)
-{
-}
-
 /*
  * This one is needed not to drag the PMU bandwagon, jevents generated
  * pmu_sys_event_tables, etc and evsel__find_pmu() is used so far just for
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index cadb2df23c87..35ea4813f468 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -346,114 +346,6 @@ static const char *get_ratio_color(enum grc_type type, double ratio)
 	return color;
 }
 
-static struct evsel *perf_stat__find_event(struct evlist *evsel_list,
-						const char *name)
-{
-	struct evsel *c2;
-
-	evlist__for_each_entry (evsel_list, c2) {
-		if (!strcasecmp(c2->name, name) && !c2->collect_stat)
-			return c2;
-	}
-	return NULL;
-}
-
-/* Mark MetricExpr target events and link events using them to them. */
-void perf_stat__collect_metric_expr(struct evlist *evsel_list)
-{
-	struct evsel *counter, *leader, **metric_events, *oc;
-	bool found;
-	struct expr_parse_ctx *ctx;
-	struct hashmap_entry *cur;
-	size_t bkt;
-	int i;
-
-	ctx = expr__ctx_new();
-	if (!ctx) {
-		pr_debug("expr__ctx_new failed");
-		return;
-	}
-	evlist__for_each_entry(evsel_list, counter) {
-		bool invalid = false;
-
-		leader = evsel__leader(counter);
-		if (!counter->metric_expr)
-			continue;
-
-		expr__ctx_clear(ctx);
-		metric_events = counter->metric_events;
-		if (!metric_events) {
-			if (expr__find_ids(counter->metric_expr,
-					   counter->name,
-					   ctx) < 0)
-				continue;
-
-			metric_events = calloc(sizeof(struct evsel *),
-					       hashmap__size(ctx->ids) + 1);
-			if (!metric_events) {
-				expr__ctx_free(ctx);
-				return;
-			}
-			counter->metric_events = metric_events;
-		}
-
-		i = 0;
-		hashmap__for_each_entry(ctx->ids, cur, bkt) {
-			const char *metric_name = cur->pkey;
-
-			found = false;
-			if (leader) {
-				/* Search in group */
-				for_each_group_member (oc, leader) {
-					if (!strcasecmp(oc->name,
-							metric_name) &&
-						!oc->collect_stat) {
-						found = true;
-						break;
-					}
-				}
-			}
-			if (!found) {
-				/* Search ignoring groups */
-				oc = perf_stat__find_event(evsel_list,
-							   metric_name);
-			}
-			if (!oc) {
-				/* Deduping one is good enough to handle duplicated PMUs. */
-				static char *printed;
-
-				/*
-				 * Adding events automatically would be difficult, because
-				 * it would risk creating groups that are not schedulable.
-				 * perf stat doesn't understand all the scheduling constraints
-				 * of events. So we ask the user instead to add the missing
-				 * events.
-				 */
-				if (!printed ||
-				    strcasecmp(printed, metric_name)) {
-					fprintf(stderr,
-						"Add %s event to groups to get metric expression for %s\n",
-						metric_name,
-						counter->name);
-					free(printed);
-					printed = strdup(metric_name);
-				}
-				invalid = true;
-				continue;
-			}
-			metric_events[i++] = oc;
-			oc->collect_stat = true;
-		}
-		metric_events[i] = NULL;
-		if (invalid) {
-			free(metric_events);
-			counter->metric_events = NULL;
-			counter->metric_expr = NULL;
-		}
-	}
-	expr__ctx_free(ctx);
-}
-
 static double runtime_stat_avg(struct runtime_stat *st,
 			       enum stat_type type, int map_idx,
 			       struct runtime_stat_data *rsd)
@@ -1299,10 +1191,6 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 			color = NULL;
 		print_metric(config, ctxp, color, "%8.1f%%", "Core Bound",
 				core_bound * 100.);
-	} else if (evsel->metric_expr) {
-		generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
-			       evsel->name, evsel->metric_name, NULL, 1,
-			       map_idx, out, st);
 	} else if (runtime_stat_n(st, STAT_NSECS, map_idx, &rsd) != 0) {
 		char unit = ' ';
 		char unit_buf[10] = "/sec";
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 499c3bf81333..b1c29156c560 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -257,7 +257,6 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 				   struct perf_stat_output_ctx *out,
 				   struct rblist *metric_events,
 				   struct runtime_stat *st);
-void perf_stat__collect_metric_expr(struct evlist *);
 
 int evlist__alloc_stats(struct perf_stat_config *config,
 			struct evlist *evlist, bool alloc_raw);
-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 6/9] perf jevents: Combine table prefix and suffix writing
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (4 preceding siblings ...)
  2022-12-21 22:34 ` [PATCH v2 5/9] perf stat: Remove evsel metric_name/expr Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2022-12-21 22:34 ` [PATCH v2 7/9] perf pmu-events: Introduce pmu_metrics_table Ian Rogers
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Combine into a single function to simplify, in a later change, writing
metrics separately.

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

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index ee3d4cdf01be..7b9714b25d0a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -19,10 +19,10 @@ _sys_event_tables = []
 # JsonEvent. Architecture standard events are in json files in the top
 # f'{_args.starting_dir}/{_args.arch}' directory.
 _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 = []
+# Name of table to be written out
+_pending_events_tblname = None
 # Global BigCString shared by all structures.
 _bcs = None
 # Order specific JsonEvent attributes will be visited.
@@ -376,24 +376,13 @@ def preprocess_arch_std_files(archpath: str) -> None:
           _arch_std_events[event.name.lower()] = event
 
 
-def print_events_table_prefix(tblname: str) -> None:
-  """Called when a new events table is started."""
-  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 compact_pmu_event {tblname}[] = {{\n')
-  _close_table = True
-
-
 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 e in read_json_events(item.path, topic):
     _pending_events.append(e)
 
 
-def print_events_table_suffix() -> None:
+def print_pending_events() -> None:
   """Optionally close events table."""
 
   def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
@@ -405,17 +394,19 @@ def print_events_table_suffix() -> None:
     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
-  if not _close_table:
+  global _pending_events
+  if not _pending_events:
     return
 
-  global _pending_events
+  global _pending_events_tblname
+  _args.output_file.write(
+      f'static const struct compact_pmu_event {_pending_events_tblname}[] = {{\n')
+
   for event in sorted(_pending_events, key=event_cmp_key):
     _args.output_file.write(event.to_c_string())
-    _pending_events = []
+  _pending_events = []
 
   _args.output_file.write('};\n\n')
-  _close_table = False
 
 def get_topic(topic: str) -> str:
   if topic.endswith('metrics.json'):
@@ -453,12 +444,13 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
 
   # model directory, reset topic
   if item.is_dir() and is_leaf_dir(item.path):
-    print_events_table_suffix()
+    print_pending_events()
 
     tblname = file_name_to_table_name(parents, item.name)
     if item.name == 'sys':
       _sys_event_tables.append(tblname)
-    print_events_table_prefix(tblname)
+    global _pending_events_tblname
+    _pending_events_tblname = tblname
     return
 
   # base dir or too deep
@@ -802,7 +794,7 @@ struct compact_pmu_event {
   for arch in archs:
     arch_path = f'{_args.starting_dir}/{arch}'
     ftw(arch_path, [], process_one_file)
-    print_events_table_suffix()
+    print_pending_events()
 
   print_mapping_table(archs)
   print_system_mapping_table()
-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 7/9] perf pmu-events: Introduce pmu_metrics_table
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (5 preceding siblings ...)
  2022-12-21 22:34 ` [PATCH v2 6/9] perf jevents: Combine table prefix and suffix writing Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2023-01-23 15:35   ` John Garry
  2022-12-21 22:34 ` [PATCH v2 8/9] perf jevents: Generate metrics and events as separate tables Ian Rogers
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Add a metrics table that is just a cast from pmu_events_table. This
changes the APIs so that event and metric usage of the underlying
table is different. Later changes will separate the tables.

This introduction fixes a NO_JEVENTS=1 regression on:
 68: Parse and process metrics                                       : Ok
 70: Event expansion for cgroups                                     : Ok
caused by the necessary test metrics not being found.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/arm64/util/pmu.c         | 23 ++++++++++-
 tools/perf/pmu-events/empty-pmu-events.c | 52 ++++++++++++++++++++----
 tools/perf/pmu-events/jevents.py         | 24 ++++++++---
 tools/perf/pmu-events/pmu-events.h       | 10 +++--
 tools/perf/tests/expand-cgroup.c         |  4 +-
 tools/perf/tests/parse-metric.c          |  4 +-
 tools/perf/tests/pmu-events.c            |  5 ++-
 tools/perf/util/metricgroup.c            | 50 +++++++++++------------
 tools/perf/util/metricgroup.h            |  2 +-
 tools/perf/util/pmu.c                    |  9 +++-
 tools/perf/util/pmu.h                    |  1 +
 11 files changed, 133 insertions(+), 51 deletions(-)

diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
index 477e513972a4..f8ae479a06db 100644
--- a/tools/perf/arch/arm64/util/pmu.c
+++ b/tools/perf/arch/arm64/util/pmu.c
@@ -19,7 +19,28 @@ const struct pmu_events_table *pmu_events_table__find(void)
 		if (pmu->cpus->nr != cpu__max_cpu().cpu)
 			return NULL;
 
-		return perf_pmu__find_table(pmu);
+		return perf_pmu__find_events_table(pmu);
+	}
+
+	return NULL;
+}
+
+const struct pmu_metrics_table *pmu_metrics_table__find(void)
+{
+	struct perf_pmu *pmu = NULL;
+
+	while ((pmu = perf_pmu__scan(pmu))) {
+		if (!is_pmu_core(pmu->name))
+			continue;
+
+		/*
+		 * The cpumap should cover all CPUs. Otherwise, some CPUs may
+		 * not support some events or have different event IDs.
+		 */
+		if (pmu->cpus->nr != cpu__max_cpu().cpu)
+			return NULL;
+
+		return perf_pmu__find_metrics_table(pmu);
 	}
 
 	return NULL;
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 5572a4d1eddb..d50f60a571dd 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -278,14 +278,12 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_ev
 	return 0;
 }
 
-int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_metric_iter_fn fn,
-				     void *data)
+int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
+				      void *data)
 {
-	struct pmu_metrics_table *table = (struct pmu_metrics_table *)etable;
-
 	for (const struct pmu_metric *pm = &table->entries[0]; pm->metric_group || pm->metric_name;
 	     pm++) {
-		int ret = fn(pm, etable, data);
+		int ret = fn(pm, table, data);
 
 		if (ret)
 			return ret;
@@ -293,7 +291,7 @@ int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_
 	return 0;
 }
 
-const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
 {
 	const struct pmu_events_table *table = NULL;
 	char *cpuid = perf_pmu__getcpuid(pmu);
@@ -321,6 +319,34 @@ const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
 	return table;
 }
 
+const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
+{
+	const struct pmu_metrics_table *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->cpuid)
+			break;
+
+		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+			table = &map->metric_table;
+			break;
+		}
+	}
+	free(cpuid);
+	return table;
+}
+
 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];
@@ -332,6 +358,17 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
 	return NULL;
 }
 
+const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
+{
+	for (const struct pmu_events_map *tables = &pmu_events_map[0];
+	     tables->arch;
+	     tables++) {
+		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+			return &tables->metric_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];
@@ -350,8 +387,7 @@ int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
 	for (const struct pmu_events_map *tables = &pmu_events_map[0];
 	     tables->arch;
 	     tables++) {
-		int ret = pmu_events_table_for_each_metric(
-			(const struct pmu_events_table *)&tables->metric_table, fn, data);
+		int ret = pmu_metrics_table_for_each_metric(&tables->metric_table, fn, data);
 
 		if (ret)
 			return ret;
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 7b9714b25d0a..be2cf8a8779c 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -609,17 +609,19 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
         return 0;
 }
 
-int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
+int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *mtable,
                                      pmu_metric_iter_fn fn,
                                      void *data)
 {
+        struct pmu_events_table *table = (struct pmu_events_table *)mtable;
+
         for (size_t i = 0; i < table->length; i++) {
                 struct pmu_metric pm;
                 int ret;
 
                 decompress_metric(table->entries[i].offset, &pm);
                 if (pm.metric_name) {
-                        ret = fn(&pm, table, data);
+                        ret = fn(&pm, mtable, data);
                         if (ret)
                                 return ret;
                 }
@@ -627,7 +629,7 @@ int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
         return 0;
 }
 
-const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
 {
         const struct pmu_events_table *table = NULL;
         char *cpuid = perf_pmu__getcpuid(pmu);
@@ -654,6 +656,11 @@ const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
         return table;
 }
 
+const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
+{
+        return (struct pmu_metrics_table *)perf_pmu__find_events_table(pmu);
+}
+
 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];
@@ -665,6 +672,11 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
         return NULL;
 }
 
+const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
+{
+       return (struct pmu_metrics_table *)find_core_events_table(arch, cpuid);
+}
+
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
 {
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
@@ -683,7 +695,8 @@ int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
              tables->arch;
              tables++) {
-                int ret = pmu_events_table_for_each_metric(&tables->table, fn, data);
+                int ret = pmu_metrics_table_for_each_metric(
+                                (struct pmu_metrics_table *)&tables->table, fn, data);
 
                 if (ret)
                         return ret;
@@ -720,7 +733,8 @@ int pmu_for_each_sys_metric(pmu_metric_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_metric(&tables->table, fn, data);
+                int ret = pmu_metrics_table_for_each_metric(
+                                (struct pmu_metrics_table *)&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 e137f3857c03..b7d4a66b8ad2 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -39,26 +39,30 @@ struct pmu_metric {
 };
 
 struct pmu_events_table;
+struct pmu_metrics_table;
 
 typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
 				 const struct pmu_events_table *table,
 				 void *data);
 
 typedef int (*pmu_metric_iter_fn)(const struct pmu_metric *pm,
-				  const struct pmu_events_table *table,
+				  const struct pmu_metrics_table *table,
 				  void *data);
 
 int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
 				    void *data);
-int pmu_events_table_for_each_metric(const struct pmu_events_table *table, pmu_metric_iter_fn fn,
+int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
 				     void *data);
 
-const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu);
+const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu);
 const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid);
+const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid);
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
 int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data);
 
 const struct pmu_events_table *find_sys_events_table(const char *name);
+const struct pmu_metrics_table *find_sys_metrics_table(const char *name);
 int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
 int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data);
 
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index 51fb5f34c1dd..672a27f37060 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -180,13 +180,13 @@ static int expand_metric_events(void)
 	struct evlist *evlist;
 	struct rblist metric_events;
 	const char metric_str[] = "CPI";
-	const struct pmu_events_table *pme_test;
+	const struct pmu_metrics_table *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");
+	pme_test = find_core_metrics_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 21b7ac00d798..9fec6040950c 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_events_table *pme_test;
+	const struct pmu_metrics_table *pme_test;
 	struct perf_cpu_map *cpus;
 	struct runtime_stat st;
 	struct evlist *evlist;
@@ -96,7 +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");
+	pme_test = find_core_metrics_table("testarch", "testcpu");
 	err = metricgroup__parse_groups_test(evlist, pme_test, name,
 					     false, false,
 					     &metric_events);
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index c2b3ada57cbc..9f2e385e0991 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -813,7 +813,8 @@ struct metric {
 	struct metric_ref metric_ref;
 };
 
-static int test__parsing_callback(const struct pmu_metric *pm, const struct pmu_events_table *table,
+static int test__parsing_callback(const struct pmu_metric *pm,
+				  const struct pmu_metrics_table *table,
 				  void *data)
 {
 	int *failures = data;
@@ -995,7 +996,7 @@ static int metric_parse_fake(const char *metric_name, const char *str)
 }
 
 static int test__parsing_fake_callback(const struct pmu_metric *pm,
-				       const struct pmu_events_table *table __maybe_unused,
+				       const struct pmu_metrics_table *table __maybe_unused,
 				       void *data __maybe_unused)
 {
 	return metric_parse_fake(pm->metric_name, pm->metric_expr);
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 47fd02af66f1..46314ad571e4 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -457,7 +457,7 @@ struct metricgroup_iter_data {
 };
 
 static int metricgroup__sys_event_iter(const struct pmu_metric *pm,
-				       const struct pmu_events_table *table,
+				       const struct pmu_metrics_table *table,
 				       void *data)
 {
 	struct metricgroup_iter_data *d = data;
@@ -477,7 +477,7 @@ static int metricgroup__sys_event_iter(const struct pmu_metric *pm,
 }
 
 static int metricgroup__add_to_mep_groups_callback(const struct pmu_metric *pm,
-						const struct pmu_events_table *table __maybe_unused,
+						const struct pmu_metrics_table *table __maybe_unused,
 						void *vdata)
 {
 	struct rblist *groups = vdata;
@@ -488,16 +488,16 @@ static int metricgroup__add_to_mep_groups_callback(const struct pmu_metric *pm,
 void metricgroup__print(const struct print_callbacks *print_cb, void *print_state)
 {
 	struct rblist groups;
-	const struct pmu_events_table *table;
+	const struct pmu_metrics_table *table;
 	struct rb_node *node, *next;
 
 	rblist__init(&groups);
 	groups.node_new = mep_new;
 	groups.node_cmp = mep_cmp;
 	groups.node_delete = mep_delete;
-	table = pmu_events_table__find();
+	table = pmu_metrics_table__find();
 	if (table) {
-		pmu_events_table_for_each_metric(table,
+		pmu_metrics_table_for_each_metric(table,
 						 metricgroup__add_to_mep_groups_callback,
 						 &groups);
 	}
@@ -765,11 +765,11 @@ struct metricgroup_add_iter_data {
 	bool system_wide;
 	struct metric *root_metric;
 	const struct visited_metric *visited;
-	const struct pmu_events_table *table;
+	const struct pmu_metrics_table *table;
 };
 
 static bool metricgroup__find_metric(const char *metric,
-				     const struct pmu_events_table *table,
+				     const struct pmu_metrics_table *table,
 				     struct pmu_metric *pm);
 
 static int add_metric(struct list_head *metric_list,
@@ -780,7 +780,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool system_wide,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_events_table *table);
+		      const struct pmu_metrics_table *table);
 
 /**
  * resolve_metric - Locate metrics within the root metric and recursively add
@@ -807,7 +807,7 @@ static int resolve_metric(struct list_head *metric_list,
 			  bool system_wide,
 			  struct metric *root_metric,
 			  const struct visited_metric *visited,
-			  const struct pmu_events_table *table)
+			  const struct pmu_metrics_table *table)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -889,7 +889,7 @@ static int __add_metric(struct list_head *metric_list,
 			bool system_wide,
 			struct metric *root_metric,
 			const struct visited_metric *visited,
-			const struct pmu_events_table *table)
+			const struct pmu_metrics_table *table)
 {
 	const struct visited_metric *vm;
 	int ret;
@@ -982,7 +982,7 @@ struct metricgroup__find_metric_data {
 };
 
 static int metricgroup__find_metric_callback(const struct pmu_metric *pm,
-					     const struct pmu_events_table *table  __maybe_unused,
+					     const struct pmu_metrics_table *table  __maybe_unused,
 					     void *vdata)
 {
 	struct metricgroup__find_metric_data *data = vdata;
@@ -995,7 +995,7 @@ static int metricgroup__find_metric_callback(const struct pmu_metric *pm,
 }
 
 static bool metricgroup__find_metric(const char *metric,
-				     const struct pmu_events_table *table,
+				     const struct pmu_metrics_table *table,
 				     struct pmu_metric *pm)
 {
 	struct metricgroup__find_metric_data data = {
@@ -1003,7 +1003,7 @@ static bool metricgroup__find_metric(const char *metric,
 		.pm = pm,
 	};
 
-	return pmu_events_table_for_each_metric(table, metricgroup__find_metric_callback, &data)
+	return pmu_metrics_table_for_each_metric(table, metricgroup__find_metric_callback, &data)
 		? true : false;
 }
 
@@ -1015,7 +1015,7 @@ static int add_metric(struct list_head *metric_list,
 		      bool system_wide,
 		      struct metric *root_metric,
 		      const struct visited_metric *visited,
-		      const struct pmu_events_table *table)
+		      const struct pmu_metrics_table *table)
 {
 	int ret = 0;
 
@@ -1045,7 +1045,7 @@ static int add_metric(struct list_head *metric_list,
 }
 
 static int metricgroup__add_metric_sys_event_iter(const struct pmu_metric *pm,
-						const struct pmu_events_table *table __maybe_unused,
+						const struct pmu_metrics_table *table __maybe_unused,
 						void *data)
 {
 	struct metricgroup_add_iter_data *d = data;
@@ -1105,7 +1105,7 @@ struct metricgroup__add_metric_data {
 };
 
 static int metricgroup__add_metric_callback(const struct pmu_metric *pm,
-					    const struct pmu_events_table *table,
+					    const struct pmu_metrics_table *table,
 					    void *vdata)
 {
 	struct metricgroup__add_metric_data *data = vdata;
@@ -1143,7 +1143,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
 				   const char *user_requested_cpu_list,
 				   bool system_wide,
 				   struct list_head *metric_list,
-				   const struct pmu_events_table *table)
+				   const struct pmu_metrics_table *table)
 {
 	LIST_HEAD(list);
 	int ret;
@@ -1163,7 +1163,7 @@ 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.
 		 */
-		ret = pmu_events_table_for_each_metric(table, metricgroup__add_metric_callback,
+		ret = pmu_metrics_table_for_each_metric(table, metricgroup__add_metric_callback,
 						       &data);
 		if (ret)
 			goto out;
@@ -1219,7 +1219,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,
 					const char *user_requested_cpu_list,
 					bool system_wide, struct list_head *metric_list,
-					const struct pmu_events_table *table)
+					const struct pmu_metrics_table *table)
 {
 	char *list_itr, *list_copy, *metric_name, *modifier;
 	int ret, count = 0;
@@ -1429,7 +1429,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 			bool system_wide,
 			struct perf_pmu *fake_pmu,
 			struct rblist *metric_events_list,
-			const struct pmu_events_table *table)
+			const struct pmu_metrics_table *table)
 {
 	struct evlist *combined_evlist = NULL;
 	LIST_HEAD(metric_list);
@@ -1577,7 +1577,7 @@ int metricgroup__parse_groups(struct evlist *perf_evlist,
 			      bool system_wide,
 			      struct rblist *metric_events)
 {
-	const struct pmu_events_table *table = pmu_events_table__find();
+	const struct pmu_metrics_table *table = pmu_metrics_table__find();
 
 	if (!table)
 		return -EINVAL;
@@ -1588,7 +1588,7 @@ int metricgroup__parse_groups(struct evlist *perf_evlist,
 }
 
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_events_table *table,
+				   const struct pmu_metrics_table *table,
 				   const char *str,
 				   bool metric_no_group,
 				   bool metric_no_merge,
@@ -1601,7 +1601,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
 }
 
 static int metricgroup__has_metric_callback(const struct pmu_metric *pm,
-					    const struct pmu_events_table *table __maybe_unused,
+					    const struct pmu_metrics_table *table __maybe_unused,
 					    void *vdata)
 {
 	const char *metric = vdata;
@@ -1617,12 +1617,12 @@ static int metricgroup__has_metric_callback(const struct pmu_metric *pm,
 
 bool metricgroup__has_metric(const char *metric)
 {
-	const struct pmu_events_table *table = pmu_events_table__find();
+	const struct pmu_metrics_table *table = pmu_metrics_table__find();
 
 	if (!table)
 		return false;
 
-	return pmu_events_table_for_each_metric(table, metricgroup__has_metric_callback,
+	return pmu_metrics_table_for_each_metric(table, metricgroup__has_metric_callback,
 						(void *)metric) ? true : false;
 }
 
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index b1f186d0f514..84030321a057 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -73,7 +73,7 @@ int metricgroup__parse_groups(struct evlist *perf_evlist,
 			      bool system_wide,
 			      struct rblist *metric_events);
 int metricgroup__parse_groups_test(struct evlist *evlist,
-				   const struct pmu_events_table *table,
+				   const struct pmu_metrics_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 d627f99b5a63..09014e85203b 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -718,7 +718,12 @@ char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 
 __weak const struct pmu_events_table *pmu_events_table__find(void)
 {
-	return perf_pmu__find_table(NULL);
+	return perf_pmu__find_events_table(NULL);
+}
+
+__weak const struct pmu_metrics_table *pmu_metrics_table__find(void)
+{
+	return perf_pmu__find_metrics_table(NULL);
 }
 
 /*
@@ -846,7 +851,7 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 {
 	const struct pmu_events_table *table;
 
-	table = perf_pmu__find_table(pmu);
+	table = perf_pmu__find_events_table(pmu);
 	if (!table)
 		return;
 
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 4d8d64209b4b..c1fb70bf6f84 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -230,6 +230,7 @@ void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu,
 
 char *perf_pmu__getcpuid(struct perf_pmu *pmu);
 const struct pmu_events_table *pmu_events_table__find(void);
+const struct pmu_metrics_table *pmu_metrics_table__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.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 8/9] perf jevents: Generate metrics and events as separate tables
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (6 preceding siblings ...)
  2022-12-21 22:34 ` [PATCH v2 7/9] perf pmu-events: Introduce pmu_metrics_table Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2023-01-23 15:18   ` John Garry
  2022-12-21 22:34 ` [PATCH v2 9/9] perf jevents: Add model list option Ian Rogers
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

Turn a perf json event into an event, metric or both. This reduces the
number of events needed to scan to find an event or metric. As events
no longer need the relatively seldom used metric fields, 4 bytes is
saved per event. This reduces the big C string's size by 335kb (14.8%)
on x86.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/pmu-events/jevents.py | 244 +++++++++++++++++++++++--------
 tools/perf/tests/pmu-events.c    |   3 +-
 2 files changed, 189 insertions(+), 58 deletions(-)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index be2cf8a8779c..c98443319145 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -13,28 +13,40 @@ import collections
 
 # Global command line arguments.
 _args = None
+# List of regular event tables.
+_event_tables = []
 # List of event tables generated from "/sys" directories.
 _sys_event_tables = []
+# List of regular metric tables.
+_metric_tables = []
+# List of metric tables generated from "/sys" directories.
+_sys_metric_tables = []
+# Mapping between sys event table names and sys metric table names.
+_sys_event_table_to_metric_table_mapping = {}
 # Map from an event name to an architecture standard
 # JsonEvent. Architecture standard events are in json files in the top
 # f'{_args.starting_dir}/{_args.arch}' directory.
 _arch_std_events = {}
 # Events to write out when the table is closed
 _pending_events = []
-# Name of table to be written out
+# Name of events table to be written out
 _pending_events_tblname = None
+# Metrics to write out when the table is closed
+_pending_metrics = []
+# Name of metrics table to be written out
+_pending_metrics_tblname = None
 # 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',
+    'name', 'pmu', 'topic', 'desc',
     # 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'
+    'long_desc'
 ]
 
 # Attributes that are in pmu_metric rather than pmu_event.
@@ -52,14 +64,16 @@ def removesuffix(s: str, suffix: str) -> str:
   return s[0:-len(suffix)] if s.endswith(suffix) else s
 
 
-def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
+def file_name_to_table_name(prefix: str, parents: Sequence[str],
+                            dirname: str) -> str:
   """Generate a C table name from directory names."""
-  tblname = 'pme'
+  tblname = prefix
   for p in parents:
     tblname += '_' + p
   tblname += '_' + dirname
   return tblname.replace('-', '_')
 
+
 def c_len(s: str) -> int:
   """Return the length of s a C string
 
@@ -277,7 +291,7 @@ class JsonEvent:
     self.metric_constraint = jd.get('MetricConstraint')
     self.metric_expr = None
     if 'MetricExpr' in jd:
-       self.metric_expr = metric.ParsePerfJson(jd['MetricExpr']).Simplify()
+      self.metric_expr = metric.ParsePerfJson(jd['MetricExpr']).Simplify()
 
     arch_std = jd.get('ArchStdEvent')
     if precise and self.desc and '(Precise Event)' not in self.desc:
@@ -326,23 +340,24 @@ class JsonEvent:
         s += f'\t{attr} = {value},\n'
     return s + '}'
 
-  def build_c_string(self) -> str:
+  def build_c_string(self, metric: bool) -> str:
     s = ''
-    for attr in _json_event_attributes:
+    for attr in _json_metric_attributes if metric else _json_event_attributes:
       x = getattr(self, attr)
-      if x and attr == 'metric_expr':
+      if metric and x and attr == 'metric_expr':
         # Convert parsed metric expressions into a string. Slashes
         # must be doubled in the file.
         x = x.ToPerfJson().replace('\\', '\\\\')
       s += f'{x}\\000' if x else '\\000'
     return s
 
-  def to_c_string(self) -> str:
+  def to_c_string(self, metric: bool) -> str:
     """Representation of the event as a C struct initializer."""
 
-    s = self.build_c_string()
+    s = self.build_c_string(metric)
     return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
 
+
 @lru_cache(maxsize=None)
 def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
   """Read json events from the specified file."""
@@ -379,7 +394,10 @@ def preprocess_arch_std_files(archpath: str) -> None:
 def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
   """Add contents of file to _pending_events table."""
   for e in read_json_events(item.path, topic):
-    _pending_events.append(e)
+    if e.name:
+      _pending_events.append(e)
+    if e.metric_name:
+      _pending_metrics.append(e)
 
 
 def print_pending_events() -> None:
@@ -399,15 +417,54 @@ def print_pending_events() -> None:
     return
 
   global _pending_events_tblname
+  if _pending_events_tblname.endswith('_sys'):
+    global _sys_event_tables
+    _sys_event_tables.append(_pending_events_tblname)
+  else:
+    global event_tables
+    _event_tables.append(_pending_events_tblname)
+
   _args.output_file.write(
       f'static const struct compact_pmu_event {_pending_events_tblname}[] = {{\n')
 
   for event in sorted(_pending_events, key=event_cmp_key):
-    _args.output_file.write(event.to_c_string())
+    _args.output_file.write(event.to_c_string(metric=False))
   _pending_events = []
 
   _args.output_file.write('};\n\n')
 
+def print_pending_metrics() -> None:
+  """Optionally close metrics table."""
+
+  def metric_cmp_key(j: JsonEvent) -> Tuple[bool, str, str]:
+    def fix_none(s: Optional[str]) -> str:
+      if s is None:
+        return ''
+      return s
+
+    return (j.desc is not None, fix_none(j.pmu), fix_none(j.metric_name))
+
+  global _pending_metrics
+  if not _pending_metrics:
+    return
+
+  global _pending_metrics_tblname
+  if _pending_metrics_tblname.endswith('_sys'):
+    global _sys_metric_tables
+    _sys_metric_tables.append(_pending_metrics_tblname)
+  else:
+    global metric_tables
+    _metric_tables.append(_pending_metrics_tblname)
+
+  _args.output_file.write(
+      f'static const struct compact_pmu_event {_pending_metrics_tblname}[] = {{\n')
+
+  for metric in sorted(_pending_metrics, key=metric_cmp_key):
+    _args.output_file.write(metric.to_c_string(metric=True))
+  _pending_metrics = []
+
+  _args.output_file.write('};\n\n')
+
 def get_topic(topic: str) -> str:
   if topic.endswith('metrics.json'):
     return 'metrics'
@@ -430,12 +487,13 @@ def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
 
   topic = get_topic(item.name)
   for event in read_json_events(item.path, topic):
-    _bcs.add(event.build_c_string())
+    if event.name:
+      _bcs.add(event.build_c_string(metric=False))
+    if event.metric_name:
+      _bcs.add(event.build_c_string(metric=True))
 
 def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   """Process a JSON file during the main walk."""
-  global _sys_event_tables
-
   def is_leaf_dir(path: str) -> bool:
     for item in os.scandir(path):
       if item.is_dir():
@@ -445,12 +503,15 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
   # model directory, reset topic
   if item.is_dir() and is_leaf_dir(item.path):
     print_pending_events()
+    print_pending_metrics()
 
-    tblname = file_name_to_table_name(parents, item.name)
-    if item.name == 'sys':
-      _sys_event_tables.append(tblname)
     global _pending_events_tblname
-    _pending_events_tblname = tblname
+    _pending_events_tblname = file_name_to_table_name('pmu_events_', parents, item.name)
+    global _pending_metrics_tblname
+    _pending_metrics_tblname = file_name_to_table_name('pmu_metrics_', parents, item.name)
+
+    if item.name == 'sys':
+      _sys_event_table_to_metric_table_mapping[_pending_events_tblname] = _pending_metrics_tblname
     return
 
   # base dir or too deep
@@ -475,6 +536,12 @@ struct pmu_events_table {
         size_t length;
 };
 
+/* Struct used to make the PMU metric table implementation opaque to callers. */
+struct pmu_metrics_table {
+        const struct compact_pmu_event *entries;
+        size_t length;
+};
+
 /*
  * 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.
@@ -486,7 +553,8 @@ struct pmu_events_table {
 struct pmu_events_map {
         const char *arch;
         const char *cpuid;
-        struct pmu_events_table table;
+        struct pmu_events_table event_table;
+        struct pmu_metrics_table metric_table;
 };
 
 /*
@@ -500,9 +568,13 @@ const struct pmu_events_map pmu_events_map[] = {
       _args.output_file.write("""{
 \t.arch = "testarch",
 \t.cpuid = "testcpu",
-\t.table = {
-\t.entries = pme_test_soc_cpu,
-\t.length = ARRAY_SIZE(pme_test_soc_cpu),
+\t.event_table = {
+\t\t.entries = pmu_events__test_soc_cpu,
+\t\t.length = ARRAY_SIZE(pmu_events__test_soc_cpu),
+\t},
+\t.metric_table = {
+\t\t.entries = pmu_metrics__test_soc_cpu,
+\t\t.length = ARRAY_SIZE(pmu_metrics__test_soc_cpu),
 \t}
 },
 """)
@@ -513,14 +585,29 @@ const struct pmu_events_map pmu_events_map[] = {
         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('/', '_'))
+            event_tblname = file_name_to_table_name('pmu_events_', [], row[2].replace('/', '_'))
+            if event_tblname in _event_tables:
+              event_size = f'ARRAY_SIZE({event_tblname})'
+            else:
+              event_tblname = 'NULL'
+              event_size = '0'
+            metric_tblname = file_name_to_table_name('pmu_metrics_', [], row[2].replace('/', '_'))
+            if metric_tblname in _metric_tables:
+              metric_size = f'ARRAY_SIZE({metric_tblname})'
+            else:
+              metric_tblname = 'NULL'
+              metric_size = '0'
             cpuid = row[0].replace('\\', '\\\\')
             _args.output_file.write(f"""{{
 \t.arch = "{arch}",
 \t.cpuid = "{cpuid}",
-\t.table = {{
-\t\t.entries = {tblname},
-\t\t.length = ARRAY_SIZE({tblname})
+\t.event_table = {{
+\t\t.entries = {event_tblname},
+\t\t.length = {event_size}
+\t}},
+\t.metric_table = {{
+\t\t.entries = {metric_tblname},
+\t\t.length = {metric_size}
 \t}}
 }},
 """)
@@ -529,7 +616,8 @@ const struct pmu_events_map pmu_events_map[] = {
   _args.output_file.write("""{
 \t.arch = 0,
 \t.cpuid = 0,
-\t.table = { 0, 0 },
+\t.event_table = { 0, 0 },
+\t.metric_table = { 0, 0 },
 }
 };
 """)
@@ -540,14 +628,36 @@ def print_system_mapping_table() -> None:
   _args.output_file.write("""
 struct pmu_sys_events {
 \tconst char *name;
-\tstruct pmu_events_table table;
+\tstruct pmu_events_table event_table;
+\tstruct pmu_metrics_table metric_table;
 };
 
 static const struct pmu_sys_events pmu_sys_event_tables[] = {
 """)
+  printed_metric_tables = []
   for tblname in _sys_event_tables:
     _args.output_file.write(f"""\t{{
-\t\t.table = {{
+\t\t.event_table = {{
+\t\t\t.entries = {tblname},
+\t\t\t.length = ARRAY_SIZE({tblname})
+\t\t}},""")
+    metric_tblname = _sys_event_table_to_metric_table_mapping[tblname]
+    if metric_tblname in _sys_metric_tables:
+      _args.output_file.write(f"""
+\t\t.metric_table = {{
+\t\t\t.entries = {metric_tblname},
+\t\t\t.length = ARRAY_SIZE({metric_tblname})
+\t\t}},""")
+      printed_metric_tables.append(metric_tblname)
+    _args.output_file.write(f"""
+\t\t.name = \"{tblname}\",
+\t}},
+""")
+  for tblname in _sys_metric_tables:
+    if tblname in printed_metric_tables:
+      continue
+    _args.output_file.write(f"""\t{{
+\t\t.metric_table = {{
 \t\t\t.entries = {tblname},
 \t\t\t.length = ARRAY_SIZE({tblname})
 \t\t}},
@@ -555,7 +665,8 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
 \t}},
 """)
   _args.output_file.write("""\t{
-\t\t.table = { 0, 0 }
+\t\t.event_table = { 0, 0 },
+\t\t.metric_table = { 0, 0 },
 \t},
 };
 
@@ -564,10 +675,7 @@ static void decompress_event(int offset, struct pmu_event *pe)
 \tconst char *p = &big_c_string[offset];
 """)
   for attr in _json_event_attributes:
-    if attr in _json_metric_attributes and 'metric_' in attr:
-      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
-    else:
-      _args.output_file.write(f"""
+    _args.output_file.write(f"""
 \tpe->{attr} = (*p == '\\0' ? NULL : p);
 """)
     if attr == _json_event_attributes[-1]:
@@ -579,14 +687,11 @@ static void decompress_metric(int offset, struct pmu_metric *pm)
 {
 \tconst char *p = &big_c_string[offset];
 """)
-  for attr in _json_event_attributes:
-    if attr in _json_metric_attributes:
-      _args.output_file.write(f"""
+  for attr in _json_metric_attributes:
+    _args.output_file.write(f"""
 \tpm->{attr} = (*p == '\\0' ? NULL : p);
 """)
-    else:
-      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
-    if attr == _json_event_attributes[-1]:
+    if attr == _json_metric_attributes[-1]:
       continue
     _args.output_file.write('\twhile (*p++);')
   _args.output_file.write("""}
@@ -609,19 +714,17 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
         return 0;
 }
 
-int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *mtable,
+int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *table,
                                      pmu_metric_iter_fn fn,
                                      void *data)
 {
-        struct pmu_events_table *table = (struct pmu_events_table *)mtable;
-
         for (size_t i = 0; i < table->length; i++) {
                 struct pmu_metric pm;
                 int ret;
 
                 decompress_metric(table->entries[i].offset, &pm);
                 if (pm.metric_name) {
-                        ret = fn(&pm, mtable, data);
+                        ret = fn(&pm, table, data);
                         if (ret)
                                 return ret;
                 }
@@ -648,7 +751,7 @@ const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
                         break;
 
                 if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
-                        table = &map->table;
+                        table = &map->event_table;
                         break;
                 }
         }
@@ -658,7 +761,29 @@ const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
 
 const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
 {
-        return (struct pmu_metrics_table *)perf_pmu__find_events_table(pmu);
+        const struct pmu_metrics_table *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->arch)
+                        break;
+
+                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+                        table = &map->metric_table;
+                        break;
+                }
+        }
+        free(cpuid);
+        return table;
 }
 
 const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
@@ -667,14 +792,20 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
              tables->arch;
              tables++) {
                 if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
-                        return &tables->table;
+                        return &tables->event_table;
         }
         return NULL;
 }
 
 const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
 {
-       return (struct pmu_metrics_table *)find_core_events_table(arch, cpuid);
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->arch;
+             tables++) {
+                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+                        return &tables->metric_table;
+        }
+        return NULL;
 }
 
 int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
@@ -682,7 +813,7 @@ 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->arch;
              tables++) {
-                int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
+                int ret = pmu_events_table_for_each_event(&tables->event_table, fn, data);
 
                 if (ret)
                         return ret;
@@ -695,8 +826,7 @@ int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
         for (const struct pmu_events_map *tables = &pmu_events_map[0];
              tables->arch;
              tables++) {
-                int ret = pmu_metrics_table_for_each_metric(
-                                (struct pmu_metrics_table *)&tables->table, fn, data);
+                int ret = pmu_metrics_table_for_each_metric(&tables->metric_table, fn, data);
 
                 if (ret)
                         return ret;
@@ -710,7 +840,7 @@ const struct pmu_events_table *find_sys_events_table(const char *name)
              tables->name;
              tables++) {
                 if (!strcmp(tables->name, name))
-                        return &tables->table;
+                        return &tables->event_table;
         }
         return NULL;
 }
@@ -720,7 +850,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->event_table, fn, data);
 
                 if (ret)
                         return ret;
@@ -733,8 +863,7 @@ int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data)
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
              tables->name;
              tables++) {
-                int ret = pmu_metrics_table_for_each_metric(
-                                (struct pmu_metrics_table *)&tables->table, fn, data);
+                int ret = pmu_metrics_table_for_each_metric(&tables->metric_table, fn, data);
 
                 if (ret)
                         return ret;
@@ -809,6 +938,7 @@ struct compact_pmu_event {
     arch_path = f'{_args.starting_dir}/{arch}'
     ftw(arch_path, [], process_one_file)
     print_pending_events()
+    print_pending_metrics()
 
   print_mapping_table(archs)
   print_system_mapping_table()
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 9f2e385e0991..962c3c0d53ba 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -469,7 +469,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_events_table *sys_event_table = find_sys_events_table("pme_test_soc_sys");
+	const struct pmu_events_table *sys_event_table =
+		find_sys_events_table("pmu_events__test_soc_sys");
 	const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
 	int map_events = 0, expected_events, err;
 
-- 
2.39.0.314.g84b9a713c41-goog


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

* [PATCH v2 9/9] perf jevents: Add model list option
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (7 preceding siblings ...)
  2022-12-21 22:34 ` [PATCH v2 8/9] perf jevents: Generate metrics and events as separate tables Ian Rogers
@ 2022-12-21 22:34 ` Ian Rogers
  2023-01-19 15:54 ` [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
  2023-01-23 13:25 ` John Garry
  10 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2022-12-21 22:34 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Ian Rogers, Perry Taylor, Caleb Biggers, Stephane Eranian

This allows the set of generated jevents events and metrics be limited
to a subset of the model names. Appropriate if trying to minimize the
binary size where only a set of models are possible.

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

diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
index 15b9e8fdbffa..a14de24ecb69 100644
--- a/tools/perf/pmu-events/Build
+++ b/tools/perf/pmu-events/Build
@@ -10,6 +10,7 @@ JEVENTS_PY	=  pmu-events/jevents.py
 ifeq ($(JEVENTS_ARCH),)
 JEVENTS_ARCH=$(SRCARCH)
 endif
+JEVENTS_MODEL ?= all
 
 #
 # Locate/process JSON files in pmu-events/arch/
@@ -23,5 +24,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) pmu-events/metric.py
 	$(call rule_mkdir)
-	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
+	$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) $(JEVENTS_MODEL) pmu-events/arch $@
 endif
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index c98443319145..e9eba51e8557 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -886,12 +886,16 @@ def main() -> None:
           action: Callable[[Sequence[str], os.DirEntry], None]) -> None:
     """Replicate the directory/file walking behavior of C's file tree walk."""
     for item in os.scandir(path):
+      if (len(parents) == 0 and item.is_dir() and _args.model != 'all' and
+          'test' not in item.name and item.name not in _args.model.split(',')):
+        continue
       action(parents, item)
       if item.is_dir():
         ftw(item.path, parents + [item.name], action)
 
   ap = argparse.ArgumentParser()
   ap.add_argument('arch', help='Architecture name like x86')
+  ap.add_argument('model', help='Model such as skylake, normally "all"', default='all')
   ap.add_argument(
       'starting_dir',
       type=dir_path,
-- 
2.39.0.314.g84b9a713c41-goog


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

* Re: [PATCH v2 0/9] jevents/pmu-events improvements
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (8 preceding siblings ...)
  2022-12-21 22:34 ` [PATCH v2 9/9] perf jevents: Add model list option Ian Rogers
@ 2023-01-19 15:54 ` Ian Rogers
  2023-01-23 13:25 ` John Garry
  10 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2023-01-19 15:54 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Perry Taylor, Caleb Biggers, Stephane Eranian

On Wed, Dec 21, 2022 at 2:34 PM Ian Rogers <irogers@google.com> wrote:
>
> Add an optimization to jevents using the metric code, rewrite metrics
> in terms of each other in order to minimize size and improve
> readability. For example, on Power8
> other_stall_cpi is rewritten from:
> "PM_CMPLU_STALL / PM_RUN_INST_CMPL - PM_CMPLU_STALL_BRU_CRU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_FXU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_VSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_LSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NTCG_FLUSH / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NO_NTF / PM_RUN_INST_CMPL"
> to:
> "stall_cpi - bru_cru_stall_cpi - fxu_stall_cpi - vsu_stall_cpi - lsu_stall_cpi - ntcg_flush_cpi - no_ntf_stall_cpi"
> Which more closely matches the definition on Power9.
>
> A limitation of the substitutions are that they depend on strict
> equality and the shape of the tree. This means that for "a + b + c"
> then a substitution of "a + b" will succeed while "b + c" will fail
> (the LHS for "+ c" is "a + b" not just "b").
>
> Separate out the events and metrics in the pmu-events tables saving
> 14.8% in the table size while making it that metrics no longer need to
> iterate over all events and vice versa. These changes remove evsel's
> direct metric support as the pmu_event no longer has a metric to
> populate it. This is a minor issue as the code wasn't working
> properly, metrics for this are rare and can still be properly ran
> using '-M'.
>
> Add an ability to just build certain models into the jevents generated
> pmu-metrics.c code. This functionality is appropriate for operating
> systems like ChromeOS, that aim to minimize binary size and know all
> the target CPU models.
>
> v2. Rebase. Modify the code that skips rewriting a metric with the
>     same name with itself, to make the name check case insensitive.
>
> Ian Rogers (9):
>   perf jevents metric: Correct Function equality
>   perf jevents metric: Add ability to rewrite metrics in terms of others
>   perf jevents: Rewrite metrics in the same file with each other
>   perf pmu-events: Separate metric out of pmu_event
>   perf stat: Remove evsel metric_name/expr
>   perf jevents: Combine table prefix and suffix writing
>   perf pmu-events: Introduce pmu_metrics_table
>   perf jevents: Generate metrics and events as separate tables
>   perf jevents: Add model list option

Ping. Looking for reviews.

Thanks,
Ian

>  tools/perf/arch/arm64/util/pmu.c         |  23 +-
>  tools/perf/arch/powerpc/util/header.c    |   4 +-
>  tools/perf/builtin-list.c                |  20 +-
>  tools/perf/builtin-stat.c                |   1 -
>  tools/perf/pmu-events/Build              |   3 +-
>  tools/perf/pmu-events/empty-pmu-events.c | 111 ++++++-
>  tools/perf/pmu-events/jevents.py         | 353 ++++++++++++++++++-----
>  tools/perf/pmu-events/metric.py          |  79 ++++-
>  tools/perf/pmu-events/metric_test.py     |  10 +
>  tools/perf/pmu-events/pmu-events.h       |  26 +-
>  tools/perf/tests/expand-cgroup.c         |   4 +-
>  tools/perf/tests/parse-metric.c          |   4 +-
>  tools/perf/tests/pmu-events.c            |  68 ++---
>  tools/perf/util/cgroup.c                 |   1 -
>  tools/perf/util/evsel.c                  |   2 -
>  tools/perf/util/evsel.h                  |   2 -
>  tools/perf/util/metricgroup.c            | 203 +++++++------
>  tools/perf/util/metricgroup.h            |   4 +-
>  tools/perf/util/parse-events.c           |   2 -
>  tools/perf/util/pmu.c                    |  44 +--
>  tools/perf/util/pmu.h                    |  10 +-
>  tools/perf/util/print-events.c           |  32 +-
>  tools/perf/util/print-events.h           |   3 +-
>  tools/perf/util/python.c                 |   7 -
>  tools/perf/util/stat-shadow.c            | 112 -------
>  tools/perf/util/stat.h                   |   1 -
>  26 files changed, 666 insertions(+), 463 deletions(-)
>
> --
> 2.39.0.314.g84b9a713c41-goog
>

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

* Re: [PATCH v2 0/9] jevents/pmu-events improvements
  2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
                   ` (9 preceding siblings ...)
  2023-01-19 15:54 ` [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
@ 2023-01-23 13:25 ` John Garry
  2023-01-24  5:04   ` Ian Rogers
  10 siblings, 1 reply; 20+ messages in thread
From: John Garry @ 2023-01-23 13:25 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Perry Taylor, Caleb Biggers, Stephane Eranian

On 21/12/2022 22:34, Ian Rogers wrote:
> Add an optimization to jevents using the metric code, rewrite metrics
> in terms of each other in order to minimize size and improve
> readability. For example, on Power8
> other_stall_cpi is rewritten from:
> "PM_CMPLU_STALL / PM_RUN_INST_CMPL - PM_CMPLU_STALL_BRU_CRU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_FXU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_VSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_LSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NTCG_FLUSH / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NO_NTF / PM_RUN_INST_CMPL"
> to:
> "stall_cpi - bru_cru_stall_cpi - fxu_stall_cpi - vsu_stall_cpi - lsu_stall_cpi - ntcg_flush_cpi - no_ntf_stall_cpi"
> Which more closely matches the definition on Power9.
> 
> A limitation of the substitutions are that they depend on strict
> equality and the shape of the tree. This means that for "a + b + c"
> then a substitution of "a + b" will succeed while "b + c" will fail
> (the LHS for "+ c" is "a + b" not just "b").
> 
> Separate out the events and metrics in the pmu-events tables saving
> 14.8% in the table size while making it that metrics no longer need to
> iterate over all events and vice versa. These changes remove evsel's
> direct metric support as the pmu_event no longer has a metric to
> populate it. This is a minor issue as the code wasn't working
> properly, metrics for this are rare and can still be properly ran
> using '-M'.
> 
> Add an ability to just build certain models into the jevents generated
> pmu-metrics.c code. This functionality is appropriate for operating
> systems like ChromeOS, that aim to minimize binary size and know all
> the target CPU models.

 From a glance, this does not look like it would work for arm64. As I 
see in the code, we check the model in the arch folder for the test to 
see if built. For arm64, as it uses arch/implementator/model folder org, 
and not just arch/model (like x86)

So on the assumption that it does not work for arm64 (or just any arch 
which uses arch/implementator/model folder org), it would be nice to 
have that feature also. Or maybe also support not just specifying model 
but also implementator.

> 
> v2. Rebase. Modify the code that skips rewriting a metric with the
>      same name with itself, to make the name check case insensitive.
> 


Unfortunately you might need another rebase as this does not apply to 
acme perf/core (if that is what you want), now for me at:

5670ebf54bd2 (HEAD, origin/tmp.perf/core, origin/perf/core, perf/core)
perf cs-etm: Ensure that Coresight timestamps don't go backwards

> Ian Rogers (9):
>    perf jevents metric: Correct Function equality
>    perf jevents metric: Add ability to rewrite metrics in terms of others
>    perf jevents: Rewrite metrics in the same file with each other
>    perf pmu-events: Separate metric out of pmu_event
>    perf stat: Remove evsel metric_name/expr
>    perf jevents: Combine table prefix and suffix writing
>    perf pmu-events: Introduce pmu_metrics_table
>    perf jevents: Generate metrics and events as separate tables
>    perf jevents: Add model list option

Thanks,
John

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

* Re: [PATCH v2 5/9] perf stat: Remove evsel metric_name/expr
  2022-12-21 22:34 ` [PATCH v2 5/9] perf stat: Remove evsel metric_name/expr Ian Rogers
@ 2023-01-23 14:42   ` John Garry
  0 siblings, 0 replies; 20+ messages in thread
From: John Garry @ 2023-01-23 14:42 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Perry Taylor, Caleb Biggers, Stephane Eranian

On 21/12/2022 22:34, Ian Rogers wrote:
> Metrics are their own unit and these variables held broken metrics
> previously and now just hold the value NULL. Remove code that used
> these variables.
> 
> Signed-off-by: Ian Rogers<irogers@google.com>

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

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

* Re: [PATCH v2 4/9] perf pmu-events: Separate metric out of pmu_event
  2022-12-21 22:34 ` [PATCH v2 4/9] perf pmu-events: Separate metric out of pmu_event Ian Rogers
@ 2023-01-23 15:15   ` John Garry
  2023-01-24  4:39     ` Ian Rogers
  0 siblings, 1 reply; 20+ messages in thread
From: John Garry @ 2023-01-23 15: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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Perry Taylor, Caleb Biggers, Stephane Eranian

On 21/12/2022 22:34, Ian Rogers wrote:
> Previously both events and metrics were encoded in struct
> pmu_event. Create a new pmu_metric that has the metric related
> variables and remove these from pmu_event. Add iterators for
> pmu_metric and use in places that metrics are desired rather than
> events.
> 
> Note, this change removes the setting of evsel's metric_name/expr as
> these fields are no longer part of struct pmu_event. The metric
> remains but is no longer implicitly requested when the event is. This
> impacts a few Intel uncore events, however, as the ScaleUnit is shared
> by the event and the metric this utility is questionable. Also the
> MetricNames look broken (contain spaces) in some cases and when trying
> to use the functionality with '-e' the metrics fail but regular
> metrics with '-M' work. For example, on SkylakeX '-M' works:
> 

I like this change. It's quite large for a single patch. Just some 
sparse comments below.

BTW, it there a better name for metric struct variable than "pm"? To me 
and many other people, pm is power management.

> ```
> $ perf stat -M LLC_MISSES.PCIE_WRITE -a sleep 1
> 
>   Performance counter stats for 'system wide':
> 
>                   0      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 #  57896.0 Bytes  LLC_MISSES.PCIE_WRITE  (49.84%)
>               7,174      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1                                        (49.85%)
>                   0      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3                                        (50.16%)
>                  63      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0                                        (50.15%)
> 
>         1.004576381 seconds time elapsed
> ```
> 
> whilst the event '-e' version is broken even with --group/-g (fwiw, we should also remove -g [1]):
> 
> ```
> $ perf stat -g -e LLC_MISSES.PCIE_WRITE -g -a sleep 1
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> 
>   Performance counter stats for 'system wide':
> 
>              27,316 Bytes LLC_MISSES.PCIE_WRITE
> 
>         1.004505469 seconds time elapsed
> ```
> 
> The code also carries warnings where the user is supposed to select
> events for metrics [2] but given the lack of use of such a feature,
> let's clean the code and just remove.
> 
> With NO_JEVENTS=1 the empty-pmu-events.c is used and the separation to
> use metrics causes "Parse and process metrics" and "Event expansion
> for cgroups" to fail as they fail to find necessary metrics. This is
> fixed in a later change.
> 
> [1] https://urldefense.com/v3/__https://lore.kernel.org/lkml/20220707195610.303254-1-irogers@google.com/__;!!ACWV5N9M2RV99hQ!MTNgf7sIIl2VCxBzo-biSeul-ZQkuU73pT6gBbsb6y0AqsVlgGCcmuigDyevtrgmpHDN1QkEJwbJYvREu3Q$
> [2] https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/util/stat-shadow.c?id=01b8957b738f42f96a130079bc951b3cc78c5b8a*n425__;Iw!!ACWV5N9M2RV99hQ!MTNgf7sIIl2VCxBzo-biSeul-ZQkuU73pT6gBbsb6y0AqsVlgGCcmuigDyevtrgmpHDN1QkEJwbJ8H0tppQ$
> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/arch/powerpc/util/header.c    |   4 +-
>   tools/perf/builtin-list.c                |  20 +--
>   tools/perf/pmu-events/empty-pmu-events.c |  73 ++++++++--
>   tools/perf/pmu-events/jevents.py         |  82 +++++++++++-
>   tools/perf/pmu-events/pmu-events.h       |  20 ++-
>   tools/perf/tests/pmu-events.c            |  62 +++------
>   tools/perf/util/metricgroup.c            | 161 +++++++++++------------
>   tools/perf/util/metricgroup.h            |   2 +-
>   tools/perf/util/parse-events.c           |   2 -
>   tools/perf/util/pmu.c                    |  35 +----
>   tools/perf/util/pmu.h                    |   9 --
>   tools/perf/util/print-events.c           |  32 ++---
>   tools/perf/util/print-events.h           |   3 +-
>   13 files changed, 266 insertions(+), 239 deletions(-)
> 
> diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
> index e8fe36b10d20..78eef77d8a8d 100644
> --- a/tools/perf/arch/powerpc/util/header.c
> +++ b/tools/perf/arch/powerpc/util/header.c
> @@ -40,11 +40,11 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
>   	return bufp;
>   }
>   
> -int arch_get_runtimeparam(const struct pmu_event *pe)
> +int arch_get_runtimeparam(const struct pmu_metric *pm)
>   {
>   	int count;
>   	char path[PATH_MAX] = "/devices/hv_24x7/interface/";
>   
> -	atoi(pe->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
> +	atoi(pm->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
>   	return sysfs__read_int(path, &count) < 0 ? 1 : count;
>   }
> diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
> index 137d73edb541..791f513ae5b4 100644
> --- a/tools/perf/builtin-list.c
> +++ b/tools/perf/builtin-list.c
> @@ -99,8 +99,7 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
>   				const char *scale_unit __maybe_unused,
>   				bool deprecated, const char *event_type_desc,
>   				const char *desc, const char *long_desc,
> -				const char *encoding_desc,
> -				const char *metric_name, const char *metric_expr)
> +				const char *encoding_desc)
>   {
>   	struct print_state *print_state = ps;
>   	int pos;
> @@ -159,10 +158,6 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
>   	if (print_state->detailed && encoding_desc) {
>   		printf("%*s", 8, "");
>   		wordwrap(encoding_desc, 8, pager_get_columns(), 0);
> -		if (metric_name)
> -			printf(" MetricName: %s", metric_name);
> -		if (metric_expr)
> -			printf(" MetricExpr: %s", metric_expr);
>   		putchar('\n');
>   	}
>   }
> @@ -308,8 +303,7 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic,
>   			     const char *scale_unit,
>   			     bool deprecated, const char *event_type_desc,
>   			     const char *desc, const char *long_desc,
> -			     const char *encoding_desc,
> -			     const char *metric_name, const char *metric_expr)
> +			     const char *encoding_desc)
>   {
>   	struct json_print_state *print_state = ps;
>   	bool need_sep = false;
> @@ -366,16 +360,6 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic,
>   				  encoding_desc);
>   		need_sep = true;
>   	}
> -	if (metric_name) {
> -		fix_escape_printf(&buf, "%s\t\"MetricName\": \"%S\"", need_sep ? ",\n" : "",
> -				  metric_name);
> -		need_sep = true;
> -	}
> -	if (metric_expr) {
> -		fix_escape_printf(&buf, "%s\t\"MetricExpr\": \"%S\"", need_sep ? ",\n" : "",
> -				  metric_expr);
> -		need_sep = true;
> -	}
>   	printf("%s}", need_sep ? "\n" : "");
>   	strbuf_release(&buf);
>   }
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 480e8f0d30c8..5572a4d1eddb 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -11,7 +11,7 @@
>   #include <string.h>
>   #include <stddef.h>
>   
> -static const struct pmu_event pme_test_soc_cpu[] = {
> +static const struct pmu_event pmu_events__test_soc_cpu[] = {
>   	{
>   		.name = "l3_cache_rd",
>   		.event = "event=0x40",
> @@ -105,6 +105,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
>   		.desc = "L2 BTB Correction",
>   		.topic = "branch",
>   	},
> +	{
> +		.name = 0,
> +		.event = 0,
> +		.desc = 0,
> +	},
> +};
> +
> +static const struct pmu_metric pmu_metrics__test_soc_cpu[] = {
>   	{
>   		.metric_expr	= "1 / IPC",
>   		.metric_name	= "CPI",
> @@ -170,9 +178,8 @@ static const struct pmu_event pme_test_soc_cpu[] = {
>   		.metric_name	= "L1D_Cache_Fill_BW",
>   	},
>   	{
> -		.name = 0,
> -		.event = 0,
> -		.desc = 0,
> +		.metric_expr = 0,
> +		.metric_name = 0,
>   	},
>   };
>   
> @@ -181,6 +188,11 @@ struct pmu_events_table {
>   	const struct pmu_event *entries;
>   };
>   
> +/* Struct used to make the PMU metric table implementation opaque to callers. */
> +struct pmu_metrics_table {
> +	const struct pmu_metric *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.
> @@ -192,7 +204,8 @@ struct pmu_events_table {
>   struct pmu_events_map {
>   	const char *arch;
>   	const char *cpuid;
> -	const struct pmu_events_table table;
> +	const struct pmu_events_table event_table;
> +	const struct pmu_metrics_table metric_table;
>   };
>   
>   /*
> @@ -203,12 +216,14 @@ static const struct pmu_events_map pmu_events_map[] = {
>   	{
>   		.arch = "testarch",
>   		.cpuid = "testcpu",
> -		.table = { pme_test_soc_cpu },
> +		.event_table = { pmu_events__test_soc_cpu },
> +		.metric_table = { pmu_metrics__test_soc_cpu },
>   	},
>   	{
>   		.arch = 0,
>   		.cpuid = 0,
> -		.table = { 0 },
> +		.event_table = { 0 },
> +		.metric_table = { 0 },
>   	},
>   };
>   
> @@ -254,9 +269,7 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   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++) {
> +	for (const struct pmu_event *pe = &table->entries[0]; pe->name; pe++) {
>   		int ret = fn(pe, table, data);
>   
>   		if (ret)
> @@ -265,6 +278,21 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_ev
>   	return 0;
>   }
>   
> +int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_metric_iter_fn fn,
> +				     void *data)
> +{
> +	struct pmu_metrics_table *table = (struct pmu_metrics_table *)etable;

This is odd. Would the change be too big if we combined patches to avoid 
casting like this? I assume that this is going away later...

> +
> +	for (const struct pmu_metric *pm = &table->entries[0]; pm->metric_group || pm->metric_name;

Is it valid to only have metric_group or metric_name set?

> +	     pm++) {
> +		int ret = fn(pm, etable, data);
> +
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
>   const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
>   {
>   	const struct pmu_events_table *table = NULL;
> @@ -285,7 +313,7 @@ const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
>   			break;
>   
>   		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> -			table = &map->table;
> +			table = &map->event_table;
>   			break;
>   		}
>   	}
> @@ -299,7 +327,7 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
>   	     tables->arch;
>   	     tables++) {
>   		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> -			return &tables->table;
> +			return &tables->event_table;
>   	}
>   	return NULL;
>   }
> @@ -309,7 +337,21 @@ 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->arch;
>   	     tables++) {
> -		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
> +		int ret = pmu_events_table_for_each_event(&tables->event_table, fn, data);
> +
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
> +int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
> +{
> +	for (const struct pmu_events_map *tables = &pmu_events_map[0];
> +	     tables->arch;
> +	     tables++) {

again, you can combine here

> +		int ret = pmu_events_table_for_each_metric(
> +			(const struct pmu_events_table *)&tables->metric_table, fn, data);
>   
>   		if (ret)
>   			return ret;
> @@ -340,3 +382,8 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
>   	}
>   	return 0;
>   }
> +
> +int pmu_for_each_sys_metric(pmu_metric_iter_fn fn __maybe_unused, void *data __maybe_unused)
> +{
> +	return 0;
> +}
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 229402565425..ee3d4cdf01be 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -37,6 +37,11 @@ _json_event_attributes = [
>       'metric_constraint', 'metric_expr', 'long_desc'
>   ]
>   
> +# Attributes that are in pmu_metric rather than pmu_event.
> +_json_metric_attributes = [
> +    'metric_name', 'metric_group', 'metric_constraint', 'metric_expr', 'desc',
> +    'long_desc', 'unit', 'compat', 'aggr_mode'
> +]
>   
>   def removesuffix(s: str, suffix: str) -> str:
>     """Remove the suffix from a string
> @@ -562,12 +567,15 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>   \t},
>   };
>   
> -static void decompress(int offset, struct pmu_event *pe)
> +static void decompress_event(int offset, struct pmu_event *pe)
>   {
>   \tconst char *p = &big_c_string[offset];
>   """)
>     for attr in _json_event_attributes:
> -    _args.output_file.write(f"""
> +    if attr in _json_metric_attributes and 'metric_' in attr:
> +      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
> +    else:
> +      _args.output_file.write(f"""
>   \tpe->{attr} = (*p == '\\0' ? NULL : p);
>   """)
>       if attr == _json_event_attributes[-1]:
> @@ -575,6 +583,22 @@ static void decompress(int offset, struct pmu_event *pe)
>       _args.output_file.write('\twhile (*p++);')
>     _args.output_file.write("""}
>   
> +static void decompress_metric(int offset, struct pmu_metric *pm)
> +{
> +\tconst char *p = &big_c_string[offset];
> +""")
> +  for attr in _json_event_attributes:
> +    if attr in _json_metric_attributes:
> +      _args.output_file.write(f"""
> +\tpm->{attr} = (*p == '\\0' ? NULL : p);
> +""")
> +    else:
> +      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
> +    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)
> @@ -583,10 +607,30 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
>                   struct pmu_event pe;
>                   int ret;
>   
> -                decompress(table->entries[i].offset, &pe);
> -                ret = fn(&pe, table, data);
> -                if (ret)
> -                        return ret;
> +                decompress_event(table->entries[i].offset, &pe);
> +                if (pe.name) {
> +                        ret = fn(&pe, table, data);
> +                        if (ret)
> +                                return ret;
> +                }
> +        }
> +        return 0;
> +}
> +
> +int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
> +                                     pmu_metric_iter_fn fn,
> +                                     void *data)
> +{
> +        for (size_t i = 0; i < table->length; i++) {
> +                struct pmu_metric pm;
> +                int ret;
> +
> +                decompress_metric(table->entries[i].offset, &pm);
> +                if (pm.metric_name) {
> +                        ret = fn(&pm, table, data);
> +                        if (ret)
> +                                return ret;
> +                }
>           }
>           return 0;
>   }
> @@ -642,6 +686,19 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
>           return 0;
>   }
>   
> +int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
> +{
> +        for (const struct pmu_events_map *tables = &pmu_events_map[0];
> +             tables->arch;
> +             tables++) {
> +                int ret = pmu_events_table_for_each_metric(&tables->table, fn, data);
> +
> +                if (ret)
> +                        return ret;
> +        }
> +        return 0;
> +}
> +
>   const struct pmu_events_table *find_sys_events_table(const char *name)
>   {
>           for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> @@ -665,6 +722,19 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
>           }
>           return 0;
>   }
> +
> +int pmu_for_each_sys_metric(pmu_metric_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_metric(&tables->table, fn, data);
> +
> +                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 fe343c4d8016..e137f3857c03 100644
> --- a/tools/perf/pmu-events/pmu-events.h
> +++ b/tools/perf/pmu-events/pmu-events.h
> @@ -23,11 +23,19 @@ struct pmu_event {
>   	const char *unit;
>   	const char *perpkg;
>   	const char *aggr_mode;
> -	const char *metric_expr;
> +	const char *deprecated;
> +};
> +
> +struct pmu_metric {

In terms of formatting patches, it could have been better to first 
introdue struct pmu_metric being same as struct pmu_event, and make the 
changes of /s/struct pmu_event pe;/struct pmu_event pm;/, and then 
secondly the meaningful change to get rid of the inappropiate members in 
struct pmu_metric and struct pmu_event. It's just harder to review it 
all together.

>   	const char *metric_name;
>   	const char *metric_group;
> -	const char *deprecated;
> +	const char *metric_expr;

I would prefer the shorter name "expr" (as opposed to "metric_expr") as 
we know it's a metric struct already. But that does not seem to be 
coding style, so ...

> +	const char *unit;
> +	const char *compat;
> +	const char *aggr_mode;
>   	const char *metric_constraint;
> +	const char *desc;
> +	const char *long_desc;
>   };
>   
>   struct pmu_events_table;
> @@ -36,14 +44,22 @@ typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
>   				 const struct pmu_events_table *table,
>   				 void *data);
>   
> +typedef int (*pmu_metric_iter_fn)(const struct pmu_metric *pm,
> +				  const struct pmu_events_table *table,
> +				  void *data);
> +
>   int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
>   				    void *data);
> +int pmu_events_table_for_each_metric(const struct pmu_events_table *table, pmu_metric_iter_fn fn,
> +				     void *data);
>   
>   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);
> +int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data);
>   
>   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);
> +int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data);
>   
>   #endif
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index a9f2330f6257..c2b3ada57cbc 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -337,36 +337,12 @@ static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event
>   		return -1;
>   	}
>   
> -	if (!is_same(e1->metric_expr, e2->metric_expr)) {
> -		pr_debug2("testing event e1 %s: mismatched metric_expr, %s vs %s\n",
> -			  e1->name, e1->metric_expr, e2->metric_expr);
> -		return -1;

is there something new to replace this (I didn't check)?

> -	}
> -
> -	if (!is_same(e1->metric_name, e2->metric_name)) {
> -		pr_debug2("testing event e1 %s: mismatched metric_name, %s vs %s\n",
> -			  e1->name,	e1->metric_name, e2->metric_name);
> -		return -1;
> -	}
> -
> -	if (!is_same(e1->metric_group, e2->metric_group)) {
> -		pr_debug2("testing event e1 %s: mismatched metric_group, %s vs %s\n",
> -			  e1->name, e1->metric_group, e2->metric_group);
> -		return -1;
> -	}
> -
>   	if (!is_same(e1->deprecated, e2->deprecated)) {
>   		pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n",
>   			  e1->name, e1->deprecated, e2->deprecated);
>   		return -1;
>   	}
>   
> -	if (!is_same(e1->metric_constraint, e2->metric_constraint)) {
> -		pr_debug2("testing event e1 %s: mismatched metric_constant, %s vs %s\n",
> -			  e1->name, e1->metric_constraint, e2->metric_constraint);
> -		return -1;
> -	}
> -
>   	return 0;
>   }
>   
> @@ -432,9 +408,6 @@ static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
>   	struct perf_pmu_test_event const **test_event_table;
>   	bool found = false;
>   
> -	if (!pe->name)
> -		return 0;
> -
>   	if (pe->pmu)
>   		test_event_table = &uncore_events[0];
>   	else
> @@ -840,7 +813,7 @@ struct metric {
>   	struct metric_ref metric_ref;
>   };
>   
> -static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_events_table *table,
> +static int test__parsing_callback(const struct pmu_metric *pm, const struct pmu_events_table *table,
>   				  void *data)
>   {
>   	int *failures = data;
> @@ -854,10 +827,10 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
>   	};
>   	int err = 0;
>   
> -	if (!pe->metric_expr)
> +	if (!pm->metric_expr)
>   		return 0;
>   
> -	pr_debug("Found metric '%s'\n", pe->metric_name);
> +	pr_debug("Found metric '%s'\n", pm->metric_name);
>   	(*failures)++;
>   
>   	/*
> @@ -877,14 +850,14 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
>   	perf_evlist__set_maps(&evlist->core, cpus, NULL);
>   	runtime_stat__init(&st);
>   
> -	err = metricgroup__parse_groups_test(evlist, table, pe->metric_name,
> +	err = metricgroup__parse_groups_test(evlist, table, pm->metric_name,
>   					     false, false,
>   					     &metric_events);
>   	if (err) {
> -		if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") ||
> -		    !strcmp(pe->metric_name, "M3")) {
> +		if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
> +		    !strcmp(pm->metric_name, "M3")) {
>   			(*failures)--;
> -			pr_debug("Expected broken metric %s skipping\n", pe->metric_name);
> +			pr_debug("Expected broken metric %s skipping\n", pm->metric_name);
>   			err = 0;
>   		}
>   		goto out_err;
> @@ -912,7 +885,7 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
>   			struct metric_expr *mexp;
>   
>   			list_for_each_entry (mexp, &me->head, nd) {
> -				if (strcmp(mexp->metric_name, pe->metric_name))
> +				if (strcmp(mexp->metric_name, pm->metric_name))
>   					continue;
>   				pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st));
>   				err = 0;
> @@ -921,11 +894,11 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
>   			}
>   		}
>   	}
> -	pr_debug("Didn't find parsed metric %s", pe->metric_name);
> +	pr_debug("Didn't find parsed metric %s", pm->metric_name);
>   	err = 1;
>   out_err:
>   	if (err)
> -		pr_debug("Broken metric %s\n", pe->metric_name);
> +		pr_debug("Broken metric %s\n", pm->metric_name);
>   
>   	/* ... cleanup. */
>   	metricgroup__rblist_exit(&metric_events);
> @@ -941,8 +914,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
>   {
>   	int failures = 0;
>   
> -	pmu_for_each_core_event(test__parsing_callback, &failures);
> -	pmu_for_each_sys_event(test__parsing_callback, &failures);
> +	pmu_for_each_core_metric(test__parsing_callback, &failures);
> +	pmu_for_each_sys_metric(test__parsing_callback, &failures);
>   
>   	return failures == 0 ? TEST_OK : TEST_FAIL;
>   }
> @@ -1021,14 +994,11 @@ static int metric_parse_fake(const char *metric_name, const char *str)
>   	return ret;
>   }
>   
> -static int test__parsing_fake_callback(const struct pmu_event *pe,
> +static int test__parsing_fake_callback(const struct pmu_metric *pm,
>   				       const struct pmu_events_table *table __maybe_unused,
>   				       void *data __maybe_unused)
>   {
> -	if (!pe->metric_expr)
> -		return 0;
> -
> -	return metric_parse_fake(pe->metric_name, pe->metric_expr);
> +	return metric_parse_fake(pm->metric_name, pm->metric_expr);
>   }
>   
>   /*
> @@ -1047,11 +1017,11 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
>   			return err;
>   	}
>   
> -	err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
> +	err = pmu_for_each_core_metric(test__parsing_fake_callback, NULL);
>   	if (err)
>   		return err;
>   
> -	return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
> +	return pmu_for_each_sys_metric(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 b9c273ed080a..47fd02af66f1 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -167,14 +167,14 @@ static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
>   		   "    echo 1 > /proc/sys/kernel/nmi_watchdog\n");
>   }
>   
> -static bool metricgroup__has_constraint(const struct pmu_event *pe)
> +static bool metricgroup__has_constraint(const struct pmu_metric *pm)
>   {
> -	if (!pe->metric_constraint)
> +	if (!pm->metric_constraint)
>   		return false;
>   
> -	if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") &&
> +	if (!strcmp(pm->metric_constraint, "NO_NMI_WATCHDOG") &&
>   	    sysctl__nmi_watchdog_enabled()) {
> -		metricgroup___watchdog_constraint_hint(pe->metric_name, false);
> +		metricgroup___watchdog_constraint_hint(pm->metric_name, false);
>   		return true;
>   	}
>   
> @@ -193,7 +193,7 @@ static void metric__free(struct metric *m)
>   	free(m);
>   }
>   
> -static struct metric *metric__new(const struct pmu_event *pe,
> +static struct metric *metric__new(const struct pmu_metric *pm,
>   				  const char *modifier,
>   				  bool metric_no_group,
>   				  int runtime,
> @@ -210,15 +210,15 @@ static struct metric *metric__new(const struct pmu_event *pe,
>   	if (!m->pctx)
>   		goto out_err;
>   
> -	m->metric_name = pe->metric_name;
> +	m->metric_name = pm->metric_name;
>   	m->modifier = NULL;
>   	if (modifier) {
>   		m->modifier = strdup(modifier);
>   		if (!m->modifier)
>   			goto out_err;
>   	}
> -	m->metric_expr = pe->metric_expr;
> -	m->metric_unit = pe->unit;
> +	m->metric_expr = pm->metric_expr;
> +	m->metric_unit = pm->unit;
>   	m->pctx->sctx.user_requested_cpu_list = NULL;
>   	if (user_requested_cpu_list) {
>   		m->pctx->sctx.user_requested_cpu_list = strdup(user_requested_cpu_list);
> @@ -227,7 +227,7 @@ static struct metric *metric__new(const struct pmu_event *pe,
>   	}
>   	m->pctx->sctx.runtime = runtime;
>   	m->pctx->sctx.system_wide = system_wide;
> -	m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
> +	m->has_constraint = metric_no_group || metricgroup__has_constraint(pm);
>   	m->metric_refs = NULL;
>   	m->evlist = NULL;
>   
> @@ -348,10 +348,10 @@ static bool match_metric(const char *n, const char *list)
>   	return false;
>   }
>   
> -static bool match_pe_metric(const struct pmu_event *pe, const char *metric)
> +static bool match_pm_metric(const struct pmu_metric *pm, const char *metric)
>   {
> -	return match_metric(pe->metric_group, metric) ||
> -	       match_metric(pe->metric_name, metric);
> +	return match_metric(pm->metric_group, metric) ||
> +	       match_metric(pm->metric_name, metric);
>   }
>   
>   /** struct mep - RB-tree node for building printing information. */
> @@ -420,13 +420,13 @@ static struct mep *mep_lookup(struct rblist *groups, const char *metric_group,
>   	return NULL;
>   }
>   
> -static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
> +static int metricgroup__add_to_mep_groups(const struct pmu_metric *pm,
>   					struct rblist *groups)
>   {
>   	const char *g;
>   	char *omg, *mg;
>   
> -	mg = strdup(pe->metric_group ?: "No_group");
> +	mg = strdup(pm->metric_group ?: "No_group");
>   	if (!mg)
>   		return -ENOMEM;
>   	omg = mg;
> @@ -435,15 +435,15 @@ static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
>   
>   		g = skip_spaces(g);
>   		if (strlen(g))
> -			me = mep_lookup(groups, g, pe->metric_name);
> +			me = mep_lookup(groups, g, pm->metric_name);
>   		else
> -			me = mep_lookup(groups, "No_group", pe->metric_name);
> +			me = mep_lookup(groups, "No_group", pm->metric_name);
>   
>   		if (me) {
> -			me->metric_desc = pe->desc;
> -			me->metric_long_desc = pe->long_desc;
> -			me->metric_expr = pe->metric_expr;
> -			me->metric_unit = pe->unit;
> +			me->metric_desc = pm->desc;
> +			me->metric_long_desc = pm->long_desc;
> +			me->metric_expr = pm->metric_expr;

could struct pmu_metric be a sub-struct in struct mep?

> +			me->metric_unit = pm->unit;
>   		}
>   	}
>   	free(omg);
> @@ -452,40 +452,37 @@ static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
>   }
>   
>   struct metricgroup_iter_data {
> -	pmu_event_iter_fn fn;
> +	pmu_metric_iter_fn fn;
>   	void *data;
>   };
>   
> -static int metricgroup__sys_event_iter(const struct pmu_event *pe,
> +static int metricgroup__sys_event_iter(const struct pmu_metric *pm,
>   				       const struct pmu_events_table *table,
>   				       void *data)
>   {
>   	struct metricgroup_iter_data *d = data;
>   	struct perf_pmu *pmu = NULL;
>   
> -	if (!pe->metric_expr || !pe->compat)
> +	if (!pm->metric_expr || !pm->compat)
>   		return 0;
>   
>   	while ((pmu = perf_pmu__scan(pmu))) {
>   
> -		if (!pmu->id || strcmp(pmu->id, pe->compat))
> +		if (!pmu->id || strcmp(pmu->id, pm->compat))
>   			continue;
>   
> -		return d->fn(pe, table, d->data);
> +		return d->fn(pm, table, d->data);
>   	}
>   	return 0;
>   }
>   
> -static int metricgroup__add_to_mep_groups_callback(const struct pmu_event *pe,
> +static int metricgroup__add_to_mep_groups_callback(const struct pmu_metric *pm,
>   						const struct pmu_events_table *table __maybe_unused,
>   						void *vdata)
>   {
>   	struct rblist *groups = vdata;
>   
> -	if (!pe->metric_name)
> -		return 0;
> -
> -	return metricgroup__add_to_mep_groups(pe, groups);
> +	return metricgroup__add_to_mep_groups(pm, groups);
>   }
>   
>   void metricgroup__print(const struct print_callbacks *print_cb, void *print_state)
> @@ -500,16 +497,16 @@ void metricgroup__print(const struct print_callbacks *print_cb, void *print_stat
>   	groups.node_delete = mep_delete;
>   	table = pmu_events_table__find();
>   	if (table) {
> -		pmu_events_table_for_each_event(table,
> -						metricgroup__add_to_mep_groups_callback,
> -						&groups);
> +		pmu_events_table_for_each_metric(table,
> +						 metricgroup__add_to_mep_groups_callback,
> +						 &groups);
>   	}
>   	{
>   		struct metricgroup_iter_data data = {
>   			.fn = metricgroup__add_to_mep_groups_callback,
>   			.data = &groups,
>   		};
> -		pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
> +		pmu_for_each_sys_metric(metricgroup__sys_event_iter, &data);
>   	}
>   
>   	for (node = rb_first_cached(&groups.entries); node; node = next) {
> @@ -743,7 +740,7 @@ static int metricgroup__build_event_string(struct strbuf *events,
>   #undef RETURN_IF_NON_ZERO
>   }
>   
> -int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused)
> +int __weak arch_get_runtimeparam(const struct pmu_metric *pm __maybe_unused)
>   {
>   	return 1;
>   }
> @@ -773,10 +770,10 @@ struct metricgroup_add_iter_data {
>   
>   static bool metricgroup__find_metric(const char *metric,
>   				     const struct pmu_events_table *table,
> -				     struct pmu_event *pe);
> +				     struct pmu_metric *pm);
>   
>   static int add_metric(struct list_head *metric_list,
> -		      const struct pmu_event *pe,
> +		      const struct pmu_metric *pm,
>   		      const char *modifier,
>   		      bool metric_no_group,
>   		      const char *user_requested_cpu_list,
> @@ -816,10 +813,10 @@ static int resolve_metric(struct list_head *metric_list,
>   	size_t bkt;
>   	struct to_resolve {
>   		/* The metric to resolve. */
> -		struct pmu_event pe;
> +		struct pmu_metric pm;
>   		/*
>   		 * The key in the IDs map, this may differ from in case,
> -		 * etc. from pe->metric_name.
> +		 * etc. from pm->metric_name.
>   		 */
>   		const char *key;
>   	} *pending = NULL;
> @@ -830,15 +827,15 @@ static int resolve_metric(struct list_head *metric_list,
>   	 * the pending array.
>   	 */
>   	hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
> -		struct pmu_event pe;
> +		struct pmu_metric pm;
>   
> -		if (metricgroup__find_metric(cur->pkey, table, &pe)) {
> +		if (metricgroup__find_metric(cur->pkey, table, &pm)) {
>   			pending = realloc(pending,
>   					(pending_cnt + 1) * sizeof(struct to_resolve));
>   			if (!pending)
>   				return -ENOMEM;
>   
> -			memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
> +			memcpy(&pending[pending_cnt].pm, &pm, sizeof(pm));
>   			pending[pending_cnt].key = cur->pkey;
>   			pending_cnt++;
>   		}
> @@ -853,7 +850,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].pm, modifier, metric_no_group,
>   				 user_requested_cpu_list, system_wide, root_metric, visited,
>   				 table);
>   		if (ret)
> @@ -867,7 +864,7 @@ static int resolve_metric(struct list_head *metric_list,
>   /**
>    * __add_metric - Add a metric to metric_list.
>    * @metric_list: The list the metric is added to.
> - * @pe: The pmu_event containing the metric to be added.
> + * @pm: The pmu_metric containing the metric to be added.
>    * @modifier: if non-null event modifiers like "u".
>    * @metric_no_group: Should events written to events be grouped "{}" or
>    *                   global. Grouping is the default but due to multiplexing the
> @@ -884,7 +881,7 @@ static int resolve_metric(struct list_head *metric_list,
>    *       architecture perf is running upon.
>    */
>   static int __add_metric(struct list_head *metric_list,
> -			const struct pmu_event *pe,
> +			const struct pmu_metric *pm,
>   			const char *modifier,
>   			bool metric_no_group,
>   			int runtime,
> @@ -898,13 +895,13 @@ static int __add_metric(struct list_head *metric_list,
>   	int ret;
>   	bool is_root = !root_metric;
>   	struct visited_metric visited_node = {
> -		.name = pe->metric_name,
> +		.name = pm->metric_name,
>   		.parent = visited,
>   	};
>   
>   	for (vm = visited; vm; vm = vm->parent) {
> -		if (!strcmp(pe->metric_name, vm->name)) {
> -			pr_err("failed: recursion detected for %s\n", pe->metric_name);
> +		if (!strcmp(pm->metric_name, vm->name)) {
> +			pr_err("failed: recursion detected for %s\n", pm->metric_name);
>   			return -1;
>   		}
>   	}
> @@ -914,7 +911,7 @@ static int __add_metric(struct list_head *metric_list,
>   		 * This metric is the root of a tree and may reference other
>   		 * metrics that are added recursively.
>   		 */
> -		root_metric = metric__new(pe, modifier, metric_no_group, runtime,
> +		root_metric = metric__new(pm, modifier, metric_no_group, runtime,
>   					  user_requested_cpu_list, system_wide);
>   		if (!root_metric)
>   			return -ENOMEM;
> @@ -929,7 +926,7 @@ static int __add_metric(struct list_head *metric_list,
>   		 */
>   		if (root_metric->metric_refs) {
>   			for (; root_metric->metric_refs[cnt].metric_name; cnt++) {
> -				if (!strcmp(pe->metric_name,
> +				if (!strcmp(pm->metric_name,
>   					    root_metric->metric_refs[cnt].metric_name))
>   					return 0;
>   			}
> @@ -947,8 +944,8 @@ static int __add_metric(struct list_head *metric_list,
>   		 * need to change them, so there's no need to create
>   		 * our own copy.
>   		 */
> -		root_metric->metric_refs[cnt].metric_name = pe->metric_name;
> -		root_metric->metric_refs[cnt].metric_expr = pe->metric_expr;
> +		root_metric->metric_refs[cnt].metric_name = pm->metric_name;
> +		root_metric->metric_refs[cnt].metric_expr = pm->metric_expr;
>   
>   		/* Null terminate array. */
>   		root_metric->metric_refs[cnt+1].metric_name = NULL;
> @@ -959,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
>   	 * For both the parent and referenced metrics, we parse
>   	 * all the metric's IDs and add it to the root context.
>   	 */
> -	if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) {
> +	if (expr__find_ids(pm->metric_expr, NULL, root_metric->pctx) < 0) {
>   		/* Broken metric. */
>   		ret = -EINVAL;
>   	} else {
> @@ -981,37 +978,37 @@ static int __add_metric(struct list_head *metric_list,
>   
>   struct metricgroup__find_metric_data {
>   	const char *metric;
> -	struct pmu_event *pe;
> +	struct pmu_metric *pm;
>   };
>   
> -static int metricgroup__find_metric_callback(const struct pmu_event *pe,
> +static int metricgroup__find_metric_callback(const struct pmu_metric *pm,
>   					     const struct pmu_events_table *table  __maybe_unused,
>   					     void *vdata)
>   {
>   	struct metricgroup__find_metric_data *data = vdata;
>   
> -	if (!match_metric(pe->metric_name, data->metric))
> +	if (!match_metric(pm->metric_name, data->metric))
>   		return 0;
>   
> -	memcpy(data->pe, pe, sizeof(*pe));
> +	memcpy(data->pm, pm, sizeof(*pm));
>   	return 1;
>   }
>   
>   static bool metricgroup__find_metric(const char *metric,
>   				     const struct pmu_events_table *table,
> -				     struct pmu_event *pe)
> +				     struct pmu_metric *pm)
>   {
>   	struct metricgroup__find_metric_data data = {
>   		.metric = metric,
> -		.pe = pe,
> +		.pm = pm,
>   	};
>   
> -	return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
> +	return pmu_events_table_for_each_metric(table, metricgroup__find_metric_callback, &data)
>   		? true : false;

comment on pre-existing code: since it returns bool, I don't think the 
ternary operator is required at all. There are many instances of this.

>   }
>   
>   static int add_metric(struct list_head *metric_list,
> -		      const struct pmu_event *pe,
> +		      const struct pmu_metric *pm,
>   		      const char *modifier,
>   		      bool metric_no_group,
>   		      const char *user_requested_cpu_list,
> @@ -1022,16 +1019,16 @@ static int add_metric(struct list_head *metric_list,
>   {
>   	int ret = 0;
>   
> -	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> +	pr_debug("metric expr %s for %s\n", pm->metric_expr, pm->metric_name);
>   
> -	if (!strstr(pe->metric_expr, "?")) {
> -		ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> +	if (!strstr(pm->metric_expr, "?")) {
> +		ret = __add_metric(metric_list, pm, modifier, metric_no_group, 0,
>   				   user_requested_cpu_list, system_wide, root_metric,
>   				   visited, table);
>   	} else {
>   		int j, count;
>   
> -		count = arch_get_runtimeparam(pe);
> +		count = arch_get_runtimeparam(pm);
>   
>   		/* This loop is added to create multiple
>   		 * events depend on count value and add
> @@ -1039,7 +1036,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,
> +			ret = __add_metric(metric_list, pm, modifier, metric_no_group, j,
>   					   user_requested_cpu_list, system_wide,
>   					   root_metric, visited, table);
>   	}
> @@ -1047,17 +1044,17 @@ static int add_metric(struct list_head *metric_list,
>   	return ret;
>   }
>   
> -static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
> +static int metricgroup__add_metric_sys_event_iter(const struct pmu_metric *pm,
>   						const struct pmu_events_table *table __maybe_unused,
>   						void *data)
>   {
>   	struct metricgroup_add_iter_data *d = data;
>   	int ret;
>   
> -	if (!match_pe_metric(pe, d->metric_name))
> +	if (!match_pm_metric(pm, d->metric_name))
>   		return 0;
>   
> -	ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> +	ret = add_metric(d->metric_list, pm, d->modifier, d->metric_no_group,
>   			 d->user_requested_cpu_list, d->system_wide,
>   			 d->root_metric, d->visited, d->table);
>   	if (ret)
> @@ -1107,19 +1104,19 @@ struct metricgroup__add_metric_data {
>   	bool has_match;
>   };
>   
> -static int metricgroup__add_metric_callback(const struct pmu_event *pe,
> +static int metricgroup__add_metric_callback(const struct pmu_metric *pm,
>   					    const struct pmu_events_table *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))) {
> +	if (pm->metric_expr &&
> +		(match_metric(pm->metric_group, data->metric_name) ||
> +		 match_metric(pm->metric_name, data->metric_name))) {
>   
>   		data->has_match = true;
> -		ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
> +		ret = add_metric(data->list, pm, data->modifier, data->metric_no_group,
>   				 data->user_requested_cpu_list, data->system_wide,
>   				 /*root_metric=*/NULL, /*visited_metrics=*/NULL, table);
>   	}
> @@ -1166,8 +1163,8 @@ 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.
>   		 */
> -		ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
> -						      &data);
> +		ret = pmu_events_table_for_each_metric(table, metricgroup__add_metric_callback,
> +						       &data);
>   		if (ret)
>   			goto out;
>   
> @@ -1189,7 +1186,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
>   			},
>   		};
>   
> -		pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
> +		pmu_for_each_sys_metric(metricgroup__sys_event_iter, &data);
>   	}
>   	/* End of pmu events. */
>   	if (!has_match)
> @@ -1603,16 +1600,16 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
>   			    &perf_pmu__fake, metric_events, table);
>   }
>   
> -static int metricgroup__has_metric_callback(const struct pmu_event *pe,
> +static int metricgroup__has_metric_callback(const struct pmu_metric *pm,
>   					    const struct pmu_events_table *table __maybe_unused,
>   					    void *vdata)
>   {
>   	const char *metric = vdata;
>   
> -	if (!pe->metric_expr)
> +	if (!pm->metric_expr)
>   		return 0;
>   
> -	if (match_metric(pe->metric_name, metric))
> +	if (match_metric(pm->metric_name, metric))
>   		return 1;
>   
>   	return 0;
> @@ -1625,8 +1622,8 @@ bool metricgroup__has_metric(const char *metric)
>   	if (!table)
>   		return false;
>   
> -	return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
> -					       (void *)metric) ? true : false;
> +	return pmu_events_table_for_each_metric(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/metricgroup.h b/tools/perf/util/metricgroup.h
> index 0013cf582173..b1f186d0f514 100644
> --- a/tools/perf/util/metricgroup.h
> +++ b/tools/perf/util/metricgroup.h
> @@ -81,7 +81,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
>   
>   void metricgroup__print(const struct print_callbacks *print_cb, void *print_state);
>   bool metricgroup__has_metric(const char *metric);
> -int arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused);
> +int arch_get_runtimeparam(const struct pmu_metric *pm);
>   void metricgroup__rblist_exit(struct rblist *metric_events);
>   
>   int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index 21cce83462b3..0336ff27c15f 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -1570,8 +1570,6 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
>   	evsel->scale = info.scale;
>   	evsel->per_pkg = info.per_pkg;
>   	evsel->snapshot = info.snapshot;
> -	evsel->metric_expr = info.metric_expr;
> -	evsel->metric_name = info.metric_name;
>   	return 0;
>   }
>   
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index 2bdeb89352e7..d627f99b5a63 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -283,10 +283,6 @@ static void perf_pmu_update_alias(struct perf_pmu_alias *old,
>   	perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
>   			    &newalias->long_desc);
>   	perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
> -	perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
> -			    &newalias->metric_expr);
> -	perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
> -			    &newalias->metric_name);
>   	perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
>   	old->scale = newalias->scale;
>   	old->per_pkg = newalias->per_pkg;
> @@ -302,8 +298,6 @@ void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
>   	zfree(&newalias->long_desc);
>   	zfree(&newalias->topic);
>   	zfree(&newalias->str);
> -	zfree(&newalias->metric_expr);
> -	zfree(&newalias->metric_name);
>   	zfree(&newalias->pmu_name);
>   	parse_events_terms__purge(&newalias->terms);
>   	free(newalias);
> @@ -340,16 +334,13 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
>   	int num;
>   	char newval[256];
>   	char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL,
> -	     *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL,
> -	     *pmu_name = NULL;
> +	     *deprecated = NULL, *pmu_name = NULL;
>   
>   	if (pe) {
>   		long_desc = (char *)pe->long_desc;
>   		topic = (char *)pe->topic;
>   		unit = (char *)pe->unit;
>   		perpkg = (char *)pe->perpkg;
> -		metric_expr = (char *)pe->metric_expr;
> -		metric_name = (char *)pe->metric_name;
>   		deprecated = (char *)pe->deprecated;
>   		pmu_name = (char *)pe->pmu;
>   	}
> @@ -404,8 +395,6 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
>   		perf_pmu__parse_snapshot(alias, dir, name);
>   	}
>   
> -	alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
> -	alias->metric_name = metric_name ? strdup(metric_name): NULL;
>   	alias->desc = desc ? strdup(desc) : NULL;
>   	alias->long_desc = long_desc ? strdup(long_desc) :
>   				desc ? strdup(desc) : NULL;
> @@ -822,9 +811,6 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
>   	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;
>   
> @@ -879,12 +865,6 @@ static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
>   	struct pmu_sys_event_iter_data *idata = data;
>   	struct perf_pmu *pmu = idata->pmu;
>   
> -	if (!pe->name) {
> -		if (pe->metric_group || pe->metric_name)
> -			return 0;
> -		return -EINVAL;
> -	}
> -
>   	if (!pe->compat || !pe->pmu)
>   		return 0;
>   
> @@ -1469,8 +1449,6 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
>   	info->unit     = NULL;
>   	info->scale    = 0.0;
>   	info->snapshot = false;
> -	info->metric_expr = NULL;
> -	info->metric_name = NULL;
>   
>   	list_for_each_entry_safe(term, h, head_terms, list) {
>   		alias = pmu_find_alias(pmu, term);
> @@ -1486,8 +1464,6 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
>   
>   		if (alias->per_pkg)
>   			info->per_pkg = true;
> -		info->metric_expr = alias->metric_expr;
> -		info->metric_name = alias->metric_name;
>   
>   		list_del_init(&term->list);
>   		parse_events_term__delete(term);
> @@ -1703,8 +1679,7 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
>   	for (j = 0; j < len; j++) {
>   		const char *name, *alias = NULL, *scale_unit = NULL,
>   			*desc = NULL, *long_desc = NULL,
> -			*encoding_desc = NULL, *topic = NULL,
> -			*metric_name = NULL, *metric_expr = NULL;
> +			*encoding_desc = NULL, *topic = NULL;
>   		bool deprecated = false;
>   		size_t buf_used;
>   
> @@ -1742,8 +1717,6 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
>   			buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
>   					"%s/%s/", aliases[j].pmu->name,
>   					aliases[j].event->str) + 1;
> -			metric_name = aliases[j].event->metric_name;
> -			metric_expr = aliases[j].event->metric_expr;
>   			deprecated = aliases[j].event->deprecated;
>   		}
>   		print_cb->print_event(print_state,
> @@ -1756,9 +1729,7 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
>   				"Kernel PMU event",
>   				desc,
>   				long_desc,
> -				encoding_desc,
> -				metric_name,
> -				metric_expr);
> +				encoding_desc);
>   	}
>   	if (printed && pager_in_use())
>   		printf("\n");
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index 69ca0004f94f..4d8d64209b4b 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -133,8 +133,6 @@ extern struct perf_pmu perf_pmu__fake;
>   
>   struct perf_pmu_info {
>   	const char *unit;
> -	const char *metric_expr;
> -	const char *metric_name;
>   	double scale;
>   	bool per_pkg;
>   	bool snapshot;
> @@ -188,13 +186,6 @@ struct perf_pmu_alias {
>   	 * default.
>   	 */
>   	bool deprecated;
> -	/**
> -	 * @metric_expr: A metric expression associated with an event. Doing
> -	 * this makes little sense due to scale and unit applying to both.
> -	 */
> -	char *metric_expr;
> -	/** @metric_name: A name for the metric. unit applying to both. */
> -	char *metric_name;
>   	/** @pmu_name: The name copied from struct perf_pmu. */
>   	char *pmu_name;
>   };
> diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c
> index 2646ae18d9f9..62e9ea7dcf40 100644
> --- a/tools/perf/util/print-events.c
> +++ b/tools/perf/util/print-events.c
> @@ -101,9 +101,7 @@ void print_tracepoint_events(const struct print_callbacks *print_cb, void *print
>   					"Tracepoint event",
>   					/*desc=*/NULL,
>   					/*long_desc=*/NULL,
> -					/*encoding_desc=*/NULL,
> -					/*metric_name=*/NULL,
> -					/*metric_expr=*/NULL);
> +					/*encoding_desc=*/NULL);
>   		}
>   		free(dir_path);
>   		free(evt_namelist);
> @@ -195,9 +193,7 @@ void print_sdt_events(const struct print_callbacks *print_cb, void *print_state)
>   				"SDT event",
>   				/*desc=*/NULL,
>   				/*long_desc=*/NULL,
> -				/*encoding_desc=*/NULL,
> -				/*metric_name=*/NULL,
> -				/*metric_expr=*/NULL);
> +				/*encoding_desc=*/NULL);
>   
>   		free(evt_name);
>   	}
> @@ -255,9 +251,7 @@ int print_hwcache_events(const struct print_callbacks *print_cb, void *print_sta
>   				event_type_descriptors[PERF_TYPE_HW_CACHE],
>   				/*desc=*/NULL,
>   				/*long_desc=*/NULL,
> -				/*encoding_desc=*/NULL,
> -				/*metric_name=*/NULL,
> -				/*metric_expr=*/NULL);
> +				/*encoding_desc=*/NULL);
>   	}
>   	strlist__delete(evt_name_list);
>   	return 0;
> @@ -277,9 +271,7 @@ void print_tool_events(const struct print_callbacks *print_cb, void *print_state
>   				"Tool event",
>   				/*desc=*/NULL,
>   				/*long_desc=*/NULL,
> -				/*encoding_desc=*/NULL,
> -				/*metric_name=*/NULL,
> -				/*metric_expr=*/NULL);
> +				/*encoding_desc=*/NULL);
>   	}
>   }
>   
> @@ -331,9 +323,7 @@ void print_symbol_events(const struct print_callbacks *print_cb, void *print_sta
>   				event_type_descriptors[type],
>   				/*desc=*/NULL,
>   				/*long_desc=*/NULL,
> -				/*encoding_desc=*/NULL,
> -				/*metric_name=*/NULL,
> -				/*metric_expr=*/NULL);
> +				/*encoding_desc=*/NULL);
>   	}
>   	strlist__delete(evt_name_list);
>   }
> @@ -364,9 +354,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
>   			event_type_descriptors[PERF_TYPE_RAW],
>   			/*desc=*/NULL,
>   			/*long_desc=*/NULL,
> -			/*encoding_desc=*/NULL,
> -			/*metric_name=*/NULL,
> -			/*metric_expr=*/NULL);
> +			/*encoding_desc=*/NULL);
>   
>   	print_cb->print_event(print_state,
>   			/*topic=*/NULL,
> @@ -378,9 +366,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
>   			event_type_descriptors[PERF_TYPE_RAW],
>   			"(see 'man perf-list' on how to encode it)",
>   			/*long_desc=*/NULL,
> -			/*encoding_desc=*/NULL,
> -			/*metric_name=*/NULL,
> -			/*metric_expr=*/NULL);
> +			/*encoding_desc=*/NULL);
>   
>   	print_cb->print_event(print_state,
>   			/*topic=*/NULL,
> @@ -392,9 +378,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
>   			event_type_descriptors[PERF_TYPE_BREAKPOINT],
>   			/*desc=*/NULL,
>   			/*long_desc=*/NULL,
> -			/*encoding_desc=*/NULL,
> -			/*metric_name=*/NULL,
> -			/*metric_expr=*/NULL);
> +			/*encoding_desc=*/NULL);
>   
>   	print_tracepoint_events(print_cb, print_state);
>   
> diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h
> index c237e53c4487..716dcf4b4859 100644
> --- a/tools/perf/util/print-events.h
> +++ b/tools/perf/util/print-events.h
> @@ -16,8 +16,7 @@ struct print_callbacks {
>   			const char *scale_unit,
>   			bool deprecated, const char *event_type_desc,
>   			const char *desc, const char *long_desc,
> -			const char *encoding_desc,
> -			const char *metric_name, const char *metric_expr);
> +			const char *encoding_desc);
>   	void (*print_metric)(void *print_state,
>   			const char *group,
>   			const char *name,


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

* Re: [PATCH v2 8/9] perf jevents: Generate metrics and events as separate tables
  2022-12-21 22:34 ` [PATCH v2 8/9] perf jevents: Generate metrics and events as separate tables Ian Rogers
@ 2023-01-23 15:18   ` John Garry
  2023-01-24  4:49     ` Ian Rogers
  0 siblings, 1 reply; 20+ messages in thread
From: John Garry @ 2023-01-23 15:18 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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Perry Taylor, Caleb Biggers, Stephane Eranian

On 21/12/2022 22:34, Ian Rogers wrote:
> Turn a perf json event into an event, metric or both. This reduces the
> number of events needed to scan to find an event or metric. As events
> no longer need the relatively seldom used metric fields, 4 bytes is
> saved per event. This reduces the big C string's size by 335kb (14.8%)
> on x86.
> 
> Signed-off-by: Ian Rogers<irogers@google.com>

It would have been good to show an example of how the output changes. I 
could not apply the series (see cover), and knowing what to expect makes 
reviewing the code easier...

Thanks,
John

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

* Re: [PATCH v2 7/9] perf pmu-events: Introduce pmu_metrics_table
  2022-12-21 22:34 ` [PATCH v2 7/9] perf pmu-events: Introduce pmu_metrics_table Ian Rogers
@ 2023-01-23 15:35   ` John Garry
  2023-01-24  4:48     ` Ian Rogers
  0 siblings, 1 reply; 20+ messages in thread
From: John Garry @ 2023-01-23 15: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,
	Adrian Hunter, Kan Liang, Kim Phillips, Florian Fischer,
	Ravi Bangoria, Xing Zhengjun, Rob Herring, Kang Minchul,
	linux-arm-kernel, linux-perf-users, linux-kernel, Sandipan Das,
	Jing Zhang, linuxppc-dev, Kajol Jain
  Cc: Perry Taylor, Caleb Biggers, Stephane Eranian

On 21/12/2022 22:34, Ian Rogers wrote:
> Add a metrics table that is just a cast from pmu_events_table. This
> changes the APIs so that event and metric usage of the underlying
> table is different. Later changes will separate the tables.
> 
> This introduction fixes a NO_JEVENTS=1 regression on:
>   68: Parse and process metrics                                       : Ok
>   70: Event expansion for cgroups                                     : Ok
> caused by the necessary test metrics not being found.
> 

I have just checked some of this code so far...

> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>   tools/perf/arch/arm64/util/pmu.c         | 23 ++++++++++-
>   tools/perf/pmu-events/empty-pmu-events.c | 52 ++++++++++++++++++++----
>   tools/perf/pmu-events/jevents.py         | 24 ++++++++---
>   tools/perf/pmu-events/pmu-events.h       | 10 +++--
>   tools/perf/tests/expand-cgroup.c         |  4 +-
>   tools/perf/tests/parse-metric.c          |  4 +-
>   tools/perf/tests/pmu-events.c            |  5 ++-
>   tools/perf/util/metricgroup.c            | 50 +++++++++++------------
>   tools/perf/util/metricgroup.h            |  2 +-
>   tools/perf/util/pmu.c                    |  9 +++-
>   tools/perf/util/pmu.h                    |  1 +
>   11 files changed, 133 insertions(+), 51 deletions(-)
> 
> diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> index 477e513972a4..f8ae479a06db 100644
> --- a/tools/perf/arch/arm64/util/pmu.c
> +++ b/tools/perf/arch/arm64/util/pmu.c
> @@ -19,7 +19,28 @@ const struct pmu_events_table *pmu_events_table__find(void)
>   		if (pmu->cpus->nr != cpu__max_cpu().cpu)
>   			return NULL;
>   
> -		return perf_pmu__find_table(pmu);
> +		return perf_pmu__find_events_table(pmu);
> +	}
> +
> +	return NULL;
> +}
> +
> +const struct pmu_metrics_table *pmu_metrics_table__find(void)
> +{
> +	struct perf_pmu *pmu = NULL;
> +
> +	while ((pmu = perf_pmu__scan(pmu))) {
> +		if (!is_pmu_core(pmu->name))
> +			continue;
> +
> +		/*
> +		 * The cpumap should cover all CPUs. Otherwise, some CPUs may
> +		 * not support some events or have different event IDs.
> +		 */
> +		if (pmu->cpus->nr != cpu__max_cpu().cpu)
> +			return NULL;
> +
> +		return perf_pmu__find_metrics_table(pmu);

I think that this code will be conflicting with the recent arm64 metric 
support. And now it seems even more scope for factoring out code.

>   	}
>   
>   	return NULL;
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 5572a4d1eddb..d50f60a571dd 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -278,14 +278,12 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_ev
>   	return 0;
>   }
>   
> -int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_metric_iter_fn fn,
> -				     void *data)
> +int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
> +				      void *data)
>   {
> -	struct pmu_metrics_table *table = (struct pmu_metrics_table *)etable;
> -
>   	for (const struct pmu_metric *pm = &table->entries[0]

nit on coding style: do we normally declare local variables like this? 
It condenses the code but makes a bit less readable, IMHO

> ; pm->metric_group || pm->metric_name;
>   	     pm++) {
> -		int ret = fn(pm, etable, data);
> +		int ret = fn(pm, table, data);
>   
>   		if (ret)
>   			return ret;
> @@ -293,7 +291,7 @@ int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_
>   	return 0;
>   }
>   
> -const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
> +const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
>   {
>   	const struct pmu_events_table *table = NULL;
>   	char *cpuid = perf_pmu__getcpuid(pmu);
> @@ -321,6 +319,34 @@ const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
>   	return table;
>   }
>   
> +const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
> +{
> +	const struct pmu_metrics_table *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++];

To me, this is all strange code. Again this is a comment on the current 
code: Consider pmu_for_each_sys_event() as an example, we have a while 
loop for each member of pmu_sys_event_tables[]. But pmu_sys_event_tables 
is hardcoded for a single member, so why loop? It seems the same for all 
these "for each" helper in the "empty" events c file.

> +
> +		if (!map->cpuid)
> +			break;
> +
> +		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> +			table = &map->metric_table;
> +			break;
> +		}
> +	}
> +	free(cpuid);
> +	return table;
> +}
> +
>   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];
> @@ -332,6 +358,17 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
>   	return NULL;
>   }
>   
> +const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
> +{
> +	for (const struct pmu_events_map *tables = &pmu_events_map[0];
> +	     tables->arch;
> +	     tables++) {

combine with previous line?

> +		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> +			return &tables->metric_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];
> @@ -350,8 +387,7 @@ int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
>   	for (const struct pmu_events_map *tables = &pmu_events_map[0];
>   	     tables->arch;
>   	     tables++) {
> -		int ret = pmu_events_table_for_each_metric(
> -			(const struct pmu_events_table *)&tables->metric_table, fn, data);
> +		int ret = pmu_metrics_table_for_each_metric(&tables->metric_table, fn, data);
>   
>   		if (ret)
>   			return ret;
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 7b9714b25d0a..be2cf8a8779c 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -609,17 +609,19 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
>           return 0;
>   }
>   
> -int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
> +int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *mtable,
>                                        pmu_metric_iter_fn fn,
>                                        void *data)
>   {
> +        struct pmu_events_table *table = (struct pmu_events_table *)mtable;

As I may have hinted before, can we avoid casts like this, even if 
transient?

> +
>           for (size_t i = 0; i < table->length; i++) {
>                   struct pmu_metric pm;
>                   int ret;
>   
>                   decompress_metric(table->entries[i].offset, &pm);
>                   if (pm.metric_name) {
> -                        ret = fn(&pm, table, data);
> +                        ret = fn(&pm, mtable, data);
>                           if (ret)
>                                   return ret;
>                   }




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

* Re: [PATCH v2 4/9] perf pmu-events: Separate metric out of pmu_event
  2023-01-23 15:15   ` John Garry
@ 2023-01-24  4:39     ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2023-01-24  4:39 UTC (permalink / raw)
  To: John Garry
  Cc: Mark Rutland, Kang Minchul, Sandipan Das, Peter Zijlstra,
	Perry Taylor, Stephane Eranian, linux-kernel, James Clark,
	Kim Phillips, Will Deacon, Kan Liang, Rob Herring,
	Alexander Shishkin, Ingo Molnar, Xing Zhengjun, Mike Leach,
	Kajol Jain, Arnaldo Carvalho de Melo, Namhyung Kim,
	Caleb Biggers, linux-arm-kernel, Ravi Bangoria, Florian Fischer,
	Adrian Hunter, linux-perf-users, Jiri Olsa, Leo Yan,
	linuxppc-dev, Jing Zhang

On Mon, Jan 23, 2023 at 7:16 AM John Garry <john.g.garry@oracle.com> wrote:
>
> On 21/12/2022 22:34, Ian Rogers wrote:
> > Previously both events and metrics were encoded in struct
> > pmu_event. Create a new pmu_metric that has the metric related
> > variables and remove these from pmu_event. Add iterators for
> > pmu_metric and use in places that metrics are desired rather than
> > events.
> >
> > Note, this change removes the setting of evsel's metric_name/expr as
> > these fields are no longer part of struct pmu_event. The metric
> > remains but is no longer implicitly requested when the event is. This
> > impacts a few Intel uncore events, however, as the ScaleUnit is shared
> > by the event and the metric this utility is questionable. Also the
> > MetricNames look broken (contain spaces) in some cases and when trying
> > to use the functionality with '-e' the metrics fail but regular
> > metrics with '-M' work. For example, on SkylakeX '-M' works:
> >
>
> I like this change. It's quite large for a single patch. Just some
> sparse comments below.
>
> BTW, it there a better name for metric struct variable than "pm"? To me
> and many other people, pm is power management.

Agreed. There a few things like that in the code, I dislike the
overload on "core". I've left it as pm as pmu_event became pe, so it
is consistent for pmu_metric to become pm. We can do a global rename
as a follow up.

> > ```
> > $ perf stat -M LLC_MISSES.PCIE_WRITE -a sleep 1
> >
> >   Performance counter stats for 'system wide':
> >
> >                   0      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 #  57896.0 Bytes  LLC_MISSES.PCIE_WRITE  (49.84%)
> >               7,174      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1                                        (49.85%)
> >                   0      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3                                        (50.16%)
> >                  63      UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0                                        (50.15%)
> >
> >         1.004576381 seconds time elapsed
> > ```
> >
> > whilst the event '-e' version is broken even with --group/-g (fwiw, we should also remove -g [1]):
> >
> > ```
> > $ perf stat -g -e LLC_MISSES.PCIE_WRITE -g -a sleep 1
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> > Add UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 event to groups to get metric expression for LLC_MISSES.PCIE_WRITE
> >
> >   Performance counter stats for 'system wide':
> >
> >              27,316 Bytes LLC_MISSES.PCIE_WRITE
> >
> >         1.004505469 seconds time elapsed
> > ```
> >
> > The code also carries warnings where the user is supposed to select
> > events for metrics [2] but given the lack of use of such a feature,
> > let's clean the code and just remove.
> >
> > With NO_JEVENTS=1 the empty-pmu-events.c is used and the separation to
> > use metrics causes "Parse and process metrics" and "Event expansion
> > for cgroups" to fail as they fail to find necessary metrics. This is
> > fixed in a later change.
> >
> > [1] https://urldefense.com/v3/__https://lore.kernel.org/lkml/20220707195610.303254-1-irogers@google.com/__;!!ACWV5N9M2RV99hQ!MTNgf7sIIl2VCxBzo-biSeul-ZQkuU73pT6gBbsb6y0AqsVlgGCcmuigDyevtrgmpHDN1QkEJwbJYvREu3Q$
> > [2] https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/util/stat-shadow.c?id=01b8957b738f42f96a130079bc951b3cc78c5b8a*n425__;Iw!!ACWV5N9M2RV99hQ!MTNgf7sIIl2VCxBzo-biSeul-ZQkuU73pT6gBbsb6y0AqsVlgGCcmuigDyevtrgmpHDN1QkEJwbJ8H0tppQ$
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/arch/powerpc/util/header.c    |   4 +-
> >   tools/perf/builtin-list.c                |  20 +--
> >   tools/perf/pmu-events/empty-pmu-events.c |  73 ++++++++--
> >   tools/perf/pmu-events/jevents.py         |  82 +++++++++++-
> >   tools/perf/pmu-events/pmu-events.h       |  20 ++-
> >   tools/perf/tests/pmu-events.c            |  62 +++------
> >   tools/perf/util/metricgroup.c            | 161 +++++++++++------------
> >   tools/perf/util/metricgroup.h            |   2 +-
> >   tools/perf/util/parse-events.c           |   2 -
> >   tools/perf/util/pmu.c                    |  35 +----
> >   tools/perf/util/pmu.h                    |   9 --
> >   tools/perf/util/print-events.c           |  32 ++---
> >   tools/perf/util/print-events.h           |   3 +-
> >   13 files changed, 266 insertions(+), 239 deletions(-)
> >
> > diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
> > index e8fe36b10d20..78eef77d8a8d 100644
> > --- a/tools/perf/arch/powerpc/util/header.c
> > +++ b/tools/perf/arch/powerpc/util/header.c
> > @@ -40,11 +40,11 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
> >       return bufp;
> >   }
> >
> > -int arch_get_runtimeparam(const struct pmu_event *pe)
> > +int arch_get_runtimeparam(const struct pmu_metric *pm)
> >   {
> >       int count;
> >       char path[PATH_MAX] = "/devices/hv_24x7/interface/";
> >
> > -     atoi(pe->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
> > +     atoi(pm->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
> >       return sysfs__read_int(path, &count) < 0 ? 1 : count;
> >   }
> > diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
> > index 137d73edb541..791f513ae5b4 100644
> > --- a/tools/perf/builtin-list.c
> > +++ b/tools/perf/builtin-list.c
> > @@ -99,8 +99,7 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
> >                               const char *scale_unit __maybe_unused,
> >                               bool deprecated, const char *event_type_desc,
> >                               const char *desc, const char *long_desc,
> > -                             const char *encoding_desc,
> > -                             const char *metric_name, const char *metric_expr)
> > +                             const char *encoding_desc)
> >   {
> >       struct print_state *print_state = ps;
> >       int pos;
> > @@ -159,10 +158,6 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
> >       if (print_state->detailed && encoding_desc) {
> >               printf("%*s", 8, "");
> >               wordwrap(encoding_desc, 8, pager_get_columns(), 0);
> > -             if (metric_name)
> > -                     printf(" MetricName: %s", metric_name);
> > -             if (metric_expr)
> > -                     printf(" MetricExpr: %s", metric_expr);
> >               putchar('\n');
> >       }
> >   }
> > @@ -308,8 +303,7 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic,
> >                            const char *scale_unit,
> >                            bool deprecated, const char *event_type_desc,
> >                            const char *desc, const char *long_desc,
> > -                          const char *encoding_desc,
> > -                          const char *metric_name, const char *metric_expr)
> > +                          const char *encoding_desc)
> >   {
> >       struct json_print_state *print_state = ps;
> >       bool need_sep = false;
> > @@ -366,16 +360,6 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic,
> >                                 encoding_desc);
> >               need_sep = true;
> >       }
> > -     if (metric_name) {
> > -             fix_escape_printf(&buf, "%s\t\"MetricName\": \"%S\"", need_sep ? ",\n" : "",
> > -                               metric_name);
> > -             need_sep = true;
> > -     }
> > -     if (metric_expr) {
> > -             fix_escape_printf(&buf, "%s\t\"MetricExpr\": \"%S\"", need_sep ? ",\n" : "",
> > -                               metric_expr);
> > -             need_sep = true;
> > -     }
> >       printf("%s}", need_sep ? "\n" : "");
> >       strbuf_release(&buf);
> >   }
> > diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> > index 480e8f0d30c8..5572a4d1eddb 100644
> > --- a/tools/perf/pmu-events/empty-pmu-events.c
> > +++ b/tools/perf/pmu-events/empty-pmu-events.c
> > @@ -11,7 +11,7 @@
> >   #include <string.h>
> >   #include <stddef.h>
> >
> > -static const struct pmu_event pme_test_soc_cpu[] = {
> > +static const struct pmu_event pmu_events__test_soc_cpu[] = {
> >       {
> >               .name = "l3_cache_rd",
> >               .event = "event=0x40",
> > @@ -105,6 +105,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
> >               .desc = "L2 BTB Correction",
> >               .topic = "branch",
> >       },
> > +     {
> > +             .name = 0,
> > +             .event = 0,
> > +             .desc = 0,
> > +     },
> > +};
> > +
> > +static const struct pmu_metric pmu_metrics__test_soc_cpu[] = {
> >       {
> >               .metric_expr    = "1 / IPC",
> >               .metric_name    = "CPI",
> > @@ -170,9 +178,8 @@ static const struct pmu_event pme_test_soc_cpu[] = {
> >               .metric_name    = "L1D_Cache_Fill_BW",
> >       },
> >       {
> > -             .name = 0,
> > -             .event = 0,
> > -             .desc = 0,
> > +             .metric_expr = 0,
> > +             .metric_name = 0,
> >       },
> >   };
> >
> > @@ -181,6 +188,11 @@ struct pmu_events_table {
> >       const struct pmu_event *entries;
> >   };
> >
> > +/* Struct used to make the PMU metric table implementation opaque to callers. */
> > +struct pmu_metrics_table {
> > +     const struct pmu_metric *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.
> > @@ -192,7 +204,8 @@ struct pmu_events_table {
> >   struct pmu_events_map {
> >       const char *arch;
> >       const char *cpuid;
> > -     const struct pmu_events_table table;
> > +     const struct pmu_events_table event_table;
> > +     const struct pmu_metrics_table metric_table;
> >   };
> >
> >   /*
> > @@ -203,12 +216,14 @@ static const struct pmu_events_map pmu_events_map[] = {
> >       {
> >               .arch = "testarch",
> >               .cpuid = "testcpu",
> > -             .table = { pme_test_soc_cpu },
> > +             .event_table = { pmu_events__test_soc_cpu },
> > +             .metric_table = { pmu_metrics__test_soc_cpu },
> >       },
> >       {
> >               .arch = 0,
> >               .cpuid = 0,
> > -             .table = { 0 },
> > +             .event_table = { 0 },
> > +             .metric_table = { 0 },
> >       },
> >   };
> >
> > @@ -254,9 +269,7 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >   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++) {
> > +     for (const struct pmu_event *pe = &table->entries[0]; pe->name; pe++) {
> >               int ret = fn(pe, table, data);
> >
> >               if (ret)
> > @@ -265,6 +278,21 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_ev
> >       return 0;
> >   }
> >
> > +int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_metric_iter_fn fn,
> > +                                  void *data)
> > +{
> > +     struct pmu_metrics_table *table = (struct pmu_metrics_table *)etable;
>
> This is odd. Would the change be too big if we combined patches to avoid
> casting like this? I assume that this is going away later...

Yep. Done this way to minimize the patch sizes.

> > +
> > +     for (const struct pmu_metric *pm = &table->entries[0]; pm->metric_group || pm->metric_name;
>
> Is it valid to only have metric_group or metric_name set?

Agreed. I think using the expr is the best solution, albeit temporary
in the patch series. Fwiw, it was done this way as the logic was moved
from pmu_events_table_for_each_event.

> > +          pm++) {
> > +             int ret = fn(pm, etable, data);
> > +
> > +             if (ret)
> > +                     return ret;
> > +     }
> > +     return 0;
> > +}
> > +
> >   const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
> >   {
> >       const struct pmu_events_table *table = NULL;
> > @@ -285,7 +313,7 @@ const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
> >                       break;
> >
> >               if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > -                     table = &map->table;
> > +                     table = &map->event_table;
> >                       break;
> >               }
> >       }
> > @@ -299,7 +327,7 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
> >            tables->arch;
> >            tables++) {
> >               if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> > -                     return &tables->table;
> > +                     return &tables->event_table;
> >       }
> >       return NULL;
> >   }
> > @@ -309,7 +337,21 @@ 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->arch;
> >            tables++) {
> > -             int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
> > +             int ret = pmu_events_table_for_each_event(&tables->event_table, fn, data);
> > +
> > +             if (ret)
> > +                     return ret;
> > +     }
> > +     return 0;
> > +}
> > +
> > +int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
> > +{
> > +     for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > +          tables->arch;
> > +          tables++) {
>
> again, you can combine here

Right, done this way to reduce patch size. Later patch splits the tables.

> > +             int ret = pmu_events_table_for_each_metric(
> > +                     (const struct pmu_events_table *)&tables->metric_table, fn, data);
> >
> >               if (ret)
> >                       return ret;
> > @@ -340,3 +382,8 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
> >       }
> >       return 0;
> >   }
> > +
> > +int pmu_for_each_sys_metric(pmu_metric_iter_fn fn __maybe_unused, void *data __maybe_unused)
> > +{
> > +     return 0;
> > +}
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index 229402565425..ee3d4cdf01be 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -37,6 +37,11 @@ _json_event_attributes = [
> >       'metric_constraint', 'metric_expr', 'long_desc'
> >   ]
> >
> > +# Attributes that are in pmu_metric rather than pmu_event.
> > +_json_metric_attributes = [
> > +    'metric_name', 'metric_group', 'metric_constraint', 'metric_expr', 'desc',
> > +    'long_desc', 'unit', 'compat', 'aggr_mode'
> > +]
> >
> >   def removesuffix(s: str, suffix: str) -> str:
> >     """Remove the suffix from a string
> > @@ -562,12 +567,15 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> >   \t},
> >   };
> >
> > -static void decompress(int offset, struct pmu_event *pe)
> > +static void decompress_event(int offset, struct pmu_event *pe)
> >   {
> >   \tconst char *p = &big_c_string[offset];
> >   """)
> >     for attr in _json_event_attributes:
> > -    _args.output_file.write(f"""
> > +    if attr in _json_metric_attributes and 'metric_' in attr:
> > +      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
> > +    else:
> > +      _args.output_file.write(f"""
> >   \tpe->{attr} = (*p == '\\0' ? NULL : p);
> >   """)
> >       if attr == _json_event_attributes[-1]:
> > @@ -575,6 +583,22 @@ static void decompress(int offset, struct pmu_event *pe)
> >       _args.output_file.write('\twhile (*p++);')
> >     _args.output_file.write("""}
> >
> > +static void decompress_metric(int offset, struct pmu_metric *pm)
> > +{
> > +\tconst char *p = &big_c_string[offset];
> > +""")
> > +  for attr in _json_event_attributes:
> > +    if attr in _json_metric_attributes:
> > +      _args.output_file.write(f"""
> > +\tpm->{attr} = (*p == '\\0' ? NULL : p);
> > +""")
> > +    else:
> > +      _args.output_file.write(f'\n\t/* Skip {attr} */\n')
> > +    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)
> > @@ -583,10 +607,30 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> >                   struct pmu_event pe;
> >                   int ret;
> >
> > -                decompress(table->entries[i].offset, &pe);
> > -                ret = fn(&pe, table, data);
> > -                if (ret)
> > -                        return ret;
> > +                decompress_event(table->entries[i].offset, &pe);
> > +                if (pe.name) {
> > +                        ret = fn(&pe, table, data);
> > +                        if (ret)
> > +                                return ret;
> > +                }
> > +        }
> > +        return 0;
> > +}
> > +
> > +int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
> > +                                     pmu_metric_iter_fn fn,
> > +                                     void *data)
> > +{
> > +        for (size_t i = 0; i < table->length; i++) {
> > +                struct pmu_metric pm;
> > +                int ret;
> > +
> > +                decompress_metric(table->entries[i].offset, &pm);
> > +                if (pm.metric_name) {
> > +                        ret = fn(&pm, table, data);
> > +                        if (ret)
> > +                                return ret;
> > +                }
> >           }
> >           return 0;
> >   }
> > @@ -642,6 +686,19 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
> >           return 0;
> >   }
> >
> > +int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
> > +{
> > +        for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > +             tables->arch;
> > +             tables++) {
> > +                int ret = pmu_events_table_for_each_metric(&tables->table, fn, data);
> > +
> > +                if (ret)
> > +                        return ret;
> > +        }
> > +        return 0;
> > +}
> > +
> >   const struct pmu_events_table *find_sys_events_table(const char *name)
> >   {
> >           for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> > @@ -665,6 +722,19 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
> >           }
> >           return 0;
> >   }
> > +
> > +int pmu_for_each_sys_metric(pmu_metric_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_metric(&tables->table, fn, data);
> > +
> > +                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 fe343c4d8016..e137f3857c03 100644
> > --- a/tools/perf/pmu-events/pmu-events.h
> > +++ b/tools/perf/pmu-events/pmu-events.h
> > @@ -23,11 +23,19 @@ struct pmu_event {
> >       const char *unit;
> >       const char *perpkg;
> >       const char *aggr_mode;
> > -     const char *metric_expr;
> > +     const char *deprecated;
> > +};
> > +
> > +struct pmu_metric {
>
> In terms of formatting patches, it could have been better to first
> introdue struct pmu_metric being same as struct pmu_event, and make the
> changes of /s/struct pmu_event pe;/struct pmu_event pm;/, and then
> secondly the meaningful change to get rid of the inappropiate members in
> struct pmu_metric and struct pmu_event. It's just harder to review it
> all together.

Ok, I'll switch it this way in v3. Having done v3 I've now made this 3
changes following this suggestion, I've also folded in the empty pmu
metrics fixes. Fwiw, I'd done the non empty case and then tried to
retro fit. I think we should probably change the empty-pmu-events.c
and have a way to generate from jevents.py, then check in the
generated file to avoid the python dependency.

> >       const char *metric_name;
> >       const char *metric_group;
> > -     const char *deprecated;
> > +     const char *metric_expr;
>
> I would prefer the shorter name "expr" (as opposed to "metric_expr") as
> we know it's a metric struct already. But that does not seem to be
> coding style, so ...

Agreed. Let's do it as a later cleanup.

> > +     const char *unit;
> > +     const char *compat;
> > +     const char *aggr_mode;
> >       const char *metric_constraint;
> > +     const char *desc;
> > +     const char *long_desc;
> >   };
> >
> >   struct pmu_events_table;
> > @@ -36,14 +44,22 @@ typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
> >                                const struct pmu_events_table *table,
> >                                void *data);
> >
> > +typedef int (*pmu_metric_iter_fn)(const struct pmu_metric *pm,
> > +                               const struct pmu_events_table *table,
> > +                               void *data);
> > +
> >   int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
> >                                   void *data);
> > +int pmu_events_table_for_each_metric(const struct pmu_events_table *table, pmu_metric_iter_fn fn,
> > +                                  void *data);
> >
> >   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);
> > +int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data);
> >
> >   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);
> > +int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data);
> >
> >   #endif
> > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> > index a9f2330f6257..c2b3ada57cbc 100644
> > --- a/tools/perf/tests/pmu-events.c
> > +++ b/tools/perf/tests/pmu-events.c
> > @@ -337,36 +337,12 @@ static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event
> >               return -1;
> >       }
> >
> > -     if (!is_same(e1->metric_expr, e2->metric_expr)) {
> > -             pr_debug2("testing event e1 %s: mismatched metric_expr, %s vs %s\n",
> > -                       e1->name, e1->metric_expr, e2->metric_expr);
> > -             return -1;
>
> is there something new to replace this (I didn't check)?

The variables no longer exist and in the original test they weren't
ever defined.

> > -     }
> > -
> > -     if (!is_same(e1->metric_name, e2->metric_name)) {
> > -             pr_debug2("testing event e1 %s: mismatched metric_name, %s vs %s\n",
> > -                       e1->name,     e1->metric_name, e2->metric_name);
> > -             return -1;
> > -     }
> > -
> > -     if (!is_same(e1->metric_group, e2->metric_group)) {
> > -             pr_debug2("testing event e1 %s: mismatched metric_group, %s vs %s\n",
> > -                       e1->name, e1->metric_group, e2->metric_group);
> > -             return -1;
> > -     }
> > -
> >       if (!is_same(e1->deprecated, e2->deprecated)) {
> >               pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n",
> >                         e1->name, e1->deprecated, e2->deprecated);
> >               return -1;
> >       }
> >
> > -     if (!is_same(e1->metric_constraint, e2->metric_constraint)) {
> > -             pr_debug2("testing event e1 %s: mismatched metric_constant, %s vs %s\n",
> > -                       e1->name, e1->metric_constraint, e2->metric_constraint);
> > -             return -1;
> > -     }
> > -
> >       return 0;
> >   }
> >
> > @@ -432,9 +408,6 @@ static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
> >       struct perf_pmu_test_event const **test_event_table;
> >       bool found = false;
> >
> > -     if (!pe->name)
> > -             return 0;
> > -
> >       if (pe->pmu)
> >               test_event_table = &uncore_events[0];
> >       else
> > @@ -840,7 +813,7 @@ struct metric {
> >       struct metric_ref metric_ref;
> >   };
> >
> > -static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_events_table *table,
> > +static int test__parsing_callback(const struct pmu_metric *pm, const struct pmu_events_table *table,
> >                                 void *data)
> >   {
> >       int *failures = data;
> > @@ -854,10 +827,10 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
> >       };
> >       int err = 0;
> >
> > -     if (!pe->metric_expr)
> > +     if (!pm->metric_expr)
> >               return 0;
> >
> > -     pr_debug("Found metric '%s'\n", pe->metric_name);
> > +     pr_debug("Found metric '%s'\n", pm->metric_name);
> >       (*failures)++;
> >
> >       /*
> > @@ -877,14 +850,14 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
> >       perf_evlist__set_maps(&evlist->core, cpus, NULL);
> >       runtime_stat__init(&st);
> >
> > -     err = metricgroup__parse_groups_test(evlist, table, pe->metric_name,
> > +     err = metricgroup__parse_groups_test(evlist, table, pm->metric_name,
> >                                            false, false,
> >                                            &metric_events);
> >       if (err) {
> > -             if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") ||
> > -                 !strcmp(pe->metric_name, "M3")) {
> > +             if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
> > +                 !strcmp(pm->metric_name, "M3")) {
> >                       (*failures)--;
> > -                     pr_debug("Expected broken metric %s skipping\n", pe->metric_name);
> > +                     pr_debug("Expected broken metric %s skipping\n", pm->metric_name);
> >                       err = 0;
> >               }
> >               goto out_err;
> > @@ -912,7 +885,7 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
> >                       struct metric_expr *mexp;
> >
> >                       list_for_each_entry (mexp, &me->head, nd) {
> > -                             if (strcmp(mexp->metric_name, pe->metric_name))
> > +                             if (strcmp(mexp->metric_name, pm->metric_name))
> >                                       continue;
> >                               pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st));
> >                               err = 0;
> > @@ -921,11 +894,11 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
> >                       }
> >               }
> >       }
> > -     pr_debug("Didn't find parsed metric %s", pe->metric_name);
> > +     pr_debug("Didn't find parsed metric %s", pm->metric_name);
> >       err = 1;
> >   out_err:
> >       if (err)
> > -             pr_debug("Broken metric %s\n", pe->metric_name);
> > +             pr_debug("Broken metric %s\n", pm->metric_name);
> >
> >       /* ... cleanup. */
> >       metricgroup__rblist_exit(&metric_events);
> > @@ -941,8 +914,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> >   {
> >       int failures = 0;
> >
> > -     pmu_for_each_core_event(test__parsing_callback, &failures);
> > -     pmu_for_each_sys_event(test__parsing_callback, &failures);
> > +     pmu_for_each_core_metric(test__parsing_callback, &failures);
> > +     pmu_for_each_sys_metric(test__parsing_callback, &failures);
> >
> >       return failures == 0 ? TEST_OK : TEST_FAIL;
> >   }
> > @@ -1021,14 +994,11 @@ static int metric_parse_fake(const char *metric_name, const char *str)
> >       return ret;
> >   }
> >
> > -static int test__parsing_fake_callback(const struct pmu_event *pe,
> > +static int test__parsing_fake_callback(const struct pmu_metric *pm,
> >                                      const struct pmu_events_table *table __maybe_unused,
> >                                      void *data __maybe_unused)
> >   {
> > -     if (!pe->metric_expr)
> > -             return 0;
> > -
> > -     return metric_parse_fake(pe->metric_name, pe->metric_expr);
> > +     return metric_parse_fake(pm->metric_name, pm->metric_expr);
> >   }
> >
> >   /*
> > @@ -1047,11 +1017,11 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
> >                       return err;
> >       }
> >
> > -     err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
> > +     err = pmu_for_each_core_metric(test__parsing_fake_callback, NULL);
> >       if (err)
> >               return err;
> >
> > -     return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
> > +     return pmu_for_each_sys_metric(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 b9c273ed080a..47fd02af66f1 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -167,14 +167,14 @@ static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
> >                  "    echo 1 > /proc/sys/kernel/nmi_watchdog\n");
> >   }
> >
> > -static bool metricgroup__has_constraint(const struct pmu_event *pe)
> > +static bool metricgroup__has_constraint(const struct pmu_metric *pm)
> >   {
> > -     if (!pe->metric_constraint)
> > +     if (!pm->metric_constraint)
> >               return false;
> >
> > -     if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") &&
> > +     if (!strcmp(pm->metric_constraint, "NO_NMI_WATCHDOG") &&
> >           sysctl__nmi_watchdog_enabled()) {
> > -             metricgroup___watchdog_constraint_hint(pe->metric_name, false);
> > +             metricgroup___watchdog_constraint_hint(pm->metric_name, false);
> >               return true;
> >       }
> >
> > @@ -193,7 +193,7 @@ static void metric__free(struct metric *m)
> >       free(m);
> >   }
> >
> > -static struct metric *metric__new(const struct pmu_event *pe,
> > +static struct metric *metric__new(const struct pmu_metric *pm,
> >                                 const char *modifier,
> >                                 bool metric_no_group,
> >                                 int runtime,
> > @@ -210,15 +210,15 @@ static struct metric *metric__new(const struct pmu_event *pe,
> >       if (!m->pctx)
> >               goto out_err;
> >
> > -     m->metric_name = pe->metric_name;
> > +     m->metric_name = pm->metric_name;
> >       m->modifier = NULL;
> >       if (modifier) {
> >               m->modifier = strdup(modifier);
> >               if (!m->modifier)
> >                       goto out_err;
> >       }
> > -     m->metric_expr = pe->metric_expr;
> > -     m->metric_unit = pe->unit;
> > +     m->metric_expr = pm->metric_expr;
> > +     m->metric_unit = pm->unit;
> >       m->pctx->sctx.user_requested_cpu_list = NULL;
> >       if (user_requested_cpu_list) {
> >               m->pctx->sctx.user_requested_cpu_list = strdup(user_requested_cpu_list);
> > @@ -227,7 +227,7 @@ static struct metric *metric__new(const struct pmu_event *pe,
> >       }
> >       m->pctx->sctx.runtime = runtime;
> >       m->pctx->sctx.system_wide = system_wide;
> > -     m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
> > +     m->has_constraint = metric_no_group || metricgroup__has_constraint(pm);
> >       m->metric_refs = NULL;
> >       m->evlist = NULL;
> >
> > @@ -348,10 +348,10 @@ static bool match_metric(const char *n, const char *list)
> >       return false;
> >   }
> >
> > -static bool match_pe_metric(const struct pmu_event *pe, const char *metric)
> > +static bool match_pm_metric(const struct pmu_metric *pm, const char *metric)
> >   {
> > -     return match_metric(pe->metric_group, metric) ||
> > -            match_metric(pe->metric_name, metric);
> > +     return match_metric(pm->metric_group, metric) ||
> > +            match_metric(pm->metric_name, metric);
> >   }
> >
> >   /** struct mep - RB-tree node for building printing information. */
> > @@ -420,13 +420,13 @@ static struct mep *mep_lookup(struct rblist *groups, const char *metric_group,
> >       return NULL;
> >   }
> >
> > -static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
> > +static int metricgroup__add_to_mep_groups(const struct pmu_metric *pm,
> >                                       struct rblist *groups)
> >   {
> >       const char *g;
> >       char *omg, *mg;
> >
> > -     mg = strdup(pe->metric_group ?: "No_group");
> > +     mg = strdup(pm->metric_group ?: "No_group");
> >       if (!mg)
> >               return -ENOMEM;
> >       omg = mg;
> > @@ -435,15 +435,15 @@ static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
> >
> >               g = skip_spaces(g);
> >               if (strlen(g))
> > -                     me = mep_lookup(groups, g, pe->metric_name);
> > +                     me = mep_lookup(groups, g, pm->metric_name);
> >               else
> > -                     me = mep_lookup(groups, "No_group", pe->metric_name);
> > +                     me = mep_lookup(groups, "No_group", pm->metric_name);
> >
> >               if (me) {
> > -                     me->metric_desc = pe->desc;
> > -                     me->metric_long_desc = pe->long_desc;
> > -                     me->metric_expr = pe->metric_expr;
> > -                     me->metric_unit = pe->unit;
> > +                     me->metric_desc = pm->desc;
> > +                     me->metric_long_desc = pm->long_desc;
> > +                     me->metric_expr = pm->metric_expr;
>
> could struct pmu_metric be a sub-struct in struct mep?

struct mep is only used for 'perf list' and has a subset of the
information in struct pmu_metric. The metric_group is also mutated. I
like the idea of merging them and having a single assignment here, but
it would add some overhead for limited gain.

> > +                     me->metric_unit = pm->unit;
> >               }
> >       }
> >       free(omg);
> > @@ -452,40 +452,37 @@ static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
> >   }
> >
> >   struct metricgroup_iter_data {
> > -     pmu_event_iter_fn fn;
> > +     pmu_metric_iter_fn fn;
> >       void *data;
> >   };
> >
> > -static int metricgroup__sys_event_iter(const struct pmu_event *pe,
> > +static int metricgroup__sys_event_iter(const struct pmu_metric *pm,
> >                                      const struct pmu_events_table *table,
> >                                      void *data)
> >   {
> >       struct metricgroup_iter_data *d = data;
> >       struct perf_pmu *pmu = NULL;
> >
> > -     if (!pe->metric_expr || !pe->compat)
> > +     if (!pm->metric_expr || !pm->compat)
> >               return 0;
> >
> >       while ((pmu = perf_pmu__scan(pmu))) {
> >
> > -             if (!pmu->id || strcmp(pmu->id, pe->compat))
> > +             if (!pmu->id || strcmp(pmu->id, pm->compat))
> >                       continue;
> >
> > -             return d->fn(pe, table, d->data);
> > +             return d->fn(pm, table, d->data);
> >       }
> >       return 0;
> >   }
> >
> > -static int metricgroup__add_to_mep_groups_callback(const struct pmu_event *pe,
> > +static int metricgroup__add_to_mep_groups_callback(const struct pmu_metric *pm,
> >                                               const struct pmu_events_table *table __maybe_unused,
> >                                               void *vdata)
> >   {
> >       struct rblist *groups = vdata;
> >
> > -     if (!pe->metric_name)
> > -             return 0;
> > -
> > -     return metricgroup__add_to_mep_groups(pe, groups);
> > +     return metricgroup__add_to_mep_groups(pm, groups);
> >   }
> >
> >   void metricgroup__print(const struct print_callbacks *print_cb, void *print_state)
> > @@ -500,16 +497,16 @@ void metricgroup__print(const struct print_callbacks *print_cb, void *print_stat
> >       groups.node_delete = mep_delete;
> >       table = pmu_events_table__find();
> >       if (table) {
> > -             pmu_events_table_for_each_event(table,
> > -                                             metricgroup__add_to_mep_groups_callback,
> > -                                             &groups);
> > +             pmu_events_table_for_each_metric(table,
> > +                                              metricgroup__add_to_mep_groups_callback,
> > +                                              &groups);
> >       }
> >       {
> >               struct metricgroup_iter_data data = {
> >                       .fn = metricgroup__add_to_mep_groups_callback,
> >                       .data = &groups,
> >               };
> > -             pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
> > +             pmu_for_each_sys_metric(metricgroup__sys_event_iter, &data);
> >       }
> >
> >       for (node = rb_first_cached(&groups.entries); node; node = next) {
> > @@ -743,7 +740,7 @@ static int metricgroup__build_event_string(struct strbuf *events,
> >   #undef RETURN_IF_NON_ZERO
> >   }
> >
> > -int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused)
> > +int __weak arch_get_runtimeparam(const struct pmu_metric *pm __maybe_unused)
> >   {
> >       return 1;
> >   }
> > @@ -773,10 +770,10 @@ struct metricgroup_add_iter_data {
> >
> >   static bool metricgroup__find_metric(const char *metric,
> >                                    const struct pmu_events_table *table,
> > -                                  struct pmu_event *pe);
> > +                                  struct pmu_metric *pm);
> >
> >   static int add_metric(struct list_head *metric_list,
> > -                   const struct pmu_event *pe,
> > +                   const struct pmu_metric *pm,
> >                     const char *modifier,
> >                     bool metric_no_group,
> >                     const char *user_requested_cpu_list,
> > @@ -816,10 +813,10 @@ static int resolve_metric(struct list_head *metric_list,
> >       size_t bkt;
> >       struct to_resolve {
> >               /* The metric to resolve. */
> > -             struct pmu_event pe;
> > +             struct pmu_metric pm;
> >               /*
> >                * The key in the IDs map, this may differ from in case,
> > -              * etc. from pe->metric_name.
> > +              * etc. from pm->metric_name.
> >                */
> >               const char *key;
> >       } *pending = NULL;
> > @@ -830,15 +827,15 @@ static int resolve_metric(struct list_head *metric_list,
> >        * the pending array.
> >        */
> >       hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
> > -             struct pmu_event pe;
> > +             struct pmu_metric pm;
> >
> > -             if (metricgroup__find_metric(cur->pkey, table, &pe)) {
> > +             if (metricgroup__find_metric(cur->pkey, table, &pm)) {
> >                       pending = realloc(pending,
> >                                       (pending_cnt + 1) * sizeof(struct to_resolve));
> >                       if (!pending)
> >                               return -ENOMEM;
> >
> > -                     memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
> > +                     memcpy(&pending[pending_cnt].pm, &pm, sizeof(pm));
> >                       pending[pending_cnt].key = cur->pkey;
> >                       pending_cnt++;
> >               }
> > @@ -853,7 +850,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].pm, modifier, metric_no_group,
> >                                user_requested_cpu_list, system_wide, root_metric, visited,
> >                                table);
> >               if (ret)
> > @@ -867,7 +864,7 @@ static int resolve_metric(struct list_head *metric_list,
> >   /**
> >    * __add_metric - Add a metric to metric_list.
> >    * @metric_list: The list the metric is added to.
> > - * @pe: The pmu_event containing the metric to be added.
> > + * @pm: The pmu_metric containing the metric to be added.
> >    * @modifier: if non-null event modifiers like "u".
> >    * @metric_no_group: Should events written to events be grouped "{}" or
> >    *                   global. Grouping is the default but due to multiplexing the
> > @@ -884,7 +881,7 @@ static int resolve_metric(struct list_head *metric_list,
> >    *       architecture perf is running upon.
> >    */
> >   static int __add_metric(struct list_head *metric_list,
> > -                     const struct pmu_event *pe,
> > +                     const struct pmu_metric *pm,
> >                       const char *modifier,
> >                       bool metric_no_group,
> >                       int runtime,
> > @@ -898,13 +895,13 @@ static int __add_metric(struct list_head *metric_list,
> >       int ret;
> >       bool is_root = !root_metric;
> >       struct visited_metric visited_node = {
> > -             .name = pe->metric_name,
> > +             .name = pm->metric_name,
> >               .parent = visited,
> >       };
> >
> >       for (vm = visited; vm; vm = vm->parent) {
> > -             if (!strcmp(pe->metric_name, vm->name)) {
> > -                     pr_err("failed: recursion detected for %s\n", pe->metric_name);
> > +             if (!strcmp(pm->metric_name, vm->name)) {
> > +                     pr_err("failed: recursion detected for %s\n", pm->metric_name);
> >                       return -1;
> >               }
> >       }
> > @@ -914,7 +911,7 @@ static int __add_metric(struct list_head *metric_list,
> >                * This metric is the root of a tree and may reference other
> >                * metrics that are added recursively.
> >                */
> > -             root_metric = metric__new(pe, modifier, metric_no_group, runtime,
> > +             root_metric = metric__new(pm, modifier, metric_no_group, runtime,
> >                                         user_requested_cpu_list, system_wide);
> >               if (!root_metric)
> >                       return -ENOMEM;
> > @@ -929,7 +926,7 @@ static int __add_metric(struct list_head *metric_list,
> >                */
> >               if (root_metric->metric_refs) {
> >                       for (; root_metric->metric_refs[cnt].metric_name; cnt++) {
> > -                             if (!strcmp(pe->metric_name,
> > +                             if (!strcmp(pm->metric_name,
> >                                           root_metric->metric_refs[cnt].metric_name))
> >                                       return 0;
> >                       }
> > @@ -947,8 +944,8 @@ static int __add_metric(struct list_head *metric_list,
> >                * need to change them, so there's no need to create
> >                * our own copy.
> >                */
> > -             root_metric->metric_refs[cnt].metric_name = pe->metric_name;
> > -             root_metric->metric_refs[cnt].metric_expr = pe->metric_expr;
> > +             root_metric->metric_refs[cnt].metric_name = pm->metric_name;
> > +             root_metric->metric_refs[cnt].metric_expr = pm->metric_expr;
> >
> >               /* Null terminate array. */
> >               root_metric->metric_refs[cnt+1].metric_name = NULL;
> > @@ -959,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
> >        * For both the parent and referenced metrics, we parse
> >        * all the metric's IDs and add it to the root context.
> >        */
> > -     if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) {
> > +     if (expr__find_ids(pm->metric_expr, NULL, root_metric->pctx) < 0) {
> >               /* Broken metric. */
> >               ret = -EINVAL;
> >       } else {
> > @@ -981,37 +978,37 @@ static int __add_metric(struct list_head *metric_list,
> >
> >   struct metricgroup__find_metric_data {
> >       const char *metric;
> > -     struct pmu_event *pe;
> > +     struct pmu_metric *pm;
> >   };
> >
> > -static int metricgroup__find_metric_callback(const struct pmu_event *pe,
> > +static int metricgroup__find_metric_callback(const struct pmu_metric *pm,
> >                                            const struct pmu_events_table *table  __maybe_unused,
> >                                            void *vdata)
> >   {
> >       struct metricgroup__find_metric_data *data = vdata;
> >
> > -     if (!match_metric(pe->metric_name, data->metric))
> > +     if (!match_metric(pm->metric_name, data->metric))
> >               return 0;
> >
> > -     memcpy(data->pe, pe, sizeof(*pe));
> > +     memcpy(data->pm, pm, sizeof(*pm));
> >       return 1;
> >   }
> >
> >   static bool metricgroup__find_metric(const char *metric,
> >                                    const struct pmu_events_table *table,
> > -                                  struct pmu_event *pe)
> > +                                  struct pmu_metric *pm)
> >   {
> >       struct metricgroup__find_metric_data data = {
> >               .metric = metric,
> > -             .pe = pe,
> > +             .pm = pm,
> >       };
> >
> > -     return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
> > +     return pmu_events_table_for_each_metric(table, metricgroup__find_metric_callback, &data)
> >               ? true : false;
>
> comment on pre-existing code: since it returns bool, I don't think the
> ternary operator is required at all. There are many instances of this.

There'd be an implicit int -> bool conversion, which is why this
exists. Perhaps changing the return type to int as the int pattern is
ubiquitous.

Thanks,
Ian


> >   }
> >
> >   static int add_metric(struct list_head *metric_list,
> > -                   const struct pmu_event *pe,
> > +                   const struct pmu_metric *pm,
> >                     const char *modifier,
> >                     bool metric_no_group,
> >                     const char *user_requested_cpu_list,
> > @@ -1022,16 +1019,16 @@ static int add_metric(struct list_head *metric_list,
> >   {
> >       int ret = 0;
> >
> > -     pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> > +     pr_debug("metric expr %s for %s\n", pm->metric_expr, pm->metric_name);
> >
> > -     if (!strstr(pe->metric_expr, "?")) {
> > -             ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> > +     if (!strstr(pm->metric_expr, "?")) {
> > +             ret = __add_metric(metric_list, pm, modifier, metric_no_group, 0,
> >                                  user_requested_cpu_list, system_wide, root_metric,
> >                                  visited, table);
> >       } else {
> >               int j, count;
> >
> > -             count = arch_get_runtimeparam(pe);
> > +             count = arch_get_runtimeparam(pm);
> >
> >               /* This loop is added to create multiple
> >                * events depend on count value and add
> > @@ -1039,7 +1036,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,
> > +                     ret = __add_metric(metric_list, pm, modifier, metric_no_group, j,
> >                                          user_requested_cpu_list, system_wide,
> >                                          root_metric, visited, table);
> >       }
> > @@ -1047,17 +1044,17 @@ static int add_metric(struct list_head *metric_list,
> >       return ret;
> >   }
> >
> > -static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
> > +static int metricgroup__add_metric_sys_event_iter(const struct pmu_metric *pm,
> >                                               const struct pmu_events_table *table __maybe_unused,
> >                                               void *data)
> >   {
> >       struct metricgroup_add_iter_data *d = data;
> >       int ret;
> >
> > -     if (!match_pe_metric(pe, d->metric_name))
> > +     if (!match_pm_metric(pm, d->metric_name))
> >               return 0;
> >
> > -     ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> > +     ret = add_metric(d->metric_list, pm, d->modifier, d->metric_no_group,
> >                        d->user_requested_cpu_list, d->system_wide,
> >                        d->root_metric, d->visited, d->table);
> >       if (ret)
> > @@ -1107,19 +1104,19 @@ struct metricgroup__add_metric_data {
> >       bool has_match;
> >   };
> >
> > -static int metricgroup__add_metric_callback(const struct pmu_event *pe,
> > +static int metricgroup__add_metric_callback(const struct pmu_metric *pm,
> >                                           const struct pmu_events_table *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))) {
> > +     if (pm->metric_expr &&
> > +             (match_metric(pm->metric_group, data->metric_name) ||
> > +              match_metric(pm->metric_name, data->metric_name))) {
> >
> >               data->has_match = true;
> > -             ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
> > +             ret = add_metric(data->list, pm, data->modifier, data->metric_no_group,
> >                                data->user_requested_cpu_list, data->system_wide,
> >                                /*root_metric=*/NULL, /*visited_metrics=*/NULL, table);
> >       }
> > @@ -1166,8 +1163,8 @@ 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.
> >                */
> > -             ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
> > -                                                   &data);
> > +             ret = pmu_events_table_for_each_metric(table, metricgroup__add_metric_callback,
> > +                                                    &data);
> >               if (ret)
> >                       goto out;
> >
> > @@ -1189,7 +1186,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> >                       },
> >               };
> >
> > -             pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
> > +             pmu_for_each_sys_metric(metricgroup__sys_event_iter, &data);
> >       }
> >       /* End of pmu events. */
> >       if (!has_match)
> > @@ -1603,16 +1600,16 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
> >                           &perf_pmu__fake, metric_events, table);
> >   }
> >
> > -static int metricgroup__has_metric_callback(const struct pmu_event *pe,
> > +static int metricgroup__has_metric_callback(const struct pmu_metric *pm,
> >                                           const struct pmu_events_table *table __maybe_unused,
> >                                           void *vdata)
> >   {
> >       const char *metric = vdata;
> >
> > -     if (!pe->metric_expr)
> > +     if (!pm->metric_expr)
> >               return 0;
> >
> > -     if (match_metric(pe->metric_name, metric))
> > +     if (match_metric(pm->metric_name, metric))
> >               return 1;
> >
> >       return 0;
> > @@ -1625,8 +1622,8 @@ bool metricgroup__has_metric(const char *metric)
> >       if (!table)
> >               return false;
> >
> > -     return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
> > -                                            (void *)metric) ? true : false;
> > +     return pmu_events_table_for_each_metric(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/metricgroup.h b/tools/perf/util/metricgroup.h
> > index 0013cf582173..b1f186d0f514 100644
> > --- a/tools/perf/util/metricgroup.h
> > +++ b/tools/perf/util/metricgroup.h
> > @@ -81,7 +81,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
> >
> >   void metricgroup__print(const struct print_callbacks *print_cb, void *print_state);
> >   bool metricgroup__has_metric(const char *metric);
> > -int arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused);
> > +int arch_get_runtimeparam(const struct pmu_metric *pm);
> >   void metricgroup__rblist_exit(struct rblist *metric_events);
> >
> >   int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
> > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> > index 21cce83462b3..0336ff27c15f 100644
> > --- a/tools/perf/util/parse-events.c
> > +++ b/tools/perf/util/parse-events.c
> > @@ -1570,8 +1570,6 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
> >       evsel->scale = info.scale;
> >       evsel->per_pkg = info.per_pkg;
> >       evsel->snapshot = info.snapshot;
> > -     evsel->metric_expr = info.metric_expr;
> > -     evsel->metric_name = info.metric_name;
> >       return 0;
> >   }
> >
> > diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> > index 2bdeb89352e7..d627f99b5a63 100644
> > --- a/tools/perf/util/pmu.c
> > +++ b/tools/perf/util/pmu.c
> > @@ -283,10 +283,6 @@ static void perf_pmu_update_alias(struct perf_pmu_alias *old,
> >       perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
> >                           &newalias->long_desc);
> >       perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
> > -     perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
> > -                         &newalias->metric_expr);
> > -     perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
> > -                         &newalias->metric_name);
> >       perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
> >       old->scale = newalias->scale;
> >       old->per_pkg = newalias->per_pkg;
> > @@ -302,8 +298,6 @@ void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
> >       zfree(&newalias->long_desc);
> >       zfree(&newalias->topic);
> >       zfree(&newalias->str);
> > -     zfree(&newalias->metric_expr);
> > -     zfree(&newalias->metric_name);
> >       zfree(&newalias->pmu_name);
> >       parse_events_terms__purge(&newalias->terms);
> >       free(newalias);
> > @@ -340,16 +334,13 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
> >       int num;
> >       char newval[256];
> >       char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL,
> > -          *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL,
> > -          *pmu_name = NULL;
> > +          *deprecated = NULL, *pmu_name = NULL;
> >
> >       if (pe) {
> >               long_desc = (char *)pe->long_desc;
> >               topic = (char *)pe->topic;
> >               unit = (char *)pe->unit;
> >               perpkg = (char *)pe->perpkg;
> > -             metric_expr = (char *)pe->metric_expr;
> > -             metric_name = (char *)pe->metric_name;
> >               deprecated = (char *)pe->deprecated;
> >               pmu_name = (char *)pe->pmu;
> >       }
> > @@ -404,8 +395,6 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
> >               perf_pmu__parse_snapshot(alias, dir, name);
> >       }
> >
> > -     alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
> > -     alias->metric_name = metric_name ? strdup(metric_name): NULL;
> >       alias->desc = desc ? strdup(desc) : NULL;
> >       alias->long_desc = long_desc ? strdup(long_desc) :
> >                               desc ? strdup(desc) : NULL;
> > @@ -822,9 +811,6 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
> >       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;
> >
> > @@ -879,12 +865,6 @@ static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
> >       struct pmu_sys_event_iter_data *idata = data;
> >       struct perf_pmu *pmu = idata->pmu;
> >
> > -     if (!pe->name) {
> > -             if (pe->metric_group || pe->metric_name)
> > -                     return 0;
> > -             return -EINVAL;
> > -     }
> > -
> >       if (!pe->compat || !pe->pmu)
> >               return 0;
> >
> > @@ -1469,8 +1449,6 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
> >       info->unit     = NULL;
> >       info->scale    = 0.0;
> >       info->snapshot = false;
> > -     info->metric_expr = NULL;
> > -     info->metric_name = NULL;
> >
> >       list_for_each_entry_safe(term, h, head_terms, list) {
> >               alias = pmu_find_alias(pmu, term);
> > @@ -1486,8 +1464,6 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
> >
> >               if (alias->per_pkg)
> >                       info->per_pkg = true;
> > -             info->metric_expr = alias->metric_expr;
> > -             info->metric_name = alias->metric_name;
> >
> >               list_del_init(&term->list);
> >               parse_events_term__delete(term);
> > @@ -1703,8 +1679,7 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
> >       for (j = 0; j < len; j++) {
> >               const char *name, *alias = NULL, *scale_unit = NULL,
> >                       *desc = NULL, *long_desc = NULL,
> > -                     *encoding_desc = NULL, *topic = NULL,
> > -                     *metric_name = NULL, *metric_expr = NULL;
> > +                     *encoding_desc = NULL, *topic = NULL;
> >               bool deprecated = false;
> >               size_t buf_used;
> >
> > @@ -1742,8 +1717,6 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
> >                       buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
> >                                       "%s/%s/", aliases[j].pmu->name,
> >                                       aliases[j].event->str) + 1;
> > -                     metric_name = aliases[j].event->metric_name;
> > -                     metric_expr = aliases[j].event->metric_expr;
> >                       deprecated = aliases[j].event->deprecated;
> >               }
> >               print_cb->print_event(print_state,
> > @@ -1756,9 +1729,7 @@ void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
> >                               "Kernel PMU event",
> >                               desc,
> >                               long_desc,
> > -                             encoding_desc,
> > -                             metric_name,
> > -                             metric_expr);
> > +                             encoding_desc);
> >       }
> >       if (printed && pager_in_use())
> >               printf("\n");
> > diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> > index 69ca0004f94f..4d8d64209b4b 100644
> > --- a/tools/perf/util/pmu.h
> > +++ b/tools/perf/util/pmu.h
> > @@ -133,8 +133,6 @@ extern struct perf_pmu perf_pmu__fake;
> >
> >   struct perf_pmu_info {
> >       const char *unit;
> > -     const char *metric_expr;
> > -     const char *metric_name;
> >       double scale;
> >       bool per_pkg;
> >       bool snapshot;
> > @@ -188,13 +186,6 @@ struct perf_pmu_alias {
> >        * default.
> >        */
> >       bool deprecated;
> > -     /**
> > -      * @metric_expr: A metric expression associated with an event. Doing
> > -      * this makes little sense due to scale and unit applying to both.
> > -      */
> > -     char *metric_expr;
> > -     /** @metric_name: A name for the metric. unit applying to both. */
> > -     char *metric_name;
> >       /** @pmu_name: The name copied from struct perf_pmu. */
> >       char *pmu_name;
> >   };
> > diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c
> > index 2646ae18d9f9..62e9ea7dcf40 100644
> > --- a/tools/perf/util/print-events.c
> > +++ b/tools/perf/util/print-events.c
> > @@ -101,9 +101,7 @@ void print_tracepoint_events(const struct print_callbacks *print_cb, void *print
> >                                       "Tracepoint event",
> >                                       /*desc=*/NULL,
> >                                       /*long_desc=*/NULL,
> > -                                     /*encoding_desc=*/NULL,
> > -                                     /*metric_name=*/NULL,
> > -                                     /*metric_expr=*/NULL);
> > +                                     /*encoding_desc=*/NULL);
> >               }
> >               free(dir_path);
> >               free(evt_namelist);
> > @@ -195,9 +193,7 @@ void print_sdt_events(const struct print_callbacks *print_cb, void *print_state)
> >                               "SDT event",
> >                               /*desc=*/NULL,
> >                               /*long_desc=*/NULL,
> > -                             /*encoding_desc=*/NULL,
> > -                             /*metric_name=*/NULL,
> > -                             /*metric_expr=*/NULL);
> > +                             /*encoding_desc=*/NULL);
> >
> >               free(evt_name);
> >       }
> > @@ -255,9 +251,7 @@ int print_hwcache_events(const struct print_callbacks *print_cb, void *print_sta
> >                               event_type_descriptors[PERF_TYPE_HW_CACHE],
> >                               /*desc=*/NULL,
> >                               /*long_desc=*/NULL,
> > -                             /*encoding_desc=*/NULL,
> > -                             /*metric_name=*/NULL,
> > -                             /*metric_expr=*/NULL);
> > +                             /*encoding_desc=*/NULL);
> >       }
> >       strlist__delete(evt_name_list);
> >       return 0;
> > @@ -277,9 +271,7 @@ void print_tool_events(const struct print_callbacks *print_cb, void *print_state
> >                               "Tool event",
> >                               /*desc=*/NULL,
> >                               /*long_desc=*/NULL,
> > -                             /*encoding_desc=*/NULL,
> > -                             /*metric_name=*/NULL,
> > -                             /*metric_expr=*/NULL);
> > +                             /*encoding_desc=*/NULL);
> >       }
> >   }
> >
> > @@ -331,9 +323,7 @@ void print_symbol_events(const struct print_callbacks *print_cb, void *print_sta
> >                               event_type_descriptors[type],
> >                               /*desc=*/NULL,
> >                               /*long_desc=*/NULL,
> > -                             /*encoding_desc=*/NULL,
> > -                             /*metric_name=*/NULL,
> > -                             /*metric_expr=*/NULL);
> > +                             /*encoding_desc=*/NULL);
> >       }
> >       strlist__delete(evt_name_list);
> >   }
> > @@ -364,9 +354,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
> >                       event_type_descriptors[PERF_TYPE_RAW],
> >                       /*desc=*/NULL,
> >                       /*long_desc=*/NULL,
> > -                     /*encoding_desc=*/NULL,
> > -                     /*metric_name=*/NULL,
> > -                     /*metric_expr=*/NULL);
> > +                     /*encoding_desc=*/NULL);
> >
> >       print_cb->print_event(print_state,
> >                       /*topic=*/NULL,
> > @@ -378,9 +366,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
> >                       event_type_descriptors[PERF_TYPE_RAW],
> >                       "(see 'man perf-list' on how to encode it)",
> >                       /*long_desc=*/NULL,
> > -                     /*encoding_desc=*/NULL,
> > -                     /*metric_name=*/NULL,
> > -                     /*metric_expr=*/NULL);
> > +                     /*encoding_desc=*/NULL);
> >
> >       print_cb->print_event(print_state,
> >                       /*topic=*/NULL,
> > @@ -392,9 +378,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
> >                       event_type_descriptors[PERF_TYPE_BREAKPOINT],
> >                       /*desc=*/NULL,
> >                       /*long_desc=*/NULL,
> > -                     /*encoding_desc=*/NULL,
> > -                     /*metric_name=*/NULL,
> > -                     /*metric_expr=*/NULL);
> > +                     /*encoding_desc=*/NULL);
> >
> >       print_tracepoint_events(print_cb, print_state);
> >
> > diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h
> > index c237e53c4487..716dcf4b4859 100644
> > --- a/tools/perf/util/print-events.h
> > +++ b/tools/perf/util/print-events.h
> > @@ -16,8 +16,7 @@ struct print_callbacks {
> >                       const char *scale_unit,
> >                       bool deprecated, const char *event_type_desc,
> >                       const char *desc, const char *long_desc,
> > -                     const char *encoding_desc,
> > -                     const char *metric_name, const char *metric_expr);
> > +                     const char *encoding_desc);
> >       void (*print_metric)(void *print_state,
> >                       const char *group,
> >                       const char *name,
>

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

* Re: [PATCH v2 7/9] perf pmu-events: Introduce pmu_metrics_table
  2023-01-23 15:35   ` John Garry
@ 2023-01-24  4:48     ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2023-01-24  4:48 UTC (permalink / raw)
  To: John Garry
  Cc: Mark Rutland, Kang Minchul, Sandipan Das, Peter Zijlstra,
	Perry Taylor, Stephane Eranian, linux-kernel, James Clark,
	Kim Phillips, Will Deacon, Kan Liang, Rob Herring,
	Alexander Shishkin, Ingo Molnar, Xing Zhengjun, Mike Leach,
	Kajol Jain, Arnaldo Carvalho de Melo, Namhyung Kim,
	Caleb Biggers, linux-arm-kernel, Ravi Bangoria, Florian Fischer,
	Adrian Hunter, linux-perf-users, Jiri Olsa, Leo Yan,
	linuxppc-dev, Jing Zhang

On Mon, Jan 23, 2023 at 7:36 AM John Garry <john.g.garry@oracle.com> wrote:
>
> On 21/12/2022 22:34, Ian Rogers wrote:
> > Add a metrics table that is just a cast from pmu_events_table. This
> > changes the APIs so that event and metric usage of the underlying
> > table is different. Later changes will separate the tables.
> >
> > This introduction fixes a NO_JEVENTS=1 regression on:
> >   68: Parse and process metrics                                       : Ok
> >   70: Event expansion for cgroups                                     : Ok
> > caused by the necessary test metrics not being found.
> >
>
> I have just checked some of this code so far...
>
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >   tools/perf/arch/arm64/util/pmu.c         | 23 ++++++++++-
> >   tools/perf/pmu-events/empty-pmu-events.c | 52 ++++++++++++++++++++----
> >   tools/perf/pmu-events/jevents.py         | 24 ++++++++---
> >   tools/perf/pmu-events/pmu-events.h       | 10 +++--
> >   tools/perf/tests/expand-cgroup.c         |  4 +-
> >   tools/perf/tests/parse-metric.c          |  4 +-
> >   tools/perf/tests/pmu-events.c            |  5 ++-
> >   tools/perf/util/metricgroup.c            | 50 +++++++++++------------
> >   tools/perf/util/metricgroup.h            |  2 +-
> >   tools/perf/util/pmu.c                    |  9 +++-
> >   tools/perf/util/pmu.h                    |  1 +
> >   11 files changed, 133 insertions(+), 51 deletions(-)
> >
> > diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> > index 477e513972a4..f8ae479a06db 100644
> > --- a/tools/perf/arch/arm64/util/pmu.c
> > +++ b/tools/perf/arch/arm64/util/pmu.c
> > @@ -19,7 +19,28 @@ const struct pmu_events_table *pmu_events_table__find(void)
> >               if (pmu->cpus->nr != cpu__max_cpu().cpu)
> >                       return NULL;
> >
> > -             return perf_pmu__find_table(pmu);
> > +             return perf_pmu__find_events_table(pmu);
> > +     }
> > +
> > +     return NULL;
> > +}
> > +
> > +const struct pmu_metrics_table *pmu_metrics_table__find(void)
> > +{
> > +     struct perf_pmu *pmu = NULL;
> > +
> > +     while ((pmu = perf_pmu__scan(pmu))) {
> > +             if (!is_pmu_core(pmu->name))
> > +                     continue;
> > +
> > +             /*
> > +              * The cpumap should cover all CPUs. Otherwise, some CPUs may
> > +              * not support some events or have different event IDs.
> > +              */
> > +             if (pmu->cpus->nr != cpu__max_cpu().cpu)
> > +                     return NULL;
> > +
> > +             return perf_pmu__find_metrics_table(pmu);
>
> I think that this code will be conflicting with the recent arm64 metric
> support. And now it seems even more scope for factoring out code.

v3 will rebase and fix.

> >       }
> >
> >       return NULL;
> > diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> > index 5572a4d1eddb..d50f60a571dd 100644
> > --- a/tools/perf/pmu-events/empty-pmu-events.c
> > +++ b/tools/perf/pmu-events/empty-pmu-events.c
> > @@ -278,14 +278,12 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_ev
> >       return 0;
> >   }
> >
> > -int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_metric_iter_fn fn,
> > -                                  void *data)
> > +int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
> > +                                   void *data)
> >   {
> > -     struct pmu_metrics_table *table = (struct pmu_metrics_table *)etable;
> > -
> >       for (const struct pmu_metric *pm = &table->entries[0]
>
> nit on coding style: do we normally declare local variables like this?
> It condenses the code but makes a bit less readable, IMHO

The main reason to do it is to reduce the scope of pm to just be the
loop body. There's some discussion relating to this to do with the
move to C11:
https://lwn.net/Articles/885941/

> > ; pm->metric_group || pm->metric_name;
> >            pm++) {
> > -             int ret = fn(pm, etable, data);
> > +             int ret = fn(pm, table, data);
> >
> >               if (ret)
> >                       return ret;
> > @@ -293,7 +291,7 @@ int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_
> >       return 0;
> >   }
> >
> > -const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
> > +const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
> >   {
> >       const struct pmu_events_table *table = NULL;
> >       char *cpuid = perf_pmu__getcpuid(pmu);
> > @@ -321,6 +319,34 @@ const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
> >       return table;
> >   }
> >
> > +const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
> > +{
> > +     const struct pmu_metrics_table *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++];
>
> To me, this is all strange code. Again this is a comment on the current
> code: Consider pmu_for_each_sys_event() as an example, we have a while
> loop for each member of pmu_sys_event_tables[]. But pmu_sys_event_tables
> is hardcoded for a single member, so why loop? It seems the same for all
> these "for each" helper in the "empty" events c file.

Agreed. I think we should generate the empty case and then event if
there is just 1 iteration, we know that the code is that way because
of the auto-generation.

> > +
> > +             if (!map->cpuid)
> > +                     break;
> > +
> > +             if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > +                     table = &map->metric_table;
> > +                     break;
> > +             }
> > +     }
> > +     free(cpuid);
> > +     return table;
> > +}
> > +
> >   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];
> > @@ -332,6 +358,17 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
> >       return NULL;
> >   }
> >
> > +const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
> > +{
> > +     for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > +          tables->arch;
> > +          tables++) {
>
> combine with previous line?

Done.

> > +             if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> > +                     return &tables->metric_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];
> > @@ -350,8 +387,7 @@ int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
> >       for (const struct pmu_events_map *tables = &pmu_events_map[0];
> >            tables->arch;
> >            tables++) {
> > -             int ret = pmu_events_table_for_each_metric(
> > -                     (const struct pmu_events_table *)&tables->metric_table, fn, data);
> > +             int ret = pmu_metrics_table_for_each_metric(&tables->metric_table, fn, data);
> >
> >               if (ret)
> >                       return ret;
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index 7b9714b25d0a..be2cf8a8779c 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -609,17 +609,19 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> >           return 0;
> >   }
> >
> > -int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
> > +int pmu_metrics_table_for_each_metric(const struct pmu_metrics_table *mtable,
> >                                        pmu_metric_iter_fn fn,
> >                                        void *data)
> >   {
> > +        struct pmu_events_table *table = (struct pmu_events_table *)mtable;
>
> As I may have hinted before, can we avoid casts like this, even if
> transient?

It was a trade-off with patch size. Will try to improve in v3.

Thanks,
Ian

> > +
> >           for (size_t i = 0; i < table->length; i++) {
> >                   struct pmu_metric pm;
> >                   int ret;
> >
> >                   decompress_metric(table->entries[i].offset, &pm);
> >                   if (pm.metric_name) {
> > -                        ret = fn(&pm, table, data);
> > +                        ret = fn(&pm, mtable, data);
> >                           if (ret)
> >                                   return ret;
> >                   }
>
>
>

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

* Re: [PATCH v2 8/9] perf jevents: Generate metrics and events as separate tables
  2023-01-23 15:18   ` John Garry
@ 2023-01-24  4:49     ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2023-01-24  4:49 UTC (permalink / raw)
  To: John Garry
  Cc: Mark Rutland, Kang Minchul, Sandipan Das, Peter Zijlstra,
	Perry Taylor, Stephane Eranian, linux-kernel, James Clark,
	Kim Phillips, Will Deacon, Kan Liang, Rob Herring,
	Alexander Shishkin, Ingo Molnar, Xing Zhengjun, Mike Leach,
	Kajol Jain, Arnaldo Carvalho de Melo, Namhyung Kim,
	Caleb Biggers, linux-arm-kernel, Ravi Bangoria, Florian Fischer,
	Adrian Hunter, linux-perf-users, Jiri Olsa, Leo Yan,
	linuxppc-dev, Jing Zhang

On Mon, Jan 23, 2023 at 7:18 AM John Garry <john.g.garry@oracle.com> wrote:
>
> On 21/12/2022 22:34, Ian Rogers wrote:
> > Turn a perf json event into an event, metric or both. This reduces the
> > number of events needed to scan to find an event or metric. As events
> > no longer need the relatively seldom used metric fields, 4 bytes is
> > saved per event. This reduces the big C string's size by 335kb (14.8%)
> > on x86.
> >
> > Signed-off-by: Ian Rogers<irogers@google.com>
>
> It would have been good to show an example of how the output changes. I
> could not apply the series (see cover), and knowing what to expect makes
> reviewing the code easier...
>
> Thanks,
> John

Thanks, will add in v3.

Ian

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

* Re: [PATCH v2 0/9] jevents/pmu-events improvements
  2023-01-23 13:25 ` John Garry
@ 2023-01-24  5:04   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2023-01-24  5:04 UTC (permalink / raw)
  To: John Garry
  Cc: Mark Rutland, Kang Minchul, Sandipan Das, Peter Zijlstra,
	Perry Taylor, Stephane Eranian, linux-kernel, James Clark,
	Kim Phillips, Will Deacon, Kan Liang, Rob Herring,
	Alexander Shishkin, Ingo Molnar, Xing Zhengjun, Mike Leach,
	Kajol Jain, Arnaldo Carvalho de Melo, Namhyung Kim,
	Caleb Biggers, linux-arm-kernel, Ravi Bangoria, Florian Fischer,
	Adrian Hunter, linux-perf-users, Jiri Olsa, Leo Yan,
	linuxppc-dev, Jing Zhang

On Mon, Jan 23, 2023 at 5:26 AM John Garry <john.g.garry@oracle.com> wrote:
>
> On 21/12/2022 22:34, Ian Rogers wrote:
> > Add an optimization to jevents using the metric code, rewrite metrics
> > in terms of each other in order to minimize size and improve
> > readability. For example, on Power8
> > other_stall_cpi is rewritten from:
> > "PM_CMPLU_STALL / PM_RUN_INST_CMPL - PM_CMPLU_STALL_BRU_CRU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_FXU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_VSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_LSU / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NTCG_FLUSH / PM_RUN_INST_CMPL - PM_CMPLU_STALL_NO_NTF / PM_RUN_INST_CMPL"
> > to:
> > "stall_cpi - bru_cru_stall_cpi - fxu_stall_cpi - vsu_stall_cpi - lsu_stall_cpi - ntcg_flush_cpi - no_ntf_stall_cpi"
> > Which more closely matches the definition on Power9.
> >
> > A limitation of the substitutions are that they depend on strict
> > equality and the shape of the tree. This means that for "a + b + c"
> > then a substitution of "a + b" will succeed while "b + c" will fail
> > (the LHS for "+ c" is "a + b" not just "b").
> >
> > Separate out the events and metrics in the pmu-events tables saving
> > 14.8% in the table size while making it that metrics no longer need to
> > iterate over all events and vice versa. These changes remove evsel's
> > direct metric support as the pmu_event no longer has a metric to
> > populate it. This is a minor issue as the code wasn't working
> > properly, metrics for this are rare and can still be properly ran
> > using '-M'.
> >
> > Add an ability to just build certain models into the jevents generated
> > pmu-metrics.c code. This functionality is appropriate for operating
> > systems like ChromeOS, that aim to minimize binary size and know all
> > the target CPU models.
>
>  From a glance, this does not look like it would work for arm64. As I
> see in the code, we check the model in the arch folder for the test to
> see if built. For arm64, as it uses arch/implementator/model folder org,
> and not just arch/model (like x86)
>
> So on the assumption that it does not work for arm64 (or just any arch
> which uses arch/implementator/model folder org), it would be nice to
> have that feature also. Or maybe also support not just specifying model
> but also implementator.

Hmm.. this is tricky as x86 isn't following the implementor pattern. I
will tweak the comment for the ARM64 case where --model will select an
implementor.

> >
> > v2. Rebase. Modify the code that skips rewriting a metric with the
> >      same name with itself, to make the name check case insensitive.
> >
>
>
> Unfortunately you might need another rebase as this does not apply to
> acme perf/core (if that is what you want), now for me at:
>
> 5670ebf54bd2 (HEAD, origin/tmp.perf/core, origin/perf/core, perf/core)
> perf cs-etm: Ensure that Coresight timestamps don't go backwards

Will do, thanks!
Ian

> > Ian Rogers (9):
> >    perf jevents metric: Correct Function equality
> >    perf jevents metric: Add ability to rewrite metrics in terms of others
> >    perf jevents: Rewrite metrics in the same file with each other
> >    perf pmu-events: Separate metric out of pmu_event
> >    perf stat: Remove evsel metric_name/expr
> >    perf jevents: Combine table prefix and suffix writing
> >    perf pmu-events: Introduce pmu_metrics_table
> >    perf jevents: Generate metrics and events as separate tables
> >    perf jevents: Add model list option
>
> Thanks,
> John

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

end of thread, other threads:[~2023-01-24  5:05 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-21 22:34 [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
2022-12-21 22:34 ` [PATCH v2 1/9] perf jevents metric: Correct Function equality Ian Rogers
2022-12-21 22:34 ` [PATCH v2 2/9] perf jevents metric: Add ability to rewrite metrics in terms of others Ian Rogers
2022-12-21 22:34 ` [PATCH v2 3/9] perf jevents: Rewrite metrics in the same file with each other Ian Rogers
2022-12-21 22:34 ` [PATCH v2 4/9] perf pmu-events: Separate metric out of pmu_event Ian Rogers
2023-01-23 15:15   ` John Garry
2023-01-24  4:39     ` Ian Rogers
2022-12-21 22:34 ` [PATCH v2 5/9] perf stat: Remove evsel metric_name/expr Ian Rogers
2023-01-23 14:42   ` John Garry
2022-12-21 22:34 ` [PATCH v2 6/9] perf jevents: Combine table prefix and suffix writing Ian Rogers
2022-12-21 22:34 ` [PATCH v2 7/9] perf pmu-events: Introduce pmu_metrics_table Ian Rogers
2023-01-23 15:35   ` John Garry
2023-01-24  4:48     ` Ian Rogers
2022-12-21 22:34 ` [PATCH v2 8/9] perf jevents: Generate metrics and events as separate tables Ian Rogers
2023-01-23 15:18   ` John Garry
2023-01-24  4:49     ` Ian Rogers
2022-12-21 22:34 ` [PATCH v2 9/9] perf jevents: Add model list option Ian Rogers
2023-01-19 15:54 ` [PATCH v2 0/9] jevents/pmu-events improvements Ian Rogers
2023-01-23 13:25 ` John Garry
2023-01-24  5:04   ` Ian Rogers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).