xref: /openbmc/linux/tools/perf/pmu-events/jevents.py (revision e47749f1)
1ffc606adSIan Rogers#!/usr/bin/env python3
2ffc606adSIan Rogers# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
3ffc606adSIan Rogers"""Convert directories of JSON events to C code."""
4ffc606adSIan Rogersimport argparse
5ffc606adSIan Rogersimport csv
6df5499ddSIan Rogersfrom functools import lru_cache
7ffc606adSIan Rogersimport json
840769665SIan Rogersimport metric
9ffc606adSIan Rogersimport os
10ffc606adSIan Rogersimport sys
119118259cSIan Rogersfrom typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
129118259cSIan Rogersimport collections
13ffc606adSIan Rogers
14ffc606adSIan Rogers# Global command line arguments.
15ffc606adSIan Rogers_args = None
1662774db2SIan Rogers# List of regular event tables.
1762774db2SIan Rogers_event_tables = []
18ffc606adSIan Rogers# List of event tables generated from "/sys" directories.
19ffc606adSIan Rogers_sys_event_tables = []
2062774db2SIan Rogers# List of regular metric tables.
2162774db2SIan Rogers_metric_tables = []
2262774db2SIan Rogers# List of metric tables generated from "/sys" directories.
2362774db2SIan Rogers_sys_metric_tables = []
2462774db2SIan Rogers# Mapping between sys event table names and sys metric table names.
2562774db2SIan Rogers_sys_event_table_to_metric_table_mapping = {}
26ffc606adSIan Rogers# Map from an event name to an architecture standard
27ffc606adSIan Rogers# JsonEvent. Architecture standard events are in json files in the top
28ffc606adSIan Rogers# f'{_args.starting_dir}/{_args.arch}' directory.
29ffc606adSIan Rogers_arch_std_events = {}
307b2f844cSIan Rogers# Events to write out when the table is closed
317b2f844cSIan Rogers_pending_events = []
3262774db2SIan Rogers# Name of events table to be written out
339f587cc9SIan Rogers_pending_events_tblname = None
3462774db2SIan Rogers# Metrics to write out when the table is closed
3562774db2SIan Rogers_pending_metrics = []
3662774db2SIan Rogers# Name of metrics table to be written out
3762774db2SIan Rogers_pending_metrics_tblname = None
389118259cSIan Rogers# Global BigCString shared by all structures.
399118259cSIan Rogers_bcs = None
4066c6e0c1SIan Rogers# Map from the name of a metric group to a description of the group.
4166c6e0c1SIan Rogers_metricgroups = {}
429118259cSIan Rogers# Order specific JsonEvent attributes will be visited.
439118259cSIan Rogers_json_event_attributes = [
449118259cSIan Rogers    # cmp_sevent related attributes.
452e255b4fSIan Rogers    'name', 'topic', 'desc',
469118259cSIan Rogers    # Seems useful, put it early.
479118259cSIan Rogers    'event',
489118259cSIan Rogers    # Short things in alphabetical order.
4936d19bbbSIan Rogers    'compat', 'deprecated', 'perpkg', 'unit',
509118259cSIan Rogers    # Longer things (the last won't be iterated over during decompress).
5162774db2SIan Rogers    'long_desc'
529118259cSIan Rogers]
53ffc606adSIan Rogers
54d9dc8874SIan Rogers# Attributes that are in pmu_metric rather than pmu_event.
55d9dc8874SIan Rogers_json_metric_attributes = [
562e255b4fSIan Rogers    'metric_name', 'metric_group', 'metric_expr', 'metric_threshold',
57b0a9e8f8SKan Liang    'desc', 'long_desc', 'unit', 'compat', 'metricgroup_no_group',
58b0a9e8f8SKan Liang    'default_metricgroup_name', 'aggr_mode', 'event_grouping'
59d9dc8874SIan Rogers]
60aa44724cSIan Rogers# Attributes that are bools or enum int values, encoded as '0', '1',...
61aa44724cSIan Rogers_json_enum_attributes = ['aggr_mode', 'deprecated', 'event_grouping', 'perpkg']
62ffc606adSIan Rogers
63ffc606adSIan Rogersdef removesuffix(s: str, suffix: str) -> str:
64ffc606adSIan Rogers  """Remove the suffix from a string
65ffc606adSIan Rogers
66ffc606adSIan Rogers  The removesuffix function is added to str in Python 3.9. We aim for 3.6
67ffc606adSIan Rogers  compatibility and so provide our own function here.
68ffc606adSIan Rogers  """
69ffc606adSIan Rogers  return s[0:-len(suffix)] if s.endswith(suffix) else s
70ffc606adSIan Rogers
71ffc606adSIan Rogers
7262774db2SIan Rogersdef file_name_to_table_name(prefix: str, parents: Sequence[str],
7362774db2SIan Rogers                            dirname: str) -> str:
74ffc606adSIan Rogers  """Generate a C table name from directory names."""
7562774db2SIan Rogers  tblname = prefix
76ffc606adSIan Rogers  for p in parents:
77ffc606adSIan Rogers    tblname += '_' + p
78ffc606adSIan Rogers  tblname += '_' + dirname
79ffc606adSIan Rogers  return tblname.replace('-', '_')
80ffc606adSIan Rogers
8162774db2SIan Rogers
829118259cSIan Rogersdef c_len(s: str) -> int:
839118259cSIan Rogers  """Return the length of s a C string
849118259cSIan Rogers
859118259cSIan Rogers  This doesn't handle all escape characters properly. It first assumes
869118259cSIan Rogers  all \ are for escaping, it then adjusts as it will have over counted
879118259cSIan Rogers  \\. The code uses \000 rather than \0 as a terminator as an adjacent
889118259cSIan Rogers  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
899118259cSIan Rogers  equal a terminator followed by the number 5 but the escape of
909118259cSIan Rogers  \05). The code adjusts for \000 but not properly for all octal, hex
919118259cSIan Rogers  or unicode values.
929118259cSIan Rogers  """
939118259cSIan Rogers  try:
949118259cSIan Rogers    utf = s.encode(encoding='utf-8',errors='strict')
959118259cSIan Rogers  except:
969118259cSIan Rogers    print(f'broken string {s}')
979118259cSIan Rogers    raise
989118259cSIan Rogers  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
999118259cSIan Rogers
1009118259cSIan Rogersclass BigCString:
1019118259cSIan Rogers  """A class to hold many strings concatenated together.
1029118259cSIan Rogers
1039118259cSIan Rogers  Generating a large number of stand-alone C strings creates a large
1049118259cSIan Rogers  number of relocations in position independent code. The BigCString
1059118259cSIan Rogers  is a helper for this case. It builds a single string which within it
1069118259cSIan Rogers  are all the other C strings (to avoid memory issues the string
1079118259cSIan Rogers  itself is held as a list of strings). The offsets within the big
1089118259cSIan Rogers  string are recorded and when stored to disk these don't need
109d0313e62SIan Rogers  relocation. To reduce the size of the string further, identical
110d0313e62SIan Rogers  strings are merged. If a longer string ends-with the same value as a
111d0313e62SIan Rogers  shorter string, these entries are also merged.
1129118259cSIan Rogers  """
1139118259cSIan Rogers  strings: Set[str]
1149118259cSIan Rogers  big_string: Sequence[str]
1159118259cSIan Rogers  offsets: Dict[str, int]
116f85d120cSIan Rogers  insert_number: int
117f85d120cSIan Rogers  insert_point: Dict[str, int]
118f85d120cSIan Rogers  metrics: Set[str]
1199118259cSIan Rogers
1209118259cSIan Rogers  def __init__(self):
1219118259cSIan Rogers    self.strings = set()
122f85d120cSIan Rogers    self.insert_number = 0;
123f85d120cSIan Rogers    self.insert_point = {}
124f85d120cSIan Rogers    self.metrics = set()
1259118259cSIan Rogers
126f85d120cSIan Rogers  def add(self, s: str, metric: bool) -> None:
1279118259cSIan Rogers    """Called to add to the big string."""
128f85d120cSIan Rogers    if s not in self.strings:
1299118259cSIan Rogers      self.strings.add(s)
130f85d120cSIan Rogers      self.insert_point[s] = self.insert_number
131f85d120cSIan Rogers      self.insert_number += 1
132f85d120cSIan Rogers      if metric:
133f85d120cSIan Rogers        self.metrics.add(s)
1349118259cSIan Rogers
1359118259cSIan Rogers  def compute(self) -> None:
1369118259cSIan Rogers    """Called once all strings are added to compute the string and offsets."""
1379118259cSIan Rogers
138d0313e62SIan Rogers    folded_strings = {}
139d0313e62SIan Rogers    # Determine if two strings can be folded, ie. let 1 string use the
140d0313e62SIan Rogers    # end of another. First reverse all strings and sort them.
141d0313e62SIan Rogers    sorted_reversed_strings = sorted([x[::-1] for x in self.strings])
142d0313e62SIan Rogers
143d0313e62SIan Rogers    # Strings 'xyz' and 'yz' will now be [ 'zy', 'zyx' ]. Scan forward
144d0313e62SIan Rogers    # for each string to see if there is a better candidate to fold it
145d0313e62SIan Rogers    # into, in the example rather than using 'yz' we can use'xyz' at
146d0313e62SIan Rogers    # an offset of 1. We record which string can be folded into which
147d0313e62SIan Rogers    # in folded_strings, we don't need to record the offset as it is
148d0313e62SIan Rogers    # trivially computed from the string lengths.
149d0313e62SIan Rogers    for pos,s in enumerate(sorted_reversed_strings):
150d0313e62SIan Rogers      best_pos = pos
151d0313e62SIan Rogers      for check_pos in range(pos + 1, len(sorted_reversed_strings)):
152d0313e62SIan Rogers        if sorted_reversed_strings[check_pos].startswith(s):
153d0313e62SIan Rogers          best_pos = check_pos
154d0313e62SIan Rogers        else:
155d0313e62SIan Rogers          break
156d0313e62SIan Rogers      if pos != best_pos:
157d0313e62SIan Rogers        folded_strings[s[::-1]] = sorted_reversed_strings[best_pos][::-1]
158d0313e62SIan Rogers
159d0313e62SIan Rogers    # Compute reverse mappings for debugging.
160d0313e62SIan Rogers    fold_into_strings = collections.defaultdict(set)
161d0313e62SIan Rogers    for key, val in folded_strings.items():
162d0313e62SIan Rogers      if key != val:
163d0313e62SIan Rogers        fold_into_strings[val].add(key)
164d0313e62SIan Rogers
1659118259cSIan Rogers    # big_string_offset is the current location within the C string
1669118259cSIan Rogers    # being appended to - comments, etc. don't count. big_string is
1679118259cSIan Rogers    # the string contents represented as a list. Strings are immutable
1689118259cSIan Rogers    # in Python and so appending to one causes memory issues, while
1699118259cSIan Rogers    # lists are mutable.
1709118259cSIan Rogers    big_string_offset = 0
1719118259cSIan Rogers    self.big_string = []
1729118259cSIan Rogers    self.offsets = {}
173d0313e62SIan Rogers
174f85d120cSIan Rogers    def string_cmp_key(s: str) -> Tuple[bool, int, str]:
175f85d120cSIan Rogers      return (s in self.metrics, self.insert_point[s], s)
176f85d120cSIan Rogers
177d0313e62SIan Rogers    # Emit all strings that aren't folded in a sorted manner.
178f85d120cSIan Rogers    for s in sorted(self.strings, key=string_cmp_key):
179d0313e62SIan Rogers      if s not in folded_strings:
1809118259cSIan Rogers        self.offsets[s] = big_string_offset
1819118259cSIan Rogers        self.big_string.append(f'/* offset={big_string_offset} */ "')
1829118259cSIan Rogers        self.big_string.append(s)
183d0313e62SIan Rogers        self.big_string.append('"')
184d0313e62SIan Rogers        if s in fold_into_strings:
185d0313e62SIan Rogers          self.big_string.append(' /* also: ' + ', '.join(fold_into_strings[s]) + ' */')
186d0313e62SIan Rogers        self.big_string.append('\n')
1879118259cSIan Rogers        big_string_offset += c_len(s)
188d0313e62SIan Rogers        continue
189d0313e62SIan Rogers
190d0313e62SIan Rogers    # Compute the offsets of the folded strings.
191d0313e62SIan Rogers    for s in folded_strings.keys():
192d0313e62SIan Rogers      assert s not in self.offsets
193d0313e62SIan Rogers      folded_s = folded_strings[s]
194d0313e62SIan Rogers      self.offsets[s] = self.offsets[folded_s] + c_len(folded_s) - c_len(s)
1959118259cSIan Rogers
1969118259cSIan Rogers_bcs = BigCString()
197ffc606adSIan Rogers
198ffc606adSIan Rogersclass JsonEvent:
199ffc606adSIan Rogers  """Representation of an event loaded from a json file dictionary."""
200ffc606adSIan Rogers
201ffc606adSIan Rogers  def __init__(self, jd: dict):
202ffc606adSIan Rogers    """Constructor passed the dictionary of parsed json values."""
203ffc606adSIan Rogers
204ffc606adSIan Rogers    def llx(x: int) -> str:
205ffc606adSIan Rogers      """Convert an int to a string similar to a printf modifier of %#llx."""
206ffc606adSIan Rogers      return '0' if x == 0 else hex(x)
207ffc606adSIan Rogers
208ffc606adSIan Rogers    def fixdesc(s: str) -> str:
209ffc606adSIan Rogers      """Fix formatting issue for the desc string."""
210ffc606adSIan Rogers      if s is None:
211ffc606adSIan Rogers        return None
212ffc606adSIan Rogers      return removesuffix(removesuffix(removesuffix(s, '.  '),
213ffc606adSIan Rogers                                       '. '), '.').replace('\n', '\\n').replace(
214ffc606adSIan Rogers                                           '\"', '\\"').replace('\r', '\\r')
215ffc606adSIan Rogers
216e1e19d05SIan Rogers    def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
217ffc606adSIan Rogers      """Returns the aggr_mode_class enum value associated with the JSON string."""
218ffc606adSIan Rogers      if not aggr_mode:
219ffc606adSIan Rogers        return None
220ffc606adSIan Rogers      aggr_mode_to_enum = {
221ffc606adSIan Rogers          'PerChip': '1',
222ffc606adSIan Rogers          'PerCore': '2',
223ffc606adSIan Rogers      }
224ffc606adSIan Rogers      return aggr_mode_to_enum[aggr_mode]
225ffc606adSIan Rogers
22690053634SIan Rogers    def convert_metric_constraint(metric_constraint: str) -> Optional[str]:
22790053634SIan Rogers      """Returns the metric_event_groups enum value associated with the JSON string."""
22890053634SIan Rogers      if not metric_constraint:
22990053634SIan Rogers        return None
23090053634SIan Rogers      metric_constraint_to_enum = {
23190053634SIan Rogers          'NO_GROUP_EVENTS': '1',
23290053634SIan Rogers          'NO_GROUP_EVENTS_NMI': '2',
23390053634SIan Rogers          'NO_NMI_WATCHDOG': '2',
23490053634SIan Rogers          'NO_GROUP_EVENTS_SMT': '3',
23590053634SIan Rogers      }
23690053634SIan Rogers      return metric_constraint_to_enum[metric_constraint]
23790053634SIan Rogers
238e1e19d05SIan Rogers    def lookup_msr(num: str) -> Optional[str]:
239ffc606adSIan Rogers      """Converts the msr number, or first in a list to the appropriate event field."""
240ffc606adSIan Rogers      if not num:
241ffc606adSIan Rogers        return None
242ffc606adSIan Rogers      msrmap = {
243ffc606adSIan Rogers          0x3F6: 'ldlat=',
244ffc606adSIan Rogers          0x1A6: 'offcore_rsp=',
245ffc606adSIan Rogers          0x1A7: 'offcore_rsp=',
246ffc606adSIan Rogers          0x3F7: 'frontend=',
247ffc606adSIan Rogers      }
248ffc606adSIan Rogers      return msrmap[int(num.split(',', 1)[0], 0)]
249ffc606adSIan Rogers
250e1e19d05SIan Rogers    def real_event(name: str, event: str) -> Optional[str]:
251ffc606adSIan Rogers      """Convert well known event names to an event string otherwise use the event argument."""
252ffc606adSIan Rogers      fixed = {
253ffc606adSIan Rogers          'inst_retired.any': 'event=0xc0,period=2000003',
254ffc606adSIan Rogers          'inst_retired.any_p': 'event=0xc0,period=2000003',
255ffc606adSIan Rogers          'cpu_clk_unhalted.ref': 'event=0x0,umask=0x03,period=2000003',
256ffc606adSIan Rogers          'cpu_clk_unhalted.thread': 'event=0x3c,period=2000003',
257ffc606adSIan Rogers          'cpu_clk_unhalted.core': 'event=0x3c,period=2000003',
258ffc606adSIan Rogers          'cpu_clk_unhalted.thread_any': 'event=0x3c,any=1,period=2000003',
259ffc606adSIan Rogers      }
260ffc606adSIan Rogers      if not name:
261ffc606adSIan Rogers        return None
262ffc606adSIan Rogers      if name.lower() in fixed:
263ffc606adSIan Rogers        return fixed[name.lower()]
264ffc606adSIan Rogers      return event
265ffc606adSIan Rogers
266e1e19d05SIan Rogers    def unit_to_pmu(unit: str) -> Optional[str]:
267ffc606adSIan Rogers      """Convert a JSON Unit to Linux PMU name."""
268ffc606adSIan Rogers      if not unit:
269d2045f87SIan Rogers        return 'default_core'
270ffc606adSIan Rogers      # Comment brought over from jevents.c:
271ffc606adSIan Rogers      # it's not realistic to keep adding these, we need something more scalable ...
272ffc606adSIan Rogers      table = {
273ffc606adSIan Rogers          'CBO': 'uncore_cbox',
274ffc606adSIan Rogers          'QPI LL': 'uncore_qpi',
275ffc606adSIan Rogers          'SBO': 'uncore_sbox',
276ffc606adSIan Rogers          'iMPH-U': 'uncore_arb',
277ffc606adSIan Rogers          'CPU-M-CF': 'cpum_cf',
278ffc606adSIan Rogers          'CPU-M-SF': 'cpum_sf',
279e0b23af8SThomas Richter          'PAI-CRYPTO' : 'pai_crypto',
280d30baf2cSThomas Richter          'PAI-EXT' : 'pai_ext',
281ffc606adSIan Rogers          'UPI LL': 'uncore_upi',
282ffc606adSIan Rogers          'hisi_sicl,cpa': 'hisi_sicl,cpa',
283ffc606adSIan Rogers          'hisi_sccl,ddrc': 'hisi_sccl,ddrc',
284ffc606adSIan Rogers          'hisi_sccl,hha': 'hisi_sccl,hha',
285ffc606adSIan Rogers          'hisi_sccl,l3c': 'hisi_sccl,l3c',
286ffc606adSIan Rogers          'imx8_ddr': 'imx8_ddr',
287ffc606adSIan Rogers          'L3PMC': 'amd_l3',
288ffc606adSIan Rogers          'DFPMC': 'amd_df',
289ffc606adSIan Rogers          'cpu_core': 'cpu_core',
290ffc606adSIan Rogers          'cpu_atom': 'cpu_atom',
29124069d81SJing Zhang          'ali_drw': 'ali_drw',
292ffc606adSIan Rogers      }
293ffc606adSIan Rogers      return table[unit] if unit in table else f'uncore_{unit.lower()}'
294ffc606adSIan Rogers
295ffc606adSIan Rogers    eventcode = 0
296ffc606adSIan Rogers    if 'EventCode' in jd:
297ffc606adSIan Rogers      eventcode = int(jd['EventCode'].split(',', 1)[0], 0)
298ffc606adSIan Rogers    if 'ExtSel' in jd:
299ffc606adSIan Rogers      eventcode |= int(jd['ExtSel']) << 8
300ffc606adSIan Rogers    configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
301ffc606adSIan Rogers    self.name = jd['EventName'].lower() if 'EventName' in jd else None
3027b2f844cSIan Rogers    self.topic = ''
303ffc606adSIan Rogers    self.compat = jd.get('Compat')
304ffc606adSIan Rogers    self.desc = fixdesc(jd.get('BriefDescription'))
305ffc606adSIan Rogers    self.long_desc = fixdesc(jd.get('PublicDescription'))
306ffc606adSIan Rogers    precise = jd.get('PEBS')
307ffc606adSIan Rogers    msr = lookup_msr(jd.get('MSRIndex'))
308ffc606adSIan Rogers    msrval = jd.get('MSRValue')
309ffc606adSIan Rogers    extra_desc = ''
310ffc606adSIan Rogers    if 'Data_LA' in jd:
311ffc606adSIan Rogers      extra_desc += '  Supports address when precise'
312ffc606adSIan Rogers      if 'Errata' in jd:
313ffc606adSIan Rogers        extra_desc += '.'
314ffc606adSIan Rogers    if 'Errata' in jd:
315ffc606adSIan Rogers      extra_desc += '  Spec update: ' + jd['Errata']
316ffc606adSIan Rogers    self.pmu = unit_to_pmu(jd.get('Unit'))
317ffc606adSIan Rogers    filter = jd.get('Filter')
318ffc606adSIan Rogers    self.unit = jd.get('ScaleUnit')
319ffc606adSIan Rogers    self.perpkg = jd.get('PerPkg')
320ffc606adSIan Rogers    self.aggr_mode = convert_aggr_mode(jd.get('AggregationMode'))
321ffc606adSIan Rogers    self.deprecated = jd.get('Deprecated')
322ffc606adSIan Rogers    self.metric_name = jd.get('MetricName')
323ffc606adSIan Rogers    self.metric_group = jd.get('MetricGroup')
324ccc66c60SIan Rogers    self.metricgroup_no_group = jd.get('MetricgroupNoGroup')
325b0a9e8f8SKan Liang    self.default_metricgroup_name = jd.get('DefaultMetricgroupName')
32690053634SIan Rogers    self.event_grouping = convert_metric_constraint(jd.get('MetricConstraint'))
32740769665SIan Rogers    self.metric_expr = None
32840769665SIan Rogers    if 'MetricExpr' in jd:
32940769665SIan Rogers      self.metric_expr = metric.ParsePerfJson(jd['MetricExpr']).Simplify()
33045e8867aSIan Rogers    # Note, the metric formula for the threshold isn't parsed as the &
33145e8867aSIan Rogers    # and > have incorrect precedence.
33245e8867aSIan Rogers    self.metric_threshold = jd.get('MetricThreshold')
33340769665SIan Rogers
334ffc606adSIan Rogers    arch_std = jd.get('ArchStdEvent')
335e1e19d05SIan Rogers    if precise and self.desc and '(Precise Event)' not in self.desc:
336ffc606adSIan Rogers      extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
337ffc606adSIan Rogers                                                                 'event)')
338ffc606adSIan Rogers    event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
339ffc606adSIan Rogers    event_fields = [
340ffc606adSIan Rogers        ('AnyThread', 'any='),
341ffc606adSIan Rogers        ('PortMask', 'ch_mask='),
342ffc606adSIan Rogers        ('CounterMask', 'cmask='),
343ffc606adSIan Rogers        ('EdgeDetect', 'edge='),
344ffc606adSIan Rogers        ('FCMask', 'fc_mask='),
345ffc606adSIan Rogers        ('Invert', 'inv='),
346ffc606adSIan Rogers        ('SampleAfterValue', 'period='),
347ffc606adSIan Rogers        ('UMask', 'umask='),
348ffc606adSIan Rogers    ]
349ffc606adSIan Rogers    for key, value in event_fields:
350ffc606adSIan Rogers      if key in jd and jd[key] != '0':
351ffc606adSIan Rogers        event += ',' + value + jd[key]
352ffc606adSIan Rogers    if filter:
353ffc606adSIan Rogers      event += f',{filter}'
354ffc606adSIan Rogers    if msr:
355ffc606adSIan Rogers      event += f',{msr}{msrval}'
356ffc606adSIan Rogers    if self.desc and extra_desc:
357ffc606adSIan Rogers      self.desc += extra_desc
358ffc606adSIan Rogers    if self.long_desc and extra_desc:
359ffc606adSIan Rogers      self.long_desc += extra_desc
3607298e876SJohn Garry    if arch_std:
3617298e876SJohn Garry      if arch_std.lower() in _arch_std_events:
362ffc606adSIan Rogers        event = _arch_std_events[arch_std.lower()].event
363ffc606adSIan Rogers        # Copy from the architecture standard event to self for undefined fields.
364ffc606adSIan Rogers        for attr, value in _arch_std_events[arch_std.lower()].__dict__.items():
365ffc606adSIan Rogers          if hasattr(self, attr) and not getattr(self, attr):
366ffc606adSIan Rogers            setattr(self, attr, value)
3677298e876SJohn Garry      else:
3687298e876SJohn Garry        raise argparse.ArgumentTypeError('Cannot find arch std event:', arch_std)
369ffc606adSIan Rogers
370ffc606adSIan Rogers    self.event = real_event(self.name, event)
371ffc606adSIan Rogers
372ffc606adSIan Rogers  def __repr__(self) -> str:
373ffc606adSIan Rogers    """String representation primarily for debugging."""
374ffc606adSIan Rogers    s = '{\n'
375ffc606adSIan Rogers    for attr, value in self.__dict__.items():
376ffc606adSIan Rogers      if value:
377ffc606adSIan Rogers        s += f'\t{attr} = {value},\n'
378ffc606adSIan Rogers    return s + '}'
379ffc606adSIan Rogers
38062774db2SIan Rogers  def build_c_string(self, metric: bool) -> str:
3819118259cSIan Rogers    s = ''
38262774db2SIan Rogers    for attr in _json_metric_attributes if metric else _json_event_attributes:
3839118259cSIan Rogers      x = getattr(self, attr)
38462774db2SIan Rogers      if metric and x and attr == 'metric_expr':
38540769665SIan Rogers        # Convert parsed metric expressions into a string. Slashes
38640769665SIan Rogers        # must be doubled in the file.
38740769665SIan Rogers        x = x.ToPerfJson().replace('\\', '\\\\')
38845e8867aSIan Rogers      if metric and x and attr == 'metric_threshold':
38945e8867aSIan Rogers        x = x.replace('\\', '\\\\')
390aa44724cSIan Rogers      if attr in _json_enum_attributes:
391aa44724cSIan Rogers        s += x if x else '0'
392aa44724cSIan Rogers      else:
3939118259cSIan Rogers        s += f'{x}\\000' if x else '\\000'
3949118259cSIan Rogers    return s
3959118259cSIan Rogers
39662774db2SIan Rogers  def to_c_string(self, metric: bool) -> str:
397ffc606adSIan Rogers    """Representation of the event as a C struct initializer."""
398ffc606adSIan Rogers
39962774db2SIan Rogers    s = self.build_c_string(metric)
4009118259cSIan Rogers    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
401ffc606adSIan Rogers
40262774db2SIan Rogers
403df5499ddSIan Rogers@lru_cache(maxsize=None)
4047b2f844cSIan Rogersdef read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
405ffc606adSIan Rogers  """Read json events from the specified file."""
406ee2ce6fdSIan Rogers  try:
407df5499ddSIan Rogers    events = json.load(open(path), object_hook=JsonEvent)
408ee2ce6fdSIan Rogers  except BaseException as err:
409ee2ce6fdSIan Rogers    print(f"Exception processing {path}")
410ee2ce6fdSIan Rogers    raise
411d6b7dd11SIan Rogers  metrics: list[Tuple[str, str, metric.Expression]] = []
412df5499ddSIan Rogers  for event in events:
4137b2f844cSIan Rogers    event.topic = topic
414df5499ddSIan Rogers    if event.metric_name and '-' not in event.metric_name:
415d6b7dd11SIan Rogers      metrics.append((event.pmu, event.metric_name, event.metric_expr))
416df5499ddSIan Rogers  updates = metric.RewriteMetricsInTermsOfOthers(metrics)
417df5499ddSIan Rogers  if updates:
418df5499ddSIan Rogers    for event in events:
419df5499ddSIan Rogers      if event.metric_name in updates:
420df5499ddSIan Rogers        # print(f'Updated {event.metric_name} from\n"{event.metric_expr}"\n'
421df5499ddSIan Rogers        #       f'to\n"{updates[event.metric_name]}"')
422df5499ddSIan Rogers        event.metric_expr = updates[event.metric_name]
423df5499ddSIan Rogers
424df5499ddSIan Rogers  return events
425ffc606adSIan Rogers
426ffc606adSIan Rogersdef preprocess_arch_std_files(archpath: str) -> None:
427ffc606adSIan Rogers  """Read in all architecture standard events."""
428ffc606adSIan Rogers  global _arch_std_events
429ffc606adSIan Rogers  for item in os.scandir(archpath):
430ffc606adSIan Rogers    if item.is_file() and item.name.endswith('.json'):
4317b2f844cSIan Rogers      for event in read_json_events(item.path, topic=''):
432ffc606adSIan Rogers        if event.name:
433ffc606adSIan Rogers          _arch_std_events[event.name.lower()] = event
4345b51e47aSJing Zhang        if event.metric_name:
4355b51e47aSJing Zhang          _arch_std_events[event.metric_name.lower()] = event
436ffc606adSIan Rogers
437ffc606adSIan Rogers
4387b2f844cSIan Rogersdef add_events_table_entries(item: os.DirEntry, topic: str) -> None:
4397b2f844cSIan Rogers  """Add contents of file to _pending_events table."""
4407b2f844cSIan Rogers  for e in read_json_events(item.path, topic):
44162774db2SIan Rogers    if e.name:
4427b2f844cSIan Rogers      _pending_events.append(e)
44362774db2SIan Rogers    if e.metric_name:
44462774db2SIan Rogers      _pending_metrics.append(e)
445ffc606adSIan Rogers
446ffc606adSIan Rogers
4479f587cc9SIan Rogersdef print_pending_events() -> None:
448ffc606adSIan Rogers  """Optionally close events table."""
4497b2f844cSIan Rogers
4502e255b4fSIan Rogers  def event_cmp_key(j: JsonEvent) -> Tuple[str, str, bool, str, str]:
4519118259cSIan Rogers    def fix_none(s: Optional[str]) -> str:
4527b2f844cSIan Rogers      if s is None:
4537b2f844cSIan Rogers        return ''
4547b2f844cSIan Rogers      return s
4557b2f844cSIan Rogers
4562e255b4fSIan Rogers    return (fix_none(j.pmu).replace(',','_'), fix_none(j.name), j.desc is not None, fix_none(j.topic),
4577b2f844cSIan Rogers            fix_none(j.metric_name))
4587b2f844cSIan Rogers
4599f587cc9SIan Rogers  global _pending_events
4609f587cc9SIan Rogers  if not _pending_events:
4617b2f844cSIan Rogers    return
4627b2f844cSIan Rogers
4639f587cc9SIan Rogers  global _pending_events_tblname
46462774db2SIan Rogers  if _pending_events_tblname.endswith('_sys'):
46562774db2SIan Rogers    global _sys_event_tables
46662774db2SIan Rogers    _sys_event_tables.append(_pending_events_tblname)
46762774db2SIan Rogers  else:
46862774db2SIan Rogers    global event_tables
46962774db2SIan Rogers    _event_tables.append(_pending_events_tblname)
47062774db2SIan Rogers
4712e255b4fSIan Rogers  first = True
4722e255b4fSIan Rogers  last_pmu = None
4732e255b4fSIan Rogers  pmus = set()
4747b2f844cSIan Rogers  for event in sorted(_pending_events, key=event_cmp_key):
4752e255b4fSIan Rogers    if event.pmu != last_pmu:
4762e255b4fSIan Rogers      if not first:
4772e255b4fSIan Rogers        _args.output_file.write('};\n')
4782e255b4fSIan Rogers      pmu_name = event.pmu.replace(',', '_')
4792e255b4fSIan Rogers      _args.output_file.write(
4802e255b4fSIan Rogers          f'static const struct compact_pmu_event {_pending_events_tblname}_{pmu_name}[] = {{\n')
4812e255b4fSIan Rogers      first = False
4822e255b4fSIan Rogers      last_pmu = event.pmu
4832e255b4fSIan Rogers      pmus.add((event.pmu, pmu_name))
4842e255b4fSIan Rogers
48562774db2SIan Rogers    _args.output_file.write(event.to_c_string(metric=False))
4867b2f844cSIan Rogers  _pending_events = []
4877b2f844cSIan Rogers
4882e255b4fSIan Rogers  _args.output_file.write(f"""
4892e255b4fSIan Rogers}};
4902e255b4fSIan Rogers
4912e255b4fSIan Rogersconst struct pmu_table_entry {_pending_events_tblname}[] = {{
4922e255b4fSIan Rogers""")
4932e255b4fSIan Rogers  for (pmu, tbl_pmu) in sorted(pmus):
4942e255b4fSIan Rogers    pmu_name = f"{pmu}\\000"
4952e255b4fSIan Rogers    _args.output_file.write(f"""{{
4962e255b4fSIan Rogers     .entries = {_pending_events_tblname}_{tbl_pmu},
4972e255b4fSIan Rogers     .num_entries = ARRAY_SIZE({_pending_events_tblname}_{tbl_pmu}),
4982e255b4fSIan Rogers     .pmu_name = {{ {_bcs.offsets[pmu_name]} /* {pmu_name} */ }},
4992e255b4fSIan Rogers}},
5002e255b4fSIan Rogers""")
5019118259cSIan Rogers  _args.output_file.write('};\n\n')
502ffc606adSIan Rogers
50362774db2SIan Rogersdef print_pending_metrics() -> None:
50462774db2SIan Rogers  """Optionally close metrics table."""
50562774db2SIan Rogers
50662774db2SIan Rogers  def metric_cmp_key(j: JsonEvent) -> Tuple[bool, str, str]:
50762774db2SIan Rogers    def fix_none(s: Optional[str]) -> str:
50862774db2SIan Rogers      if s is None:
50962774db2SIan Rogers        return ''
51062774db2SIan Rogers      return s
51162774db2SIan Rogers
51262774db2SIan Rogers    return (j.desc is not None, fix_none(j.pmu), fix_none(j.metric_name))
51362774db2SIan Rogers
51462774db2SIan Rogers  global _pending_metrics
51562774db2SIan Rogers  if not _pending_metrics:
51662774db2SIan Rogers    return
51762774db2SIan Rogers
51862774db2SIan Rogers  global _pending_metrics_tblname
51962774db2SIan Rogers  if _pending_metrics_tblname.endswith('_sys'):
52062774db2SIan Rogers    global _sys_metric_tables
52162774db2SIan Rogers    _sys_metric_tables.append(_pending_metrics_tblname)
52262774db2SIan Rogers  else:
52362774db2SIan Rogers    global metric_tables
52462774db2SIan Rogers    _metric_tables.append(_pending_metrics_tblname)
52562774db2SIan Rogers
5262e255b4fSIan Rogers  first = True
5272e255b4fSIan Rogers  last_pmu = None
5282e255b4fSIan Rogers  pmus = set()
52962774db2SIan Rogers  for metric in sorted(_pending_metrics, key=metric_cmp_key):
5302e255b4fSIan Rogers    if metric.pmu != last_pmu:
5312e255b4fSIan Rogers      if not first:
5322e255b4fSIan Rogers        _args.output_file.write('};\n')
5332e255b4fSIan Rogers      pmu_name = metric.pmu.replace(',', '_')
5342e255b4fSIan Rogers      _args.output_file.write(
5352e255b4fSIan Rogers          f'static const struct compact_pmu_event {_pending_metrics_tblname}_{pmu_name}[] = {{\n')
5362e255b4fSIan Rogers      first = False
5372e255b4fSIan Rogers      last_pmu = metric.pmu
5382e255b4fSIan Rogers      pmus.add((metric.pmu, pmu_name))
5392e255b4fSIan Rogers
54062774db2SIan Rogers    _args.output_file.write(metric.to_c_string(metric=True))
54162774db2SIan Rogers  _pending_metrics = []
54262774db2SIan Rogers
5432e255b4fSIan Rogers  _args.output_file.write(f"""
5442e255b4fSIan Rogers}};
5452e255b4fSIan Rogers
5462e255b4fSIan Rogersconst struct pmu_table_entry {_pending_metrics_tblname}[] = {{
5472e255b4fSIan Rogers""")
5482e255b4fSIan Rogers  for (pmu, tbl_pmu) in sorted(pmus):
5492e255b4fSIan Rogers    pmu_name = f"{pmu}\\000"
5502e255b4fSIan Rogers    _args.output_file.write(f"""{{
5512e255b4fSIan Rogers     .entries = {_pending_metrics_tblname}_{tbl_pmu},
5522e255b4fSIan Rogers     .num_entries = ARRAY_SIZE({_pending_metrics_tblname}_{tbl_pmu}),
5532e255b4fSIan Rogers     .pmu_name = {{ {_bcs.offsets[pmu_name]} /* {pmu_name} */ }},
5542e255b4fSIan Rogers}},
5552e255b4fSIan Rogers""")
55662774db2SIan Rogers  _args.output_file.write('};\n\n')
55762774db2SIan Rogers
5589118259cSIan Rogersdef get_topic(topic: str) -> str:
5599118259cSIan Rogers  if topic.endswith('metrics.json'):
5609118259cSIan Rogers    return 'metrics'
5619118259cSIan Rogers  return removesuffix(topic, '.json').replace('-', ' ')
5629118259cSIan Rogers
5639118259cSIan Rogersdef preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
5649118259cSIan Rogers
5659118259cSIan Rogers  if item.is_dir():
5669118259cSIan Rogers    return
5679118259cSIan Rogers
5689118259cSIan Rogers  # base dir or too deep
5699118259cSIan Rogers  level = len(parents)
5709118259cSIan Rogers  if level == 0 or level > 4:
5719118259cSIan Rogers    return
5729118259cSIan Rogers
5739118259cSIan Rogers  # Ignore other directories. If the file name does not have a .json
5749118259cSIan Rogers  # extension, ignore it. It could be a readme.txt for instance.
5759118259cSIan Rogers  if not item.is_file() or not item.name.endswith('.json'):
5769118259cSIan Rogers    return
5779118259cSIan Rogers
57866c6e0c1SIan Rogers  if item.name == 'metricgroups.json':
57966c6e0c1SIan Rogers    metricgroup_descriptions = json.load(open(item.path))
58066c6e0c1SIan Rogers    for mgroup in metricgroup_descriptions:
58166c6e0c1SIan Rogers      assert len(mgroup) > 1, parents
58266c6e0c1SIan Rogers      description = f"{metricgroup_descriptions[mgroup]}\\000"
58366c6e0c1SIan Rogers      mgroup = f"{mgroup}\\000"
584f85d120cSIan Rogers      _bcs.add(mgroup, metric=True)
585f85d120cSIan Rogers      _bcs.add(description, metric=True)
58666c6e0c1SIan Rogers      _metricgroups[mgroup] = description
58766c6e0c1SIan Rogers    return
58866c6e0c1SIan Rogers
5899118259cSIan Rogers  topic = get_topic(item.name)
5909118259cSIan Rogers  for event in read_json_events(item.path, topic):
5912e255b4fSIan Rogers    pmu_name = f"{event.pmu}\\000"
59262774db2SIan Rogers    if event.name:
593f85d120cSIan Rogers      _bcs.add(pmu_name, metric=False)
594f85d120cSIan Rogers      _bcs.add(event.build_c_string(metric=False), metric=False)
59562774db2SIan Rogers    if event.metric_name:
596f85d120cSIan Rogers      _bcs.add(pmu_name, metric=True)
597f85d120cSIan Rogers      _bcs.add(event.build_c_string(metric=True), metric=True)
598ffc606adSIan Rogers
599ffc606adSIan Rogersdef process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
600ffc606adSIan Rogers  """Process a JSON file during the main walk."""
601ffc606adSIan Rogers  def is_leaf_dir(path: str) -> bool:
602ffc606adSIan Rogers    for item in os.scandir(path):
603ffc606adSIan Rogers      if item.is_dir():
604ffc606adSIan Rogers        return False
605ffc606adSIan Rogers    return True
606ffc606adSIan Rogers
607ffc606adSIan Rogers  # model directory, reset topic
608ffc606adSIan Rogers  if item.is_dir() and is_leaf_dir(item.path):
6099f587cc9SIan Rogers    print_pending_events()
61062774db2SIan Rogers    print_pending_metrics()
611ffc606adSIan Rogers
6129f587cc9SIan Rogers    global _pending_events_tblname
61362774db2SIan Rogers    _pending_events_tblname = file_name_to_table_name('pmu_events_', parents, item.name)
61462774db2SIan Rogers    global _pending_metrics_tblname
61562774db2SIan Rogers    _pending_metrics_tblname = file_name_to_table_name('pmu_metrics_', parents, item.name)
61662774db2SIan Rogers
61762774db2SIan Rogers    if item.name == 'sys':
61862774db2SIan Rogers      _sys_event_table_to_metric_table_mapping[_pending_events_tblname] = _pending_metrics_tblname
619ffc606adSIan Rogers    return
620ffc606adSIan Rogers
621ffc606adSIan Rogers  # base dir or too deep
622ffc606adSIan Rogers  level = len(parents)
623ffc606adSIan Rogers  if level == 0 or level > 4:
624ffc606adSIan Rogers    return
625ffc606adSIan Rogers
626ffc606adSIan Rogers  # Ignore other directories. If the file name does not have a .json
627ffc606adSIan Rogers  # extension, ignore it. It could be a readme.txt for instance.
62866c6e0c1SIan Rogers  if not item.is_file() or not item.name.endswith('.json') or item.name == 'metricgroups.json':
629ffc606adSIan Rogers    return
630ffc606adSIan Rogers
6317b2f844cSIan Rogers  add_events_table_entries(item, get_topic(item.name))
632ffc606adSIan Rogers
633ffc606adSIan Rogers
634099b157cSIan Rogersdef print_mapping_table(archs: Sequence[str]) -> None:
635ffc606adSIan Rogers  """Read the mapfile and generate the struct from cpuid string to event table."""
63629be2fe0SIan Rogers  _args.output_file.write("""
6371ba3752aSIan Rogers/* Struct used to make the PMU event table implementation opaque to callers. */
6381ba3752aSIan Rogersstruct pmu_events_table {
6392e255b4fSIan Rogers        const struct pmu_table_entry *pmus;
6402e255b4fSIan Rogers        uint32_t num_pmus;
6411ba3752aSIan Rogers};
6421ba3752aSIan Rogers
64362774db2SIan Rogers/* Struct used to make the PMU metric table implementation opaque to callers. */
64462774db2SIan Rogersstruct pmu_metrics_table {
6452e255b4fSIan Rogers        const struct pmu_table_entry *pmus;
6462e255b4fSIan Rogers        uint32_t num_pmus;
64762774db2SIan Rogers};
64862774db2SIan Rogers
64929be2fe0SIan Rogers/*
65029be2fe0SIan Rogers * Map a CPU to its table of PMU events. The CPU is identified by the
65129be2fe0SIan Rogers * cpuid field, which is an arch-specific identifier for the CPU.
65229be2fe0SIan Rogers * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
65329be2fe0SIan Rogers * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
65429be2fe0SIan Rogers *
65529be2fe0SIan Rogers * The  cpuid can contain any character other than the comma.
65629be2fe0SIan Rogers */
65729be2fe0SIan Rogersstruct pmu_events_map {
65829be2fe0SIan Rogers        const char *arch;
65929be2fe0SIan Rogers        const char *cpuid;
66062774db2SIan Rogers        struct pmu_events_table event_table;
66162774db2SIan Rogers        struct pmu_metrics_table metric_table;
66229be2fe0SIan Rogers};
66329be2fe0SIan Rogers
66429be2fe0SIan Rogers/*
66529be2fe0SIan Rogers * Global table mapping each known CPU for the architecture to its
66629be2fe0SIan Rogers * table of PMU events.
66729be2fe0SIan Rogers */
66829be2fe0SIan Rogersconst struct pmu_events_map pmu_events_map[] = {
66929be2fe0SIan Rogers""")
670099b157cSIan Rogers  for arch in archs:
671099b157cSIan Rogers    if arch == 'test':
672ffc606adSIan Rogers      _args.output_file.write("""{
673099b157cSIan Rogers\t.arch = "testarch",
674ffc606adSIan Rogers\t.cpuid = "testcpu",
67562774db2SIan Rogers\t.event_table = {
6762e255b4fSIan Rogers\t\t.pmus = pmu_events__test_soc_cpu,
6772e255b4fSIan Rogers\t\t.num_pmus = ARRAY_SIZE(pmu_events__test_soc_cpu),
67862774db2SIan Rogers\t},
67962774db2SIan Rogers\t.metric_table = {
6802e255b4fSIan Rogers\t\t.pmus = pmu_metrics__test_soc_cpu,
6812e255b4fSIan Rogers\t\t.num_pmus = ARRAY_SIZE(pmu_metrics__test_soc_cpu),
6829118259cSIan Rogers\t}
683ffc606adSIan Rogers},
684099b157cSIan Rogers""")
685099b157cSIan Rogers    else:
686099b157cSIan Rogers      with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
687099b157cSIan Rogers        table = csv.reader(csvfile)
688099b157cSIan Rogers        first = True
689099b157cSIan Rogers        for row in table:
690099b157cSIan Rogers          # Skip the first row or any row beginning with #.
691099b157cSIan Rogers          if not first and len(row) > 0 and not row[0].startswith('#'):
69262774db2SIan Rogers            event_tblname = file_name_to_table_name('pmu_events_', [], row[2].replace('/', '_'))
69362774db2SIan Rogers            if event_tblname in _event_tables:
69462774db2SIan Rogers              event_size = f'ARRAY_SIZE({event_tblname})'
69562774db2SIan Rogers            else:
69662774db2SIan Rogers              event_tblname = 'NULL'
69762774db2SIan Rogers              event_size = '0'
69862774db2SIan Rogers            metric_tblname = file_name_to_table_name('pmu_metrics_', [], row[2].replace('/', '_'))
69962774db2SIan Rogers            if metric_tblname in _metric_tables:
70062774db2SIan Rogers              metric_size = f'ARRAY_SIZE({metric_tblname})'
70162774db2SIan Rogers            else:
70262774db2SIan Rogers              metric_tblname = 'NULL'
70362774db2SIan Rogers              metric_size = '0'
7045a09b1fdSIan Rogers            if event_size == '0' and metric_size == '0':
7055a09b1fdSIan Rogers              continue
706099b157cSIan Rogers            cpuid = row[0].replace('\\', '\\\\')
707099b157cSIan Rogers            _args.output_file.write(f"""{{
708099b157cSIan Rogers\t.arch = "{arch}",
709099b157cSIan Rogers\t.cpuid = "{cpuid}",
71062774db2SIan Rogers\t.event_table = {{
7112e255b4fSIan Rogers\t\t.pmus = {event_tblname},
7122e255b4fSIan Rogers\t\t.num_pmus = {event_size}
71362774db2SIan Rogers\t}},
71462774db2SIan Rogers\t.metric_table = {{
7152e255b4fSIan Rogers\t\t.pmus = {metric_tblname},
7162e255b4fSIan Rogers\t\t.num_pmus = {metric_size}
7179118259cSIan Rogers\t}}
718099b157cSIan Rogers}},
719099b157cSIan Rogers""")
720099b157cSIan Rogers          first = False
721099b157cSIan Rogers
722099b157cSIan Rogers  _args.output_file.write("""{
723099b157cSIan Rogers\t.arch = 0,
724ffc606adSIan Rogers\t.cpuid = 0,
72562774db2SIan Rogers\t.event_table = { 0, 0 },
72662774db2SIan Rogers\t.metric_table = { 0, 0 },
727099b157cSIan Rogers}
728ffc606adSIan Rogers};
729ffc606adSIan Rogers""")
730ffc606adSIan Rogers
731ffc606adSIan Rogers
732ffc606adSIan Rogersdef print_system_mapping_table() -> None:
733ffc606adSIan Rogers  """C struct mapping table array for tables from /sys directories."""
7342519db2aSIan Rogers  _args.output_file.write("""
7352519db2aSIan Rogersstruct pmu_sys_events {
7362519db2aSIan Rogers\tconst char *name;
73762774db2SIan Rogers\tstruct pmu_events_table event_table;
73862774db2SIan Rogers\tstruct pmu_metrics_table metric_table;
7392519db2aSIan Rogers};
7402519db2aSIan Rogers
7412519db2aSIan Rogersstatic const struct pmu_sys_events pmu_sys_event_tables[] = {
7422519db2aSIan Rogers""")
74362774db2SIan Rogers  printed_metric_tables = []
744ffc606adSIan Rogers  for tblname in _sys_event_tables:
745ffc606adSIan Rogers    _args.output_file.write(f"""\t{{
74662774db2SIan Rogers\t\t.event_table = {{
7472e255b4fSIan Rogers\t\t\t.pmus = {tblname},
7482e255b4fSIan Rogers\t\t\t.num_pmus = ARRAY_SIZE({tblname})
74962774db2SIan Rogers\t\t}},""")
75062774db2SIan Rogers    metric_tblname = _sys_event_table_to_metric_table_mapping[tblname]
75162774db2SIan Rogers    if metric_tblname in _sys_metric_tables:
75262774db2SIan Rogers      _args.output_file.write(f"""
75362774db2SIan Rogers\t\t.metric_table = {{
7542e255b4fSIan Rogers\t\t\t.pmus = {metric_tblname},
7552e255b4fSIan Rogers\t\t\t.num_pmus = ARRAY_SIZE({metric_tblname})
75662774db2SIan Rogers\t\t}},""")
75762774db2SIan Rogers      printed_metric_tables.append(metric_tblname)
75862774db2SIan Rogers    _args.output_file.write(f"""
75962774db2SIan Rogers\t\t.name = \"{tblname}\",
76062774db2SIan Rogers\t}},
76162774db2SIan Rogers""")
76262774db2SIan Rogers  for tblname in _sys_metric_tables:
76362774db2SIan Rogers    if tblname in printed_metric_tables:
76462774db2SIan Rogers      continue
76562774db2SIan Rogers    _args.output_file.write(f"""\t{{
76662774db2SIan Rogers\t\t.metric_table = {{
7679118259cSIan Rogers\t\t\t.entries = {tblname},
7689118259cSIan Rogers\t\t\t.length = ARRAY_SIZE({tblname})
7699118259cSIan Rogers\t\t}},
770ffc606adSIan Rogers\t\t.name = \"{tblname}\",
771ffc606adSIan Rogers\t}},
772ffc606adSIan Rogers""")
773ffc606adSIan Rogers  _args.output_file.write("""\t{
77462774db2SIan Rogers\t\t.event_table = { 0, 0 },
77562774db2SIan Rogers\t\t.metric_table = { 0, 0 },
776ffc606adSIan Rogers\t},
777ffc606adSIan Rogers};
7782519db2aSIan Rogers
779db95818eSIan Rogersstatic void decompress_event(int offset, struct pmu_event *pe)
780db95818eSIan Rogers{
781db95818eSIan Rogers\tconst char *p = &big_c_string[offset];
782db95818eSIan Rogers""")
783db95818eSIan Rogers  for attr in _json_event_attributes:
7841fa0c371SIan Rogers    _args.output_file.write(f'\n\tpe->{attr} = ')
785aa44724cSIan Rogers    if attr in _json_enum_attributes:
786aa44724cSIan Rogers      _args.output_file.write("*p - '0';\n")
7871fa0c371SIan Rogers    else:
7881fa0c371SIan Rogers      _args.output_file.write("(*p == '\\0' ? NULL : p);\n")
789db95818eSIan Rogers    if attr == _json_event_attributes[-1]:
790db95818eSIan Rogers      continue
791aa44724cSIan Rogers    if attr in _json_enum_attributes:
792aa44724cSIan Rogers      _args.output_file.write('\tp++;')
793aa44724cSIan Rogers    else:
794db95818eSIan Rogers      _args.output_file.write('\twhile (*p++);')
795db95818eSIan Rogers  _args.output_file.write("""}
796d9dc8874SIan Rogers
797d9dc8874SIan Rogersstatic void decompress_metric(int offset, struct pmu_metric *pm)
7989118259cSIan Rogers{
7999118259cSIan Rogers\tconst char *p = &big_c_string[offset];
8009118259cSIan Rogers""")
80162774db2SIan Rogers  for attr in _json_metric_attributes:
8021fa0c371SIan Rogers    _args.output_file.write(f'\n\tpm->{attr} = ')
803aa44724cSIan Rogers    if attr in _json_enum_attributes:
804aa44724cSIan Rogers      _args.output_file.write("*p - '0';\n")
8051fa0c371SIan Rogers    else:
8061fa0c371SIan Rogers      _args.output_file.write("(*p == '\\0' ? NULL : p);\n")
80762774db2SIan Rogers    if attr == _json_metric_attributes[-1]:
8089118259cSIan Rogers      continue
809aa44724cSIan Rogers    if attr in _json_enum_attributes:
810aa44724cSIan Rogers      _args.output_file.write('\tp++;')
811aa44724cSIan Rogers    else:
8129118259cSIan Rogers      _args.output_file.write('\twhile (*p++);')
8139118259cSIan Rogers  _args.output_file.write("""}
8149118259cSIan Rogers
8152e255b4fSIan Rogersstatic int pmu_events_table__for_each_event_pmu(const struct pmu_events_table *table,
8162e255b4fSIan Rogers                                                const struct pmu_table_entry *pmu,
8172e255b4fSIan Rogers                                                pmu_event_iter_fn fn,
8182e255b4fSIan Rogers                                                void *data)
8192e255b4fSIan Rogers{
8202e255b4fSIan Rogers        int ret;
8212e255b4fSIan Rogers        struct pmu_event pe = {
8222e255b4fSIan Rogers                .pmu = &big_c_string[pmu->pmu_name.offset],
8232e255b4fSIan Rogers        };
8242e255b4fSIan Rogers
8252e255b4fSIan Rogers        for (uint32_t i = 0; i < pmu->num_entries; i++) {
8262e255b4fSIan Rogers                decompress_event(pmu->entries[i].offset, &pe);
8272e255b4fSIan Rogers                if (!pe.name)
8282e255b4fSIan Rogers                        continue;
8292e255b4fSIan Rogers                ret = fn(&pe, table, data);
8302e255b4fSIan Rogers                if (ret)
8312e255b4fSIan Rogers                        return ret;
8322e255b4fSIan Rogers        }
8332e255b4fSIan Rogers        return 0;
8342e255b4fSIan Rogers }
8352e255b4fSIan Rogers
8363d504549SIan Rogersstatic int pmu_events_table__find_event_pmu(const struct pmu_events_table *table,
8373d504549SIan Rogers                                            const struct pmu_table_entry *pmu,
8383d504549SIan Rogers                                            const char *name,
8393d504549SIan Rogers                                            pmu_event_iter_fn fn,
8403d504549SIan Rogers                                            void *data)
8413d504549SIan Rogers{
8423d504549SIan Rogers        struct pmu_event pe = {
8433d504549SIan Rogers                .pmu = &big_c_string[pmu->pmu_name.offset],
8443d504549SIan Rogers        };
8453d504549SIan Rogers        int low = 0, high = pmu->num_entries - 1;
8463d504549SIan Rogers
8473d504549SIan Rogers        while (low <= high) {
8483d504549SIan Rogers                int cmp, mid = (low + high) / 2;
8493d504549SIan Rogers
8503d504549SIan Rogers                decompress_event(pmu->entries[mid].offset, &pe);
8513d504549SIan Rogers
8523d504549SIan Rogers                if (!pe.name && !name)
8533d504549SIan Rogers                        goto do_call;
8543d504549SIan Rogers
8553d504549SIan Rogers                if (!pe.name && name) {
8563d504549SIan Rogers                        low = mid + 1;
8573d504549SIan Rogers                        continue;
8583d504549SIan Rogers                }
8593d504549SIan Rogers                if (pe.name && !name) {
8603d504549SIan Rogers                        high = mid - 1;
8613d504549SIan Rogers                        continue;
8623d504549SIan Rogers                }
8633d504549SIan Rogers
8643d504549SIan Rogers                cmp = strcasecmp(pe.name, name);
8653d504549SIan Rogers                if (cmp < 0) {
8663d504549SIan Rogers                        low = mid + 1;
8673d504549SIan Rogers                        continue;
8683d504549SIan Rogers                }
8693d504549SIan Rogers                if (cmp > 0) {
8703d504549SIan Rogers                        high = mid - 1;
8713d504549SIan Rogers                        continue;
8723d504549SIan Rogers                }
8733d504549SIan Rogers  do_call:
8743d504549SIan Rogers                return fn ? fn(&pe, table, data) : 0;
8753d504549SIan Rogers        }
8763d504549SIan Rogers        return -1000;
8773d504549SIan Rogers}
8783d504549SIan Rogers
8794000519eSIan Rogersint pmu_events_table__for_each_event(const struct pmu_events_table *table,
880e3edd6cfSIan Rogers                                    struct perf_pmu *pmu,
8819118259cSIan Rogers                                    pmu_event_iter_fn fn,
882660842e4SIan Rogers                                    void *data)
883660842e4SIan Rogers{
8842e255b4fSIan Rogers        for (size_t i = 0; i < table->num_pmus; i++) {
885e3edd6cfSIan Rogers                const struct pmu_table_entry *table_pmu = &table->pmus[i];
886e3edd6cfSIan Rogers                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
887e3edd6cfSIan Rogers                int ret;
888660842e4SIan Rogers
889e3edd6cfSIan Rogers                if (pmu && !pmu__name_match(pmu, pmu_name))
890e3edd6cfSIan Rogers                        continue;
891e3edd6cfSIan Rogers
892e3edd6cfSIan Rogers                ret = pmu_events_table__for_each_event_pmu(table, table_pmu, fn, data);
893e3edd6cfSIan Rogers                if (pmu || ret)
8942e255b4fSIan Rogers                        return ret;
8952e255b4fSIan Rogers        }
8962e255b4fSIan Rogers        return 0;
8972e255b4fSIan Rogers}
8982e255b4fSIan Rogers
8993d504549SIan Rogersint pmu_events_table__find_event(const struct pmu_events_table *table,
9003d504549SIan Rogers                                 struct perf_pmu *pmu,
9013d504549SIan Rogers                                 const char *name,
9023d504549SIan Rogers                                 pmu_event_iter_fn fn,
9033d504549SIan Rogers                                 void *data)
9043d504549SIan Rogers{
9053d504549SIan Rogers        for (size_t i = 0; i < table->num_pmus; i++) {
9063d504549SIan Rogers                const struct pmu_table_entry *table_pmu = &table->pmus[i];
9073d504549SIan Rogers                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
9083d504549SIan Rogers                int ret;
9093d504549SIan Rogers
9103d504549SIan Rogers                if (!pmu__name_match(pmu, pmu_name))
9113d504549SIan Rogers                        continue;
9123d504549SIan Rogers
9133d504549SIan Rogers                ret = pmu_events_table__find_event_pmu(table, table_pmu, name, fn, data);
9143d504549SIan Rogers                if (ret != -1000)
9153d504549SIan Rogers                        return ret;
9163d504549SIan Rogers        }
9173d504549SIan Rogers        return -1000;
9183d504549SIan Rogers}
9193d504549SIan Rogers
920e6ff1eedSIan Rogerssize_t pmu_events_table__num_events(const struct pmu_events_table *table,
921e6ff1eedSIan Rogers                                    struct perf_pmu *pmu)
922e6ff1eedSIan Rogers{
923e6ff1eedSIan Rogers        size_t count = 0;
924e6ff1eedSIan Rogers
925e6ff1eedSIan Rogers        for (size_t i = 0; i < table->num_pmus; i++) {
926e6ff1eedSIan Rogers                const struct pmu_table_entry *table_pmu = &table->pmus[i];
927e6ff1eedSIan Rogers                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
928e6ff1eedSIan Rogers
929e6ff1eedSIan Rogers                if (pmu__name_match(pmu, pmu_name))
930e6ff1eedSIan Rogers                        count += table_pmu->num_entries;
931e6ff1eedSIan Rogers        }
932e6ff1eedSIan Rogers        return count;
933e6ff1eedSIan Rogers}
934e6ff1eedSIan Rogers
9352e255b4fSIan Rogersstatic int pmu_metrics_table__for_each_metric_pmu(const struct pmu_metrics_table *table,
9362e255b4fSIan Rogers                                                const struct pmu_table_entry *pmu,
9372e255b4fSIan Rogers                                                pmu_metric_iter_fn fn,
9382e255b4fSIan Rogers                                                void *data)
9392e255b4fSIan Rogers{
9402e255b4fSIan Rogers        int ret;
9412e255b4fSIan Rogers        struct pmu_metric pm = {
9422e255b4fSIan Rogers                .pmu = &big_c_string[pmu->pmu_name.offset],
9432e255b4fSIan Rogers        };
9442e255b4fSIan Rogers
9452e255b4fSIan Rogers        for (uint32_t i = 0; i < pmu->num_entries; i++) {
9462e255b4fSIan Rogers                decompress_metric(pmu->entries[i].offset, &pm);
9472e255b4fSIan Rogers                if (!pm.metric_expr)
948db95818eSIan Rogers                        continue;
9492e255b4fSIan Rogers                ret = fn(&pm, table, data);
950660842e4SIan Rogers                if (ret)
951660842e4SIan Rogers                        return ret;
952660842e4SIan Rogers        }
953660842e4SIan Rogers        return 0;
954660842e4SIan Rogers}
955660842e4SIan Rogers
9564000519eSIan Rogersint pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table,
957db95818eSIan Rogers                                     pmu_metric_iter_fn fn,
958db95818eSIan Rogers                                     void *data)
959db95818eSIan Rogers{
9602e255b4fSIan Rogers        for (size_t i = 0; i < table->num_pmus; i++) {
9612e255b4fSIan Rogers                int ret = pmu_metrics_table__for_each_metric_pmu(table, &table->pmus[i],
9622e255b4fSIan Rogers                                                                 fn, data);
963db95818eSIan Rogers
964db95818eSIan Rogers                if (ret)
965db95818eSIan Rogers                        return ret;
966db95818eSIan Rogers        }
967db95818eSIan Rogers        return 0;
968db95818eSIan Rogers}
969db95818eSIan Rogers
97096d2a746SIan Rogersconst struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
97129be2fe0SIan Rogers{
9721ba3752aSIan Rogers        const struct pmu_events_table *table = NULL;
97329be2fe0SIan Rogers        char *cpuid = perf_pmu__getcpuid(pmu);
9747c52f10cSIan Rogers        size_t i;
97529be2fe0SIan Rogers
97629be2fe0SIan Rogers        /* on some platforms which uses cpus map, cpuid can be NULL for
97729be2fe0SIan Rogers         * PMUs other than CORE PMUs.
97829be2fe0SIan Rogers         */
97929be2fe0SIan Rogers        if (!cpuid)
98029be2fe0SIan Rogers                return NULL;
98129be2fe0SIan Rogers
98229be2fe0SIan Rogers        i = 0;
98329be2fe0SIan Rogers        for (;;) {
98429be2fe0SIan Rogers                const struct pmu_events_map *map = &pmu_events_map[i++];
9851ba3752aSIan Rogers                if (!map->arch)
98629be2fe0SIan Rogers                        break;
98729be2fe0SIan Rogers
98829be2fe0SIan Rogers                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
98962774db2SIan Rogers                        table = &map->event_table;
99029be2fe0SIan Rogers                        break;
99129be2fe0SIan Rogers                }
99229be2fe0SIan Rogers        }
99329be2fe0SIan Rogers        free(cpuid);
994*e47749f1SThomas Richter        if (!pmu || !table)
99529be2fe0SIan Rogers                return table;
9967c52f10cSIan Rogers
9977c52f10cSIan Rogers        for (i = 0; i < table->num_pmus; i++) {
9987c52f10cSIan Rogers                const struct pmu_table_entry *table_pmu = &table->pmus[i];
9997c52f10cSIan Rogers                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
10007c52f10cSIan Rogers
10017c52f10cSIan Rogers                if (pmu__name_match(pmu, pmu_name))
10027c52f10cSIan Rogers                        return table;
10037c52f10cSIan Rogers        }
10047c52f10cSIan Rogers        return NULL;
100529be2fe0SIan Rogers}
100629be2fe0SIan Rogers
1007f8ea2c15SIan Rogersconst struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
1008f8ea2c15SIan Rogers{
100962774db2SIan Rogers        const struct pmu_metrics_table *table = NULL;
101062774db2SIan Rogers        char *cpuid = perf_pmu__getcpuid(pmu);
101162774db2SIan Rogers        int i;
101262774db2SIan Rogers
101362774db2SIan Rogers        /* on some platforms which uses cpus map, cpuid can be NULL for
101462774db2SIan Rogers         * PMUs other than CORE PMUs.
101562774db2SIan Rogers         */
101662774db2SIan Rogers        if (!cpuid)
101762774db2SIan Rogers                return NULL;
101862774db2SIan Rogers
101962774db2SIan Rogers        i = 0;
102062774db2SIan Rogers        for (;;) {
102162774db2SIan Rogers                const struct pmu_events_map *map = &pmu_events_map[i++];
102262774db2SIan Rogers                if (!map->arch)
102362774db2SIan Rogers                        break;
102462774db2SIan Rogers
102562774db2SIan Rogers                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
102662774db2SIan Rogers                        table = &map->metric_table;
102762774db2SIan Rogers                        break;
102862774db2SIan Rogers                }
102962774db2SIan Rogers        }
103062774db2SIan Rogers        free(cpuid);
103162774db2SIan Rogers        return table;
1032f8ea2c15SIan Rogers}
1033f8ea2c15SIan Rogers
10341ba3752aSIan Rogersconst struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
103529be2fe0SIan Rogers{
103629be2fe0SIan Rogers        for (const struct pmu_events_map *tables = &pmu_events_map[0];
10371ba3752aSIan Rogers             tables->arch;
103829be2fe0SIan Rogers             tables++) {
103929be2fe0SIan Rogers                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
104062774db2SIan Rogers                        return &tables->event_table;
104129be2fe0SIan Rogers        }
104229be2fe0SIan Rogers        return NULL;
104329be2fe0SIan Rogers}
104429be2fe0SIan Rogers
1045f8ea2c15SIan Rogersconst struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
104696d2a746SIan Rogers{
104762774db2SIan Rogers        for (const struct pmu_events_map *tables = &pmu_events_map[0];
104862774db2SIan Rogers             tables->arch;
104962774db2SIan Rogers             tables++) {
105062774db2SIan Rogers                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
105162774db2SIan Rogers                        return &tables->metric_table;
105262774db2SIan Rogers        }
105362774db2SIan Rogers        return NULL;
105496d2a746SIan Rogers}
105596d2a746SIan Rogers
105629be2fe0SIan Rogersint pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
105729be2fe0SIan Rogers{
105829be2fe0SIan Rogers        for (const struct pmu_events_map *tables = &pmu_events_map[0];
10591ba3752aSIan Rogers             tables->arch;
106029be2fe0SIan Rogers             tables++) {
1061e3edd6cfSIan Rogers                int ret = pmu_events_table__for_each_event(&tables->event_table,
1062e3edd6cfSIan Rogers                                                           /*pmu=*/ NULL, fn, data);
106329be2fe0SIan Rogers
106429be2fe0SIan Rogers                if (ret)
106529be2fe0SIan Rogers                        return ret;
106629be2fe0SIan Rogers        }
106729be2fe0SIan Rogers        return 0;
106829be2fe0SIan Rogers}
106929be2fe0SIan Rogers
1070db95818eSIan Rogersint pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
1071db95818eSIan Rogers{
1072db95818eSIan Rogers        for (const struct pmu_events_map *tables = &pmu_events_map[0];
1073db95818eSIan Rogers             tables->arch;
1074db95818eSIan Rogers             tables++) {
10754000519eSIan Rogers                int ret = pmu_metrics_table__for_each_metric(&tables->metric_table, fn, data);
1076db95818eSIan Rogers
1077db95818eSIan Rogers                if (ret)
1078db95818eSIan Rogers                        return ret;
1079db95818eSIan Rogers        }
1080db95818eSIan Rogers        return 0;
1081db95818eSIan Rogers}
1082db95818eSIan Rogers
10831ba3752aSIan Rogersconst struct pmu_events_table *find_sys_events_table(const char *name)
10842519db2aSIan Rogers{
10852519db2aSIan Rogers        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
10862519db2aSIan Rogers             tables->name;
10872519db2aSIan Rogers             tables++) {
10882519db2aSIan Rogers                if (!strcmp(tables->name, name))
108962774db2SIan Rogers                        return &tables->event_table;
10902519db2aSIan Rogers        }
10912519db2aSIan Rogers        return NULL;
10922519db2aSIan Rogers}
10932519db2aSIan Rogers
10942519db2aSIan Rogersint pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
10952519db2aSIan Rogers{
10962519db2aSIan Rogers        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
10972519db2aSIan Rogers             tables->name;
10982519db2aSIan Rogers             tables++) {
1099e3edd6cfSIan Rogers                int ret = pmu_events_table__for_each_event(&tables->event_table,
1100e3edd6cfSIan Rogers                                                           /*pmu=*/ NULL, fn, data);
11012519db2aSIan Rogers
11022519db2aSIan Rogers                if (ret)
11032519db2aSIan Rogers                        return ret;
11042519db2aSIan Rogers        }
11052519db2aSIan Rogers        return 0;
11062519db2aSIan Rogers}
1107db95818eSIan Rogers
1108db95818eSIan Rogersint pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data)
1109db95818eSIan Rogers{
1110db95818eSIan Rogers        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
1111db95818eSIan Rogers             tables->name;
1112db95818eSIan Rogers             tables++) {
11134000519eSIan Rogers                int ret = pmu_metrics_table__for_each_metric(&tables->metric_table, fn, data);
1114db95818eSIan Rogers
1115db95818eSIan Rogers                if (ret)
1116db95818eSIan Rogers                        return ret;
1117db95818eSIan Rogers        }
1118db95818eSIan Rogers        return 0;
1119db95818eSIan Rogers}
1120ffc606adSIan Rogers""")
1121ffc606adSIan Rogers
112266c6e0c1SIan Rogersdef print_metricgroups() -> None:
112366c6e0c1SIan Rogers  _args.output_file.write("""
112466c6e0c1SIan Rogersstatic const int metricgroups[][2] = {
112566c6e0c1SIan Rogers""")
112666c6e0c1SIan Rogers  for mgroup in sorted(_metricgroups):
112766c6e0c1SIan Rogers    description = _metricgroups[mgroup]
112866c6e0c1SIan Rogers    _args.output_file.write(
112966c6e0c1SIan Rogers        f'\t{{ {_bcs.offsets[mgroup]}, {_bcs.offsets[description]} }}, /* {mgroup} => {description} */\n'
113066c6e0c1SIan Rogers    )
113166c6e0c1SIan Rogers  _args.output_file.write("""
113266c6e0c1SIan Rogers};
113366c6e0c1SIan Rogers
113466c6e0c1SIan Rogersconst char *describe_metricgroup(const char *group)
113566c6e0c1SIan Rogers{
113666c6e0c1SIan Rogers        int low = 0, high = (int)ARRAY_SIZE(metricgroups) - 1;
113766c6e0c1SIan Rogers
113866c6e0c1SIan Rogers        while (low <= high) {
113966c6e0c1SIan Rogers                int mid = (low + high) / 2;
114066c6e0c1SIan Rogers                const char *mgroup = &big_c_string[metricgroups[mid][0]];
114166c6e0c1SIan Rogers                int cmp = strcmp(mgroup, group);
114266c6e0c1SIan Rogers
114366c6e0c1SIan Rogers                if (cmp == 0) {
114466c6e0c1SIan Rogers                        return &big_c_string[metricgroups[mid][1]];
114566c6e0c1SIan Rogers                } else if (cmp < 0) {
114666c6e0c1SIan Rogers                        low = mid + 1;
114766c6e0c1SIan Rogers                } else {
114866c6e0c1SIan Rogers                        high = mid - 1;
114966c6e0c1SIan Rogers                }
115066c6e0c1SIan Rogers        }
115166c6e0c1SIan Rogers        return NULL;
115266c6e0c1SIan Rogers}
115366c6e0c1SIan Rogers""")
1154ffc606adSIan Rogers
1155ffc606adSIan Rogersdef main() -> None:
1156ffc606adSIan Rogers  global _args
1157ffc606adSIan Rogers
1158ffc606adSIan Rogers  def dir_path(path: str) -> str:
1159ffc606adSIan Rogers    """Validate path is a directory for argparse."""
1160ffc606adSIan Rogers    if os.path.isdir(path):
1161ffc606adSIan Rogers      return path
1162ffc606adSIan Rogers    raise argparse.ArgumentTypeError(f'\'{path}\' is not a valid directory')
1163ffc606adSIan Rogers
1164ffc606adSIan Rogers  def ftw(path: str, parents: Sequence[str],
1165ffc606adSIan Rogers          action: Callable[[Sequence[str], os.DirEntry], None]) -> None:
1166ffc606adSIan Rogers    """Replicate the directory/file walking behavior of C's file tree walk."""
116763620367SBernhard M. Wiedemann    for item in sorted(os.scandir(path), key=lambda e: e.name):
11685a09b1fdSIan Rogers      if _args.model != 'all' and item.is_dir():
11695a09b1fdSIan Rogers        # Check if the model matches one in _args.model.
11705a09b1fdSIan Rogers        if len(parents) == _args.model.split(',')[0].count('/'):
11715a09b1fdSIan Rogers          # We're testing the correct directory.
11725a09b1fdSIan Rogers          item_path = '/'.join(parents) + ('/' if len(parents) > 0 else '') + item.name
11735a09b1fdSIan Rogers          if 'test' not in item_path and item_path not in _args.model.split(','):
11745a09b1fdSIan Rogers            continue
1175ffc606adSIan Rogers      action(parents, item)
1176ffc606adSIan Rogers      if item.is_dir():
1177ffc606adSIan Rogers        ftw(item.path, parents + [item.name], action)
1178ffc606adSIan Rogers
1179ffc606adSIan Rogers  ap = argparse.ArgumentParser()
1180ffc606adSIan Rogers  ap.add_argument('arch', help='Architecture name like x86')
11815a09b1fdSIan Rogers  ap.add_argument('model', help='''Select a model such as skylake to
11825a09b1fdSIan Rogersreduce the code size.  Normally set to "all". For architectures like
11835a09b1fdSIan RogersARM64 with an implementor/model, the model must include the implementor
11845a09b1fdSIan Rogerssuch as "arm/cortex-a34".''',
11855a09b1fdSIan Rogers                  default='all')
1186ffc606adSIan Rogers  ap.add_argument(
1187ffc606adSIan Rogers      'starting_dir',
1188ffc606adSIan Rogers      type=dir_path,
1189ffc606adSIan Rogers      help='Root of tree containing architecture directories containing json files'
1190ffc606adSIan Rogers  )
1191ffc606adSIan Rogers  ap.add_argument(
11929118259cSIan Rogers      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
1193ffc606adSIan Rogers  _args = ap.parse_args()
1194ffc606adSIan Rogers
11952519db2aSIan Rogers  _args.output_file.write("""
1196c7e97f21SNamhyung Kim#include <pmu-events/pmu-events.h>
119729be2fe0SIan Rogers#include "util/header.h"
119829be2fe0SIan Rogers#include "util/pmu.h"
11992519db2aSIan Rogers#include <string.h>
12002519db2aSIan Rogers#include <stddef.h>
12012519db2aSIan Rogers
12029118259cSIan Rogersstruct compact_pmu_event {
12039118259cSIan Rogers        int offset;
12049118259cSIan Rogers};
12059118259cSIan Rogers
12062e255b4fSIan Rogersstruct pmu_table_entry {
12072e255b4fSIan Rogers        const struct compact_pmu_event *entries;
12082e255b4fSIan Rogers        uint32_t num_entries;
12092e255b4fSIan Rogers        struct compact_pmu_event pmu_name;
12102e255b4fSIan Rogers};
12112e255b4fSIan Rogers
12122519db2aSIan Rogers""")
1213099b157cSIan Rogers  archs = []
1214099b157cSIan Rogers  for item in os.scandir(_args.starting_dir):
1215099b157cSIan Rogers    if not item.is_dir():
1216099b157cSIan Rogers      continue
1217099b157cSIan Rogers    if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
1218099b157cSIan Rogers      archs.append(item.name)
1219099b157cSIan Rogers
1220099b157cSIan Rogers  if len(archs) < 2:
1221099b157cSIan Rogers    raise IOError(f'Missing architecture directory \'{_args.arch}\'')
1222099b157cSIan Rogers
1223099b157cSIan Rogers  archs.sort()
1224099b157cSIan Rogers  for arch in archs:
1225099b157cSIan Rogers    arch_path = f'{_args.starting_dir}/{arch}'
1226ffc606adSIan Rogers    preprocess_arch_std_files(arch_path)
12279118259cSIan Rogers    ftw(arch_path, [], preprocess_one_file)
12289118259cSIan Rogers
12299118259cSIan Rogers  _bcs.compute()
12309118259cSIan Rogers  _args.output_file.write('static const char *const big_c_string =\n')
12319118259cSIan Rogers  for s in _bcs.big_string:
12329118259cSIan Rogers    _args.output_file.write(s)
12339118259cSIan Rogers  _args.output_file.write(';\n\n')
12349118259cSIan Rogers  for arch in archs:
12359118259cSIan Rogers    arch_path = f'{_args.starting_dir}/{arch}'
1236ffc606adSIan Rogers    ftw(arch_path, [], process_one_file)
12379f587cc9SIan Rogers    print_pending_events()
123862774db2SIan Rogers    print_pending_metrics()
1239ffc606adSIan Rogers
1240099b157cSIan Rogers  print_mapping_table(archs)
1241ffc606adSIan Rogers  print_system_mapping_table()
124266c6e0c1SIan Rogers  print_metricgroups()
1243ffc606adSIan Rogers
1244ffc606adSIan Rogersif __name__ == '__main__':
1245ffc606adSIan Rogers  main()
1246