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 20from ftrace_format_parser import ProtoType 21 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 29CPP_COPYRIGHT_HEADER = '''\ 30/* THIS FILE IS GENERATE 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'''.format(THIS_FILE) 45 46GN_COPYRIGHT_HEADER = '''\ 47# THIS FILE IS GENERATE BY {}, PLEASE DON'T EDIT IT! 48# Copyright (C) 2021 Huawei Device Co., Ltd. 49# Licensed under the Apache License, Version 2.0 (the "License"); 50# you may not use this file except in compliance with the License. 51# You may obtain a copy of the License at 52# 53# http://www.apache.org/licenses/LICENSE-2.0 54# 55# Unless required by applicable law or agreed to in writing, software 56# distributed under the License is distributed on an "AS IS" BASIS, 57# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 58# See the License for the specific language governing permissions and 59# limitations under the License. 60'''.format(THIS_FILE) 61 62PARSE_FUNCTION_ARGS = '({}, {}, {}, {})'.format('FtraceEvent& ftraceEvent', 63 'uint8_t data[]', 'size_t size', 'const EventFormat& format') 64PARSE_REGISTER_MACRO = 'REGISTER_FTRACE_EVENT_PARSE_FUNCTION' 65 66CHECK_FUNCTION_ARGS = '(const FtraceEvent& event) -> bool' 67FORMAT_FUNCTION_ARGS = '(const FtraceEvent& event) -> std::string' 68FORMAT_REGISTER_MACRO = 'REGISTER_FTRACE_EVENT_FORMATTER' 69 70 71def to_camel_case(name): 72 return ''.join([p.capitalize() for p in name.split('_')]) 73 74 75def fix_field_name(name): 76 replace_map = { 77 'errno': 'error_code', 78 'sa_handler': 'sig_handler', 79 'sa_flags': 'sig_flags' 80 } 81 if name in replace_map: 82 name = replace_map[name] 83 return str.lower(name) 84 85 86def ensure_dir_exists(file_path): 87 file_dir = os.path.dirname(file_path) 88 if not os.path.exists(file_dir): 89 os.mkdir(file_dir) 90 91 92class EventParserCodeGenerator(FtraceEventCodeGenerator): 93 def __init__(self, events_dir, allow_list): 94 super().__init__(events_dir, allow_list) 95 96 def parser_file_path(self, category): 97 file_name = 'ftrace_{}_event_parser.cpp'.format(category) 98 return os.path.join(self.output_dir, file_name) 99 100 def generate_code(self): 101 generated_cpp_sources = [] 102 103 for event in self.target_event_formats: 104 type_name = '{}/{}'.format(event.category, event.name) 105 logger.info('ftrace_events: "{}"'.format(type_name)) 106 107 # generate sub event parser code 108 for category in self.grouped_event_formats: 109 parser_src_file = self.parser_file_path(category) 110 generated_cpp_sources.append(parser_src_file) 111 112 logger.info('Generate {} ...'.format(parser_src_file)) 113 ensure_dir_exists(parser_src_file) 114 115 with open(parser_src_file, 'w', encoding='utf-8') as f: 116 f.write(CPP_COPYRIGHT_HEADER) 117 f.write('#include "sub_event_parser.h"\n') 118 f.write('\n') 119 f.write("FTRACE_NS_BEGIN\n") 120 f.write("namespace {\n") 121 self.generate_parse_functions(category, f) 122 f.write("} // namespace\n") 123 f.write("FTRACE_NS_END\n") 124 f.write('\n') 125 126 # generate .gni 127 generated_cpp_gni = os.path.join(self.output_dir, AUTO_GENERATED_GNI) 128 logger.info('Generate {} ...'.format(generated_cpp_gni)) 129 with open(generated_cpp_gni, 'w', encoding='utf-8') as f: 130 f.write(GN_COPYRIGHT_HEADER) 131 f.write('\n') 132 f.write('auto_generated_cpp_sources = [\n') 133 for path in generated_cpp_sources: 134 src = '{}'.format(os.path.basename(path)) 135 f.write(' "{}",\n'.format(src)) 136 f.write(']\n') 137 138 def generate_parse_functions(self, category, f): 139 count = 0 140 for event in self.grouped_event_formats[category]: 141 count += 1 142 if count > 1: 143 f.write('\n') 144 f.write('{}({},\n'.format(PARSE_REGISTER_MACRO, event.name)) 145 f.write('[] {} {{\n'.format(PARSE_FUNCTION_ARGS)) 146 f.write(' int i = 0;\n') 147 f.write(' auto msg = ftraceEvent.mutable_{}_format();\n'.format( 148 str.lower(event.name))) 149 for i in range(len(event.remain_fields)): 150 self.generate_parse_field_lines(event, f, i) 151 f.write("});\n") 152 153 @staticmethod 154 def generate_parse_field_lines(event, f, i): 155 field_info = event.remain_fields[i] 156 field_name = fix_field_name(field_info.name) 157 type_info = field_info.to_proto_type() 158 parse_func = None 159 if type_info.tid == ProtoType.STRING: 160 parse_func = 'ParseStrField' 161 elif type_info.tid == ProtoType.INTEGER: 162 assert type_info.size in [4, 8] 163 c_type = None 164 if type_info.size == 4: 165 c_type = 'int32_t' if type_info.signed else 'uint32_t' 166 elif type_info.size == 8: 167 c_type = 'int64_t' if type_info.signed else 'uint64_t' 168 parse_func = 'ParseIntField<{}>'.format(c_type) 169 else: 170 logger.warning('WARNING: unkown proto type:{} {}'.format( 171 event.name, field_name)) 172 assert parse_func 173 f.write(' msg->set_{}(FtraceFieldParser::'.format(field_name)) 174 f.write('{}(format.fields, i++, data, size));\n'.format(parse_func)) 175 176 177class EventFormatterCodeGenerator(FtraceEventCodeGenerator): 178 def __init__(self, events_dir, allow_list): 179 super().__init__(events_dir, allow_list) 180 181 def formatter_file_path(self, category): 182 file_name = 'ftrace_{}_event_formatter.cpp'.format(category) 183 return os.path.join(self.output_dir, file_name) 184 185 def generate_code(self): 186 generated_cpp_sources = [] 187 188 # generate sub event parser code 189 for category in self.grouped_event_formats: 190 formatter_src_file = self.formatter_file_path(category) 191 generated_cpp_sources.append(formatter_src_file) 192 193 logger.info('Generate {} ...'.format(formatter_src_file)) 194 ensure_dir_exists(formatter_src_file) 195 196 with open(formatter_src_file, 'w', encoding='utf-8') as f: 197 f.write(CPP_COPYRIGHT_HEADER) 198 f.write('#include "event_formatter.h"\n') 199 f.write('#include <sstream>\n') 200 f.write('\n') 201 f.write("FTRACE_NS_BEGIN\n") 202 f.write("namespace {\n") 203 self.generate_format_functions(category, f) 204 f.write("} // namespace\n") 205 f.write("FTRACE_NS_END\n") 206 f.write('\n') 207 208 # generate .gni 209 generated_cpp_gni = os.path.join(self.output_dir, AUTO_GENERATED_GNI) 210 logger.info('Generate {} ...'.format(generated_cpp_gni)) 211 with open(generated_cpp_gni, 'w', encoding='utf-8') as f: 212 f.write(GN_COPYRIGHT_HEADER) 213 f.write('\n') 214 f.write('auto_generated_cpp_sources = [\n') 215 for path in generated_cpp_sources: 216 src = '{}'.format(os.path.basename(path)) 217 f.write(' "{}",\n'.format(src)) 218 f.write(']\n') 219 220 def generate_format_functions(self, category, f): 221 count = 0 222 for event in self.grouped_event_formats[category]: 223 count += 1 224 if count > 1: 225 f.write('\n') 226 f.write('{}({},\n'.format(FORMAT_REGISTER_MACRO, event.name)) 227 f.write('[] {} {{\n'.format(CHECK_FUNCTION_ARGS, )) 228 f.write(' return event.has_{}_format();'.format( 229 str.lower(event.name))) 230 f.write('},') # end of check function 231 f.write('[] {} {{\n'.format(FORMAT_FUNCTION_ARGS)) 232 f.write(' auto msg = event.{}_format();\n'.format( 233 str.lower(event.name))) 234 f.write(" std::stringstream sout;\n") 235 f.write(' sout << "{}:";\n'.format(event.name)) 236 for field_info in event.remain_fields: 237 field_name = fix_field_name(field_info.name) 238 f.write(' sout << " {}=" << msg.{}();\n'.format(field_name, 239 field_name)) 240 f.write(" return sout.str();\n") 241 f.write("});\n") # end of format function 242 243 244def main(): 245 parser = argparse.ArgumentParser( 246 description='FTrace C++ code generator.') 247 parser.add_argument('-a', dest='allow_list', required=True, type=str, 248 help='event allow list file path') 249 parser.add_argument('-e', dest='events_dir', required=True, type=str, 250 help='event formats directory') 251 parser.add_argument('-p', dest='parser_out', required=False, type=str, 252 help='parser code output directory') 253 parser.add_argument('-f', dest='formatter_out', required=False, type=str, 254 help='formaater code output directory') 255 256 args = parser.parse_args(sys.argv[1:]) 257 allow_list = args.allow_list 258 events_dir = args.events_dir 259 parser_out = args.parser_out 260 formatter_out = args.formatter_out 261 262 # check arguments 263 if not os.path.isfile(allow_list): 264 parser.print_usage() 265 exit(1) 266 if not os.path.isdir(events_dir): 267 parser.print_usage() 268 exit(2) 269 270 if parser_out: 271 if not os.path.isdir(parser_out): 272 parser.print_usage() 273 exit(3) 274 parser_gen = EventParserCodeGenerator(events_dir, allow_list) 275 parser_gen.generate(os.path.join(parser_out)) 276 277 if formatter_out: 278 if not os.path.isdir(formatter_out): 279 parser.print_usage() 280 exit(4) 281 fmtter_gen = EventFormatterCodeGenerator(events_dir, allow_list) 282 fmtter_gen.generate(formatter_out) 283 284 285if __name__ == '__main__': 286 main() 287