1 /*
2 * Copyright (C) 2022 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/public/abi/data_source_abi.h"
18
19 #include <bitset>
20
21 #include "perfetto/tracing/data_source.h"
22 #include "perfetto/tracing/internal/basic_types.h"
23 #include "protos/perfetto/common/data_source_descriptor.gen.h"
24 #include "protos/perfetto/config/data_source_config.gen.h"
25 #include "src/shared_lib/reset_for_testing.h"
26 #include "src/shared_lib/stream_writer.h"
27
28 namespace {
29
30 using ::perfetto::internal::DataSourceInstanceThreadLocalState;
31 using ::perfetto::internal::DataSourceThreadLocalState;
32 using ::perfetto::internal::DataSourceType;
33
34 thread_local DataSourceThreadLocalState*
35 g_tls_cache[perfetto::internal::kMaxDataSources];
36
37 } // namespace
38
39 // Implementation of a shared library data source type (there's one of these per
40 // type, not per instance).
41 //
42 // Returned to the C side when invoking PerfettoDsCreateImpl(). The C side only
43 // has an opaque pointer to this.
44 struct PerfettoDsImpl {
45 // Instance lifecycle callbacks.
46 PerfettoDsOnSetupCb on_setup_cb = nullptr;
47 PerfettoDsOnStartCb on_start_cb = nullptr;
48 PerfettoDsOnStopCb on_stop_cb = nullptr;
49
50 // These are called to create/delete custom thread-local instance state.
51 PerfettoDsOnCreateCustomState on_create_tls_cb = nullptr;
52 PerfettoDsOnDeleteCustomState on_delete_tls_cb = nullptr;
53
54 // These are called to create/delete custom thread-local instance incremental
55 // state.
56 PerfettoDsOnCreateCustomState on_create_incr_cb = nullptr;
57 PerfettoDsOnDeleteCustomState on_delete_incr_cb = nullptr;
58
59 // Passed to all the callbacks as the `user_arg` param.
60 void* cb_user_arg;
61
62 DataSourceType cpp_type;
63 std::atomic<bool> enabled{false};
64 std::mutex mu;
65 // Guarded by mu
66 std::bitset<perfetto::internal::kMaxDataSourceInstances> enabled_instances;
67
IsRegisteredPerfettoDsImpl68 bool IsRegistered() {
69 return cpp_type.static_state()->index !=
70 perfetto::internal::kMaxDataSources;
71 }
72 };
73
74 namespace perfetto {
75 namespace shlib {
76
77 // These are only exposed to tests.
78
ResetDataSourceTls()79 void ResetDataSourceTls() {
80 memset(g_tls_cache, 0, sizeof(g_tls_cache));
81 }
82
DsImplDestroy(struct PerfettoDsImpl * ds_impl)83 void DsImplDestroy(struct PerfettoDsImpl* ds_impl) {
84 delete ds_impl;
85 }
86
87 } // namespace shlib
88 } // namespace perfetto
89
90 namespace {
91
92 // Represents a global data source instance (there can be more than one of these
93 // for a single data source type).
94 class ShlibDataSource : public perfetto::DataSourceBase {
95 public:
ShlibDataSource(PerfettoDsImpl * type)96 explicit ShlibDataSource(PerfettoDsImpl* type) : type_(*type) {}
97
OnSetup(const SetupArgs & args)98 void OnSetup(const SetupArgs& args) override {
99 if (type_.on_setup_cb) {
100 std::vector<uint8_t> serialized_config = args.config->SerializeAsArray();
101 inst_ctx_ = type_.on_setup_cb(
102 args.internal_instance_index, serialized_config.data(),
103 serialized_config.size(), type_.cb_user_arg);
104 }
105 std::lock_guard<std::mutex> lock(type_.mu);
106 const bool was_enabled = type_.enabled_instances.any();
107 type_.enabled_instances.set(args.internal_instance_index);
108 if (!was_enabled && type_.enabled_instances.any()) {
109 type_.enabled.store(true, std::memory_order_release);
110 }
111 }
112
OnStart(const StartArgs & args)113 void OnStart(const StartArgs& args) override {
114 if (type_.on_start_cb) {
115 type_.on_start_cb(args.internal_instance_index, type_.cb_user_arg,
116 inst_ctx_);
117 }
118 }
119
OnStop(const StopArgs & args)120 void OnStop(const StopArgs& args) override {
121 if (type_.on_stop_cb) {
122 type_.on_stop_cb(
123 args.internal_instance_index, type_.cb_user_arg, inst_ctx_,
124 const_cast<PerfettoDsOnStopArgs*>(
125 reinterpret_cast<const PerfettoDsOnStopArgs*>(&args)));
126 }
127
128 std::lock_guard<std::mutex> lock(type_.mu);
129 type_.enabled_instances.reset(args.internal_instance_index);
130 if (type_.enabled_instances.none()) {
131 type_.enabled.store(false, std::memory_order_release);
132 }
133 }
134
type() const135 const PerfettoDsImpl& type() const { return type_; }
136
inst_ctx() const137 void* inst_ctx() const { return inst_ctx_; }
138
139 private:
140 PerfettoDsImpl& type_;
141 void* inst_ctx_ = nullptr;
142 };
143
144 struct DataSourceTraits {
GetDataSourceTLS__anon4c454edf0211::DataSourceTraits145 static DataSourceThreadLocalState* GetDataSourceTLS(
146 perfetto::internal::DataSourceStaticState* static_state,
147 perfetto::internal::TracingTLS* root_tls) {
148 auto* ds_tls = &root_tls->data_sources_tls[static_state->index];
149 // ds_tls->static_state can be:
150 // * nullptr
151 // * equal to static_state
152 // * equal to the static state of a different data source, in tests (when
153 // ResetForTesting() has been used)
154 // In any case, there's no need to do anything, the caller will reinitialize
155 // static_state.
156 return ds_tls;
157 }
158 };
159
160 struct TracePointTraits {
161 using TracePointData = DataSourceType*;
GetActiveInstances__anon4c454edf0211::TracePointTraits162 static std::atomic<uint32_t>* GetActiveInstances(TracePointData s) {
163 return s->valid_instances();
164 }
165 };
166
CreateShlibTls(DataSourceInstanceThreadLocalState * tls_inst,uint32_t inst_idx,void * ctx)167 DataSourceInstanceThreadLocalState::ObjectWithDeleter CreateShlibTls(
168 DataSourceInstanceThreadLocalState* tls_inst,
169 uint32_t inst_idx,
170 void* ctx) {
171 auto* ds_impl = reinterpret_cast<PerfettoDsImpl*>(ctx);
172
173 void* custom_state = ds_impl->on_create_tls_cb(
174 inst_idx, reinterpret_cast<PerfettoDsTracerImpl*>(tls_inst),
175 ds_impl->cb_user_arg);
176 return DataSourceInstanceThreadLocalState::ObjectWithDeleter(
177 custom_state, ds_impl->on_delete_tls_cb);
178 }
179
180 DataSourceInstanceThreadLocalState::ObjectWithDeleter
CreateShlibIncrementalState(DataSourceInstanceThreadLocalState * tls_inst,uint32_t inst_idx,void * ctx)181 CreateShlibIncrementalState(DataSourceInstanceThreadLocalState* tls_inst,
182 uint32_t inst_idx,
183 void* ctx) {
184 auto* ds_impl = reinterpret_cast<PerfettoDsImpl*>(ctx);
185
186 void* custom_state = ds_impl->on_create_incr_cb(
187 inst_idx, reinterpret_cast<PerfettoDsTracerImpl*>(tls_inst),
188 ds_impl->cb_user_arg);
189 return DataSourceInstanceThreadLocalState::ObjectWithDeleter(
190 custom_state, ds_impl->on_delete_incr_cb);
191 }
192
193 } // namespace
194
195 // Exposed through data_source_abi.h
196 std::atomic<bool> perfetto_atomic_false{false};
197
PerfettoDsImplCreate()198 struct PerfettoDsImpl* PerfettoDsImplCreate() {
199 return new PerfettoDsImpl();
200 }
201
PerfettoDsSetOnSetupCallback(struct PerfettoDsImpl * ds_impl,PerfettoDsOnSetupCb cb)202 void PerfettoDsSetOnSetupCallback(struct PerfettoDsImpl* ds_impl,
203 PerfettoDsOnSetupCb cb) {
204 PERFETTO_CHECK(!ds_impl->IsRegistered());
205 ds_impl->on_setup_cb = cb;
206 }
207
PerfettoDsSetOnStartCallback(struct PerfettoDsImpl * ds_impl,PerfettoDsOnStartCb cb)208 void PerfettoDsSetOnStartCallback(struct PerfettoDsImpl* ds_impl,
209 PerfettoDsOnStartCb cb) {
210 PERFETTO_CHECK(!ds_impl->IsRegistered());
211 ds_impl->on_start_cb = cb;
212 }
213
PerfettoDsSetOnStopCallback(struct PerfettoDsImpl * ds_impl,PerfettoDsOnStopCb cb)214 void PerfettoDsSetOnStopCallback(struct PerfettoDsImpl* ds_impl,
215 PerfettoDsOnStopCb cb) {
216 PERFETTO_CHECK(!ds_impl->IsRegistered());
217 ds_impl->on_stop_cb = cb;
218 }
219
PerfettoDsSetOnCreateTls(struct PerfettoDsImpl * ds_impl,PerfettoDsOnCreateCustomState cb)220 void PerfettoDsSetOnCreateTls(struct PerfettoDsImpl* ds_impl,
221 PerfettoDsOnCreateCustomState cb) {
222 PERFETTO_CHECK(!ds_impl->IsRegistered());
223 ds_impl->on_create_tls_cb = cb;
224 }
225
PerfettoDsSetOnDeleteTls(struct PerfettoDsImpl * ds_impl,PerfettoDsOnDeleteCustomState cb)226 void PerfettoDsSetOnDeleteTls(struct PerfettoDsImpl* ds_impl,
227 PerfettoDsOnDeleteCustomState cb) {
228 PERFETTO_CHECK(!ds_impl->IsRegistered());
229 ds_impl->on_delete_tls_cb = cb;
230 }
231
PerfettoDsSetOnCreateIncr(struct PerfettoDsImpl * ds_impl,PerfettoDsOnCreateCustomState cb)232 void PerfettoDsSetOnCreateIncr(struct PerfettoDsImpl* ds_impl,
233 PerfettoDsOnCreateCustomState cb) {
234 PERFETTO_CHECK(!ds_impl->IsRegistered());
235 ds_impl->on_create_incr_cb = cb;
236 }
237
PerfettoDsSetOnDeleteIncr(struct PerfettoDsImpl * ds_impl,PerfettoDsOnDeleteCustomState cb)238 void PerfettoDsSetOnDeleteIncr(struct PerfettoDsImpl* ds_impl,
239 PerfettoDsOnDeleteCustomState cb) {
240 PERFETTO_CHECK(!ds_impl->IsRegistered());
241 ds_impl->on_delete_incr_cb = cb;
242 }
243
PerfettoDsSetCbUserArg(struct PerfettoDsImpl * ds_impl,void * user_arg)244 void PerfettoDsSetCbUserArg(struct PerfettoDsImpl* ds_impl, void* user_arg) {
245 PERFETTO_CHECK(!ds_impl->IsRegistered());
246 ds_impl->cb_user_arg = user_arg;
247 }
248
PerfettoDsImplRegister(struct PerfettoDsImpl * ds_impl,PERFETTO_ATOMIC (bool)** enabled_ptr,const void * descriptor,size_t descriptor_size)249 bool PerfettoDsImplRegister(struct PerfettoDsImpl* ds_impl,
250 PERFETTO_ATOMIC(bool) * *enabled_ptr,
251 const void* descriptor,
252 size_t descriptor_size) {
253 perfetto::DataSourceDescriptor dsd;
254 dsd.ParseFromArray(descriptor, descriptor_size);
255
256 std::unique_ptr<PerfettoDsImpl> data_source_type(ds_impl);
257
258 auto factory = [ds_impl]() {
259 return std::unique_ptr<perfetto::DataSourceBase>(
260 new ShlibDataSource(ds_impl));
261 };
262
263 DataSourceType::CreateCustomTlsFn create_custom_tls_fn = nullptr;
264 DataSourceType::CreateIncrementalStateFn create_incremental_state_fn =
265 nullptr;
266 void* cb_ctx = nullptr;
267 if (data_source_type->on_create_incr_cb &&
268 data_source_type->on_delete_incr_cb) {
269 create_incremental_state_fn = CreateShlibIncrementalState;
270 cb_ctx = data_source_type.get();
271 }
272 if (data_source_type->on_create_tls_cb &&
273 data_source_type->on_delete_tls_cb) {
274 create_custom_tls_fn = CreateShlibTls;
275 cb_ctx = data_source_type.get();
276 }
277
278 perfetto::internal::DataSourceParams params;
279 params.supports_multiple_instances = true;
280 params.requires_callbacks_under_lock = false;
281 bool success = data_source_type->cpp_type.Register(
282 dsd, factory, params, perfetto::BufferExhaustedPolicy::kDrop,
283 create_custom_tls_fn, create_incremental_state_fn, cb_ctx);
284 if (!success) {
285 return false;
286 }
287 *enabled_ptr = &data_source_type->enabled;
288 perfetto::base::ignore_result(data_source_type.release());
289 return true;
290 }
291
PerfettoDsImplUpdateDescriptor(struct PerfettoDsImpl * ds_impl,const void * descriptor,size_t descriptor_size)292 void PerfettoDsImplUpdateDescriptor(struct PerfettoDsImpl* ds_impl,
293 const void* descriptor,
294 size_t descriptor_size) {
295 perfetto::DataSourceDescriptor dsd;
296 dsd.ParseFromArray(descriptor, descriptor_size);
297
298 ds_impl->cpp_type.UpdateDescriptor(dsd);
299 }
300
PerfettoDsOnStopArgsPostpone(PerfettoDsOnStopArgs * args)301 PerfettoDsAsyncStopper* PerfettoDsOnStopArgsPostpone(
302 PerfettoDsOnStopArgs* args) {
303 auto* cb = new std::function<void()>();
304 *cb = reinterpret_cast<const ShlibDataSource::StopArgs*>(args)
305 ->HandleStopAsynchronously();
306 return reinterpret_cast<PerfettoDsAsyncStopper*>(cb);
307 }
308
PerfettoDsStopDone(PerfettoDsAsyncStopper * stopper)309 void PerfettoDsStopDone(PerfettoDsAsyncStopper* stopper) {
310 auto* cb = reinterpret_cast<std::function<void()>*>(stopper);
311 (*cb)();
312 delete cb;
313 }
314
PerfettoDsImplGetInstanceLocked(struct PerfettoDsImpl * ds_impl,PerfettoDsInstanceIndex idx)315 void* PerfettoDsImplGetInstanceLocked(struct PerfettoDsImpl* ds_impl,
316 PerfettoDsInstanceIndex idx) {
317 auto* internal_state = ds_impl->cpp_type.static_state()->TryGet(idx);
318 if (!internal_state) {
319 return nullptr;
320 }
321 std::unique_lock<std::recursive_mutex> lock(internal_state->lock);
322 auto* data_source =
323 static_cast<ShlibDataSource*>(internal_state->data_source.get());
324 if (&data_source->type() != ds_impl) {
325 // The data source instance has been destroyed and recreated as a different
326 // type while we where tracing.
327 return nullptr;
328 }
329 void* inst_ctx = data_source->inst_ctx();
330 if (inst_ctx != nullptr) {
331 lock.release();
332 }
333 return inst_ctx;
334 }
335
PerfettoDsImplReleaseInstanceLocked(struct PerfettoDsImpl * ds_impl,PerfettoDsInstanceIndex idx)336 void PerfettoDsImplReleaseInstanceLocked(struct PerfettoDsImpl* ds_impl,
337 PerfettoDsInstanceIndex idx) {
338 auto* internal_state = ds_impl->cpp_type.static_state()->TryGet(idx);
339 PERFETTO_CHECK(internal_state);
340 internal_state->lock.unlock();
341 }
342
PerfettoDsImplGetCustomTls(struct PerfettoDsImpl *,struct PerfettoDsTracerImpl * tracer,PerfettoDsInstanceIndex)343 void* PerfettoDsImplGetCustomTls(struct PerfettoDsImpl*,
344 struct PerfettoDsTracerImpl* tracer,
345 PerfettoDsInstanceIndex) {
346 auto* tls_inst =
347 reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
348
349 PERFETTO_DCHECK(tls_inst->data_source_custom_tls);
350 return tls_inst->data_source_custom_tls.get();
351 }
352
PerfettoDsImplGetIncrementalState(struct PerfettoDsImpl * ds_impl,struct PerfettoDsTracerImpl * tracer,PerfettoDsInstanceIndex idx)353 void* PerfettoDsImplGetIncrementalState(struct PerfettoDsImpl* ds_impl,
354 struct PerfettoDsTracerImpl* tracer,
355 PerfettoDsInstanceIndex idx) {
356 auto* tls_inst =
357 reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
358
359 return ds_impl->cpp_type.GetIncrementalState(tls_inst, idx);
360 }
361
PerfettoDsImplTraceIterateBegin(struct PerfettoDsImpl * ds_impl)362 struct PerfettoDsImplTracerIterator PerfettoDsImplTraceIterateBegin(
363 struct PerfettoDsImpl* ds_impl) {
364 DataSourceThreadLocalState** tls =
365 &g_tls_cache[ds_impl->cpp_type.static_state()->index];
366
367 struct PerfettoDsImplTracerIterator ret = {0, nullptr, nullptr};
368 uint32_t cached_instances =
369 ds_impl->cpp_type.valid_instances()->load(std::memory_order_relaxed);
370 if (!cached_instances) {
371 return ret;
372 }
373 bool res =
374 ds_impl->cpp_type.TracePrologue<DataSourceTraits, TracePointTraits>(
375 tls, &cached_instances, &ds_impl->cpp_type);
376 if (!res) {
377 return ret;
378 }
379 DataSourceType::InstancesIterator it =
380 ds_impl->cpp_type.BeginIteration<TracePointTraits>(cached_instances, *tls,
381 &ds_impl->cpp_type);
382 ret.inst_id = it.i;
383 (*tls)->root_tls->cached_instances = it.cached_instances;
384 ret.tracer = reinterpret_cast<struct PerfettoDsTracerImpl*>(it.instance);
385 if (!ret.tracer) {
386 ds_impl->cpp_type.TraceEpilogue(*tls);
387 }
388
389 ret.tls = reinterpret_cast<struct PerfettoDsTlsImpl*>(*tls);
390 return ret;
391 }
392
PerfettoDsImplTraceIterateNext(struct PerfettoDsImpl * ds_impl,struct PerfettoDsImplTracerIterator * iterator)393 void PerfettoDsImplTraceIterateNext(
394 struct PerfettoDsImpl* ds_impl,
395 struct PerfettoDsImplTracerIterator* iterator) {
396 auto* tls = reinterpret_cast<DataSourceThreadLocalState*>(iterator->tls);
397
398 DataSourceType::InstancesIterator it;
399 it.i = iterator->inst_id;
400 it.cached_instances = tls->root_tls->cached_instances;
401 it.instance =
402 reinterpret_cast<DataSourceInstanceThreadLocalState*>(iterator->tracer);
403
404 ds_impl->cpp_type.NextIteration<TracePointTraits>(&it, tls,
405 &ds_impl->cpp_type);
406
407 iterator->inst_id = it.i;
408 tls->root_tls->cached_instances = it.cached_instances;
409 iterator->tracer =
410 reinterpret_cast<struct PerfettoDsTracerImpl*>(it.instance);
411
412 if (!iterator->tracer) {
413 ds_impl->cpp_type.TraceEpilogue(tls);
414 }
415 }
416
PerfettoDsImplTraceIterateBreak(struct PerfettoDsImpl * ds_impl,struct PerfettoDsImplTracerIterator * iterator)417 void PerfettoDsImplTraceIterateBreak(
418 struct PerfettoDsImpl* ds_impl,
419 struct PerfettoDsImplTracerIterator* iterator) {
420 auto* tls = reinterpret_cast<DataSourceThreadLocalState*>(iterator->tls);
421
422 ds_impl->cpp_type.TraceEpilogue(tls);
423 }
424
PerfettoDsTracerImplPacketBegin(struct PerfettoDsTracerImpl * tracer)425 struct PerfettoStreamWriter PerfettoDsTracerImplPacketBegin(
426 struct PerfettoDsTracerImpl* tracer) {
427 auto* tls_inst =
428 reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
429
430 auto message_handle = tls_inst->trace_writer->NewTracePacket();
431 struct PerfettoStreamWriter ret;
432 protozero::ScatteredStreamWriter* sw = message_handle.TakeStreamWriter();
433 ret.impl = reinterpret_cast<PerfettoStreamWriterImpl*>(sw);
434 perfetto::UpdateStreamWriter(*sw, &ret);
435 return ret;
436 }
437
PerfettoDsTracerImplPacketEnd(struct PerfettoDsTracerImpl * tracer,struct PerfettoStreamWriter * w)438 void PerfettoDsTracerImplPacketEnd(struct PerfettoDsTracerImpl* tracer,
439 struct PerfettoStreamWriter* w) {
440 auto* tls_inst =
441 reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
442 auto* sw = reinterpret_cast<protozero::ScatteredStreamWriter*>(w->impl);
443
444 sw->set_write_ptr(w->write_ptr);
445 tls_inst->trace_writer->FinishTracePacket();
446 }
447
PerfettoDsTracerImplFlush(struct PerfettoDsTracerImpl * tracer,PerfettoDsTracerOnFlushCb cb,void * user_arg)448 void PerfettoDsTracerImplFlush(struct PerfettoDsTracerImpl* tracer,
449 PerfettoDsTracerOnFlushCb cb,
450 void* user_arg) {
451 auto* tls_inst =
452 reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
453
454 std::function<void()> fn;
455 if (cb != nullptr) {
456 fn = [user_arg, cb]() { cb(user_arg); };
457 }
458 tls_inst->trace_writer->Flush(fn);
459 }
460