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