• 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
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        'new': 'seq_new'
97    }
98    if name in replace_map:
99        name = replace_map[name]
100    return str.lower(name)
101
102
103class FtraceEventProtoGenerator(FtraceEventCodeGenerator):
104    def __init__(self, events_dir, allow_list):
105        super().__init__(events_dir, allow_list)
106
107    def generate_code(self):
108        proto_file_list = []
109        for category in self.grouped_event_formats:
110            proto_name = '{}.proto'.format(category)
111            proto_path = os.path.join(self.output_dir, proto_name)
112            proto_file_list.append(proto_path)
113            self.generate_event_proto(category, proto_path)
114
115        bundle_proto_head = [PROTO_COMMON_HEADER]
116        bundle_proto_body = [PROTO_MESSAGE_HEAD]
117        event_category_count = 0
118        for category in self.grouped_event_formats:
119            event_category_count += 1
120            proto_name = '{}.proto'.format(category)
121            bundle_proto_head.append('import "{}";\n'.format(proto_name))
122            for i in range(len(self.grouped_event_formats[category])):
123                event_format = self.grouped_event_formats[category][i]
124                message_name = '{}_format'.format(event_format.name)
125                message_type = to_camel_case(message_name)
126                message_id = event_category_count * 100 + i
127                message_name = fix_field_name(message_name)
128                bundle_proto_body.append(
129                    '        {} {} = {};\n'.format(message_type,
130                                                   message_name,
131                                                   message_id))
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, FTRACE_BUNDLE_PROTO)
137        proto_file_list.append(bundle_proto_path)
138        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, AUTO_GENERATED_GNI)
143        logger.info('Generate {} ...'.format(protos_gni_path))
144        with open(protos_gni_path, 'w+') as f:
145            f.write(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(PROTO_COMMON_HEADER)
155            f.write('// category: {}\n'.format(category))
156            logger.info('Generate {} ...'.format(proto_path))
157            for event_format in self.grouped_event_formats[category]:
158                logger.debug(
159                    '{}/{}:'.format(event_format.category, event_format.name))
160                message_name = '{}_format'.format(event_format.name)
161                message_type = to_camel_case(message_name)
162                device_format_file = '{}/{}/{}/format'.format(
163                    '/sys/kernel/debug/tracing/events',
164                    event_format.category, event_format.name)
165
166                field_count = 1
167                f.write('// {}\n'.format(device_format_file))
168                f.write('message {} {{\n'.format(message_type))
169                for field in event_format.remain_fields:
170                    type_string = field.to_proto_type().to_string()
171                    field_name = fix_field_name(field.name)
172                    logger.debug('    {}: {}'.format(field, type_string))
173                    f.write('    {} {} = {};\n'.format(type_string, field_name,
174                                                       field_count))
175                    field_count += 1
176                f.write('}\n')
177                f.write('\n')
178
179
180def main():
181    parser = argparse.ArgumentParser(
182        description='FTrace proto code generator.')
183    parser.add_argument('-a', dest='allow_list', required=True, type=str,
184                        help='event allow list file path')
185    parser.add_argument('-e', dest='events_dir', required=True, type=str,
186                        help='event formats directory')
187    parser.add_argument('-o', dest='output_dir', required=True, type=str,
188                        help='code file output directory')
189
190    args = parser.parse_args(sys.argv[1:])
191    events_dir = args.events_dir
192    output_dir = args.output_dir
193    allow_list = args.allow_list
194
195    generator = FtraceEventProtoGenerator(events_dir, allow_list)
196    generator.generate(output_dir)
197
198
199if __name__ == '__main__':
200    main()
201