#!/usr/bin/env python3
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
"""Convert directories of JSON events to C code."""
import argparse
import csv
from functools import lru_cache
import json
import metric
import os
import sys
from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
import collections
# Global command line arguments.
_args = None
# List of regular event tables.
_event_tables = []
# List of event tables generated from "/sys" directories.
_sys_event_tables = []
# List of regular metric tables.
_metric_tables = []
# List of metric tables generated from "/sys" directories.
_sys_metric_tables = []
# Mapping between sys event table names and sys metric table names.
_sys_event_table_to_metric_table_mapping = {}
# Map from an event name to an architecture standard
# JsonEvent. Architecture standard events are in json files in the top
# f'{_args.starting_dir}/{_args.arch}' directory.
_arch_std_events = {}
# Events to write out when the table is closed
_pending_events = []
# Name of events table to be written out
_pending_events_tblname = None
# Metrics to write out when the table is closed
_pending_metrics = []
# Name of metrics table to be written out
_pending_metrics_tblname = None
# Global BigCString shared by all structures.
_bcs = None
# Map from the name of a metric group to a description of the group.
_metricgroups = {}
# Order specific JsonEvent attributes will be visited.
_json_event_attributes = [
# cmp_sevent related attributes.
'name', 'topic', 'desc',
# Seems useful, put it early.
'event',
# Short things in alphabetical order.
'compat', 'deprecated', 'perpkg', 'unit',
# Longer things (the last won't be iterated over during decompress).
'long_desc'
]
# Attributes that are in pmu_metric rather than pmu_event.
_json_metric_attributes = [
'metric_name', 'metric_group', 'metric_expr', 'metric_threshold',
'desc', 'long_desc', 'unit', 'compat', 'metricgroup_no_group',
'default_metricgroup_name', 'aggr_mode', 'event_grouping'
]
# Attributes that are bools or enum int values, encoded as '0', '1',...
_json_enum_attributes = ['aggr_mode', 'deprecated', 'event_grouping', 'perpkg']
def removesuffix(s: str, suffix: str) -> str:
"""Remove the suffix from a string
The removesuffix function is added to str in Python 3.9. We aim for 3.6
compatibility and so provide our own function here.
"""
return s[0:-len(suffix)] if s.endswith(suffix) else s
def file_name_to_table_name(prefix: str, parents: Sequence[str],
dirname: str) -> str:
"""Generate a C table name from directory names."""
tblname = prefix
for p in parents:
tblname += '_' + p
tblname += '_' + dirname
return tblname.replace('-', '_')
def c_len(s: str) -> int:
"""Return the length of s a C string
This doesn't handle all escape characters properly. It first assumes
all \\ are for escaping, it then adjusts as it will have over counted
\\. The code uses \000 rather than \0 as a terminator as an adjacent
number would be folded into a string of \0 (ie. "\0" + "5" doesn't
equal a terminator followed by the number 5 but the escape of
\05). The code adjusts for \000 but not properly for all octal, hex
or unicode values.
"""
try:
utf = s.encode(encoding='utf-8',errors='strict')
except:
print(f'broken string {s}')
raise
return len(utf) - utf.count(b'\\') + utf.count(b'\\\\