• 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    }
97    if name in replace_map:
98        name = replace_map[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 = [PROTO_COMMON_HEADER]
115        bundle_proto_body = [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(message_type,
129                                                   message_name,
130                                                   message_id))
131        bundle_proto_head.append('\n')
132        bundle_proto_body.append('    }\n')
133        bundle_proto_body.append('}\n')
134
135        bundle_proto_path = os.path.join(self.output_dir, FTRACE_BUNDLE_PROTO)
136        proto_file_list.append(bundle_proto_path)
137        logger.info('Generate {} ...'.format(bundle_proto_path))
138        with open(bundle_proto_path, 'w+') as f:
139            f.writelines(bundle_proto_head + bundle_proto_body)
140
141        protos_gni_path = os.path.join(self.output_dir, AUTO_GENERATED_GNI)
142        logger.info('Generate {} ...'.format(protos_gni_path))
143        with open(protos_gni_path, 'w+') as f:
144            f.write(GN_COPYRIGHT_HEADER)
145            f.write('auto_generated_ftrace_proto_sources = [\n')
146            for proto_path in proto_file_list:
147                f.write('  "{}",\n'.format(os.path.basename(proto_path)))
148            f.write(']\n')
149
150    def generate_event_proto(self, category, proto_path):
151        with open(proto_path, 'w+') as f:
152            f.write(PROTO_COMMON_HEADER)
153            f.write('// category: {}\n'.format(category))
154            logger.info('Generate {} ...'.format(proto_path))
155            for event_format in self.grouped_event_formats[category]:
156                logger.debug(
157                    '{}/{}:'.format(event_format.category, event_format.name))
158                message_name = '{}_format'.format(event_format.name)
159                message_type = to_camel_case(message_name)
160                device_format_file = '{}/{}/{}/format'.format(
161                    '/sys/kernel/debug/tracing/events',
162                    event_format.category, event_format.name)
163
164                field_count = 1
165                f.write('// {}\n'.format(device_format_file))
166                f.write('message {} {{\n'.format(message_type))
167                for field in event_format.remain_fields:
168                    type_string = field.to_proto_type().to_string()
169                    field_name = fix_field_name(field.name)
170                    logger.debug('    {}: {}'.format(field, type_string))
171                    f.write('    {} {} = {};\n'.format(type_string, field_name,
172                                                       field_count))
173                    field_count += 1
174                f.write('}\n')
175                f.write('\n')
176
177
178def main():
179    parser = argparse.ArgumentParser(
180        description='FTrace proto code generator.')
181    parser.add_argument('-a', dest='allow_list', required=True, type=str,
182                        help='event allow list file path')
183    parser.add_argument('-e', dest='events_dir', required=True, type=str,
184                        help='event formats directory')
185    parser.add_argument('-o', dest='output_dir', required=True, type=str,
186                        help='code file output directory')
187
188    args = parser.parse_args(sys.argv[1:])
189    events_dir = args.events_dir
190    output_dir = args.output_dir
191    allow_list = args.allow_list
192
193    generator = FtraceEventProtoGenerator(events_dir, allow_list)
194    generator.generate(output_dir)
195
196
197if __name__ == '__main__':
198    main()
199