• 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 #ifndef INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_
18 #define INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_
19 
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "perfetto/public/abi/atomic.h"
24 #include "perfetto/public/abi/data_source_abi.h"
25 #include "perfetto/public/abi/heap_buffer.h"
26 #include "perfetto/public/compiler.h"
27 #include "perfetto/public/pb_msg.h"
28 #include "perfetto/public/pb_utils.h"
29 #include "perfetto/public/protos/common/data_source_descriptor.pzc.h"
30 #include "perfetto/public/protos/trace/trace_packet.pzc.h"
31 
32 // A data source type.
33 struct PerfettoDs {
34   // Pointer to a (atomic) boolean, which is set to true if there is at
35   // least one enabled instance of this data source type.
36   PERFETTO_ATOMIC(bool) * enabled;
37   struct PerfettoDsImpl* impl;
38 };
39 
40 // Initializes a PerfettoDs struct.
41 #define PERFETTO_DS_INIT() \
42   { &perfetto_atomic_false, PERFETTO_NULL }
43 
44 // All the callbacks are optional and can be NULL if not needed.
45 //
46 struct PerfettoDsParams {
47   // Instance lifecycle callbacks.
48   //
49   // Can be called from any thread.
50   PerfettoDsOnSetupCb on_setup_cb;
51   PerfettoDsOnStartCb on_start_cb;
52   PerfettoDsOnStopCb on_stop_cb;
53   PerfettoDsOnDestroyCb on_destroy_cb;
54   PerfettoDsOnFlushCb on_flush_cb;
55 
56   // These are called to create/delete custom thread-local instance state, which
57   // can be accessed with PerfettoDsTracerImplGetCustomTls().
58   //
59   // Called from inside a trace point. Trace points inside these will be
60   // ignored.
61   PerfettoDsOnCreateCustomState on_create_tls_cb;
62   PerfettoDsOnDeleteCustomState on_delete_tls_cb;
63 
64   // These are called to create/delete custom thread-local instance incremental
65   // state. Incremental state may be cleared periodically by the tracing service
66   // and can be accessed with PerfettoDsTracerImplGetIncrementalState().
67   //
68   // Called from inside a trace point. Trace points inside these will be
69   // ignored.
70   PerfettoDsOnCreateCustomState on_create_incr_cb;
71   PerfettoDsOnDeleteCustomState on_delete_incr_cb;
72 
73   // Passed to all the callbacks as the `user_arg` param.
74   void* user_arg;
75 
76   // How to behave when running out of shared memory buffer space.
77   enum PerfettoDsBufferExhaustedPolicy buffer_exhausted_policy;
78 
79   // When true the data source is expected to ack the stop request through the
80   // NotifyDataSourceStopped() IPC.
81   bool will_notify_on_stop;
82 };
83 
PerfettoDsParamsDefault(void)84 static inline struct PerfettoDsParams PerfettoDsParamsDefault(void) {
85   struct PerfettoDsParams ret = {PERFETTO_NULL,
86                                  PERFETTO_NULL,
87                                  PERFETTO_NULL,
88                                  PERFETTO_NULL,
89                                  PERFETTO_NULL,
90                                  PERFETTO_NULL,
91                                  PERFETTO_NULL,
92                                  PERFETTO_NULL,
93                                  PERFETTO_NULL,
94                                  PERFETTO_NULL,
95                                  PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP,
96                                  true};
97   return ret;
98 }
99 
100 // Registers the data source type `ds`, named `data_source_name` with the global
101 // perfetto producer.
PerfettoDsRegister(struct PerfettoDs * ds,const char * data_source_name,struct PerfettoDsParams params)102 static inline bool PerfettoDsRegister(struct PerfettoDs* ds,
103                                       const char* data_source_name,
104                                       struct PerfettoDsParams params) {
105   struct PerfettoDsImpl* ds_impl;
106   bool success;
107   void* desc_buf;
108   size_t desc_size;
109 
110   ds->enabled = &perfetto_atomic_false;
111   ds->impl = PERFETTO_NULL;
112 
113   {
114     struct PerfettoPbMsgWriter writer;
115     struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
116     struct perfetto_protos_DataSourceDescriptor desc;
117     PerfettoPbMsgInit(&desc.msg, &writer);
118 
119     perfetto_protos_DataSourceDescriptor_set_cstr_name(&desc, data_source_name);
120     perfetto_protos_DataSourceDescriptor_set_will_notify_on_stop(
121         &desc, params.will_notify_on_stop);
122 
123     desc_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
124     desc_buf = malloc(desc_size);
125     PerfettoHeapBufferCopyInto(hb, &writer.writer, desc_buf, desc_size);
126     PerfettoHeapBufferDestroy(hb, &writer.writer);
127   }
128 
129   if (!desc_buf) {
130     return false;
131   }
132 
133   ds_impl = PerfettoDsImplCreate();
134   if (params.on_setup_cb) {
135     PerfettoDsSetOnSetupCallback(ds_impl, params.on_setup_cb);
136   }
137   if (params.on_start_cb) {
138     PerfettoDsSetOnStartCallback(ds_impl, params.on_start_cb);
139   }
140   if (params.on_stop_cb) {
141     PerfettoDsSetOnStopCallback(ds_impl, params.on_stop_cb);
142   }
143   if (params.on_destroy_cb) {
144     PerfettoDsSetOnDestroyCallback(ds_impl, params.on_destroy_cb);
145   }
146   if (params.on_flush_cb) {
147     PerfettoDsSetOnFlushCallback(ds_impl, params.on_flush_cb);
148   }
149   if (params.on_create_tls_cb) {
150     PerfettoDsSetOnCreateTls(ds_impl, params.on_create_tls_cb);
151   }
152   if (params.on_delete_tls_cb) {
153     PerfettoDsSetOnDeleteTls(ds_impl, params.on_delete_tls_cb);
154   }
155   if (params.on_create_incr_cb) {
156     PerfettoDsSetOnCreateIncr(ds_impl, params.on_create_incr_cb);
157   }
158   if (params.on_delete_incr_cb) {
159     PerfettoDsSetOnDeleteIncr(ds_impl, params.on_delete_incr_cb);
160   }
161   if (params.user_arg) {
162     PerfettoDsSetCbUserArg(ds_impl, params.user_arg);
163   }
164   if (params.buffer_exhausted_policy !=
165       PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP) {
166     PerfettoDsSetBufferExhaustedPolicy(ds_impl, params.buffer_exhausted_policy);
167   }
168 
169   success = PerfettoDsImplRegister(ds_impl, &ds->enabled, desc_buf, desc_size);
170   free(desc_buf);
171   if (!success) {
172     return false;
173   }
174   ds->impl = ds_impl;
175   return true;
176 }
177 
178 // Iterator for all the active instances (on this thread) of a data source type.
179 struct PerfettoDsTracerIterator {
180   struct PerfettoDsImplTracerIterator impl;
181 };
182 
PerfettoDsTraceIterateBegin(struct PerfettoDs * ds)183 static inline struct PerfettoDsTracerIterator PerfettoDsTraceIterateBegin(
184     struct PerfettoDs* ds) {
185   struct PerfettoDsTracerIterator ret;
186   PERFETTO_ATOMIC(bool)* enabled = ds->enabled;
187   if (PERFETTO_LIKELY(!PERFETTO_ATOMIC_LOAD_EXPLICIT(
188           enabled, PERFETTO_MEMORY_ORDER_RELAXED))) {
189     // Tracing fast path: bail out immediately if the enabled flag is false.
190     ret.impl.tracer = PERFETTO_NULL;
191   } else {
192     // Else, make an ABI call to start iteration over the data source type
193     // active instances.
194     ret.impl = PerfettoDsImplTraceIterateBegin(ds->impl);
195   }
196   return ret;
197 }
198 
PerfettoDsTraceIterateNext(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)199 static inline void PerfettoDsTraceIterateNext(
200     struct PerfettoDs* ds,
201     struct PerfettoDsTracerIterator* iterator) {
202   PerfettoDsImplTraceIterateNext(ds->impl, &iterator->impl);
203 }
204 
PerfettoDsTraceIterateBreak(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)205 static inline void PerfettoDsTraceIterateBreak(
206     struct PerfettoDs* ds,
207     struct PerfettoDsTracerIterator* iterator) {
208   if (iterator->impl.tracer) {
209     PerfettoDsImplTraceIterateBreak(ds->impl, &iterator->impl);
210   }
211 }
212 
213 // For loop over the active instances of a data source type.
214 //
215 // `NAME` is the data source type (struct PerfettoDs).
216 //
217 // A local variable called `ITERATOR` will be instantiated. It can be used to
218 // perform tracing on each instance.
219 //
220 // N.B. The iteration MUST NOT be interrupted early with `break`.
221 // PERFETTO_DS_TRACE_BREAK should be used instead.
222 #define PERFETTO_DS_TRACE(NAME, ITERATOR)         \
223   for (struct PerfettoDsTracerIterator ITERATOR = \
224            PerfettoDsTraceIterateBegin(&(NAME));  \
225        (ITERATOR).impl.tracer != NULL;            \
226        PerfettoDsTraceIterateNext(&(NAME), &(ITERATOR)))
227 
228 // Used to break the iteration in a PERFETTO_DS_TRACE loop.
229 #define PERFETTO_DS_TRACE_BREAK(NAME, ITERATOR)      \
230   PerfettoDsTraceIterateBreak(&(NAME), &(ITERATOR)); \
231   break
232 
PerfettoDsGetCustomTls(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)233 static inline void* PerfettoDsGetCustomTls(
234     struct PerfettoDs* ds,
235     struct PerfettoDsTracerIterator* iterator) {
236   return PerfettoDsImplGetCustomTls(ds->impl, iterator->impl.tracer,
237                                     iterator->impl.inst_id);
238 }
239 
PerfettoDsGetIncrementalState(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)240 static inline void* PerfettoDsGetIncrementalState(
241     struct PerfettoDs* ds,
242     struct PerfettoDsTracerIterator* iterator) {
243   return PerfettoDsImplGetIncrementalState(ds->impl, iterator->impl.tracer,
244                                            iterator->impl.inst_id);
245 }
246 
247 // Used to write a TracePacket on a data source instance. Stores the writer and
248 // the TracePacket message.
249 struct PerfettoDsRootTracePacket {
250   struct PerfettoPbMsgWriter writer;
251   struct perfetto_protos_TracePacket msg;
252 };
253 
254 // Initializes `root` to write a new packet to the data source instance pointed
255 // by `iterator`.
PerfettoDsTracerPacketBegin(struct PerfettoDsTracerIterator * iterator,struct PerfettoDsRootTracePacket * root)256 static inline void PerfettoDsTracerPacketBegin(
257     struct PerfettoDsTracerIterator* iterator,
258     struct PerfettoDsRootTracePacket* root) {
259   root->writer.writer = PerfettoDsTracerImplPacketBegin(iterator->impl.tracer);
260   PerfettoPbMsgInit(&root->msg.msg, &root->writer);
261 }
262 
263 // Finishes writing the packet pointed by `root` on the data source instance
264 // pointer by `iterator`.
PerfettoDsTracerPacketEnd(struct PerfettoDsTracerIterator * iterator,struct PerfettoDsRootTracePacket * root)265 static inline void PerfettoDsTracerPacketEnd(
266     struct PerfettoDsTracerIterator* iterator,
267     struct PerfettoDsRootTracePacket* root) {
268   PerfettoPbMsgFinalize(&root->msg.msg);
269   PerfettoDsTracerImplPacketEnd(iterator->impl.tracer, &root->writer.writer);
270 }
271 
PerfettoDsTracerFlush(struct PerfettoDsTracerIterator * iterator,PerfettoDsTracerOnFlushCb cb,void * ctx)272 static inline void PerfettoDsTracerFlush(
273     struct PerfettoDsTracerIterator* iterator,
274     PerfettoDsTracerOnFlushCb cb,
275     void* ctx) {
276   PerfettoDsTracerImplFlush(iterator->impl.tracer, cb, ctx);
277 }
278 
279 #endif  // INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_
280