1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright (C) 2021 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15import os 16import sys 17import argparse 18import logging 19from ftrace_format_parser import FtraceEventCodeGenerator 20 21FTRACE_BUNDLE_PROTO = 'ftrace_event.proto' 22AUTO_GENERATED_GNI = 'autogenerated.gni' 23 24THIS_FILE = os.path.basename(__file__) 25logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', 26 level=logging.INFO) 27logger = logging.getLogger(THIS_FILE) 28 29PROTO_COMMON_HEADER = '''\ 30// THIS FILE IS GENERATED BY {}, PLEASE DON'T EDIT IT! 31// Copyright (c) 2021 Huawei Device Co., Ltd. 32// Licensed under the Apache License, Version 2.0 (the "License"); 33// you may not use this file except in compliance with the License. 34// You may obtain a copy of the License at 35// 36// http://www.apache.org/licenses/LICENSE-2.0 37// 38// Unless required by applicable law or agreed to in writing, software 39// distributed under the License is distributed on an "AS IS" BASIS, 40// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 41// See the License for the specific language governing permissions and 42// limitations under the License. 43// 44 45syntax = "proto3"; 46 47option optimize_for = LITE_RUNTIME; 48 49'''.format(THIS_FILE) 50 51GN_COPYRIGHT_HEADER = '''\ 52# THIS FILE IS GENERATE BY {}, PLEASE DON'T EDIT IT! 53# Copyright (C) 2021 Huawei Device Co., Ltd. 54# Licensed under the Apache License, Version 2.0 (the "License"); 55# you may not use this file except in compliance with the License. 56# You may obtain a copy of the License at 57# 58# http://www.apache.org/licenses/LICENSE-2.0 59# 60# Unless required by applicable law or agreed to in writing, software 61# distributed under the License is distributed on an "AS IS" BASIS, 62# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 63# See the License for the specific language governing permissions and 64# limitations under the License. 65'''.format(THIS_FILE) 66 67MAX_EVENTS_IN_CATEGORY = 100 68 69PROTO_MESSAGE_HEAD = '''\ 70message FtraceEvent { 71 uint64 timestamp = 1; 72 int32 tgid = 2; 73 string comm = 3; 74 75 message CommonFileds { 76 uint32 type = 1; 77 uint32 flags = 2; 78 uint32 preempt_count = 3; 79 int32 pid = 4; 80 }; 81 CommonFileds common_fields = 50; 82 83 oneof event { 84''' 85 86 87def to_camel_case(name): 88 return ''.join([p.capitalize() for p in name.split('_')]) 89 90 91def fix_field_name(name): 92 replace_map = { 93 'errno': 'error_code', 94 'sa_handler': 'sig_handler', 95 'sa_flags': 'sig_flags' 96 } 97 if name in replace_map: 98 name = replace_map[name] 99 return str.lower(name) 100 101 102class FtraceEventProtoGenerator(FtraceEventCodeGenerator): 103 def __init__(self, events_dir, allow_list): 104 super().__init__(events_dir, allow_list) 105 106 def generate_code(self): 107 proto_file_list = [] 108 for category in self.grouped_event_formats: 109 proto_name = '{}.proto'.format(category) 110 proto_path = os.path.join(self.output_dir, proto_name) 111 proto_file_list.append(proto_path) 112 self.generate_event_proto(category, proto_path) 113 114 bundle_proto_head = [PROTO_COMMON_HEADER] 115 bundle_proto_body = [PROTO_MESSAGE_HEAD] 116 event_category_count = 0 117 for category in self.grouped_event_formats: 118 event_category_count += 1 119 proto_name = '{}.proto'.format(category) 120 bundle_proto_head.append('import "{}";\n'.format(proto_name)) 121 for i in range(len(self.grouped_event_formats[category])): 122 event_format = self.grouped_event_formats[category][i] 123 message_name = '{}_format'.format(event_format.name) 124 message_type = to_camel_case(message_name) 125 message_id = event_category_count * 100 + i 126 message_name = fix_field_name(message_name) 127 bundle_proto_body.append( 128 ' {} {} = {};\n'.format(message_type, 129 message_name, 130 message_id)) 131 bundle_proto_head.append('\n') 132 bundle_proto_body.append(' }\n') 133 bundle_proto_body.append('}\n') 134 135 bundle_proto_path = os.path.join(self.output_dir, FTRACE_BUNDLE_PROTO) 136 proto_file_list.append(bundle_proto_path) 137 logger.info('Generate {} ...'.format(bundle_proto_path)) 138 with open(bundle_proto_path, 'w+') as f: 139 f.writelines(bundle_proto_head + bundle_proto_body) 140 141 protos_gni_path = os.path.join(self.output_dir, AUTO_GENERATED_GNI) 142 logger.info('Generate {} ...'.format(protos_gni_path)) 143 with open(protos_gni_path, 'w+') as f: 144 f.write(GN_COPYRIGHT_HEADER) 145 f.write('auto_generated_ftrace_proto_sources = [\n') 146 for proto_path in proto_file_list: 147 f.write(' "{}",\n'.format(os.path.basename(proto_path))) 148 f.write(']\n') 149 150 def generate_event_proto(self, category, proto_path): 151 with open(proto_path, 'w+') as f: 152 f.write(PROTO_COMMON_HEADER) 153 f.write('// category: {}\n'.format(category)) 154 logger.info('Generate {} ...'.format(proto_path)) 155 for event_format in self.grouped_event_formats[category]: 156 logger.debug( 157 '{}/{}:'.format(event_format.category, event_format.name)) 158 message_name = '{}_format'.format(event_format.name) 159 message_type = to_camel_case(message_name) 160 device_format_file = '{}/{}/{}/format'.format( 161 '/sys/kernel/debug/tracing/events', 162 event_format.category, event_format.name) 163 164 field_count = 1 165 f.write('// {}\n'.format(device_format_file)) 166 f.write('message {} {{\n'.format(message_type)) 167 for field in event_format.remain_fields: 168 type_string = field.to_proto_type().to_string() 169 field_name = fix_field_name(field.name) 170 logger.debug(' {}: {}'.format(field, type_string)) 171 f.write(' {} {} = {};\n'.format(type_string, field_name, 172 field_count)) 173 field_count += 1 174 f.write('}\n') 175 f.write('\n') 176 177 178def main(): 179 parser = argparse.ArgumentParser( 180 description='FTrace proto code generator.') 181 parser.add_argument('-a', dest='allow_list', required=True, type=str, 182 help='event allow list file path') 183 parser.add_argument('-e', dest='events_dir', required=True, type=str, 184 help='event formats directory') 185 parser.add_argument('-o', dest='output_dir', required=True, type=str, 186 help='code file output directory') 187 188 args = parser.parse_args(sys.argv[1:]) 189 events_dir = args.events_dir 190 output_dir = args.output_dir 191 allow_list = args.allow_list 192 193 generator = FtraceEventProtoGenerator(events_dir, allow_list) 194 generator.generate(output_dir) 195 196 197if __name__ == '__main__': 198 main() 199