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