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