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