• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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