1 /*
2 * Copyright (C) 2019 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/tracing/tracing.h"
18
19 #include <atomic>
20 #include <condition_variable>
21 #include <mutex>
22
23 #include "perfetto/ext/base/no_destructor.h"
24 #include "perfetto/ext/base/waitable_event.h"
25 #include "perfetto/tracing/internal/track_event_internal.h"
26 #include "src/tracing/internal/tracing_muxer_impl.h"
27
28 namespace perfetto {
29 namespace {
30 bool g_was_initialized = false;
31
32 // Wrapped in a function to avoid global constructor
InitializedMutex()33 std::mutex& InitializedMutex() {
34 static base::NoDestructor<std::mutex> initialized_mutex;
35 return initialized_mutex.ref();
36 }
37 } // namespace
38
39 // static
InitializeInternal(const TracingInitArgs & args)40 void Tracing::InitializeInternal(const TracingInitArgs& args) {
41 std::unique_lock<std::mutex> lock(InitializedMutex());
42 // If it's the first time Initialize is called, set some global params.
43 if (!g_was_initialized) {
44 // Make sure the headers and implementation files agree on the build config.
45 PERFETTO_CHECK(args.dcheck_is_on_ == PERFETTO_DCHECK_IS_ON());
46 if (args.log_message_callback) {
47 base::SetLogMessageCallback(args.log_message_callback);
48 }
49
50 if (args.use_monotonic_clock) {
51 PERFETTO_CHECK(!args.use_monotonic_raw_clock);
52 internal::TrackEventInternal::SetClockId(
53 protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
54 } else if (args.use_monotonic_raw_clock) {
55 internal::TrackEventInternal::SetClockId(
56 protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW);
57 }
58
59 if (args.disallow_merging_with_system_tracks) {
60 internal::TrackEventInternal::SetDisallowMergingWithSystemTracks(true);
61 }
62 }
63
64 internal::TracingMuxerImpl::InitializeInstance(args);
65 internal::TrackRegistry::InitializeInstance();
66 g_was_initialized = true;
67 }
68
69 // static
IsInitialized()70 bool Tracing::IsInitialized() {
71 std::unique_lock<std::mutex> lock(InitializedMutex());
72 return g_was_initialized;
73 }
74
75 // static
Shutdown()76 void Tracing::Shutdown() {
77 std::unique_lock<std::mutex> lock(InitializedMutex());
78 if (!g_was_initialized)
79 return;
80 internal::TracingMuxerImpl::Shutdown();
81 g_was_initialized = false;
82 }
83
84 // static
ResetForTesting()85 void Tracing::ResetForTesting() {
86 std::unique_lock<std::mutex> lock(InitializedMutex());
87 if (!g_was_initialized)
88 return;
89 base::SetLogMessageCallback(nullptr);
90 internal::TracingMuxerImpl::ResetForTesting();
91 internal::TrackRegistry::ResetForTesting();
92 g_was_initialized = false;
93 }
94
95 // static
NewTraceInternal(BackendType backend,TracingConsumerBackend * (* system_backend_factory)())96 std::unique_ptr<TracingSession> Tracing::NewTraceInternal(
97 BackendType backend,
98 TracingConsumerBackend* (*system_backend_factory)()) {
99 return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
100 ->CreateTracingSession(backend, system_backend_factory);
101 }
102
103 // static
SetupStartupTracing(const TraceConfig & config,Tracing::SetupStartupTracingOpts opts)104 std::unique_ptr<StartupTracingSession> Tracing::SetupStartupTracing(
105 const TraceConfig& config,
106 Tracing::SetupStartupTracingOpts opts) {
107 return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
108 ->CreateStartupTracingSession(config, std::move(opts));
109 }
110
111 // static
SetupStartupTracingBlocking(const TraceConfig & config,Tracing::SetupStartupTracingOpts opts)112 std::unique_ptr<StartupTracingSession> Tracing::SetupStartupTracingBlocking(
113 const TraceConfig& config,
114 Tracing::SetupStartupTracingOpts opts) {
115 return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
116 ->CreateStartupTracingSessionBlocking(config, std::move(opts));
117 }
118
119 // static
ActivateTriggers(const std::vector<std::string> & triggers,uint32_t ttl_ms)120 void Tracing::ActivateTriggers(const std::vector<std::string>& triggers,
121 uint32_t ttl_ms) {
122 internal::TracingMuxer::Get()->ActivateTriggers(triggers, ttl_ms);
123 }
124
125 TracingSession::~TracingSession() = default;
126
127 // Can be called from any thread.
FlushBlocking(uint32_t timeout_ms)128 bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
129 std::atomic<bool> flush_result;
130 base::WaitableEvent flush_ack;
131
132 // The non blocking Flush() can be called on any thread. It does the PostTask
133 // internally.
134 Flush(
135 [&flush_ack, &flush_result](bool res) {
136 flush_result = res;
137 flush_ack.Notify();
138 },
139 timeout_ms);
140 flush_ack.Wait();
141 return flush_result;
142 }
143
ReadTraceBlocking()144 std::vector<char> TracingSession::ReadTraceBlocking() {
145 std::vector<char> raw_trace;
146 std::mutex mutex;
147 std::condition_variable cv;
148
149 bool all_read = false;
150
151 ReadTrace([&mutex, &raw_trace, &all_read, &cv](ReadTraceCallbackArgs cb) {
152 raw_trace.insert(raw_trace.end(), cb.data, cb.data + cb.size);
153 std::unique_lock<std::mutex> lock(mutex);
154 all_read = !cb.has_more;
155 if (all_read)
156 cv.notify_one();
157 });
158
159 {
160 std::unique_lock<std::mutex> lock(mutex);
161 cv.wait(lock, [&all_read] { return all_read; });
162 }
163 return raw_trace;
164 }
165
166 TracingSession::GetTraceStatsCallbackArgs
GetTraceStatsBlocking()167 TracingSession::GetTraceStatsBlocking() {
168 std::mutex mutex;
169 std::condition_variable cv;
170 GetTraceStatsCallbackArgs result;
171 bool stats_read = false;
172
173 GetTraceStats(
174 [&mutex, &result, &stats_read, &cv](GetTraceStatsCallbackArgs args) {
175 result = std::move(args);
176 std::unique_lock<std::mutex> lock(mutex);
177 stats_read = true;
178 cv.notify_one();
179 });
180
181 {
182 std::unique_lock<std::mutex> lock(mutex);
183 cv.wait(lock, [&stats_read] { return stats_read; });
184 }
185 return result;
186 }
187
188 TracingSession::QueryServiceStateCallbackArgs
QueryServiceStateBlocking()189 TracingSession::QueryServiceStateBlocking() {
190 std::mutex mutex;
191 std::condition_variable cv;
192 QueryServiceStateCallbackArgs result;
193 bool status_read = false;
194
195 QueryServiceState(
196 [&mutex, &result, &status_read, &cv](QueryServiceStateCallbackArgs args) {
197 result = std::move(args);
198 std::unique_lock<std::mutex> lock(mutex);
199 status_read = true;
200 cv.notify_one();
201 });
202
203 {
204 std::unique_lock<std::mutex> lock(mutex);
205 cv.wait(lock, [&status_read] { return status_read; });
206 }
207 return result;
208 }
209
210 StartupTracingSession::~StartupTracingSession() = default;
211
212 } // namespace perfetto
213