• 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/compiler.h"
26 #include "perfetto/public/pb_msg.h"
27 #include "perfetto/public/pb_utils.h"
28 #include "perfetto/public/protos/trace/trace_packet.pzc.h"
29 
30 // A data source type.
31 struct PerfettoDs {
32   // Pointer to a (atomic) boolean, which is set to true if there is at
33   // least one enabled instance of this data source type.
34   PERFETTO_ATOMIC(bool) * enabled;
35   struct PerfettoDsImpl* impl;
36 };
37 
38 // Initializes a PerfettoDs struct.
39 #define PERFETTO_DS_INIT() \
40   { &perfetto_atomic_false, PERFETTO_NULL }
41 
42 // All the callbacks are optional and can be NULL if not needed.
43 struct PerfettoDsCallbacks {
44   // Instance lifecycle callbacks:
45   PerfettoDsOnSetupCb on_setup_cb;
46   PerfettoDsOnStartCb on_start_cb;
47   PerfettoDsOnStopCb on_stop_cb;
48 
49   // These are called to create/delete custom thread-local instance state, which
50   // can be accessed with PerfettoDsTracerImplGetCustomTls().
51   PerfettoDsOnCreateCustomState on_create_tls_cb;
52   PerfettoDsOnDeleteCustomState on_delete_tls_cb;
53 
54   // These are called to create/delete custom thread-local instance incremental
55   // state. Incremental state may be cleared periodically by the tracing service
56   // and can be accessed with PerfettoDsTracerImplGetIncrementalState().
57   PerfettoDsOnCreateCustomState on_create_incr_cb;
58   PerfettoDsOnDeleteCustomState on_delete_incr_cb;
59 
60   // Passed to all the callbacks as the `user_arg` param.
61   void* user_arg;
62 };
63 
PerfettoDsNoCallbacks(void)64 static inline struct PerfettoDsCallbacks PerfettoDsNoCallbacks(void) {
65   struct PerfettoDsCallbacks ret = {PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL,
66                                     PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL,
67                                     PERFETTO_NULL, PERFETTO_NULL};
68   return ret;
69 }
70 
71 // Registers the data source type `ds`, named `data_source_name` with the global
72 // perfetto producer.
73 //
74 // `callbacks` are called when certain events happen on the data source type.
75 // PerfettoDsNoCallbacks() can be used if callbacks are not needed.
76 //
77 // TODO(ddiproietto): Accept the full DataSourceDescriptor, not just the
78 // data_source_name
PerfettoDsRegister(struct PerfettoDs * ds,const char * data_source_name,struct PerfettoDsCallbacks callbacks)79 static inline bool PerfettoDsRegister(struct PerfettoDs* ds,
80                                       const char* data_source_name,
81                                       struct PerfettoDsCallbacks callbacks) {
82   struct PerfettoDsImpl* ds_impl;
83   bool success;
84   // Build the DataSourceDescriptor protobuf message.
85   size_t data_source_name_len = strlen(data_source_name);
86   uint8_t* data_source_desc = PERFETTO_STATIC_CAST(
87       uint8_t*, malloc(data_source_name_len + PERFETTO_PB_VARINT_MAX_SIZE_32 +
88                        PERFETTO_PB_VARINT_MAX_SIZE_64));
89   uint8_t* write_ptr = data_source_desc;
90   const int32_t name_field_id = 1;  // perfetto.protos.DataSourceDescriptor.name
91   write_ptr = PerfettoPbWriteVarInt(
92       PerfettoPbMakeTag(name_field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED),
93       write_ptr);
94   write_ptr = PerfettoPbWriteVarInt(data_source_name_len, write_ptr);
95   memcpy(write_ptr, data_source_name, data_source_name_len);
96   write_ptr += data_source_name_len;
97 
98   ds_impl = PerfettoDsImplCreate();
99   if (callbacks.on_setup_cb) {
100     PerfettoDsSetOnSetupCallback(ds_impl, callbacks.on_setup_cb);
101   }
102   if (callbacks.on_start_cb) {
103     PerfettoDsSetOnStartCallback(ds_impl, callbacks.on_start_cb);
104   }
105   if (callbacks.on_stop_cb) {
106     PerfettoDsSetOnStopCallback(ds_impl, callbacks.on_stop_cb);
107   }
108   if (callbacks.on_create_tls_cb) {
109     PerfettoDsSetOnCreateTls(ds_impl, callbacks.on_create_tls_cb);
110   }
111   if (callbacks.on_delete_tls_cb) {
112     PerfettoDsSetOnDeleteTls(ds_impl, callbacks.on_delete_tls_cb);
113   }
114   if (callbacks.on_create_incr_cb) {
115     PerfettoDsSetOnCreateIncr(ds_impl, callbacks.on_create_incr_cb);
116   }
117   if (callbacks.on_delete_incr_cb) {
118     PerfettoDsSetOnDeleteIncr(ds_impl, callbacks.on_delete_incr_cb);
119   }
120   if (callbacks.user_arg) {
121     PerfettoDsSetCbUserArg(ds_impl, callbacks.user_arg);
122   }
123 
124   success = PerfettoDsImplRegister(
125       ds_impl, &ds->enabled, data_source_desc,
126       PERFETTO_STATIC_CAST(size_t, write_ptr - data_source_desc));
127   free(data_source_desc);
128   if (!success) {
129     return false;
130   }
131   ds->impl = ds_impl;
132   return true;
133 }
134 
135 // Iterator for all the active instances (on this thread) of a data source type.
136 struct PerfettoDsTracerIterator {
137   struct PerfettoDsImplTracerIterator impl;
138 };
139 
PerfettoDsTraceIterateBegin(struct PerfettoDs * ds)140 static inline struct PerfettoDsTracerIterator PerfettoDsTraceIterateBegin(
141     struct PerfettoDs* ds) {
142   struct PerfettoDsTracerIterator ret;
143   PERFETTO_ATOMIC(bool)* enabled = ds->enabled;
144   if (PERFETTO_LIKELY(!PERFETTO_ATOMIC_LOAD_EXPLICIT(
145           enabled, PERFETTO_MEMORY_ORDER_RELAXED))) {
146     // Tracing fast path: bail out immediately if the enabled flag is false.
147     ret.impl.tracer = PERFETTO_NULL;
148   } else {
149     // Else, make an ABI call to start iteration over the data source type
150     // active instances.
151     ret.impl = PerfettoDsImplTraceIterateBegin(ds->impl);
152   }
153   return ret;
154 }
155 
PerfettoDsTraceIterateNext(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)156 static inline void PerfettoDsTraceIterateNext(
157     struct PerfettoDs* ds,
158     struct PerfettoDsTracerIterator* iterator) {
159   PerfettoDsImplTraceIterateNext(ds->impl, &iterator->impl);
160 }
161 
PerfettoDsTraceIterateBreak(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)162 static inline void PerfettoDsTraceIterateBreak(
163     struct PerfettoDs* ds,
164     struct PerfettoDsTracerIterator* iterator) {
165   if (iterator->impl.tracer) {
166     PerfettoDsImplTraceIterateBreak(ds->impl, &iterator->impl);
167   }
168 }
169 
170 // For loop over the active instances of a data source type.
171 //
172 // `NAME` is the data source type (struct PerfettoDs).
173 //
174 // A local variable called `ITERATOR` will be instantiated. It can be used to
175 // perform tracing on each instance.
176 //
177 // N.B. The iteration MUST NOT be interrupted early with `break`.
178 // PERFETTO_DS_TRACE_BREAK should be used instead.
179 #define PERFETTO_DS_TRACE(NAME, ITERATOR)         \
180   for (struct PerfettoDsTracerIterator ITERATOR = \
181            PerfettoDsTraceIterateBegin(&(NAME));  \
182        (ITERATOR).impl.tracer != NULL;            \
183        PerfettoDsTraceIterateNext(&(NAME), &(ITERATOR)))
184 
185 // Used to break the iteration in a PERFETTO_DS_TRACE loop.
186 #define PERFETTO_DS_TRACE_BREAK(NAME, ITERATOR)      \
187   PerfettoDsTraceIterateBreak(&(NAME), &(ITERATOR)); \
188   break
189 
PerfettoDsGetCustomTls(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)190 static inline void* PerfettoDsGetCustomTls(
191     struct PerfettoDs* ds,
192     struct PerfettoDsTracerIterator* iterator) {
193   return PerfettoDsImplGetCustomTls(ds->impl, iterator->impl.tracer,
194                                     iterator->impl.inst_id);
195 }
196 
PerfettoDsGetIncrementalState(struct PerfettoDs * ds,struct PerfettoDsTracerIterator * iterator)197 static inline void* PerfettoDsGetIncrementalState(
198     struct PerfettoDs* ds,
199     struct PerfettoDsTracerIterator* iterator) {
200   return PerfettoDsImplGetIncrementalState(ds->impl, iterator->impl.tracer,
201                                            iterator->impl.inst_id);
202 }
203 
204 // Used to write a TracePacket on a data source instance. Stores the writer and
205 // the TracePacket message.
206 struct PerfettoDsRootTracePacket {
207   struct PerfettoPbMsgWriter writer;
208   struct perfetto_protos_TracePacket msg;
209 };
210 
211 // Initializes `root` to write a new packet to the data source instance pointed
212 // by `iterator`.
PerfettoDsTracerPacketBegin(struct PerfettoDsTracerIterator * iterator,struct PerfettoDsRootTracePacket * root)213 static inline void PerfettoDsTracerPacketBegin(
214     struct PerfettoDsTracerIterator* iterator,
215     struct PerfettoDsRootTracePacket* root) {
216   root->writer.writer = PerfettoDsTracerImplPacketBegin(iterator->impl.tracer);
217   PerfettoPbMsgInit(&root->msg.msg, &root->writer);
218 }
219 
220 // Finishes writing the packet pointed by `root` on the data source instance
221 // pointer by `iterator`.
PerfettoDsTracerPacketEnd(struct PerfettoDsTracerIterator * iterator,struct PerfettoDsRootTracePacket * root)222 static inline void PerfettoDsTracerPacketEnd(
223     struct PerfettoDsTracerIterator* iterator,
224     struct PerfettoDsRootTracePacket* root) {
225   PerfettoPbMsgFinalize(&root->msg.msg);
226   PerfettoDsTracerImplPacketEnd(iterator->impl.tracer, &root->writer.writer);
227 }
228 
PerfettoDsTracerFlush(struct PerfettoDsTracerIterator * iterator,PerfettoDsTracerOnFlushCb cb,void * ctx)229 static inline void PerfettoDsTracerFlush(
230     struct PerfettoDsTracerIterator* iterator,
231     PerfettoDsTracerOnFlushCb cb,
232     void* ctx) {
233   PerfettoDsTracerImplFlush(iterator->impl.tracer, cb, ctx);
234 }
235 
236 #endif  // INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_
237