• 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 <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