• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 <stdio.h>
18 
19 #include <fstream>
20 #include <iostream>
21 #include <limits>
22 #include <vector>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/ext/base/string_utils.h"
26 #include "tools/trace_to_text/deobfuscate_profile.h"
27 #include "tools/trace_to_text/symbolize_profile.h"
28 #include "tools/trace_to_text/trace_to_json.h"
29 #include "tools/trace_to_text/trace_to_profile.h"
30 #include "tools/trace_to_text/trace_to_systrace.h"
31 #include "tools/trace_to_text/trace_to_text.h"
32 
33 #if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
34 #include "perfetto_version.gen.h"
35 #else
36 #define PERFETTO_GET_GIT_REVISION() "unknown"
37 #endif
38 
39 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
40 #include <unistd.h>
41 #endif
42 
43 namespace perfetto {
44 namespace trace_to_text {
45 namespace {
46 
Usage(const char * argv0)47 int Usage(const char* argv0) {
48   fprintf(stderr,
49           "Usage: %s systrace|json|ctrace|text|profile [--pid PID] "
50           "[--timestamps TIMESTAMP1,TIMESTAMP2,...] "
51           "[--truncate start|end] "
52           "[--full-sort] "
53           "[trace.pb] "
54           "[trace.txt]\n"
55           "\nProfile mode only:\n"
56           "\t--timestamps TIMESTAMP1,TIMESTAMP2,... generate profiles "
57           "only for these timestamps\n"
58           "\t--pid PID generate profiles only for this process id\n",
59           argv0);
60   return 1;
61 }
62 
StringToUint64OrDie(const char * str)63 uint64_t StringToUint64OrDie(const char* str) {
64   char* end;
65   uint64_t number = static_cast<uint64_t>(strtoll(str, &end, 10));
66   if (*end != '\0') {
67     PERFETTO_ELOG("Invalid %s. Expected decimal integer.", str);
68     exit(1);
69   }
70   return number;
71 }
72 
Main(int argc,char ** argv)73 int Main(int argc, char** argv) {
74   std::vector<const char*> positional_args;
75   Keep truncate_keep = Keep::kAll;
76   uint64_t pid = 0;
77   std::vector<uint64_t> timestamps;
78   bool full_sort = false;
79   for (int i = 1; i < argc; i++) {
80     if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
81       printf("%s\n", PERFETTO_GET_GIT_REVISION());
82       return 0;
83     } else if (strcmp(argv[i], "-t") == 0 ||
84                strcmp(argv[i], "--truncate") == 0) {
85       i++;
86       if (i <= argc && strcmp(argv[i], "start") == 0) {
87         truncate_keep = Keep::kStart;
88       } else if (i <= argc && strcmp(argv[i], "end") == 0) {
89         truncate_keep = Keep::kEnd;
90       } else {
91         PERFETTO_ELOG(
92             "--truncate must specify whether to keep the end or the "
93             "start of the trace.");
94         return Usage(argv[0]);
95       }
96     } else if (i <= argc && strcmp(argv[i], "--pid") == 0) {
97       i++;
98       pid = StringToUint64OrDie(argv[i]);
99     } else if (i <= argc && strcmp(argv[i], "--timestamps") == 0) {
100       i++;
101       std::vector<std::string> ts_strings = base::SplitString(argv[i], ",");
102       for (const std::string& ts : ts_strings) {
103         timestamps.emplace_back(StringToUint64OrDie(ts.c_str()));
104       }
105     } else if (strcmp(argv[i], "--full-sort") == 0) {
106       full_sort = true;
107     } else {
108       positional_args.push_back(argv[i]);
109     }
110   }
111 
112   if (positional_args.size() < 1)
113     return Usage(argv[0]);
114 
115   std::istream* input_stream;
116   std::ifstream file_istream;
117   if (positional_args.size() > 1) {
118     const char* file_path = positional_args[1];
119     file_istream.open(file_path, std::ios_base::in | std::ios_base::binary);
120     if (!file_istream.is_open())
121       PERFETTO_FATAL("Could not open %s", file_path);
122     input_stream = &file_istream;
123   } else {
124     if (isatty(STDIN_FILENO)) {
125       PERFETTO_ELOG("Reading from stdin but it's connected to a TTY");
126       PERFETTO_LOG("It is unlikely that you want to type in some binary.");
127       PERFETTO_LOG("Either pass a file path to the cmdline or pipe stdin");
128       return Usage(argv[0]);
129     }
130     input_stream = &std::cin;
131   }
132 
133   std::ostream* output_stream;
134   std::ofstream file_ostream;
135   if (positional_args.size() > 2) {
136     const char* file_path = positional_args[2];
137     file_ostream.open(file_path, std::ios_base::out | std::ios_base::trunc);
138     if (!file_ostream.is_open())
139       PERFETTO_FATAL("Could not open %s", file_path);
140     output_stream = &file_ostream;
141   } else {
142     output_stream = &std::cout;
143   }
144 
145   std::string format(positional_args[0]);
146 
147   if (format != "profile" && (pid != 0 || !timestamps.empty())) {
148     PERFETTO_ELOG(
149         "--pid and --timestamps are supported only for profile format.");
150     return 1;
151   }
152 
153   if (format == "json")
154     return TraceToJson(input_stream, output_stream, /*compress=*/false,
155                        truncate_keep, full_sort);
156 
157   if (format == "systrace")
158     return TraceToSystrace(input_stream, output_stream, /*ctrace=*/false,
159                            truncate_keep, full_sort);
160 
161   if (format == "ctrace")
162     return TraceToSystrace(input_stream, output_stream, /*ctrace=*/true,
163                            truncate_keep, full_sort);
164 
165   if (truncate_keep != Keep::kAll) {
166     PERFETTO_ELOG(
167         "--truncate is unsupported for text|profile|symbolize format.");
168     return 1;
169   }
170 
171   if (full_sort) {
172     PERFETTO_ELOG(
173         "--full-sort is unsupported for text|profile|symbolize format.");
174     return 1;
175   }
176 
177   if (format == "text")
178     return TraceToText(input_stream, output_stream);
179 
180   if (format == "profile")
181     return TraceToProfile(input_stream, output_stream, pid, timestamps);
182 
183   if (format == "symbolize")
184     return SymbolizeProfile(input_stream, output_stream);
185 
186   if (format == "deobfuscate")
187     return DeobfuscateProfile(input_stream, output_stream);
188   return Usage(argv[0]);
189 }
190 
191 }  // namespace
192 }  // namespace trace_to_text
193 }  // namespace perfetto
194 
main(int argc,char ** argv)195 int main(int argc, char** argv) {
196   return perfetto::trace_to_text::Main(argc, argv);
197 }
198