Home | History | Annotate | Download | only in ftrace_proto_gen
      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 {
     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 
     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 
     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