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