• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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