162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
362306a36Sopenharmony_ci"""Convert directories of JSON events to C code."""
462306a36Sopenharmony_ciimport argparse
562306a36Sopenharmony_ciimport csv
662306a36Sopenharmony_cifrom functools import lru_cache
762306a36Sopenharmony_ciimport json
862306a36Sopenharmony_ciimport metric
962306a36Sopenharmony_ciimport os
1062306a36Sopenharmony_ciimport sys
1162306a36Sopenharmony_cifrom typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
1262306a36Sopenharmony_ciimport collections
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci# Global command line arguments.
1562306a36Sopenharmony_ci_args = None
1662306a36Sopenharmony_ci# List of regular event tables.
1762306a36Sopenharmony_ci_event_tables = []
1862306a36Sopenharmony_ci# List of event tables generated from "/sys" directories.
1962306a36Sopenharmony_ci_sys_event_tables = []
2062306a36Sopenharmony_ci# List of regular metric tables.
2162306a36Sopenharmony_ci_metric_tables = []
2262306a36Sopenharmony_ci# List of metric tables generated from "/sys" directories.
2362306a36Sopenharmony_ci_sys_metric_tables = []
2462306a36Sopenharmony_ci# Mapping between sys event table names and sys metric table names.
2562306a36Sopenharmony_ci_sys_event_table_to_metric_table_mapping = {}
2662306a36Sopenharmony_ci# Map from an event name to an architecture standard
2762306a36Sopenharmony_ci# JsonEvent. Architecture standard events are in json files in the top
2862306a36Sopenharmony_ci# f'{_args.starting_dir}/{_args.arch}' directory.
2962306a36Sopenharmony_ci_arch_std_events = {}
3062306a36Sopenharmony_ci# Events to write out when the table is closed
3162306a36Sopenharmony_ci_pending_events = []
3262306a36Sopenharmony_ci# Name of events table to be written out
3362306a36Sopenharmony_ci_pending_events_tblname = None
3462306a36Sopenharmony_ci# Metrics to write out when the table is closed
3562306a36Sopenharmony_ci_pending_metrics = []
3662306a36Sopenharmony_ci# Name of metrics table to be written out
3762306a36Sopenharmony_ci_pending_metrics_tblname = None
3862306a36Sopenharmony_ci# Global BigCString shared by all structures.
3962306a36Sopenharmony_ci_bcs = None
4062306a36Sopenharmony_ci# Map from the name of a metric group to a description of the group.
4162306a36Sopenharmony_ci_metricgroups = {}
4262306a36Sopenharmony_ci# Order specific JsonEvent attributes will be visited.
4362306a36Sopenharmony_ci_json_event_attributes = [
4462306a36Sopenharmony_ci    # cmp_sevent related attributes.
4562306a36Sopenharmony_ci    'name', 'topic', 'desc',
4662306a36Sopenharmony_ci    # Seems useful, put it early.
4762306a36Sopenharmony_ci    'event',
4862306a36Sopenharmony_ci    # Short things in alphabetical order.
4962306a36Sopenharmony_ci    'compat', 'deprecated', 'perpkg', 'unit',
5062306a36Sopenharmony_ci    # Longer things (the last won't be iterated over during decompress).
5162306a36Sopenharmony_ci    'long_desc'
5262306a36Sopenharmony_ci]
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci# Attributes that are in pmu_metric rather than pmu_event.
5562306a36Sopenharmony_ci_json_metric_attributes = [
5662306a36Sopenharmony_ci    'metric_name', 'metric_group', 'metric_expr', 'metric_threshold',
5762306a36Sopenharmony_ci    'desc', 'long_desc', 'unit', 'compat', 'metricgroup_no_group',
5862306a36Sopenharmony_ci    'default_metricgroup_name', 'aggr_mode', 'event_grouping'
5962306a36Sopenharmony_ci]
6062306a36Sopenharmony_ci# Attributes that are bools or enum int values, encoded as '0', '1',...
6162306a36Sopenharmony_ci_json_enum_attributes = ['aggr_mode', 'deprecated', 'event_grouping', 'perpkg']
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cidef removesuffix(s: str, suffix: str) -> str:
6462306a36Sopenharmony_ci  """Remove the suffix from a string
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci  The removesuffix function is added to str in Python 3.9. We aim for 3.6
6762306a36Sopenharmony_ci  compatibility and so provide our own function here.
6862306a36Sopenharmony_ci  """
6962306a36Sopenharmony_ci  return s[0:-len(suffix)] if s.endswith(suffix) else s
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cidef file_name_to_table_name(prefix: str, parents: Sequence[str],
7362306a36Sopenharmony_ci                            dirname: str) -> str:
7462306a36Sopenharmony_ci  """Generate a C table name from directory names."""
7562306a36Sopenharmony_ci  tblname = prefix
7662306a36Sopenharmony_ci  for p in parents:
7762306a36Sopenharmony_ci    tblname += '_' + p
7862306a36Sopenharmony_ci  tblname += '_' + dirname
7962306a36Sopenharmony_ci  return tblname.replace('-', '_')
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cidef c_len(s: str) -> int:
8362306a36Sopenharmony_ci  """Return the length of s a C string
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci  This doesn't handle all escape characters properly. It first assumes
8662306a36Sopenharmony_ci  all \ are for escaping, it then adjusts as it will have over counted
8762306a36Sopenharmony_ci  \\. The code uses \000 rather than \0 as a terminator as an adjacent
8862306a36Sopenharmony_ci  number would be folded into a string of \0 (ie. "\0" + "5" doesn't
8962306a36Sopenharmony_ci  equal a terminator followed by the number 5 but the escape of
9062306a36Sopenharmony_ci  \05). The code adjusts for \000 but not properly for all octal, hex
9162306a36Sopenharmony_ci  or unicode values.
9262306a36Sopenharmony_ci  """
9362306a36Sopenharmony_ci  try:
9462306a36Sopenharmony_ci    utf = s.encode(encoding='utf-8',errors='strict')
9562306a36Sopenharmony_ci  except:
9662306a36Sopenharmony_ci    print(f'broken string {s}')
9762306a36Sopenharmony_ci    raise
9862306a36Sopenharmony_ci  return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciclass BigCString:
10162306a36Sopenharmony_ci  """A class to hold many strings concatenated together.
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci  Generating a large number of stand-alone C strings creates a large
10462306a36Sopenharmony_ci  number of relocations in position independent code. The BigCString
10562306a36Sopenharmony_ci  is a helper for this case. It builds a single string which within it
10662306a36Sopenharmony_ci  are all the other C strings (to avoid memory issues the string
10762306a36Sopenharmony_ci  itself is held as a list of strings). The offsets within the big
10862306a36Sopenharmony_ci  string are recorded and when stored to disk these don't need
10962306a36Sopenharmony_ci  relocation. To reduce the size of the string further, identical
11062306a36Sopenharmony_ci  strings are merged. If a longer string ends-with the same value as a
11162306a36Sopenharmony_ci  shorter string, these entries are also merged.
11262306a36Sopenharmony_ci  """
11362306a36Sopenharmony_ci  strings: Set[str]
11462306a36Sopenharmony_ci  big_string: Sequence[str]
11562306a36Sopenharmony_ci  offsets: Dict[str, int]
11662306a36Sopenharmony_ci  insert_number: int
11762306a36Sopenharmony_ci  insert_point: Dict[str, int]
11862306a36Sopenharmony_ci  metrics: Set[str]
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci  def __init__(self):
12162306a36Sopenharmony_ci    self.strings = set()
12262306a36Sopenharmony_ci    self.insert_number = 0;
12362306a36Sopenharmony_ci    self.insert_point = {}
12462306a36Sopenharmony_ci    self.metrics = set()
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci  def add(self, s: str, metric: bool) -> None:
12762306a36Sopenharmony_ci    """Called to add to the big string."""
12862306a36Sopenharmony_ci    if s not in self.strings:
12962306a36Sopenharmony_ci      self.strings.add(s)
13062306a36Sopenharmony_ci      self.insert_point[s] = self.insert_number
13162306a36Sopenharmony_ci      self.insert_number += 1
13262306a36Sopenharmony_ci      if metric:
13362306a36Sopenharmony_ci        self.metrics.add(s)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci  def compute(self) -> None:
13662306a36Sopenharmony_ci    """Called once all strings are added to compute the string and offsets."""
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci    folded_strings = {}
13962306a36Sopenharmony_ci    # Determine if two strings can be folded, ie. let 1 string use the
14062306a36Sopenharmony_ci    # end of another. First reverse all strings and sort them.
14162306a36Sopenharmony_ci    sorted_reversed_strings = sorted([x[::-1] for x in self.strings])
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci    # Strings 'xyz' and 'yz' will now be [ 'zy', 'zyx' ]. Scan forward
14462306a36Sopenharmony_ci    # for each string to see if there is a better candidate to fold it
14562306a36Sopenharmony_ci    # into, in the example rather than using 'yz' we can use'xyz' at
14662306a36Sopenharmony_ci    # an offset of 1. We record which string can be folded into which
14762306a36Sopenharmony_ci    # in folded_strings, we don't need to record the offset as it is
14862306a36Sopenharmony_ci    # trivially computed from the string lengths.
14962306a36Sopenharmony_ci    for pos,s in enumerate(sorted_reversed_strings):
15062306a36Sopenharmony_ci      best_pos = pos
15162306a36Sopenharmony_ci      for check_pos in range(pos + 1, len(sorted_reversed_strings)):
15262306a36Sopenharmony_ci        if sorted_reversed_strings[check_pos].startswith(s):
15362306a36Sopenharmony_ci          best_pos = check_pos
15462306a36Sopenharmony_ci        else:
15562306a36Sopenharmony_ci          break
15662306a36Sopenharmony_ci      if pos != best_pos:
15762306a36Sopenharmony_ci        folded_strings[s[::-1]] = sorted_reversed_strings[best_pos][::-1]
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci    # Compute reverse mappings for debugging.
16062306a36Sopenharmony_ci    fold_into_strings = collections.defaultdict(set)
16162306a36Sopenharmony_ci    for key, val in folded_strings.items():
16262306a36Sopenharmony_ci      if key != val:
16362306a36Sopenharmony_ci        fold_into_strings[val].add(key)
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci    # big_string_offset is the current location within the C string
16662306a36Sopenharmony_ci    # being appended to - comments, etc. don't count. big_string is
16762306a36Sopenharmony_ci    # the string contents represented as a list. Strings are immutable
16862306a36Sopenharmony_ci    # in Python and so appending to one causes memory issues, while
16962306a36Sopenharmony_ci    # lists are mutable.
17062306a36Sopenharmony_ci    big_string_offset = 0
17162306a36Sopenharmony_ci    self.big_string = []
17262306a36Sopenharmony_ci    self.offsets = {}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci    def string_cmp_key(s: str) -> Tuple[bool, int, str]:
17562306a36Sopenharmony_ci      return (s in self.metrics, self.insert_point[s], s)
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci    # Emit all strings that aren't folded in a sorted manner.
17862306a36Sopenharmony_ci    for s in sorted(self.strings, key=string_cmp_key):
17962306a36Sopenharmony_ci      if s not in folded_strings:
18062306a36Sopenharmony_ci        self.offsets[s] = big_string_offset
18162306a36Sopenharmony_ci        self.big_string.append(f'/* offset={big_string_offset} */ "')
18262306a36Sopenharmony_ci        self.big_string.append(s)
18362306a36Sopenharmony_ci        self.big_string.append('"')
18462306a36Sopenharmony_ci        if s in fold_into_strings:
18562306a36Sopenharmony_ci          self.big_string.append(' /* also: ' + ', '.join(fold_into_strings[s]) + ' */')
18662306a36Sopenharmony_ci        self.big_string.append('\n')
18762306a36Sopenharmony_ci        big_string_offset += c_len(s)
18862306a36Sopenharmony_ci        continue
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci    # Compute the offsets of the folded strings.
19162306a36Sopenharmony_ci    for s in folded_strings.keys():
19262306a36Sopenharmony_ci      assert s not in self.offsets
19362306a36Sopenharmony_ci      folded_s = folded_strings[s]
19462306a36Sopenharmony_ci      self.offsets[s] = self.offsets[folded_s] + c_len(folded_s) - c_len(s)
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci_bcs = BigCString()
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ciclass JsonEvent:
19962306a36Sopenharmony_ci  """Representation of an event loaded from a json file dictionary."""
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci  def __init__(self, jd: dict):
20262306a36Sopenharmony_ci    """Constructor passed the dictionary of parsed json values."""
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci    def llx(x: int) -> str:
20562306a36Sopenharmony_ci      """Convert an int to a string similar to a printf modifier of %#llx."""
20662306a36Sopenharmony_ci      return '0' if x == 0 else hex(x)
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci    def fixdesc(s: str) -> str:
20962306a36Sopenharmony_ci      """Fix formatting issue for the desc string."""
21062306a36Sopenharmony_ci      if s is None:
21162306a36Sopenharmony_ci        return None
21262306a36Sopenharmony_ci      return removesuffix(removesuffix(removesuffix(s, '.  '),
21362306a36Sopenharmony_ci                                       '. '), '.').replace('\n', '\\n').replace(
21462306a36Sopenharmony_ci                                           '\"', '\\"').replace('\r', '\\r')
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci    def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
21762306a36Sopenharmony_ci      """Returns the aggr_mode_class enum value associated with the JSON string."""
21862306a36Sopenharmony_ci      if not aggr_mode:
21962306a36Sopenharmony_ci        return None
22062306a36Sopenharmony_ci      aggr_mode_to_enum = {
22162306a36Sopenharmony_ci          'PerChip': '1',
22262306a36Sopenharmony_ci          'PerCore': '2',
22362306a36Sopenharmony_ci      }
22462306a36Sopenharmony_ci      return aggr_mode_to_enum[aggr_mode]
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci    def convert_metric_constraint(metric_constraint: str) -> Optional[str]:
22762306a36Sopenharmony_ci      """Returns the metric_event_groups enum value associated with the JSON string."""
22862306a36Sopenharmony_ci      if not metric_constraint:
22962306a36Sopenharmony_ci        return None
23062306a36Sopenharmony_ci      metric_constraint_to_enum = {
23162306a36Sopenharmony_ci          'NO_GROUP_EVENTS': '1',
23262306a36Sopenharmony_ci          'NO_GROUP_EVENTS_NMI': '2',
23362306a36Sopenharmony_ci          'NO_NMI_WATCHDOG': '2',
23462306a36Sopenharmony_ci          'NO_GROUP_EVENTS_SMT': '3',
23562306a36Sopenharmony_ci      }
23662306a36Sopenharmony_ci      return metric_constraint_to_enum[metric_constraint]
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci    def lookup_msr(num: str) -> Optional[str]:
23962306a36Sopenharmony_ci      """Converts the msr number, or first in a list to the appropriate event field."""
24062306a36Sopenharmony_ci      if not num:
24162306a36Sopenharmony_ci        return None
24262306a36Sopenharmony_ci      msrmap = {
24362306a36Sopenharmony_ci          0x3F6: 'ldlat=',
24462306a36Sopenharmony_ci          0x1A6: 'offcore_rsp=',
24562306a36Sopenharmony_ci          0x1A7: 'offcore_rsp=',
24662306a36Sopenharmony_ci          0x3F7: 'frontend=',
24762306a36Sopenharmony_ci      }
24862306a36Sopenharmony_ci      return msrmap[int(num.split(',', 1)[0], 0)]
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci    def real_event(name: str, event: str) -> Optional[str]:
25162306a36Sopenharmony_ci      """Convert well known event names to an event string otherwise use the event argument."""
25262306a36Sopenharmony_ci      fixed = {
25362306a36Sopenharmony_ci          'inst_retired.any': 'event=0xc0,period=2000003',
25462306a36Sopenharmony_ci          'inst_retired.any_p': 'event=0xc0,period=2000003',
25562306a36Sopenharmony_ci          'cpu_clk_unhalted.ref': 'event=0x0,umask=0x03,period=2000003',
25662306a36Sopenharmony_ci          'cpu_clk_unhalted.thread': 'event=0x3c,period=2000003',
25762306a36Sopenharmony_ci          'cpu_clk_unhalted.core': 'event=0x3c,period=2000003',
25862306a36Sopenharmony_ci          'cpu_clk_unhalted.thread_any': 'event=0x3c,any=1,period=2000003',
25962306a36Sopenharmony_ci      }
26062306a36Sopenharmony_ci      if not name:
26162306a36Sopenharmony_ci        return None
26262306a36Sopenharmony_ci      if name.lower() in fixed:
26362306a36Sopenharmony_ci        return fixed[name.lower()]
26462306a36Sopenharmony_ci      return event
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci    def unit_to_pmu(unit: str) -> Optional[str]:
26762306a36Sopenharmony_ci      """Convert a JSON Unit to Linux PMU name."""
26862306a36Sopenharmony_ci      if not unit:
26962306a36Sopenharmony_ci        return 'default_core'
27062306a36Sopenharmony_ci      # Comment brought over from jevents.c:
27162306a36Sopenharmony_ci      # it's not realistic to keep adding these, we need something more scalable ...
27262306a36Sopenharmony_ci      table = {
27362306a36Sopenharmony_ci          'CBO': 'uncore_cbox',
27462306a36Sopenharmony_ci          'QPI LL': 'uncore_qpi',
27562306a36Sopenharmony_ci          'SBO': 'uncore_sbox',
27662306a36Sopenharmony_ci          'iMPH-U': 'uncore_arb',
27762306a36Sopenharmony_ci          'CPU-M-CF': 'cpum_cf',
27862306a36Sopenharmony_ci          'CPU-M-SF': 'cpum_sf',
27962306a36Sopenharmony_ci          'PAI-CRYPTO' : 'pai_crypto',
28062306a36Sopenharmony_ci          'PAI-EXT' : 'pai_ext',
28162306a36Sopenharmony_ci          'UPI LL': 'uncore_upi',
28262306a36Sopenharmony_ci          'hisi_sicl,cpa': 'hisi_sicl,cpa',
28362306a36Sopenharmony_ci          'hisi_sccl,ddrc': 'hisi_sccl,ddrc',
28462306a36Sopenharmony_ci          'hisi_sccl,hha': 'hisi_sccl,hha',
28562306a36Sopenharmony_ci          'hisi_sccl,l3c': 'hisi_sccl,l3c',
28662306a36Sopenharmony_ci          'imx8_ddr': 'imx8_ddr',
28762306a36Sopenharmony_ci          'L3PMC': 'amd_l3',
28862306a36Sopenharmony_ci          'DFPMC': 'amd_df',
28962306a36Sopenharmony_ci          'cpu_core': 'cpu_core',
29062306a36Sopenharmony_ci          'cpu_atom': 'cpu_atom',
29162306a36Sopenharmony_ci          'ali_drw': 'ali_drw',
29262306a36Sopenharmony_ci      }
29362306a36Sopenharmony_ci      return table[unit] if unit in table else f'uncore_{unit.lower()}'
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci    eventcode = 0
29662306a36Sopenharmony_ci    if 'EventCode' in jd:
29762306a36Sopenharmony_ci      eventcode = int(jd['EventCode'].split(',', 1)[0], 0)
29862306a36Sopenharmony_ci    if 'ExtSel' in jd:
29962306a36Sopenharmony_ci      eventcode |= int(jd['ExtSel']) << 8
30062306a36Sopenharmony_ci    configcode = int(jd['ConfigCode'], 0) if 'ConfigCode' in jd else None
30162306a36Sopenharmony_ci    self.name = jd['EventName'].lower() if 'EventName' in jd else None
30262306a36Sopenharmony_ci    self.topic = ''
30362306a36Sopenharmony_ci    self.compat = jd.get('Compat')
30462306a36Sopenharmony_ci    self.desc = fixdesc(jd.get('BriefDescription'))
30562306a36Sopenharmony_ci    self.long_desc = fixdesc(jd.get('PublicDescription'))
30662306a36Sopenharmony_ci    precise = jd.get('PEBS')
30762306a36Sopenharmony_ci    msr = lookup_msr(jd.get('MSRIndex'))
30862306a36Sopenharmony_ci    msrval = jd.get('MSRValue')
30962306a36Sopenharmony_ci    extra_desc = ''
31062306a36Sopenharmony_ci    if 'Data_LA' in jd:
31162306a36Sopenharmony_ci      extra_desc += '  Supports address when precise'
31262306a36Sopenharmony_ci      if 'Errata' in jd:
31362306a36Sopenharmony_ci        extra_desc += '.'
31462306a36Sopenharmony_ci    if 'Errata' in jd:
31562306a36Sopenharmony_ci      extra_desc += '  Spec update: ' + jd['Errata']
31662306a36Sopenharmony_ci    self.pmu = unit_to_pmu(jd.get('Unit'))
31762306a36Sopenharmony_ci    filter = jd.get('Filter')
31862306a36Sopenharmony_ci    self.unit = jd.get('ScaleUnit')
31962306a36Sopenharmony_ci    self.perpkg = jd.get('PerPkg')
32062306a36Sopenharmony_ci    self.aggr_mode = convert_aggr_mode(jd.get('AggregationMode'))
32162306a36Sopenharmony_ci    self.deprecated = jd.get('Deprecated')
32262306a36Sopenharmony_ci    self.metric_name = jd.get('MetricName')
32362306a36Sopenharmony_ci    self.metric_group = jd.get('MetricGroup')
32462306a36Sopenharmony_ci    self.metricgroup_no_group = jd.get('MetricgroupNoGroup')
32562306a36Sopenharmony_ci    self.default_metricgroup_name = jd.get('DefaultMetricgroupName')
32662306a36Sopenharmony_ci    self.event_grouping = convert_metric_constraint(jd.get('MetricConstraint'))
32762306a36Sopenharmony_ci    self.metric_expr = None
32862306a36Sopenharmony_ci    if 'MetricExpr' in jd:
32962306a36Sopenharmony_ci      self.metric_expr = metric.ParsePerfJson(jd['MetricExpr']).Simplify()
33062306a36Sopenharmony_ci    # Note, the metric formula for the threshold isn't parsed as the &
33162306a36Sopenharmony_ci    # and > have incorrect precedence.
33262306a36Sopenharmony_ci    self.metric_threshold = jd.get('MetricThreshold')
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci    arch_std = jd.get('ArchStdEvent')
33562306a36Sopenharmony_ci    if precise and self.desc and '(Precise Event)' not in self.desc:
33662306a36Sopenharmony_ci      extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
33762306a36Sopenharmony_ci                                                                 'event)')
33862306a36Sopenharmony_ci    event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
33962306a36Sopenharmony_ci    event_fields = [
34062306a36Sopenharmony_ci        ('AnyThread', 'any='),
34162306a36Sopenharmony_ci        ('PortMask', 'ch_mask='),
34262306a36Sopenharmony_ci        ('CounterMask', 'cmask='),
34362306a36Sopenharmony_ci        ('EdgeDetect', 'edge='),
34462306a36Sopenharmony_ci        ('FCMask', 'fc_mask='),
34562306a36Sopenharmony_ci        ('Invert', 'inv='),
34662306a36Sopenharmony_ci        ('SampleAfterValue', 'period='),
34762306a36Sopenharmony_ci        ('UMask', 'umask='),
34862306a36Sopenharmony_ci    ]
34962306a36Sopenharmony_ci    for key, value in event_fields:
35062306a36Sopenharmony_ci      if key in jd and jd[key] != '0':
35162306a36Sopenharmony_ci        event += ',' + value + jd[key]
35262306a36Sopenharmony_ci    if filter:
35362306a36Sopenharmony_ci      event += f',{filter}'
35462306a36Sopenharmony_ci    if msr:
35562306a36Sopenharmony_ci      event += f',{msr}{msrval}'
35662306a36Sopenharmony_ci    if self.desc and extra_desc:
35762306a36Sopenharmony_ci      self.desc += extra_desc
35862306a36Sopenharmony_ci    if self.long_desc and extra_desc:
35962306a36Sopenharmony_ci      self.long_desc += extra_desc
36062306a36Sopenharmony_ci    if arch_std:
36162306a36Sopenharmony_ci      if arch_std.lower() in _arch_std_events:
36262306a36Sopenharmony_ci        event = _arch_std_events[arch_std.lower()].event
36362306a36Sopenharmony_ci        # Copy from the architecture standard event to self for undefined fields.
36462306a36Sopenharmony_ci        for attr, value in _arch_std_events[arch_std.lower()].__dict__.items():
36562306a36Sopenharmony_ci          if hasattr(self, attr) and not getattr(self, attr):
36662306a36Sopenharmony_ci            setattr(self, attr, value)
36762306a36Sopenharmony_ci      else:
36862306a36Sopenharmony_ci        raise argparse.ArgumentTypeError('Cannot find arch std event:', arch_std)
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci    self.event = real_event(self.name, event)
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci  def __repr__(self) -> str:
37362306a36Sopenharmony_ci    """String representation primarily for debugging."""
37462306a36Sopenharmony_ci    s = '{\n'
37562306a36Sopenharmony_ci    for attr, value in self.__dict__.items():
37662306a36Sopenharmony_ci      if value:
37762306a36Sopenharmony_ci        s += f'\t{attr} = {value},\n'
37862306a36Sopenharmony_ci    return s + '}'
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci  def build_c_string(self, metric: bool) -> str:
38162306a36Sopenharmony_ci    s = ''
38262306a36Sopenharmony_ci    for attr in _json_metric_attributes if metric else _json_event_attributes:
38362306a36Sopenharmony_ci      x = getattr(self, attr)
38462306a36Sopenharmony_ci      if metric and x and attr == 'metric_expr':
38562306a36Sopenharmony_ci        # Convert parsed metric expressions into a string. Slashes
38662306a36Sopenharmony_ci        # must be doubled in the file.
38762306a36Sopenharmony_ci        x = x.ToPerfJson().replace('\\', '\\\\')
38862306a36Sopenharmony_ci      if metric and x and attr == 'metric_threshold':
38962306a36Sopenharmony_ci        x = x.replace('\\', '\\\\')
39062306a36Sopenharmony_ci      if attr in _json_enum_attributes:
39162306a36Sopenharmony_ci        s += x if x else '0'
39262306a36Sopenharmony_ci      else:
39362306a36Sopenharmony_ci        s += f'{x}\\000' if x else '\\000'
39462306a36Sopenharmony_ci    return s
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci  def to_c_string(self, metric: bool) -> str:
39762306a36Sopenharmony_ci    """Representation of the event as a C struct initializer."""
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci    s = self.build_c_string(metric)
40062306a36Sopenharmony_ci    return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci@lru_cache(maxsize=None)
40462306a36Sopenharmony_cidef read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
40562306a36Sopenharmony_ci  """Read json events from the specified file."""
40662306a36Sopenharmony_ci  try:
40762306a36Sopenharmony_ci    events = json.load(open(path), object_hook=JsonEvent)
40862306a36Sopenharmony_ci  except BaseException as err:
40962306a36Sopenharmony_ci    print(f"Exception processing {path}")
41062306a36Sopenharmony_ci    raise
41162306a36Sopenharmony_ci  metrics: list[Tuple[str, str, metric.Expression]] = []
41262306a36Sopenharmony_ci  for event in events:
41362306a36Sopenharmony_ci    event.topic = topic
41462306a36Sopenharmony_ci    if event.metric_name and '-' not in event.metric_name:
41562306a36Sopenharmony_ci      metrics.append((event.pmu, event.metric_name, event.metric_expr))
41662306a36Sopenharmony_ci  updates = metric.RewriteMetricsInTermsOfOthers(metrics)
41762306a36Sopenharmony_ci  if updates:
41862306a36Sopenharmony_ci    for event in events:
41962306a36Sopenharmony_ci      if event.metric_name in updates:
42062306a36Sopenharmony_ci        # print(f'Updated {event.metric_name} from\n"{event.metric_expr}"\n'
42162306a36Sopenharmony_ci        #       f'to\n"{updates[event.metric_name]}"')
42262306a36Sopenharmony_ci        event.metric_expr = updates[event.metric_name]
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci  return events
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cidef preprocess_arch_std_files(archpath: str) -> None:
42762306a36Sopenharmony_ci  """Read in all architecture standard events."""
42862306a36Sopenharmony_ci  global _arch_std_events
42962306a36Sopenharmony_ci  for item in os.scandir(archpath):
43062306a36Sopenharmony_ci    if item.is_file() and item.name.endswith('.json'):
43162306a36Sopenharmony_ci      for event in read_json_events(item.path, topic=''):
43262306a36Sopenharmony_ci        if event.name:
43362306a36Sopenharmony_ci          _arch_std_events[event.name.lower()] = event
43462306a36Sopenharmony_ci        if event.metric_name:
43562306a36Sopenharmony_ci          _arch_std_events[event.metric_name.lower()] = event
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cidef add_events_table_entries(item: os.DirEntry, topic: str) -> None:
43962306a36Sopenharmony_ci  """Add contents of file to _pending_events table."""
44062306a36Sopenharmony_ci  for e in read_json_events(item.path, topic):
44162306a36Sopenharmony_ci    if e.name:
44262306a36Sopenharmony_ci      _pending_events.append(e)
44362306a36Sopenharmony_ci    if e.metric_name:
44462306a36Sopenharmony_ci      _pending_metrics.append(e)
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cidef print_pending_events() -> None:
44862306a36Sopenharmony_ci  """Optionally close events table."""
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci  def event_cmp_key(j: JsonEvent) -> Tuple[str, str, bool, str, str]:
45162306a36Sopenharmony_ci    def fix_none(s: Optional[str]) -> str:
45262306a36Sopenharmony_ci      if s is None:
45362306a36Sopenharmony_ci        return ''
45462306a36Sopenharmony_ci      return s
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci    return (fix_none(j.pmu).replace(',','_'), fix_none(j.name), j.desc is not None, fix_none(j.topic),
45762306a36Sopenharmony_ci            fix_none(j.metric_name))
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci  global _pending_events
46062306a36Sopenharmony_ci  if not _pending_events:
46162306a36Sopenharmony_ci    return
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci  global _pending_events_tblname
46462306a36Sopenharmony_ci  if _pending_events_tblname.endswith('_sys'):
46562306a36Sopenharmony_ci    global _sys_event_tables
46662306a36Sopenharmony_ci    _sys_event_tables.append(_pending_events_tblname)
46762306a36Sopenharmony_ci  else:
46862306a36Sopenharmony_ci    global event_tables
46962306a36Sopenharmony_ci    _event_tables.append(_pending_events_tblname)
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci  first = True
47262306a36Sopenharmony_ci  last_pmu = None
47362306a36Sopenharmony_ci  pmus = set()
47462306a36Sopenharmony_ci  for event in sorted(_pending_events, key=event_cmp_key):
47562306a36Sopenharmony_ci    if event.pmu != last_pmu:
47662306a36Sopenharmony_ci      if not first:
47762306a36Sopenharmony_ci        _args.output_file.write('};\n')
47862306a36Sopenharmony_ci      pmu_name = event.pmu.replace(',', '_')
47962306a36Sopenharmony_ci      _args.output_file.write(
48062306a36Sopenharmony_ci          f'static const struct compact_pmu_event {_pending_events_tblname}_{pmu_name}[] = {{\n')
48162306a36Sopenharmony_ci      first = False
48262306a36Sopenharmony_ci      last_pmu = event.pmu
48362306a36Sopenharmony_ci      pmus.add((event.pmu, pmu_name))
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci    _args.output_file.write(event.to_c_string(metric=False))
48662306a36Sopenharmony_ci  _pending_events = []
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci  _args.output_file.write(f"""
48962306a36Sopenharmony_ci}};
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ciconst struct pmu_table_entry {_pending_events_tblname}[] = {{
49262306a36Sopenharmony_ci""")
49362306a36Sopenharmony_ci  for (pmu, tbl_pmu) in sorted(pmus):
49462306a36Sopenharmony_ci    pmu_name = f"{pmu}\\000"
49562306a36Sopenharmony_ci    _args.output_file.write(f"""{{
49662306a36Sopenharmony_ci     .entries = {_pending_events_tblname}_{tbl_pmu},
49762306a36Sopenharmony_ci     .num_entries = ARRAY_SIZE({_pending_events_tblname}_{tbl_pmu}),
49862306a36Sopenharmony_ci     .pmu_name = {{ {_bcs.offsets[pmu_name]} /* {pmu_name} */ }},
49962306a36Sopenharmony_ci}},
50062306a36Sopenharmony_ci""")
50162306a36Sopenharmony_ci  _args.output_file.write('};\n\n')
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cidef print_pending_metrics() -> None:
50462306a36Sopenharmony_ci  """Optionally close metrics table."""
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci  def metric_cmp_key(j: JsonEvent) -> Tuple[bool, str, str]:
50762306a36Sopenharmony_ci    def fix_none(s: Optional[str]) -> str:
50862306a36Sopenharmony_ci      if s is None:
50962306a36Sopenharmony_ci        return ''
51062306a36Sopenharmony_ci      return s
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci    return (j.desc is not None, fix_none(j.pmu), fix_none(j.metric_name))
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci  global _pending_metrics
51562306a36Sopenharmony_ci  if not _pending_metrics:
51662306a36Sopenharmony_ci    return
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci  global _pending_metrics_tblname
51962306a36Sopenharmony_ci  if _pending_metrics_tblname.endswith('_sys'):
52062306a36Sopenharmony_ci    global _sys_metric_tables
52162306a36Sopenharmony_ci    _sys_metric_tables.append(_pending_metrics_tblname)
52262306a36Sopenharmony_ci  else:
52362306a36Sopenharmony_ci    global metric_tables
52462306a36Sopenharmony_ci    _metric_tables.append(_pending_metrics_tblname)
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci  first = True
52762306a36Sopenharmony_ci  last_pmu = None
52862306a36Sopenharmony_ci  pmus = set()
52962306a36Sopenharmony_ci  for metric in sorted(_pending_metrics, key=metric_cmp_key):
53062306a36Sopenharmony_ci    if metric.pmu != last_pmu:
53162306a36Sopenharmony_ci      if not first:
53262306a36Sopenharmony_ci        _args.output_file.write('};\n')
53362306a36Sopenharmony_ci      pmu_name = metric.pmu.replace(',', '_')
53462306a36Sopenharmony_ci      _args.output_file.write(
53562306a36Sopenharmony_ci          f'static const struct compact_pmu_event {_pending_metrics_tblname}_{pmu_name}[] = {{\n')
53662306a36Sopenharmony_ci      first = False
53762306a36Sopenharmony_ci      last_pmu = metric.pmu
53862306a36Sopenharmony_ci      pmus.add((metric.pmu, pmu_name))
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci    _args.output_file.write(metric.to_c_string(metric=True))
54162306a36Sopenharmony_ci  _pending_metrics = []
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci  _args.output_file.write(f"""
54462306a36Sopenharmony_ci}};
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ciconst struct pmu_table_entry {_pending_metrics_tblname}[] = {{
54762306a36Sopenharmony_ci""")
54862306a36Sopenharmony_ci  for (pmu, tbl_pmu) in sorted(pmus):
54962306a36Sopenharmony_ci    pmu_name = f"{pmu}\\000"
55062306a36Sopenharmony_ci    _args.output_file.write(f"""{{
55162306a36Sopenharmony_ci     .entries = {_pending_metrics_tblname}_{tbl_pmu},
55262306a36Sopenharmony_ci     .num_entries = ARRAY_SIZE({_pending_metrics_tblname}_{tbl_pmu}),
55362306a36Sopenharmony_ci     .pmu_name = {{ {_bcs.offsets[pmu_name]} /* {pmu_name} */ }},
55462306a36Sopenharmony_ci}},
55562306a36Sopenharmony_ci""")
55662306a36Sopenharmony_ci  _args.output_file.write('};\n\n')
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cidef get_topic(topic: str) -> str:
55962306a36Sopenharmony_ci  if topic.endswith('metrics.json'):
56062306a36Sopenharmony_ci    return 'metrics'
56162306a36Sopenharmony_ci  return removesuffix(topic, '.json').replace('-', ' ')
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cidef preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci  if item.is_dir():
56662306a36Sopenharmony_ci    return
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci  # base dir or too deep
56962306a36Sopenharmony_ci  level = len(parents)
57062306a36Sopenharmony_ci  if level == 0 or level > 4:
57162306a36Sopenharmony_ci    return
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci  # Ignore other directories. If the file name does not have a .json
57462306a36Sopenharmony_ci  # extension, ignore it. It could be a readme.txt for instance.
57562306a36Sopenharmony_ci  if not item.is_file() or not item.name.endswith('.json'):
57662306a36Sopenharmony_ci    return
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci  if item.name == 'metricgroups.json':
57962306a36Sopenharmony_ci    metricgroup_descriptions = json.load(open(item.path))
58062306a36Sopenharmony_ci    for mgroup in metricgroup_descriptions:
58162306a36Sopenharmony_ci      assert len(mgroup) > 1, parents
58262306a36Sopenharmony_ci      description = f"{metricgroup_descriptions[mgroup]}\\000"
58362306a36Sopenharmony_ci      mgroup = f"{mgroup}\\000"
58462306a36Sopenharmony_ci      _bcs.add(mgroup, metric=True)
58562306a36Sopenharmony_ci      _bcs.add(description, metric=True)
58662306a36Sopenharmony_ci      _metricgroups[mgroup] = description
58762306a36Sopenharmony_ci    return
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci  topic = get_topic(item.name)
59062306a36Sopenharmony_ci  for event in read_json_events(item.path, topic):
59162306a36Sopenharmony_ci    pmu_name = f"{event.pmu}\\000"
59262306a36Sopenharmony_ci    if event.name:
59362306a36Sopenharmony_ci      _bcs.add(pmu_name, metric=False)
59462306a36Sopenharmony_ci      _bcs.add(event.build_c_string(metric=False), metric=False)
59562306a36Sopenharmony_ci    if event.metric_name:
59662306a36Sopenharmony_ci      _bcs.add(pmu_name, metric=True)
59762306a36Sopenharmony_ci      _bcs.add(event.build_c_string(metric=True), metric=True)
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cidef process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
60062306a36Sopenharmony_ci  """Process a JSON file during the main walk."""
60162306a36Sopenharmony_ci  def is_leaf_dir(path: str) -> bool:
60262306a36Sopenharmony_ci    for item in os.scandir(path):
60362306a36Sopenharmony_ci      if item.is_dir():
60462306a36Sopenharmony_ci        return False
60562306a36Sopenharmony_ci    return True
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci  # model directory, reset topic
60862306a36Sopenharmony_ci  if item.is_dir() and is_leaf_dir(item.path):
60962306a36Sopenharmony_ci    print_pending_events()
61062306a36Sopenharmony_ci    print_pending_metrics()
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci    global _pending_events_tblname
61362306a36Sopenharmony_ci    _pending_events_tblname = file_name_to_table_name('pmu_events_', parents, item.name)
61462306a36Sopenharmony_ci    global _pending_metrics_tblname
61562306a36Sopenharmony_ci    _pending_metrics_tblname = file_name_to_table_name('pmu_metrics_', parents, item.name)
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci    if item.name == 'sys':
61862306a36Sopenharmony_ci      _sys_event_table_to_metric_table_mapping[_pending_events_tblname] = _pending_metrics_tblname
61962306a36Sopenharmony_ci    return
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci  # base dir or too deep
62262306a36Sopenharmony_ci  level = len(parents)
62362306a36Sopenharmony_ci  if level == 0 or level > 4:
62462306a36Sopenharmony_ci    return
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci  # Ignore other directories. If the file name does not have a .json
62762306a36Sopenharmony_ci  # extension, ignore it. It could be a readme.txt for instance.
62862306a36Sopenharmony_ci  if not item.is_file() or not item.name.endswith('.json') or item.name == 'metricgroups.json':
62962306a36Sopenharmony_ci    return
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci  add_events_table_entries(item, get_topic(item.name))
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cidef print_mapping_table(archs: Sequence[str]) -> None:
63562306a36Sopenharmony_ci  """Read the mapfile and generate the struct from cpuid string to event table."""
63662306a36Sopenharmony_ci  _args.output_file.write("""
63762306a36Sopenharmony_ci/* Struct used to make the PMU event table implementation opaque to callers. */
63862306a36Sopenharmony_cistruct pmu_events_table {
63962306a36Sopenharmony_ci        const struct pmu_table_entry *pmus;
64062306a36Sopenharmony_ci        uint32_t num_pmus;
64162306a36Sopenharmony_ci};
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/* Struct used to make the PMU metric table implementation opaque to callers. */
64462306a36Sopenharmony_cistruct pmu_metrics_table {
64562306a36Sopenharmony_ci        const struct pmu_table_entry *pmus;
64662306a36Sopenharmony_ci        uint32_t num_pmus;
64762306a36Sopenharmony_ci};
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci/*
65062306a36Sopenharmony_ci * Map a CPU to its table of PMU events. The CPU is identified by the
65162306a36Sopenharmony_ci * cpuid field, which is an arch-specific identifier for the CPU.
65262306a36Sopenharmony_ci * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
65362306a36Sopenharmony_ci * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
65462306a36Sopenharmony_ci *
65562306a36Sopenharmony_ci * The  cpuid can contain any character other than the comma.
65662306a36Sopenharmony_ci */
65762306a36Sopenharmony_cistruct pmu_events_map {
65862306a36Sopenharmony_ci        const char *arch;
65962306a36Sopenharmony_ci        const char *cpuid;
66062306a36Sopenharmony_ci        struct pmu_events_table event_table;
66162306a36Sopenharmony_ci        struct pmu_metrics_table metric_table;
66262306a36Sopenharmony_ci};
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/*
66562306a36Sopenharmony_ci * Global table mapping each known CPU for the architecture to its
66662306a36Sopenharmony_ci * table of PMU events.
66762306a36Sopenharmony_ci */
66862306a36Sopenharmony_ciconst struct pmu_events_map pmu_events_map[] = {
66962306a36Sopenharmony_ci""")
67062306a36Sopenharmony_ci  for arch in archs:
67162306a36Sopenharmony_ci    if arch == 'test':
67262306a36Sopenharmony_ci      _args.output_file.write("""{
67362306a36Sopenharmony_ci\t.arch = "testarch",
67462306a36Sopenharmony_ci\t.cpuid = "testcpu",
67562306a36Sopenharmony_ci\t.event_table = {
67662306a36Sopenharmony_ci\t\t.pmus = pmu_events__test_soc_cpu,
67762306a36Sopenharmony_ci\t\t.num_pmus = ARRAY_SIZE(pmu_events__test_soc_cpu),
67862306a36Sopenharmony_ci\t},
67962306a36Sopenharmony_ci\t.metric_table = {
68062306a36Sopenharmony_ci\t\t.pmus = pmu_metrics__test_soc_cpu,
68162306a36Sopenharmony_ci\t\t.num_pmus = ARRAY_SIZE(pmu_metrics__test_soc_cpu),
68262306a36Sopenharmony_ci\t}
68362306a36Sopenharmony_ci},
68462306a36Sopenharmony_ci""")
68562306a36Sopenharmony_ci    else:
68662306a36Sopenharmony_ci      with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
68762306a36Sopenharmony_ci        table = csv.reader(csvfile)
68862306a36Sopenharmony_ci        first = True
68962306a36Sopenharmony_ci        for row in table:
69062306a36Sopenharmony_ci          # Skip the first row or any row beginning with #.
69162306a36Sopenharmony_ci          if not first and len(row) > 0 and not row[0].startswith('#'):
69262306a36Sopenharmony_ci            event_tblname = file_name_to_table_name('pmu_events_', [], row[2].replace('/', '_'))
69362306a36Sopenharmony_ci            if event_tblname in _event_tables:
69462306a36Sopenharmony_ci              event_size = f'ARRAY_SIZE({event_tblname})'
69562306a36Sopenharmony_ci            else:
69662306a36Sopenharmony_ci              event_tblname = 'NULL'
69762306a36Sopenharmony_ci              event_size = '0'
69862306a36Sopenharmony_ci            metric_tblname = file_name_to_table_name('pmu_metrics_', [], row[2].replace('/', '_'))
69962306a36Sopenharmony_ci            if metric_tblname in _metric_tables:
70062306a36Sopenharmony_ci              metric_size = f'ARRAY_SIZE({metric_tblname})'
70162306a36Sopenharmony_ci            else:
70262306a36Sopenharmony_ci              metric_tblname = 'NULL'
70362306a36Sopenharmony_ci              metric_size = '0'
70462306a36Sopenharmony_ci            if event_size == '0' and metric_size == '0':
70562306a36Sopenharmony_ci              continue
70662306a36Sopenharmony_ci            cpuid = row[0].replace('\\', '\\\\')
70762306a36Sopenharmony_ci            _args.output_file.write(f"""{{
70862306a36Sopenharmony_ci\t.arch = "{arch}",
70962306a36Sopenharmony_ci\t.cpuid = "{cpuid}",
71062306a36Sopenharmony_ci\t.event_table = {{
71162306a36Sopenharmony_ci\t\t.pmus = {event_tblname},
71262306a36Sopenharmony_ci\t\t.num_pmus = {event_size}
71362306a36Sopenharmony_ci\t}},
71462306a36Sopenharmony_ci\t.metric_table = {{
71562306a36Sopenharmony_ci\t\t.pmus = {metric_tblname},
71662306a36Sopenharmony_ci\t\t.num_pmus = {metric_size}
71762306a36Sopenharmony_ci\t}}
71862306a36Sopenharmony_ci}},
71962306a36Sopenharmony_ci""")
72062306a36Sopenharmony_ci          first = False
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci  _args.output_file.write("""{
72362306a36Sopenharmony_ci\t.arch = 0,
72462306a36Sopenharmony_ci\t.cpuid = 0,
72562306a36Sopenharmony_ci\t.event_table = { 0, 0 },
72662306a36Sopenharmony_ci\t.metric_table = { 0, 0 },
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci};
72962306a36Sopenharmony_ci""")
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cidef print_system_mapping_table() -> None:
73362306a36Sopenharmony_ci  """C struct mapping table array for tables from /sys directories."""
73462306a36Sopenharmony_ci  _args.output_file.write("""
73562306a36Sopenharmony_cistruct pmu_sys_events {
73662306a36Sopenharmony_ci\tconst char *name;
73762306a36Sopenharmony_ci\tstruct pmu_events_table event_table;
73862306a36Sopenharmony_ci\tstruct pmu_metrics_table metric_table;
73962306a36Sopenharmony_ci};
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic const struct pmu_sys_events pmu_sys_event_tables[] = {
74262306a36Sopenharmony_ci""")
74362306a36Sopenharmony_ci  printed_metric_tables = []
74462306a36Sopenharmony_ci  for tblname in _sys_event_tables:
74562306a36Sopenharmony_ci    _args.output_file.write(f"""\t{{
74662306a36Sopenharmony_ci\t\t.event_table = {{
74762306a36Sopenharmony_ci\t\t\t.pmus = {tblname},
74862306a36Sopenharmony_ci\t\t\t.num_pmus = ARRAY_SIZE({tblname})
74962306a36Sopenharmony_ci\t\t}},""")
75062306a36Sopenharmony_ci    metric_tblname = _sys_event_table_to_metric_table_mapping[tblname]
75162306a36Sopenharmony_ci    if metric_tblname in _sys_metric_tables:
75262306a36Sopenharmony_ci      _args.output_file.write(f"""
75362306a36Sopenharmony_ci\t\t.metric_table = {{
75462306a36Sopenharmony_ci\t\t\t.pmus = {metric_tblname},
75562306a36Sopenharmony_ci\t\t\t.num_pmus = ARRAY_SIZE({metric_tblname})
75662306a36Sopenharmony_ci\t\t}},""")
75762306a36Sopenharmony_ci      printed_metric_tables.append(metric_tblname)
75862306a36Sopenharmony_ci    _args.output_file.write(f"""
75962306a36Sopenharmony_ci\t\t.name = \"{tblname}\",
76062306a36Sopenharmony_ci\t}},
76162306a36Sopenharmony_ci""")
76262306a36Sopenharmony_ci  for tblname in _sys_metric_tables:
76362306a36Sopenharmony_ci    if tblname in printed_metric_tables:
76462306a36Sopenharmony_ci      continue
76562306a36Sopenharmony_ci    _args.output_file.write(f"""\t{{
76662306a36Sopenharmony_ci\t\t.metric_table = {{
76762306a36Sopenharmony_ci\t\t\t.entries = {tblname},
76862306a36Sopenharmony_ci\t\t\t.length = ARRAY_SIZE({tblname})
76962306a36Sopenharmony_ci\t\t}},
77062306a36Sopenharmony_ci\t\t.name = \"{tblname}\",
77162306a36Sopenharmony_ci\t}},
77262306a36Sopenharmony_ci""")
77362306a36Sopenharmony_ci  _args.output_file.write("""\t{
77462306a36Sopenharmony_ci\t\t.event_table = { 0, 0 },
77562306a36Sopenharmony_ci\t\t.metric_table = { 0, 0 },
77662306a36Sopenharmony_ci\t},
77762306a36Sopenharmony_ci};
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic void decompress_event(int offset, struct pmu_event *pe)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci\tconst char *p = &big_c_string[offset];
78262306a36Sopenharmony_ci""")
78362306a36Sopenharmony_ci  for attr in _json_event_attributes:
78462306a36Sopenharmony_ci    _args.output_file.write(f'\n\tpe->{attr} = ')
78562306a36Sopenharmony_ci    if attr in _json_enum_attributes:
78662306a36Sopenharmony_ci      _args.output_file.write("*p - '0';\n")
78762306a36Sopenharmony_ci    else:
78862306a36Sopenharmony_ci      _args.output_file.write("(*p == '\\0' ? NULL : p);\n")
78962306a36Sopenharmony_ci    if attr == _json_event_attributes[-1]:
79062306a36Sopenharmony_ci      continue
79162306a36Sopenharmony_ci    if attr in _json_enum_attributes:
79262306a36Sopenharmony_ci      _args.output_file.write('\tp++;')
79362306a36Sopenharmony_ci    else:
79462306a36Sopenharmony_ci      _args.output_file.write('\twhile (*p++);')
79562306a36Sopenharmony_ci  _args.output_file.write("""}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic void decompress_metric(int offset, struct pmu_metric *pm)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci\tconst char *p = &big_c_string[offset];
80062306a36Sopenharmony_ci""")
80162306a36Sopenharmony_ci  for attr in _json_metric_attributes:
80262306a36Sopenharmony_ci    _args.output_file.write(f'\n\tpm->{attr} = ')
80362306a36Sopenharmony_ci    if attr in _json_enum_attributes:
80462306a36Sopenharmony_ci      _args.output_file.write("*p - '0';\n")
80562306a36Sopenharmony_ci    else:
80662306a36Sopenharmony_ci      _args.output_file.write("(*p == '\\0' ? NULL : p);\n")
80762306a36Sopenharmony_ci    if attr == _json_metric_attributes[-1]:
80862306a36Sopenharmony_ci      continue
80962306a36Sopenharmony_ci    if attr in _json_enum_attributes:
81062306a36Sopenharmony_ci      _args.output_file.write('\tp++;')
81162306a36Sopenharmony_ci    else:
81262306a36Sopenharmony_ci      _args.output_file.write('\twhile (*p++);')
81362306a36Sopenharmony_ci  _args.output_file.write("""}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic int pmu_events_table__for_each_event_pmu(const struct pmu_events_table *table,
81662306a36Sopenharmony_ci                                                const struct pmu_table_entry *pmu,
81762306a36Sopenharmony_ci                                                pmu_event_iter_fn fn,
81862306a36Sopenharmony_ci                                                void *data)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci        int ret;
82162306a36Sopenharmony_ci        struct pmu_event pe = {
82262306a36Sopenharmony_ci                .pmu = &big_c_string[pmu->pmu_name.offset],
82362306a36Sopenharmony_ci        };
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci        for (uint32_t i = 0; i < pmu->num_entries; i++) {
82662306a36Sopenharmony_ci                decompress_event(pmu->entries[i].offset, &pe);
82762306a36Sopenharmony_ci                if (!pe.name)
82862306a36Sopenharmony_ci                        continue;
82962306a36Sopenharmony_ci                ret = fn(&pe, table, data);
83062306a36Sopenharmony_ci                if (ret)
83162306a36Sopenharmony_ci                        return ret;
83262306a36Sopenharmony_ci        }
83362306a36Sopenharmony_ci        return 0;
83462306a36Sopenharmony_ci }
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic int pmu_events_table__find_event_pmu(const struct pmu_events_table *table,
83762306a36Sopenharmony_ci                                            const struct pmu_table_entry *pmu,
83862306a36Sopenharmony_ci                                            const char *name,
83962306a36Sopenharmony_ci                                            pmu_event_iter_fn fn,
84062306a36Sopenharmony_ci                                            void *data)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci        struct pmu_event pe = {
84362306a36Sopenharmony_ci                .pmu = &big_c_string[pmu->pmu_name.offset],
84462306a36Sopenharmony_ci        };
84562306a36Sopenharmony_ci        int low = 0, high = pmu->num_entries - 1;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci        while (low <= high) {
84862306a36Sopenharmony_ci                int cmp, mid = (low + high) / 2;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci                decompress_event(pmu->entries[mid].offset, &pe);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci                if (!pe.name && !name)
85362306a36Sopenharmony_ci                        goto do_call;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci                if (!pe.name && name) {
85662306a36Sopenharmony_ci                        low = mid + 1;
85762306a36Sopenharmony_ci                        continue;
85862306a36Sopenharmony_ci                }
85962306a36Sopenharmony_ci                if (pe.name && !name) {
86062306a36Sopenharmony_ci                        high = mid - 1;
86162306a36Sopenharmony_ci                        continue;
86262306a36Sopenharmony_ci                }
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci                cmp = strcasecmp(pe.name, name);
86562306a36Sopenharmony_ci                if (cmp < 0) {
86662306a36Sopenharmony_ci                        low = mid + 1;
86762306a36Sopenharmony_ci                        continue;
86862306a36Sopenharmony_ci                }
86962306a36Sopenharmony_ci                if (cmp > 0) {
87062306a36Sopenharmony_ci                        high = mid - 1;
87162306a36Sopenharmony_ci                        continue;
87262306a36Sopenharmony_ci                }
87362306a36Sopenharmony_ci  do_call:
87462306a36Sopenharmony_ci                return fn ? fn(&pe, table, data) : 0;
87562306a36Sopenharmony_ci        }
87662306a36Sopenharmony_ci        return -1000;
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ciint pmu_events_table__for_each_event(const struct pmu_events_table *table,
88062306a36Sopenharmony_ci                                    struct perf_pmu *pmu,
88162306a36Sopenharmony_ci                                    pmu_event_iter_fn fn,
88262306a36Sopenharmony_ci                                    void *data)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci        for (size_t i = 0; i < table->num_pmus; i++) {
88562306a36Sopenharmony_ci                const struct pmu_table_entry *table_pmu = &table->pmus[i];
88662306a36Sopenharmony_ci                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
88762306a36Sopenharmony_ci                int ret;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci                if (pmu && !pmu__name_match(pmu, pmu_name))
89062306a36Sopenharmony_ci                        continue;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci                ret = pmu_events_table__for_each_event_pmu(table, table_pmu, fn, data);
89362306a36Sopenharmony_ci                if (pmu || ret)
89462306a36Sopenharmony_ci                        return ret;
89562306a36Sopenharmony_ci        }
89662306a36Sopenharmony_ci        return 0;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ciint pmu_events_table__find_event(const struct pmu_events_table *table,
90062306a36Sopenharmony_ci                                 struct perf_pmu *pmu,
90162306a36Sopenharmony_ci                                 const char *name,
90262306a36Sopenharmony_ci                                 pmu_event_iter_fn fn,
90362306a36Sopenharmony_ci                                 void *data)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci        for (size_t i = 0; i < table->num_pmus; i++) {
90662306a36Sopenharmony_ci                const struct pmu_table_entry *table_pmu = &table->pmus[i];
90762306a36Sopenharmony_ci                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
90862306a36Sopenharmony_ci                int ret;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci                if (!pmu__name_match(pmu, pmu_name))
91162306a36Sopenharmony_ci                        continue;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci                ret = pmu_events_table__find_event_pmu(table, table_pmu, name, fn, data);
91462306a36Sopenharmony_ci                if (ret != -1000)
91562306a36Sopenharmony_ci                        return ret;
91662306a36Sopenharmony_ci        }
91762306a36Sopenharmony_ci        return -1000;
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cisize_t pmu_events_table__num_events(const struct pmu_events_table *table,
92162306a36Sopenharmony_ci                                    struct perf_pmu *pmu)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci        size_t count = 0;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci        for (size_t i = 0; i < table->num_pmus; i++) {
92662306a36Sopenharmony_ci                const struct pmu_table_entry *table_pmu = &table->pmus[i];
92762306a36Sopenharmony_ci                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci                if (pmu__name_match(pmu, pmu_name))
93062306a36Sopenharmony_ci                        count += table_pmu->num_entries;
93162306a36Sopenharmony_ci        }
93262306a36Sopenharmony_ci        return count;
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic int pmu_metrics_table__for_each_metric_pmu(const struct pmu_metrics_table *table,
93662306a36Sopenharmony_ci                                                const struct pmu_table_entry *pmu,
93762306a36Sopenharmony_ci                                                pmu_metric_iter_fn fn,
93862306a36Sopenharmony_ci                                                void *data)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci        int ret;
94162306a36Sopenharmony_ci        struct pmu_metric pm = {
94262306a36Sopenharmony_ci                .pmu = &big_c_string[pmu->pmu_name.offset],
94362306a36Sopenharmony_ci        };
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci        for (uint32_t i = 0; i < pmu->num_entries; i++) {
94662306a36Sopenharmony_ci                decompress_metric(pmu->entries[i].offset, &pm);
94762306a36Sopenharmony_ci                if (!pm.metric_expr)
94862306a36Sopenharmony_ci                        continue;
94962306a36Sopenharmony_ci                ret = fn(&pm, table, data);
95062306a36Sopenharmony_ci                if (ret)
95162306a36Sopenharmony_ci                        return ret;
95262306a36Sopenharmony_ci        }
95362306a36Sopenharmony_ci        return 0;
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ciint pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table,
95762306a36Sopenharmony_ci                                     pmu_metric_iter_fn fn,
95862306a36Sopenharmony_ci                                     void *data)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci        for (size_t i = 0; i < table->num_pmus; i++) {
96162306a36Sopenharmony_ci                int ret = pmu_metrics_table__for_each_metric_pmu(table, &table->pmus[i],
96262306a36Sopenharmony_ci                                                                 fn, data);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci                if (ret)
96562306a36Sopenharmony_ci                        return ret;
96662306a36Sopenharmony_ci        }
96762306a36Sopenharmony_ci        return 0;
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ciconst struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci        const struct pmu_events_table *table = NULL;
97362306a36Sopenharmony_ci        char *cpuid = perf_pmu__getcpuid(pmu);
97462306a36Sopenharmony_ci        size_t i;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci        /* on some platforms which uses cpus map, cpuid can be NULL for
97762306a36Sopenharmony_ci         * PMUs other than CORE PMUs.
97862306a36Sopenharmony_ci         */
97962306a36Sopenharmony_ci        if (!cpuid)
98062306a36Sopenharmony_ci                return NULL;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci        i = 0;
98362306a36Sopenharmony_ci        for (;;) {
98462306a36Sopenharmony_ci                const struct pmu_events_map *map = &pmu_events_map[i++];
98562306a36Sopenharmony_ci                if (!map->arch)
98662306a36Sopenharmony_ci                        break;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
98962306a36Sopenharmony_ci                        table = &map->event_table;
99062306a36Sopenharmony_ci                        break;
99162306a36Sopenharmony_ci                }
99262306a36Sopenharmony_ci        }
99362306a36Sopenharmony_ci        free(cpuid);
99462306a36Sopenharmony_ci        if (!pmu || !table)
99562306a36Sopenharmony_ci                return table;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci        for (i = 0; i < table->num_pmus; i++) {
99862306a36Sopenharmony_ci                const struct pmu_table_entry *table_pmu = &table->pmus[i];
99962306a36Sopenharmony_ci                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci                if (pmu__name_match(pmu, pmu_name))
100262306a36Sopenharmony_ci                        return table;
100362306a36Sopenharmony_ci        }
100462306a36Sopenharmony_ci        return NULL;
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ciconst struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci        const struct pmu_metrics_table *table = NULL;
101062306a36Sopenharmony_ci        char *cpuid = perf_pmu__getcpuid(pmu);
101162306a36Sopenharmony_ci        int i;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci        /* on some platforms which uses cpus map, cpuid can be NULL for
101462306a36Sopenharmony_ci         * PMUs other than CORE PMUs.
101562306a36Sopenharmony_ci         */
101662306a36Sopenharmony_ci        if (!cpuid)
101762306a36Sopenharmony_ci                return NULL;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci        i = 0;
102062306a36Sopenharmony_ci        for (;;) {
102162306a36Sopenharmony_ci                const struct pmu_events_map *map = &pmu_events_map[i++];
102262306a36Sopenharmony_ci                if (!map->arch)
102362306a36Sopenharmony_ci                        break;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
102662306a36Sopenharmony_ci                        table = &map->metric_table;
102762306a36Sopenharmony_ci                        break;
102862306a36Sopenharmony_ci                }
102962306a36Sopenharmony_ci        }
103062306a36Sopenharmony_ci        free(cpuid);
103162306a36Sopenharmony_ci        return table;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ciconst struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci        for (const struct pmu_events_map *tables = &pmu_events_map[0];
103762306a36Sopenharmony_ci             tables->arch;
103862306a36Sopenharmony_ci             tables++) {
103962306a36Sopenharmony_ci                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
104062306a36Sopenharmony_ci                        return &tables->event_table;
104162306a36Sopenharmony_ci        }
104262306a36Sopenharmony_ci        return NULL;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ciconst struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci        for (const struct pmu_events_map *tables = &pmu_events_map[0];
104862306a36Sopenharmony_ci             tables->arch;
104962306a36Sopenharmony_ci             tables++) {
105062306a36Sopenharmony_ci                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
105162306a36Sopenharmony_ci                        return &tables->metric_table;
105262306a36Sopenharmony_ci        }
105362306a36Sopenharmony_ci        return NULL;
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ciint pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci        for (const struct pmu_events_map *tables = &pmu_events_map[0];
105962306a36Sopenharmony_ci             tables->arch;
106062306a36Sopenharmony_ci             tables++) {
106162306a36Sopenharmony_ci                int ret = pmu_events_table__for_each_event(&tables->event_table,
106262306a36Sopenharmony_ci                                                           /*pmu=*/ NULL, fn, data);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci                if (ret)
106562306a36Sopenharmony_ci                        return ret;
106662306a36Sopenharmony_ci        }
106762306a36Sopenharmony_ci        return 0;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ciint pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci        for (const struct pmu_events_map *tables = &pmu_events_map[0];
107362306a36Sopenharmony_ci             tables->arch;
107462306a36Sopenharmony_ci             tables++) {
107562306a36Sopenharmony_ci                int ret = pmu_metrics_table__for_each_metric(&tables->metric_table, fn, data);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci                if (ret)
107862306a36Sopenharmony_ci                        return ret;
107962306a36Sopenharmony_ci        }
108062306a36Sopenharmony_ci        return 0;
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ciconst struct pmu_events_table *find_sys_events_table(const char *name)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
108662306a36Sopenharmony_ci             tables->name;
108762306a36Sopenharmony_ci             tables++) {
108862306a36Sopenharmony_ci                if (!strcmp(tables->name, name))
108962306a36Sopenharmony_ci                        return &tables->event_table;
109062306a36Sopenharmony_ci        }
109162306a36Sopenharmony_ci        return NULL;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ciint pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
109762306a36Sopenharmony_ci             tables->name;
109862306a36Sopenharmony_ci             tables++) {
109962306a36Sopenharmony_ci                int ret = pmu_events_table__for_each_event(&tables->event_table,
110062306a36Sopenharmony_ci                                                           /*pmu=*/ NULL, fn, data);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci                if (ret)
110362306a36Sopenharmony_ci                        return ret;
110462306a36Sopenharmony_ci        }
110562306a36Sopenharmony_ci        return 0;
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ciint pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
111162306a36Sopenharmony_ci             tables->name;
111262306a36Sopenharmony_ci             tables++) {
111362306a36Sopenharmony_ci                int ret = pmu_metrics_table__for_each_metric(&tables->metric_table, fn, data);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci                if (ret)
111662306a36Sopenharmony_ci                        return ret;
111762306a36Sopenharmony_ci        }
111862306a36Sopenharmony_ci        return 0;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci""")
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cidef print_metricgroups() -> None:
112362306a36Sopenharmony_ci  _args.output_file.write("""
112462306a36Sopenharmony_cistatic const int metricgroups[][2] = {
112562306a36Sopenharmony_ci""")
112662306a36Sopenharmony_ci  for mgroup in sorted(_metricgroups):
112762306a36Sopenharmony_ci    description = _metricgroups[mgroup]
112862306a36Sopenharmony_ci    _args.output_file.write(
112962306a36Sopenharmony_ci        f'\t{{ {_bcs.offsets[mgroup]}, {_bcs.offsets[description]} }}, /* {mgroup} => {description} */\n'
113062306a36Sopenharmony_ci    )
113162306a36Sopenharmony_ci  _args.output_file.write("""
113262306a36Sopenharmony_ci};
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ciconst char *describe_metricgroup(const char *group)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci        int low = 0, high = (int)ARRAY_SIZE(metricgroups) - 1;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci        while (low <= high) {
113962306a36Sopenharmony_ci                int mid = (low + high) / 2;
114062306a36Sopenharmony_ci                const char *mgroup = &big_c_string[metricgroups[mid][0]];
114162306a36Sopenharmony_ci                int cmp = strcmp(mgroup, group);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci                if (cmp == 0) {
114462306a36Sopenharmony_ci                        return &big_c_string[metricgroups[mid][1]];
114562306a36Sopenharmony_ci                } else if (cmp < 0) {
114662306a36Sopenharmony_ci                        low = mid + 1;
114762306a36Sopenharmony_ci                } else {
114862306a36Sopenharmony_ci                        high = mid - 1;
114962306a36Sopenharmony_ci                }
115062306a36Sopenharmony_ci        }
115162306a36Sopenharmony_ci        return NULL;
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci""")
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_cidef main() -> None:
115662306a36Sopenharmony_ci  global _args
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci  def dir_path(path: str) -> str:
115962306a36Sopenharmony_ci    """Validate path is a directory for argparse."""
116062306a36Sopenharmony_ci    if os.path.isdir(path):
116162306a36Sopenharmony_ci      return path
116262306a36Sopenharmony_ci    raise argparse.ArgumentTypeError(f'\'{path}\' is not a valid directory')
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci  def ftw(path: str, parents: Sequence[str],
116562306a36Sopenharmony_ci          action: Callable[[Sequence[str], os.DirEntry], None]) -> None:
116662306a36Sopenharmony_ci    """Replicate the directory/file walking behavior of C's file tree walk."""
116762306a36Sopenharmony_ci    for item in sorted(os.scandir(path), key=lambda e: e.name):
116862306a36Sopenharmony_ci      if _args.model != 'all' and item.is_dir():
116962306a36Sopenharmony_ci        # Check if the model matches one in _args.model.
117062306a36Sopenharmony_ci        if len(parents) == _args.model.split(',')[0].count('/'):
117162306a36Sopenharmony_ci          # We're testing the correct directory.
117262306a36Sopenharmony_ci          item_path = '/'.join(parents) + ('/' if len(parents) > 0 else '') + item.name
117362306a36Sopenharmony_ci          if 'test' not in item_path and item_path not in _args.model.split(','):
117462306a36Sopenharmony_ci            continue
117562306a36Sopenharmony_ci      action(parents, item)
117662306a36Sopenharmony_ci      if item.is_dir():
117762306a36Sopenharmony_ci        ftw(item.path, parents + [item.name], action)
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci  ap = argparse.ArgumentParser()
118062306a36Sopenharmony_ci  ap.add_argument('arch', help='Architecture name like x86')
118162306a36Sopenharmony_ci  ap.add_argument('model', help='''Select a model such as skylake to
118262306a36Sopenharmony_cireduce the code size.  Normally set to "all". For architectures like
118362306a36Sopenharmony_ciARM64 with an implementor/model, the model must include the implementor
118462306a36Sopenharmony_cisuch as "arm/cortex-a34".''',
118562306a36Sopenharmony_ci                  default='all')
118662306a36Sopenharmony_ci  ap.add_argument(
118762306a36Sopenharmony_ci      'starting_dir',
118862306a36Sopenharmony_ci      type=dir_path,
118962306a36Sopenharmony_ci      help='Root of tree containing architecture directories containing json files'
119062306a36Sopenharmony_ci  )
119162306a36Sopenharmony_ci  ap.add_argument(
119262306a36Sopenharmony_ci      'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
119362306a36Sopenharmony_ci  _args = ap.parse_args()
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci  _args.output_file.write("""
119662306a36Sopenharmony_ci#include <pmu-events/pmu-events.h>
119762306a36Sopenharmony_ci#include "util/header.h"
119862306a36Sopenharmony_ci#include "util/pmu.h"
119962306a36Sopenharmony_ci#include <string.h>
120062306a36Sopenharmony_ci#include <stddef.h>
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistruct compact_pmu_event {
120362306a36Sopenharmony_ci        int offset;
120462306a36Sopenharmony_ci};
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistruct pmu_table_entry {
120762306a36Sopenharmony_ci        const struct compact_pmu_event *entries;
120862306a36Sopenharmony_ci        uint32_t num_entries;
120962306a36Sopenharmony_ci        struct compact_pmu_event pmu_name;
121062306a36Sopenharmony_ci};
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci""")
121362306a36Sopenharmony_ci  archs = []
121462306a36Sopenharmony_ci  for item in os.scandir(_args.starting_dir):
121562306a36Sopenharmony_ci    if not item.is_dir():
121662306a36Sopenharmony_ci      continue
121762306a36Sopenharmony_ci    if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
121862306a36Sopenharmony_ci      archs.append(item.name)
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci  if len(archs) < 2:
122162306a36Sopenharmony_ci    raise IOError(f'Missing architecture directory \'{_args.arch}\'')
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci  archs.sort()
122462306a36Sopenharmony_ci  for arch in archs:
122562306a36Sopenharmony_ci    arch_path = f'{_args.starting_dir}/{arch}'
122662306a36Sopenharmony_ci    preprocess_arch_std_files(arch_path)
122762306a36Sopenharmony_ci    ftw(arch_path, [], preprocess_one_file)
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci  _bcs.compute()
123062306a36Sopenharmony_ci  _args.output_file.write('static const char *const big_c_string =\n')
123162306a36Sopenharmony_ci  for s in _bcs.big_string:
123262306a36Sopenharmony_ci    _args.output_file.write(s)
123362306a36Sopenharmony_ci  _args.output_file.write(';\n\n')
123462306a36Sopenharmony_ci  for arch in archs:
123562306a36Sopenharmony_ci    arch_path = f'{_args.starting_dir}/{arch}'
123662306a36Sopenharmony_ci    ftw(arch_path, [], process_one_file)
123762306a36Sopenharmony_ci    print_pending_events()
123862306a36Sopenharmony_ci    print_pending_metrics()
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci  print_mapping_table(archs)
124162306a36Sopenharmony_ci  print_system_mapping_table()
124262306a36Sopenharmony_ci  print_metricgroups()
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ciif __name__ == '__main__':
124562306a36Sopenharmony_ci  main()
1246