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 }
38
39 // static
InitializeInternal(const TracingInitArgs & args)40 void Tracing::InitializeInternal(const TracingInitArgs& args) {
41 std::unique_lock<std::mutex> lock(InitializedMutex());
42 static TracingInitArgs init_args;
43 if (g_was_initialized) {
44 if (!(init_args == args)) {
45 PERFETTO_ELOG(
46 "Tracing::Initialize() called more than once with different args. "
47 "This is not supported, only the first call will have effect.");
48 PERFETTO_DCHECK(false);
49 }
50 return;
51 }
52
53 // Make sure the headers and implementation files agree on the build config.
54 PERFETTO_CHECK(args.dcheck_is_on_ == PERFETTO_DCHECK_IS_ON());
55 if (args.log_message_callback) {
56 base::SetLogMessageCallback(args.log_message_callback);
57 }
58 internal::TracingMuxerImpl::InitializeInstance(args);
59 internal::TrackRegistry::InitializeInstance();
60 g_was_initialized = true;
61 init_args = args;
62 }
63
64 // static
IsInitialized()65 bool Tracing::IsInitialized() {
66 std::unique_lock<std::mutex> lock(InitializedMutex());
67 return g_was_initialized;
68 }
69
70 // static
ResetForTesting()71 void Tracing::ResetForTesting() {
72 std::unique_lock<std::mutex> lock(InitializedMutex());
73 if (!g_was_initialized)
74 return;
75 base::SetLogMessageCallback(nullptr);
76 internal::TracingMuxerImpl::ResetForTesting();
77 internal::TrackRegistry::ResetForTesting();
78 g_was_initialized = false;
79 }
80
81 // static
NewTrace(BackendType backend)82 std::unique_ptr<TracingSession> Tracing::NewTrace(BackendType backend) {
83 return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
84 ->CreateTracingSession(backend);
85 }
86
87 // Can be called from any thread.
FlushBlocking(uint32_t timeout_ms)88 bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
89 std::atomic<bool> flush_result;
90 base::WaitableEvent flush_ack;
91
92 // The non blocking Flush() can be called on any thread. It does the PostTask
93 // internally.
94 Flush(
95 [&flush_ack, &flush_result](bool res) {
96 flush_result = res;
97 flush_ack.Notify();
98 },
99 timeout_ms);
100 flush_ack.Wait();
101 return flush_result;
102 }
103
ReadTraceBlocking()104 std::vector<char> TracingSession::ReadTraceBlocking() {
105 std::vector<char> raw_trace;
106 std::mutex mutex;
107 std::condition_variable cv;
108
109 bool all_read = false;
110
111 ReadTrace([&mutex, &raw_trace, &all_read, &cv](ReadTraceCallbackArgs cb) {
112 raw_trace.insert(raw_trace.end(), cb.data, cb.data + cb.size);
113 std::unique_lock<std::mutex> lock(mutex);
114 all_read = !cb.has_more;
115 if (all_read)
116 cv.notify_one();
117 });
118
119 {
120 std::unique_lock<std::mutex> lock(mutex);
121 cv.wait(lock, [&all_read] { return all_read; });
122 }
123 return raw_trace;
124 }
125
126 TracingSession::GetTraceStatsCallbackArgs
GetTraceStatsBlocking()127 TracingSession::GetTraceStatsBlocking() {
128 std::mutex mutex;
129 std::condition_variable cv;
130 GetTraceStatsCallbackArgs result;
131 bool stats_read = false;
132
133 GetTraceStats(
134 [&mutex, &result, &stats_read, &cv](GetTraceStatsCallbackArgs args) {
135 result = std::move(args);
136 std::unique_lock<std::mutex> lock(mutex);
137 stats_read = true;
138 cv.notify_one();
139 });
140
141 {
142 std::unique_lock<std::mutex> lock(mutex);
143 cv.wait(lock, [&stats_read] { return stats_read; });
144 }
145 return result;
146 }
147
148 TracingSession::QueryServiceStateCallbackArgs
QueryServiceStateBlocking()149 TracingSession::QueryServiceStateBlocking() {
150 std::mutex mutex;
151 std::condition_variable cv;
152 QueryServiceStateCallbackArgs result;
153 bool status_read = false;
154
155 QueryServiceState(
156 [&mutex, &result, &status_read, &cv](QueryServiceStateCallbackArgs args) {
157 result = std::move(args);
158 std::unique_lock<std::mutex> lock(mutex);
159 status_read = true;
160 cv.notify_one();
161 });
162
163 {
164 std::unique_lock<std::mutex> lock(mutex);
165 cv.wait(lock, [&status_read] { return status_read; });
166 }
167 return result;
168 }
169
170 } // namespace perfetto
171