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/tools/ftrace_proto_gen/ftrace_descriptor_gen.h"
33 #include "src/tools/ftrace_proto_gen/ftrace_proto_gen.h"
34 #include "src/traced/probes/ftrace/format_parser/format_parser.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 auto proto_fields = perfetto::ToProtoFields(format);
193 proto.UnionFields(proto_fields);
194 }
195
196 uint32_t i = 0;
197 for (; it->second != &event_list[i]; i++)
198 ;
199
200 // The first id used for events in FtraceEvent proto is 3.
201 uint32_t proto_field = i + 3;
202
203 // The generic event has field id 327 so any event with a id higher
204 // than that has to be incremented by 1.
205 if (proto_field >= 327)
206 proto_field++;
207
208 events_info.push_back(
209 perfetto::SingleEventInfo(proto, event.group(), proto_field));
210
211 *fout << proto.ToString();
212 PERFETTO_CHECK(!fout->fail());
213 }
214 }
215
216 {
217 std::unique_ptr<std::ostream> out = ostream_factory(
218 "src/trace_processor/importers/ftrace/ftrace_descriptors.cc");
219 perfetto::GenerateFtraceDescriptors(descriptor_pool, out.get());
220 PERFETTO_CHECK(!out->fail());
221 }
222
223 {
224 std::unique_ptr<std::ostream> out =
225 ostream_factory("src/traced/probes/ftrace/event_info.cc");
226 perfetto::GenerateEventInfo(events_info, out.get());
227 PERFETTO_CHECK(!out->fail());
228 }
229
230 if (update_build_files) {
231 std::unique_ptr<std::ostream> f =
232 ostream_factory(output_dir + "/all_protos.gni");
233
234 *f << R"(# Copyright (C) 2018 The Android Open Source Project
235 #
236 # Licensed under the Apache License, Version 2.0 (the "License");
237 # you may not use this file except in compliance with the License.
238 # You may obtain a copy of the License at
239 #
240 # http://www.apache.org/licenses/LICENSE-2.0
241 #
242 # Unless required by applicable law or agreed to in writing, software
243 # distributed under the License is distributed on an "AS IS" BASIS,
244 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
245 # See the License for the specific language governing permissions and
246 # limitations under the License.
247
248 # Autogenerated by ftrace_proto_gen.
249
250 ftrace_proto_names = [
251 "ftrace_event.proto",
252 "ftrace_event_bundle.proto",
253 "ftrace_stats.proto",
254 "test_bundle_wrapper.proto",
255 "generic.proto",
256 )";
257 for (const std::string& group : groups) {
258 *f << " \"" << group << ".proto\",\n";
259 }
260 *f << "]\n";
261 PERFETTO_CHECK(!f->fail());
262 }
263 }
264