1#!/usr/bin/env python3 2 3# perf pmu-events sorting tool 4# 5# Copyright (C) 2021 Bruce Ashfield 6# 7# SPDX-License-Identifier: MIT 8# 9 10import sys 11import os 12import re 13from collections import OrderedDict 14 15if len(sys.argv) < 2: 16 print( "[ERROR]: input and output pmu files missing" ) 17 sys.exit(1) 18 19if len(sys.argv) < 3: 20 print( "[ERROR]: output pmu file missing" ) 21 sys.exit(1) 22 23infile = sys.argv[1] 24outfile = sys.argv[2] 25 26if not os.path.exists(infile): 27 print( "ERROR. input file does not exist: %s" % infile ) 28 sys.exit(1) 29 30if os.path.exists(outfile): 31 print( "WARNING. output file will be overwritten: %s" % infile ) 32 33with open(infile, 'r') as file: 34 data = file.read() 35 36preamble_regex = re.compile( '^(.*?)^(struct|const struct|static struct|static const struct)', re.MULTILINE | re.DOTALL ) 37 38preamble = re.search( preamble_regex, data ) 39struct_block_regex = re.compile( '^(struct|const struct|static struct|static const struct).*?(\w+) (.*?)\[\] = {(.*?)^};', re.MULTILINE | re.DOTALL ) 40field_regex = re.compile( '{.*?},', re.MULTILINE | re.DOTALL ) 41cpuid_regex = re.compile( '\.cpuid = (.*?),', re.MULTILINE | re.DOTALL ) 42name_regex = re.compile( '\.name = (.*?),', re.MULTILINE | re.DOTALL ) 43 44# create a dictionary structure to store all the structs, their 45# types and then their fields. 46entry_dict = {} 47for struct in re.findall( struct_block_regex, data ): 48 # print( "struct: %s %s %s" % (struct[0],struct[1],struct[2]) ) 49 entry_dict[struct[2]] = {} 50 entry_dict[struct[2]]['type_prefix'] = struct[0] 51 entry_dict[struct[2]]['type'] = struct[1] 52 entry_dict[struct[2]]['fields'] = {} 53 for entry in re.findall( field_regex, struct[3] ): 54 #print( " entry: %s" % entry ) 55 cpuid = re.search( cpuid_regex, entry ) 56 if cpuid: 57 #print( " cpuid found: %s" % cpuid.group(1) ) 58 entry_dict[struct[2]]['fields'][cpuid.group(1)] = entry 59 60 name = re.search( name_regex, entry ) 61 if name: 62 #print( " name found: %s" % name.group(1) ) 63 entry_dict[struct[2]]['fields'][name.group(1)] = entry 64 65 # unmatched entries are most likely array terminators and 66 # should end up as the last element in the sorted list, which 67 # is achieved by using '0' as the key 68 if not cpuid and not name: 69 entry_dict[struct[2]]['fields']['0'] = entry 70 71# created ordered dictionaries from the captured values. These are ordered by 72# a sorted() iteration of the keys. We don't care about the order we read 73# things, just the sorted order. Hency why we couldn't create these during 74# reading. 75# 76# yes, there's a more concise way to do this, but our nested dictionaries of 77# fields make it complex enough that it becomes unreadable. 78entry_dict_sorted = OrderedDict() 79for i in sorted(entry_dict.keys()): 80 entry_dict_sorted[i] = {} 81 entry_dict_sorted[i]['type_prefix'] = entry_dict[i]['type_prefix'] 82 entry_dict_sorted[i]['type'] = entry_dict[i]['type'] 83 entry_dict_sorted[i]['fields'] = {} 84 for f in sorted(entry_dict[i]['fields'].keys()): 85 entry_dict_sorted[i]['fields'][f] = entry_dict[i]['fields'][f] 86 87# dump the sorted elements to the outfile 88outf = open( outfile, 'w' ) 89 90print( preamble.group(1) ) 91outf.write( preamble.group(1) ) 92for d in entry_dict_sorted: 93 outf.write( "%s %s %s[] = {\n" % (entry_dict_sorted[d]['type_prefix'], entry_dict_sorted[d]['type'],d) ) 94 for f in entry_dict_sorted[d]['fields']: 95 outf.write( entry_dict_sorted[d]['fields'][f] + '\n' ) 96 97 outf.write( "};\n" ) 98 99outf.close() 100 101