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