xref: /aosp_15_r20/external/perfetto/src/traceconv/main.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 "perfetto/ext/base/version.h"
27 #include "src/traceconv/deobfuscate_profile.h"
28 #include "src/traceconv/symbolize_profile.h"
29 #include "src/traceconv/trace_to_firefox.h"
30 #include "src/traceconv/trace_to_hprof.h"
31 #include "src/traceconv/trace_to_json.h"
32 #include "src/traceconv/trace_to_profile.h"
33 #include "src/traceconv/trace_to_systrace.h"
34 #include "src/traceconv/trace_to_text.h"
35 #include "src/traceconv/trace_unpack.h"
36 
37 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
38 #include <fcntl.h>
39 #include <io.h>
40 #else
41 #include <unistd.h>
42 #endif
43 
44 namespace perfetto {
45 namespace trace_to_text {
46 namespace {
47 
Usage(const char * argv0)48 int Usage(const char* argv0) {
49   fprintf(
50       stderr,
51       "Usage: %s MODE [OPTIONS] [input file] [output file]\n"
52       "modes:\n"
53       "  systrace|json|ctrace|text|profile|hprof|symbolize|deobfuscate|firefox"
54       "|java_heap_profile|decompress_packets\n"
55       "options:\n"
56       "  [--truncate start|end]\n"
57       "  [--full-sort]\n"
58       "\"profile\" mode options:\n"
59       "  [--perf] generate a perf profile instead of a heap profile\n"
60       "  [--no-annotations] do not suffix frame names with derived "
61       "annotations\n"
62       "  [--timestamps TIMESTAMP1,TIMESTAMP2,...] generate profiles "
63       "only for these *specific* timestamps\n"
64       "  [--pid PID] generate profiles only for this process id\n",
65       argv0);
66   return 1;
67 }
68 
StringToUint64OrDie(const char * str)69 uint64_t StringToUint64OrDie(const char* str) {
70   char* end;
71   uint64_t number = static_cast<uint64_t>(strtoll(str, &end, 10));
72   if (*end != '\0') {
73     PERFETTO_ELOG("Invalid %s. Expected decimal integer.", str);
74     exit(1);
75   }
76   return number;
77 }
78 
Main(int argc,char ** argv)79 int Main(int argc, char** argv) {
80   std::vector<const char*> positional_args;
81   Keep truncate_keep = Keep::kAll;
82   uint64_t pid = 0;
83   std::vector<uint64_t> timestamps;
84   bool full_sort = false;
85   bool perf_profile = false;
86   bool profile_no_annotations = false;
87   for (int i = 1; i < argc; i++) {
88     if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
89       printf("%s\n", base::GetVersionString());
90       return 0;
91     } else if (strcmp(argv[i], "-t") == 0 ||
92                strcmp(argv[i], "--truncate") == 0) {
93       i++;
94       if (i <= argc && strcmp(argv[i], "start") == 0) {
95         truncate_keep = Keep::kStart;
96       } else if (i <= argc && strcmp(argv[i], "end") == 0) {
97         truncate_keep = Keep::kEnd;
98       } else {
99         PERFETTO_ELOG(
100             "--truncate must specify whether to keep the end or the "
101             "start of the trace.");
102         return Usage(argv[0]);
103       }
104     } else if (i <= argc && strcmp(argv[i], "--pid") == 0) {
105       i++;
106       pid = StringToUint64OrDie(argv[i]);
107     } else if (i <= argc && strcmp(argv[i], "--timestamps") == 0) {
108       i++;
109       std::vector<std::string> ts_strings = base::SplitString(argv[i], ",");
110       for (const std::string& ts : ts_strings) {
111         timestamps.emplace_back(StringToUint64OrDie(ts.c_str()));
112       }
113     } else if (strcmp(argv[i], "--perf") == 0) {
114       perf_profile = true;
115     } else if (strcmp(argv[i], "--no-annotations") == 0) {
116       profile_no_annotations = true;
117     } else if (strcmp(argv[i], "--full-sort") == 0) {
118       full_sort = true;
119     } else {
120       positional_args.push_back(argv[i]);
121     }
122   }
123 
124   if (positional_args.empty())
125     return Usage(argv[0]);
126 
127   std::istream* input_stream;
128   std::ifstream file_istream;
129   if (positional_args.size() > 1) {
130     const char* file_path = positional_args[1];
131     file_istream.open(file_path, std::ios_base::in | std::ios_base::binary);
132     if (!file_istream.is_open())
133       PERFETTO_FATAL("Could not open %s", file_path);
134     input_stream = &file_istream;
135   } else {
136 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
137     if (isatty(STDIN_FILENO)) {
138       PERFETTO_ELOG("Reading from stdin but it's connected to a TTY");
139       PERFETTO_LOG("It is unlikely that you want to type in some binary.");
140       PERFETTO_LOG("Either pass a file path to the cmdline or pipe stdin");
141       return Usage(argv[0]);
142     }
143 #endif
144     input_stream = &std::cin;
145   }
146 
147 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
148   // We don't want the runtime to replace "\n" with "\r\n" on `std::cout`.
149   _setmode(_fileno(stdout), _O_BINARY);
150 #endif
151 
152   std::ostream* output_stream;
153   std::ofstream file_ostream;
154   if (positional_args.size() > 2) {
155     const char* file_path = positional_args[2];
156     file_ostream.open(file_path, std::ios_base::out | std::ios_base::trunc |
157                                      std::ios_base::binary);
158     if (!file_ostream.is_open())
159       PERFETTO_FATAL("Could not open %s", file_path);
160     output_stream = &file_ostream;
161   } else {
162     output_stream = &std::cout;
163   }
164 
165   std::string format(positional_args[0]);
166 
167   if ((format != "profile" && format != "hprof") &&
168       (pid != 0 || !timestamps.empty())) {
169     PERFETTO_ELOG(
170         "--pid and --timestamps are supported only for profile "
171         "formats.");
172     return 1;
173   }
174   if (perf_profile && format != "profile") {
175     PERFETTO_ELOG("--perf requires profile format.");
176     return 1;
177   }
178 
179   if (format == "json")
180     return TraceToJson(input_stream, output_stream, /*compress=*/false,
181                        truncate_keep, full_sort);
182 
183   if (format == "systrace")
184     return TraceToSystrace(input_stream, output_stream, /*ctrace=*/false,
185                            truncate_keep, full_sort);
186 
187   if (format == "ctrace")
188     return TraceToSystrace(input_stream, output_stream, /*ctrace=*/true,
189                            truncate_keep, full_sort);
190 
191   if (truncate_keep != Keep::kAll) {
192     PERFETTO_ELOG(
193         "--truncate is unsupported for "
194         "text|profile|symbolize|decompress_packets format.");
195     return 1;
196   }
197 
198   if (full_sort) {
199     PERFETTO_ELOG(
200         "--full-sort is unsupported for "
201         "text|profile|symbolize|decompress_packets format.");
202     return 1;
203   }
204 
205   if (format == "text") {
206     return TraceToText(input_stream, output_stream) ? 0 : 1;
207   }
208 
209   if (format == "profile") {
210     return perf_profile
211                ? TraceToPerfProfile(input_stream, output_stream, pid,
212                                     timestamps, !profile_no_annotations)
213                : TraceToHeapProfile(input_stream, output_stream, pid,
214                                     timestamps, !profile_no_annotations);
215   }
216 
217   if (format == "java_heap_profile") {
218     return TraceToJavaHeapProfile(input_stream, output_stream, pid, timestamps,
219                                   !profile_no_annotations);
220   }
221 
222   if (format == "hprof")
223     return TraceToHprof(input_stream, output_stream, pid, timestamps);
224 
225   if (format == "symbolize")
226     return SymbolizeProfile(input_stream, output_stream);
227 
228   if (format == "deobfuscate")
229     return DeobfuscateProfile(input_stream, output_stream);
230 
231   if (format == "firefox")
232     return TraceToFirefoxProfile(input_stream, output_stream);
233 
234   if (format == "decompress_packets")
235     return UnpackCompressedPackets(input_stream, output_stream);
236 
237   return Usage(argv[0]);
238 }
239 
240 }  // namespace
241 }  // namespace trace_to_text
242 }  // namespace perfetto
243 
main(int argc,char ** argv)244 int main(int argc, char** argv) {
245   return perfetto::trace_to_text::Main(argc, argv);
246 }
247