1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 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 21 22class Common: 23 ftrace_bundle_proto = "ftrace_event.proto" 24 auto_generated_gni = "autogenerated.gni" 25 26 this_file = os.path.basename(__file__) 27 logging.basicConfig( 28 format="%(asctime)s %(levelname)s %(message)s", level=logging.INFO 29 ) 30 logger = logging.getLogger(this_file) 31 32 proto_common_header = ( 33 "" 34 "// THIS FILE IS GENERATED BY {}, PLEASE DON'T EDIT IT!\n" 35 "// Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.\n" 36 '// Licensed under the Apache License, Version 2.0 (the "License");\n' 37 "// you may not use this file except in compliance with the License.\n" 38 "// You may obtain a copy of the License at\n" 39 "//\n" 40 "// http://www.apache.org/licenses/LICENSE-2.0\n" 41 "//\n" 42 "// Unless required by applicable law or agreed to in writing, software\n" 43 '// distributed under the License is distributed on an "AS IS" BASIS,\n' 44 "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" 45 "// See the License for the specific language governing permissions and\n" 46 "// limitations under the License.\n" 47 "//\n\n" 48 'syntax = "proto3";\n\n' 49 "option optimize_for = LITE_RUNTIME;\n\n".format(this_file) 50 ) 51 52 gn_copyright_header = ( 53 "" 54 "# THIS FILE IS GENERATE BY {}, PLEASE DON'T EDIT IT!\n" 55 "# Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.\n" 56 '# Licensed under the Apache License, Version 2.0 (the "License");\n' 57 "# you may not use this file except in compliance with the License.\n" 58 "# You may obtain a copy of the License at\n" 59 "#\n" 60 "# http://www.apache.org/licenses/LICENSE-2.0\n" 61 "#\n" 62 "# Unless required by applicable law or agreed to in writing, software\n" 63 '# distributed under the License is distributed on an "AS IS" BASIS,\n' 64 "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" 65 "# See the License for the specific language governing permissions and\n" 66 "# limitations under the License.\n".format(this_file) 67 ) 68 69 proto_message_head = ( 70 "" 71 "message FtraceEvent {\n" 72 " uint64 timestamp = 1;\n" 73 " int32 tgid = 2;\n" 74 " string comm = 3;\n\n" 75 " message CommonFileds {\n" 76 " uint32 type = 1;\n" 77 " uint32 flags = 2;\n" 78 " uint32 preempt_count = 3;\n" 79 " int32 pid = 4;\n" 80 " };\n" 81 " CommonFileds common_fields = 50;\n\n" 82 " oneof event {\n" 83 ) 84 85 86def to_camel_case(name): 87 return "".join([p.capitalize() for p in name.split("_")]) 88 89 90def fix_field_name(name): 91 replace_map = { 92 "errno": "error_code", 93 "sa_handler": "sig_handler", 94 "sa_flags": "sig_flags", 95 "new": "seq_new", 96 } 97 if name in replace_map: 98 name = replace_map.get(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 = [Common.proto_common_header] 115 bundle_proto_body = [Common.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( 129 message_type, message_name, message_id 130 ) 131 ) 132 bundle_proto_head.append("\n") 133 bundle_proto_body.append(" }\n") 134 bundle_proto_body.append("}\n") 135 136 bundle_proto_path = os.path.join(self.output_dir, Common.ftrace_bundle_proto) 137 proto_file_list.append(bundle_proto_path) 138 Common.logger.info("Generate {} ...".format(bundle_proto_path)) 139 with open(bundle_proto_path, "w+") as f: 140 f.writelines(bundle_proto_head + bundle_proto_body) 141 142 protos_gni_path = os.path.join(self.output_dir, Common.auto_generated_gni) 143 Common.logger.info("Generate {} ...".format(protos_gni_path)) 144 with open(protos_gni_path, "w+") as f: 145 f.write(Common.gn_copyright_header) 146 # proto sources 147 f.write("auto_generated_ftrace_proto_sources = [\n") 148 for proto_path in proto_file_list: 149 f.write(' "{}",\n'.format(os.path.basename(proto_path))) 150 f.write("]\n") 151 152 def generate_event_proto(self, category, proto_path): 153 with open(proto_path, "w+") as f: 154 f.write(Common.proto_common_header) 155 f.write("// category: {}\n".format(category)) 156 Common.logger.info("Generate {} ...".format(proto_path)) 157 158 if category in self.grouped_event_formats: 159 for event_format in self.grouped_event_formats[category]: 160 Common.logger.debug( 161 "{}/{}:".format(event_format.category, event_format.name) 162 ) 163 message_name = "{}_format".format(event_format.name) 164 message_type = to_camel_case(message_name) 165 device_format_file = "{}/{}/{}/format".format( 166 "/sys/kernel/debug/tracing/events", 167 event_format.category, 168 event_format.name, 169 ) 170 171 field_count = 1 172 f.write("// {}\n".format(device_format_file)) 173 f.write("message {} {{\n".format(message_type)) 174 for field in event_format.remain_fields: 175 type_string = field.to_proto_type().to_string() 176 field_name = fix_field_name(field.name) 177 Common.logger.debug(" {}: {}".format(field, type_string)) 178 f.write( 179 " {} {} = {};\n".format( 180 type_string, field_name, field_count 181 ) 182 ) 183 field_count += 1 184 f.write("}\n") 185 f.write("\n") 186 187 188def main(): 189 parser = argparse.ArgumentParser(description="FTrace proto code generator.") 190 parser.add_argument( 191 "-a", 192 dest="allow_list", 193 required=True, 194 type=str, 195 help="event allow list file path", 196 ) 197 parser.add_argument( 198 "-e", dest="events_dir", required=True, type=str, help="event formats directory" 199 ) 200 parser.add_argument( 201 "-o", 202 dest="output_dir", 203 required=True, 204 type=str, 205 help="code file output directory", 206 ) 207 208 args = parser.parse_args(sys.argv[1:]) 209 events_dir = args.events_dir 210 output_dir = args.output_dir 211 allow_list = args.allow_list 212 213 generator = FtraceEventProtoGenerator(events_dir, allow_list) 214 generator.generate(output_dir) 215 216 217if __name__ == "__main__": 218 main() 219