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