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