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