• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "perfetto/ext/base/file_utils.h"
18 #include "perfetto/ext/base/pipe.h"
19 #include "perfetto/ext/base/subprocess.h"
20 #include "perfetto/ext/base/utils.h"
21 #include "perfetto/ext/traced/traced.h"
22 #include "src/perfetto_cmd/perfetto_cmd.h"
23 #include "src/websocket_bridge/websocket_bridge.h"
24 
25 #if PERFETTO_BUILDFLAG(PERFETTO_TRACED_PERF)
26 #include "src/profiling/perf/traced_perf.h"
27 #endif
28 
29 #include <stdio.h>
30 
31 #include <tuple>
32 
33 namespace perfetto {
34 namespace {
35 
36 struct Applet {
37   using MainFunction = int (*)(int /*argc*/, char** /*argv*/);
38   const char* name;
39   MainFunction entrypoint;
40 };
41 
42 const Applet g_applets[]{
43     {"traced", ServiceMain},
44     {"traced_probes", ProbesMain},
45 #if PERFETTO_BUILDFLAG(PERFETTO_TRACED_PERF)
46     {"traced_perf", TracedPerfMain},
47 #endif
48     {"perfetto", PerfettoCmdMain},
49     {"trigger_perfetto", TriggerPerfettoMain},
50     {"websocket_bridge", WebsocketBridgeMain},
51 };
52 
PrintUsage()53 void PrintUsage() {
54   printf(R"(Welcome to Perfetto tracing!
55 
56 Tracebox is a bundle containing all the tracing services and the perfetto
57 cmdline client in one binary. It can be used either to spawn manually the
58 various subprocess or in "autostart" mode, which will take care of starting
59 and tearing down the services for you.
60 
61 Usage in autostart mode:
62   tracebox -t 10s -o trace_file.perfetto-trace sched/sched_switch
63   See tracebox --help for more options.
64 
65 Usage in manual mode:
66   tracebox applet_name [args ...]  (e.g. ./tracebox traced --help)
67   Applets:)");
68 
69   for (const Applet& applet : g_applets)
70     printf(" %s", applet.name);
71 
72   printf(R"(
73 
74 See also:
75   * https://perfetto.dev/docs/
76   * The config editor in the record page of https://ui.perfetto.dev/
77 )");
78 }
79 
TraceboxMain(int argc,char ** argv)80 int TraceboxMain(int argc, char** argv) {
81   // Manual mode: if either the 1st argument (argv[1]) or the exe name (argv[0])
82   // match the name of an applet, directly invoke that without further
83   // modifications.
84 
85   // Extract the file name from argv[0].
86   char* slash = strrchr(argv[0], '/');
87   char* argv0 = slash ? slash + 1 : argv[0];
88 
89   for (const Applet& applet : g_applets) {
90     if (!strcmp(argv0, applet.name))
91       return applet.entrypoint(argc, argv);
92     if (argc > 1 && !strcmp(argv[1], applet.name))
93       return applet.entrypoint(argc - 1, &argv[1]);
94   }
95 
96   // If no matching applet is found, switch to the autostart mode. In this mode
97   // we make tracebox behave like the cmdline client (without needing to prefix
98   // it with "perfetto"), but will also start traced and traced_probes.
99   // As part of this we also use a different namespace for the producer/consumer
100   // sockets, to avoid clashing with the system daemon.
101 
102   if (argc <= 1) {
103     PrintUsage();
104     return 1;
105   }
106 
107   auto pid_str = std::to_string(static_cast<uint64_t>(base::GetProcessId()));
108 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
109     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
110   // Use an unlinked abstract domain socket on Linux/Android.
111   std::string consumer_socket = "@traced-c-" + pid_str;
112   std::string producer_socket = "@traced-p-" + pid_str;
113 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
114   std::string consumer_socket = "/tmp/traced-c-" + pid_str;
115   std::string producer_socket = "/tmp/traced-p-" + pid_str;
116 #else
117   PERFETTO_FATAL("The autostart mode is not supported on this platform");
118 #endif
119 
120   // If the caller has set the PERFETTO_*_SOCK_NAME, respect those.
121   const char* env;
122   if ((env = getenv("PERFETTO_CONSUMER_SOCK_NAME")))
123     consumer_socket = env;
124   if ((env = getenv("PERFETTO_PRODUCER_SOCK_NAME")))
125     producer_socket = env;
126 
127   base::SetEnv("PERFETTO_CONSUMER_SOCK_NAME", consumer_socket);
128   base::SetEnv("PERFETTO_PRODUCER_SOCK_NAME", producer_socket);
129 
130   PerfettoCmd perfetto_cmd;
131 
132   // If the cmdline parsing fails, stop here, no need to spawn services.
133   // It will daemonize if --background. In that case the subprocesses will be
134   // spawned by the damonized cmdline client, which is what we want so killing
135   // the backgrounded cmdline client will also kill the other services, as they
136   // will live in the same background session.
137   auto opt_res = perfetto_cmd.ParseCmdlineAndMaybeDaemonize(argc, argv);
138   if (opt_res.has_value())
139     return *opt_res;
140 
141   std::string self_path = base::GetCurExecutablePath();
142   base::Subprocess traced({self_path, "traced"});
143 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
144   // |traced_sync_pipe| is used to synchronize with traced socket creation.
145   // traced will write "1" and close the FD when the IPC socket is listening
146   // (or traced crashed).
147   base::Pipe traced_sync_pipe = base::Pipe::Create();
148   int traced_fd = *traced_sync_pipe.wr;
149   base::SetEnv("TRACED_NOTIFY_FD", std::to_string(traced_fd));
150   traced.args.preserve_fds.emplace_back(traced_fd);
151   // Create a new process group so CTRL-C is delivered only to the cmdline
152   // process (the tracebox one) and not to traced. traced will still exit once
153   // the main process exits, but this allows graceful stopping of the trace
154   // without abruptedly killing traced{,probes} when hitting CTRL+C.
155   traced.args.posix_proc_group_id = 0;  // 0 = start a new process group.
156 #endif
157   traced.Start();
158 
159 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
160   traced_sync_pipe.wr.reset();
161 
162   std::string traced_notify_msg;
163   base::ReadPlatformHandle(*traced_sync_pipe.rd, &traced_notify_msg);
164   if (traced_notify_msg != "1")
165     PERFETTO_FATAL("The tracing service failed unexpectedly. Check the logs");
166 #endif
167 
168   base::Subprocess traced_probes(
169       {self_path, "traced_probes", "--reset-ftrace"});
170   // Put traced_probes in the same process group as traced. Same reason (CTRL+C)
171   // but it's not worth creating a new group.
172   traced_probes.args.posix_proc_group_id = traced.pid();
173 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
174   // |traced_probes_sync_pipe| is used to synchronize with traced socket
175   // creation. traced will write "1" and close the FD when the IPC socket is
176   // listening (or traced crashed).
177   base::Pipe traced_probes_sync_pipe = base::Pipe::Create();
178   int traced_probes_fd = *traced_probes_sync_pipe.wr;
179   base::SetEnv("TRACED_PROBES_NOTIFY_FD", std::to_string(traced_probes_fd));
180   traced_probes.args.preserve_fds.emplace_back(traced_probes_fd);
181 #endif
182   traced_probes.Start();
183 
184 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
185   traced_probes_sync_pipe.wr.reset();
186 
187   std::string traced_probes_notify_msg;
188   base::ReadPlatformHandle(*traced_probes_sync_pipe.rd,
189                            &traced_probes_notify_msg);
190   if (traced_probes_notify_msg != "1")
191     PERFETTO_FATAL(
192         "The traced_probes service failed unexpectedly. Check the logs");
193 #endif
194 
195 #if PERFETTO_BUILDFLAG(PERFETTO_TRACED_PERF)
196   base::Subprocess traced_perf({self_path, "traced_perf"});
197   // Put traced_perf in the same process group as traced. Same reason (CTRL+C)
198   // but it's not worth creating a new group.
199   traced_perf.args.posix_proc_group_id = traced.pid();
200 
201   base::Pipe traced_perf_sync_pipe = base::Pipe::Create();
202   int traced_perf_fd = *traced_perf_sync_pipe.wr;
203   base::SetEnv("TRACED_PERF_NOTIFY_FD", std::to_string(traced_perf_fd));
204   traced_perf.args.preserve_fds.emplace_back(traced_perf_fd);
205   traced_perf.Start();
206   traced_perf_sync_pipe.wr.reset();
207 
208   std::string traced_perf_notify_msg;
209   base::ReadPlatformHandle(*traced_perf_sync_pipe.rd,
210                            &traced_perf_notify_msg);
211   if (traced_perf_notify_msg != "1")
212     PERFETTO_FATAL(
213         "The traced_perf service failed unexpectedly. Check the logs");
214 #endif
215 
216   perfetto_cmd.ConnectToServiceRunAndMaybeNotify();
217   return 0;
218 }
219 
220 }  // namespace
221 }  // namespace perfetto
222 
main(int argc,char ** argv)223 int main(int argc, char** argv) {
224   return perfetto::TraceboxMain(argc, argv);
225 }
226