1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
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.
15 */
16
17 #include <sys/stat.h>
18 #include <fstream>
19 #include <map>
20 #include <memory>
21 #include <regex>
22 #include <set>
23 #include <sstream>
24 #include <string>
25
26 #include <google/protobuf/descriptor.h>
27 #include <google/protobuf/descriptor.pb.h>
28
29 #include "perfetto/base/logging.h"
30 #include "perfetto/ext/base/file_utils.h"
31 #include "perfetto/ext/base/getopt.h"
32 #include "src/traced/probes/ftrace/format_parser/format_parser.h"
33 #include "tools/ftrace_proto_gen/ftrace_descriptor_gen.h"
34 #include "tools/ftrace_proto_gen/ftrace_proto_gen.h"
35
36 namespace {
MakeOFStream(const std::string & filename)37 inline std::unique_ptr<std::ostream> MakeOFStream(const std::string& filename) {
38 return std::unique_ptr<std::ostream>(new std::ofstream(filename));
39 }
40
MakeVerifyStream(const std::string & filename)41 inline std::unique_ptr<std::ostream> MakeVerifyStream(
42 const std::string& filename) {
43 return std::unique_ptr<std::ostream>(new perfetto::VerifyStream(filename));
44 }
45
PrintUsage(const char * bin_name)46 void PrintUsage(const char* bin_name) {
47 fprintf(stderr,
48 "Usage: %s -w event_list_path -o output_dir -d proto_descriptor "
49 "[--check_only] input_dir...\n",
50 bin_name);
51 }
52 } // namespace
53
main(int argc,char ** argv)54 int main(int argc, char** argv) {
55 static option long_options[] = {
56 {"event_list", required_argument, nullptr, 'w'},
57 {"output_dir", required_argument, nullptr, 'o'},
58 {"proto_descriptor", required_argument, nullptr, 'd'},
59 {"update_build_files", no_argument, nullptr, 'b'},
60 {"check_only", no_argument, nullptr, 'c'},
61 {nullptr, 0, nullptr, 0}};
62
63 int c;
64
65 std::string event_list_path;
66 std::string output_dir;
67 std::string proto_descriptor;
68 bool update_build_files = false;
69
70 std::unique_ptr<std::ostream> (*ostream_factory)(const std::string&) =
71 &MakeOFStream;
72
73 while ((c = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
74 switch (c) {
75 case 'w':
76 event_list_path = optarg;
77 break;
78 case 'o':
79 output_dir = optarg;
80 break;
81 case 'd':
82 proto_descriptor = optarg;
83 break;
84 case 'b':
85 update_build_files = true;
86 break;
87 case 'c':
88 ostream_factory = &MakeVerifyStream;
89 break;
90 default: {
91 PrintUsage(argv[0]);
92 return 1;
93 }
94 }
95 }
96
97 if (optind >= argc) {
98 PrintUsage(argv[0]);
99 return 1;
100 }
101
102 PERFETTO_CHECK(!event_list_path.empty());
103 PERFETTO_CHECK(!output_dir.empty());
104 PERFETTO_CHECK(!proto_descriptor.empty());
105
106 std::vector<perfetto::FtraceEventName> event_list =
107 perfetto::ReadAllowList(event_list_path);
108 std::vector<std::string> events_info;
109
110 google::protobuf::DescriptorPool descriptor_pool;
111 descriptor_pool.AllowUnknownDependencies();
112 {
113 google::protobuf::FileDescriptorSet file_descriptor_set;
114 std::string descriptor_bytes;
115 if (!perfetto::base::ReadFile(proto_descriptor, &descriptor_bytes)) {
116 fprintf(stderr, "Failed to open %s\n", proto_descriptor.c_str());
117 return 1;
118 }
119 file_descriptor_set.ParseFromString(descriptor_bytes);
120
121 for (const auto& d : file_descriptor_set.file()) {
122 PERFETTO_CHECK(descriptor_pool.BuildFile(d));
123 }
124 }
125
126 std::set<std::string> groups;
127 std::multimap<std::string, const perfetto::FtraceEventName*> group_to_event;
128 std::set<std::string> new_events;
129 for (const auto& event : event_list) {
130 if (!event.valid())
131 continue;
132 groups.emplace(event.group());
133 group_to_event.emplace(event.group(), &event);
134 struct stat buf;
135 if (stat(
136 ("protos/perfetto/trace/ftrace/" + event.name() + ".proto").c_str(),
137 &buf) == -1) {
138 new_events.insert(event.name());
139 }
140 }
141
142 {
143 std::unique_ptr<std::ostream> out =
144 ostream_factory(output_dir + "/ftrace_event.proto");
145 perfetto::GenerateFtraceEventProto(event_list, groups, out.get());
146 }
147
148 for (const std::string& group : groups) {
149 std::string proto_file_name = group + ".proto";
150 std::string output_path = output_dir + std::string("/") + proto_file_name;
151 std::unique_ptr<std::ostream> fout = ostream_factory(output_path);
152 if (!fout) {
153 fprintf(stderr, "Failed to open %s\n", output_path.c_str());
154 return 1;
155 }
156 *fout << perfetto::ProtoHeader();
157
158 auto range = group_to_event.equal_range(group);
159 for (auto it = range.first; it != range.second; ++it) {
160 const auto& event = *it->second;
161 if (!event.valid())
162 continue;
163
164 std::string proto_name =
165 perfetto::EventNameToProtoName(group, event.name());
166 perfetto::Proto proto;
167 proto.name = proto_name;
168 proto.event_name = event.name();
169 const google::protobuf::Descriptor* d =
170 descriptor_pool.FindMessageTypeByName("perfetto.protos." +
171 proto_name);
172 if (d)
173 proto = perfetto::Proto(event.name(), *d);
174 else
175 PERFETTO_LOG("Did not find %s", proto_name.c_str());
176 for (int i = optind; i < argc; ++i) {
177 std::string input_dir = argv[i];
178 std::string input_path = input_dir + event.group() + "/" +
179 event.name() + std::string("/format");
180
181 std::string contents;
182 if (!perfetto::base::ReadFile(input_path, &contents)) {
183 continue;
184 }
185
186 perfetto::FtraceEvent format;
187 if (!perfetto::ParseFtraceEvent(contents, &format)) {
188 fprintf(stderr, "Could not parse file %s.\n", input_path.c_str());
189 return 1;
190 }
191
192 perfetto::Proto event_proto;
193 if (!perfetto::GenerateProto(group, format, &event_proto)) {
194 fprintf(stderr, "Could not generate proto for file %s\n",
195 input_path.c_str());
196 return 1;
197 }
198 proto.MergeFrom(event_proto);
199 }
200
201 uint32_t i = 0;
202 for (; it->second != &event_list[i]; i++)
203 ;
204
205 // The first id used for events in FtraceEvent proto is 3.
206 uint32_t proto_field = i + 3;
207
208 // The generic event has field id 327 so any event with a id higher
209 // than that has to be incremented by 1.
210 if (proto_field >= 327)
211 proto_field++;
212
213 events_info.push_back(
214 perfetto::SingleEventInfo(proto, event.group(), proto_field));
215
216 *fout << proto.ToString();
217 PERFETTO_CHECK(!fout->fail());
218 }
219 }
220
221 {
222 std::unique_ptr<std::ostream> out = ostream_factory(
223 "src/trace_processor/importers/ftrace/ftrace_descriptors.cc");
224 perfetto::GenerateFtraceDescriptors(descriptor_pool, out.get());
225 PERFETTO_CHECK(!out->fail());
226 }
227
228 {
229 std::unique_ptr<std::ostream> out =
230 ostream_factory("src/traced/probes/ftrace/event_info.cc");
231 perfetto::GenerateEventInfo(events_info, out.get());
232 PERFETTO_CHECK(!out->fail());
233 }
234
235 if (update_build_files) {
236 std::unique_ptr<std::ostream> f =
237 ostream_factory(output_dir + "/all_protos.gni");
238
239 *f << R"(# Copyright (C) 2018 The Android Open Source Project
240 #
241 # Licensed under the Apache License, Version 2.0 (the "License");
242 # you may not use this file except in compliance with the License.
243 # You may obtain a copy of the License at
244 #
245 # http://www.apache.org/licenses/LICENSE-2.0
246 #
247 # Unless required by applicable law or agreed to in writing, software
248 # distributed under the License is distributed on an "AS IS" BASIS,
249 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
250 # See the License for the specific language governing permissions and
251 # limitations under the License.
252
253 # Autogenerated by ftrace_proto_gen.
254
255 ftrace_proto_names = [
256 "ftrace_event.proto",
257 "ftrace_event_bundle.proto",
258 "ftrace_stats.proto",
259 "test_bundle_wrapper.proto",
260 "generic.proto",
261 )";
262 for (const std::string& group : groups) {
263 *f << " \"" << group << ".proto\",\n";
264 }
265 *f << "]\n";
266 PERFETTO_CHECK(!f->fail());
267 }
268 }
269