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