1 /*
2 * Copyright (C) 2024 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 "tracing_sdk.h"
18
19 #include <android-base/logging.h>
20 #include <cutils/trace.h>
21
22 #include <cstdarg>
23 #include <cstdlib>
24
25 #include "perfetto/public/abi/producer_abi.h"
26 #include "perfetto/public/te_category_macros.h"
27 #include "perfetto/public/te_macros.h"
28 #include "perfetto/public/track_event.h"
29 #include "tracing_perfetto.h"
30
31 namespace tracing_perfetto {
trace_event(int type,const PerfettoTeCategory * perfettoTeCategory,const char * name,tracing_perfetto::Extra * extra)32 void trace_event(int type, const PerfettoTeCategory* perfettoTeCategory,
33 const char* name, tracing_perfetto::Extra* extra) {
34 bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
35 perfettoTeCategory->enabled, PERFETTO_MEMORY_ORDER_RELAXED));
36 if (enabled) {
37 extra->push_extra(nullptr);
38 PerfettoTeHlEmitImpl(perfettoTeCategory->impl, type,
39 type == PERFETTO_TE_TYPE_COUNTER ? nullptr : name,
40 extra->get());
41 extra->clear_extras();
42 }
43 }
44
get_process_track_uuid()45 uint64_t get_process_track_uuid() {
46 return PerfettoTeProcessTrackUuid();
47 }
48
get_thread_track_uuid(pid_t tid)49 uint64_t get_thread_track_uuid(pid_t tid) {
50 // Cating a signed pid_t to unsigned
51 return PerfettoTeProcessTrackUuid() ^ PERFETTO_STATIC_CAST(uint64_t, tid);
52 }
53
Extra()54 Extra::Extra() {
55 }
56
push_extra(PerfettoTeHlExtra * ptr)57 void Extra::push_extra(PerfettoTeHlExtra* ptr) {
58 extras_.push_back(ptr);
59 }
60
pop_extra()61 void Extra::pop_extra() {
62 extras_.pop_back();
63 }
64
clear_extras()65 void Extra::clear_extras() {
66 extras_.clear();
67 }
68
delete_extra(Extra * ptr)69 void Extra::delete_extra(Extra* ptr) {
70 delete ptr;
71 }
72
get() const73 PerfettoTeHlExtra* const* Extra::get() const {
74 return extras_.data();
75 }
76
Category(const std::string & name,const std::string & tag,const std::string & severity)77 Category::Category(const std::string& name, const std::string& tag,
78 const std::string& severity)
79 : category_({.enabled = &perfetto_atomic_false}),
80 name_(name),
81 tag_(tag),
82 severity_(severity) {
83 }
84
~Category()85 Category::~Category() {
86 unregister_category();
87 }
88
register_category()89 void Category::register_category() {
90 if (category_.impl) return;
91
92 std::vector<const char*> tags;
93 if (!tag_.empty()) tags.push_back(tag_.data());
94 if (!severity_.empty()) tags.push_back(severity_.data());
95
96 category_.desc = {name_.c_str(), name_.c_str(), tags.data(), tags.size()};
97
98 PerfettoTeCategoryRegister(&category_);
99 PerfettoTePublishCategories();
100 }
101
unregister_category()102 void Category::unregister_category() {
103 if (!category_.impl) return;
104
105 PerfettoTeCategoryUnregister(&category_);
106 PerfettoTePublishCategories();
107 }
108
is_category_enabled()109 bool Category::is_category_enabled() {
110 return PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
111 (category_).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
112 }
113
get() const114 const PerfettoTeCategory* Category::get() const {
115 return &category_;
116 }
117
delete_category(Category * ptr)118 void Category::delete_category(Category* ptr) {
119 delete ptr;
120 }
121
Flow()122 Flow::Flow() : flow_{} {
123 }
124
set_process_flow(uint64_t id)125 void Flow::set_process_flow(uint64_t id) {
126 flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_FLOW;
127 PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
128 flow_.id = ret.id;
129 }
130
set_process_terminating_flow(uint64_t id)131 void Flow::set_process_terminating_flow(uint64_t id) {
132 flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_TERMINATING_FLOW;
133 PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
134 flow_.id = ret.id;
135 }
136
get() const137 const PerfettoTeHlExtraFlow* Flow::get() const {
138 return &flow_;
139 }
140
delete_flow(Flow * ptr)141 void Flow::delete_flow(Flow* ptr) {
142 delete ptr;
143 }
144
NamedTrack(uint64_t id,uint64_t parent_uuid,const std::string & name)145 NamedTrack::NamedTrack(uint64_t id, uint64_t parent_uuid,
146 const std::string& name)
147 : name_(name),
148 track_{{PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK},
149 name_.data(),
150 id,
151 parent_uuid} {
152 }
153
get() const154 const PerfettoTeHlExtraNamedTrack* NamedTrack::get() const {
155 return &track_;
156 }
157
delete_track(NamedTrack * ptr)158 void NamedTrack::delete_track(NamedTrack* ptr) {
159 delete ptr;
160 }
161
RegisteredTrack(uint64_t id,uint64_t parent_uuid,const std::string & name,bool is_counter)162 RegisteredTrack::RegisteredTrack(uint64_t id, uint64_t parent_uuid,
163 const std::string& name, bool is_counter)
164 : registered_track_{},
165 track_{{PERFETTO_TE_HL_EXTRA_TYPE_REGISTERED_TRACK},
166 &(registered_track_.impl)},
167 name_(name),
168 id_(id),
169 parent_uuid_(parent_uuid),
170 is_counter_(is_counter) {
171 register_track();
172 }
173
~RegisteredTrack()174 RegisteredTrack::~RegisteredTrack() {
175 unregister_track();
176 }
177
register_track()178 void RegisteredTrack::register_track() {
179 if (registered_track_.impl.descriptor) return;
180
181 if (is_counter_) {
182 PerfettoTeCounterTrackRegister(®istered_track_, name_.data(),
183 parent_uuid_);
184 } else {
185 PerfettoTeNamedTrackRegister(®istered_track_, name_.data(), id_,
186 parent_uuid_);
187 }
188 }
189
unregister_track()190 void RegisteredTrack::unregister_track() {
191 if (!registered_track_.impl.descriptor) return;
192 PerfettoTeRegisteredTrackUnregister(®istered_track_);
193 }
194
get() const195 const PerfettoTeHlExtraRegisteredTrack* RegisteredTrack::get() const {
196 return &track_;
197 }
198
delete_track(RegisteredTrack * ptr)199 void RegisteredTrack::delete_track(RegisteredTrack* ptr) {
200 delete ptr;
201 }
202
Proto()203 Proto::Proto() : proto_({PERFETTO_TE_HL_EXTRA_TYPE_PROTO_FIELDS}, nullptr) {
204 }
205
add_field(PerfettoTeHlProtoField * ptr)206 void Proto::add_field(PerfettoTeHlProtoField* ptr) {
207 if (!fields_.empty()) {
208 fields_.pop_back();
209 }
210
211 fields_.push_back(ptr);
212 fields_.push_back(nullptr);
213 proto_.fields = fields_.data();
214 }
215
clear_fields()216 void Proto::clear_fields() {
217 fields_.clear();
218 proto_.fields = nullptr;
219 }
220
delete_proto(Proto * ptr)221 void Proto::delete_proto(Proto* ptr) {
222 delete ptr;
223 }
224
get() const225 const PerfettoTeHlExtraProtoFields* Proto::get() const {
226 return &proto_;
227 }
228
ProtoFieldNested()229 ProtoFieldNested::ProtoFieldNested()
230 : field_({PERFETTO_TE_HL_PROTO_TYPE_NESTED}, nullptr) {
231 }
232
add_field(PerfettoTeHlProtoField * ptr)233 void ProtoFieldNested::add_field(PerfettoTeHlProtoField* ptr) {
234 if (!fields_.empty()) {
235 fields_.pop_back();
236 }
237
238 fields_.push_back(ptr);
239 fields_.push_back(nullptr);
240 field_.fields = fields_.data();
241 }
242
set_id(uint32_t id)243 void ProtoFieldNested::set_id(uint32_t id) {
244 fields_.clear();
245 field_.header.id = id;
246 field_.fields = nullptr;
247 }
248
delete_field(ProtoFieldNested * ptr)249 void ProtoFieldNested::delete_field(ProtoFieldNested* ptr) {
250 delete ptr;
251 }
252
get() const253 const PerfettoTeHlProtoFieldNested* ProtoFieldNested::get() const {
254 return &field_;
255 }
256
Session(bool is_backend_in_process,void * buf,size_t len)257 Session::Session(bool is_backend_in_process, void* buf, size_t len) {
258 session_ = PerfettoTracingSessionCreate(is_backend_in_process
259 ? PERFETTO_BACKEND_IN_PROCESS
260 : PERFETTO_BACKEND_SYSTEM);
261
262 PerfettoTracingSessionSetup(session_, buf, len);
263
264 PerfettoTracingSessionStartBlocking(session_);
265 }
266
~Session()267 Session::~Session() {
268 PerfettoTracingSessionStopBlocking(session_);
269 PerfettoTracingSessionDestroy(session_);
270 }
271
FlushBlocking(uint32_t timeout_ms)272 bool Session::FlushBlocking(uint32_t timeout_ms) {
273 return PerfettoTracingSessionFlushBlocking(session_, timeout_ms);
274 }
275
StopBlocking()276 void Session::StopBlocking() {
277 PerfettoTracingSessionStopBlocking(session_);
278 }
279
ReadBlocking()280 std::vector<uint8_t> Session::ReadBlocking() {
281 std::vector<uint8_t> data;
282 PerfettoTracingSessionReadTraceBlocking(
283 session_,
284 [](struct PerfettoTracingSessionImpl*, const void* trace_data,
285 size_t size, bool, void* user_arg) {
286 auto& dst = *static_cast<std::vector<uint8_t>*>(user_arg);
287 auto* src = static_cast<const uint8_t*>(trace_data);
288 dst.insert(dst.end(), src, src + size);
289 },
290 &data);
291 return data;
292 }
293
delete_session(Session * ptr)294 void Session::delete_session(Session* ptr) {
295 delete ptr;
296 }
297
activate_trigger(const char * name,uint32_t ttl_ms)298 void activate_trigger(const char* name, uint32_t ttl_ms) {
299 const char* names[] = {name, nullptr};
300 PerfettoProducerActivateTriggers(names, ttl_ms);
301 }
302 } // namespace tracing_perfetto
303