• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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_TRACK_EVENT_H_
18 #define INCLUDE_PERFETTO_PUBLIC_TRACK_EVENT_H_
19 
20 #include <stdint.h>
21 #include <stdlib.h>
22 
23 #include "perfetto/public/abi/heap_buffer.h"
24 #include "perfetto/public/abi/track_event_abi.h"     // IWYU pragma: export
25 #include "perfetto/public/abi/track_event_hl_abi.h"  // IWYU pragma: export
26 #include "perfetto/public/abi/track_event_ll_abi.h"  // IWYU pragma: export
27 #include "perfetto/public/compiler.h"
28 #include "perfetto/public/data_source.h"
29 #include "perfetto/public/fnv1a.h"
30 #include "perfetto/public/pb_msg.h"
31 #include "perfetto/public/protos/trace/interned_data/interned_data.pzc.h"
32 #include "perfetto/public/protos/trace/trace_packet.pzc.h"
33 #include "perfetto/public/protos/trace/track_event/counter_descriptor.pzc.h"
34 #include "perfetto/public/protos/trace/track_event/track_descriptor.pzc.h"
35 #include "perfetto/public/protos/trace/track_event/track_event.pzc.h"
36 #include "perfetto/public/thread_utils.h"
37 
38 // A registered category.
39 struct PerfettoTeCategory {
40   PERFETTO_ATOMIC(bool) * enabled;
41   struct PerfettoTeCategoryImpl* impl;
42   struct PerfettoTeCategoryDescriptor desc;
43   uint64_t cat_iid;
44 };
45 
46 // Registers the category `cat`. `cat->desc` must be filled before calling this.
47 // The rest of the structure is filled by the function.
PerfettoTeCategoryRegister(struct PerfettoTeCategory * cat)48 static inline void PerfettoTeCategoryRegister(struct PerfettoTeCategory* cat) {
49   cat->impl = PerfettoTeCategoryImplCreate(&cat->desc);
50   cat->enabled = PerfettoTeCategoryImplGetEnabled(cat->impl);
51   cat->cat_iid = PerfettoTeCategoryImplGetIid(cat->impl);
52 }
53 
54 // Calls PerfettoTeCategoryRegister() on multiple categories.
PerfettoTeRegisterCategories(struct PerfettoTeCategory * cats[],size_t size)55 static inline void PerfettoTeRegisterCategories(
56     struct PerfettoTeCategory* cats[],
57     size_t size) {
58   for (size_t i = 0; i < size; i++) {
59     PerfettoTeCategoryRegister(cats[i]);
60   }
61 }
62 
63 // Registers `cb` to be called every time a data source instance with `reg_cat`
64 // enabled is created or destroyed. `user_arg` will be passed unaltered to `cb`.
65 //
66 // `cb` can be NULL to disable the callback.
PerfettoTeCategorySetCallback(struct PerfettoTeCategory * reg_cat,PerfettoTeCategoryImplCallback cb,void * user_arg)67 static inline void PerfettoTeCategorySetCallback(
68     struct PerfettoTeCategory* reg_cat,
69     PerfettoTeCategoryImplCallback cb,
70     void* user_arg) {
71   PerfettoTeCategoryImplSetCallback(reg_cat->impl, cb, user_arg);
72 }
73 
74 // Unregisters the category `cat`.
75 //
76 // WARNING: The category cannot be used for tracing anymore after this.
77 // Executing PERFETTO_TE() on an unregistered category will cause a null pointer
78 // dereference.
PerfettoTeCategoryUnregister(struct PerfettoTeCategory * cat)79 static inline void PerfettoTeCategoryUnregister(
80     struct PerfettoTeCategory* cat) {
81   PerfettoTeCategoryImplDestroy(cat->impl);
82   cat->impl = PERFETTO_NULL;
83   cat->enabled = &perfetto_atomic_false;
84   cat->cat_iid = 0;
85 }
86 
87 // Calls PerfettoTeCategoryUnregister() on multiple categories.
88 //
89 // WARNING: The categories cannot be used for tracing anymore after this.
90 // Executing PERFETTO_TE() on unregistered categories will cause a null pointer
91 // dereference.
PerfettoTeUnregisterCategories(struct PerfettoTeCategory * cats[],size_t size)92 static inline void PerfettoTeUnregisterCategories(
93     struct PerfettoTeCategory* cats[],
94     size_t size) {
95   for (size_t i = 0; i < size; i++) {
96     PerfettoTeCategoryUnregister(cats[i]);
97   }
98 }
99 
100 // A track. Must be registered before it can be used in trace events.
101 struct PerfettoTeRegisteredTrack {
102   struct PerfettoTeRegisteredTrackImpl impl;
103 };
104 
105 // Returns the track uuid for the current process.
PerfettoTeProcessTrackUuid(void)106 static inline uint64_t PerfettoTeProcessTrackUuid(void) {
107   return perfetto_te_process_track_uuid;
108 }
109 
110 // Returns the track uuid for the current thread.
PerfettoTeThreadTrackUuid(void)111 static inline uint64_t PerfettoTeThreadTrackUuid(void) {
112   return perfetto_te_process_track_uuid ^
113          PERFETTO_STATIC_CAST(uint64_t, PerfettoGetThreadId());
114 }
115 
116 // Returns the root track uuid.
PerfettoTeGlobalTrackUuid(void)117 static inline uint64_t PerfettoTeGlobalTrackUuid(void) {
118   return 0;
119 }
120 
121 // Computes the track uuid for a counter track named `name` whose parent track
122 // has `parent_uuid`.
PerfettoTeCounterTrackUuid(const char * name,uint64_t parent_uuid)123 static inline uint64_t PerfettoTeCounterTrackUuid(const char* name,
124                                                   uint64_t parent_uuid) {
125   const uint64_t kCounterMagic = 0xb1a4a67d7970839eul;
126   uint64_t uuid = kCounterMagic;
127   uuid ^= parent_uuid;
128   uuid ^= PerfettoFnv1a(name, strlen(name));
129   return uuid;
130 }
131 
132 // Computes the track uuid for a track named `name` with unique `id` whose
133 // parent track has `parent_uuid`.
PerfettoTeNamedTrackUuid(const char * name,uint64_t id,uint64_t parent_uuid)134 static inline uint64_t PerfettoTeNamedTrackUuid(const char* name,
135                                                 uint64_t id,
136                                                 uint64_t parent_uuid) {
137   uint64_t uuid = parent_uuid;
138   uuid ^= PerfettoFnv1a(name, strlen(name));
139   uuid ^= id;
140   return uuid;
141 }
142 
143 // Serializes the descriptor for a counter track named `name` with
144 // `parent_uuid`. `track_uuid` must be the return value of
145 // PerfettoTeCounterTrackUuid().
PerfettoTeCounterTrackFillDesc(struct perfetto_protos_TrackDescriptor * desc,const char * name,uint64_t parent_track_uuid,uint64_t track_uuid)146 static inline void PerfettoTeCounterTrackFillDesc(
147     struct perfetto_protos_TrackDescriptor* desc,
148     const char* name,
149     uint64_t parent_track_uuid,
150     uint64_t track_uuid) {
151   perfetto_protos_TrackDescriptor_set_uuid(desc, track_uuid);
152   if (parent_track_uuid) {
153     perfetto_protos_TrackDescriptor_set_parent_uuid(desc, parent_track_uuid);
154   }
155   perfetto_protos_TrackDescriptor_set_cstr_name(desc, name);
156   {
157     struct perfetto_protos_CounterDescriptor counter;
158     perfetto_protos_TrackDescriptor_begin_counter(desc, &counter);
159     perfetto_protos_TrackDescriptor_end_counter(desc, &counter);
160   }
161 }
162 
163 // Serializes the descriptor for a track named `name` with unique `id` and
164 // `parent_uuid`. `track_uuid` must be the return value of
165 // PerfettoTeNamedTrackUuid().
PerfettoTeNamedTrackFillDesc(struct perfetto_protos_TrackDescriptor * desc,const char * track_name,uint64_t id,uint64_t parent_track_uuid,uint64_t track_uuid)166 static inline void PerfettoTeNamedTrackFillDesc(
167     struct perfetto_protos_TrackDescriptor* desc,
168     const char* track_name,
169     uint64_t id,
170     uint64_t parent_track_uuid,
171     uint64_t track_uuid) {
172   (void)id;
173   perfetto_protos_TrackDescriptor_set_uuid(desc, track_uuid);
174   if (parent_track_uuid) {
175     perfetto_protos_TrackDescriptor_set_parent_uuid(desc, parent_track_uuid);
176   }
177   perfetto_protos_TrackDescriptor_set_cstr_name(desc, track_name);
178 }
179 
180 // Registers a track named `name` with unique `id` and `parent_uuid` into
181 // `track`.
PerfettoTeNamedTrackRegister(struct PerfettoTeRegisteredTrack * track,const char * name,uint64_t id,uint64_t parent_track_uuid)182 static inline void PerfettoTeNamedTrackRegister(
183     struct PerfettoTeRegisteredTrack* track,
184     const char* name,
185     uint64_t id,
186     uint64_t parent_track_uuid) {
187   uint64_t uuid;
188   // Build the TrackDescriptor protobuf message.
189   struct PerfettoPbMsgWriter writer;
190   struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
191   struct perfetto_protos_TrackDescriptor desc;
192   PerfettoPbMsgInit(&desc.msg, &writer);
193 
194   uuid = PerfettoTeNamedTrackUuid(name, id, parent_track_uuid);
195 
196   PerfettoTeNamedTrackFillDesc(&desc, name, id, parent_track_uuid, uuid);
197 
198   track->impl.descriptor_size =
199       PerfettoStreamWriterGetWrittenSize(&writer.writer);
200   track->impl.descriptor = malloc(track->impl.descriptor_size);
201   track->impl.uuid = uuid;
202   PerfettoHeapBufferCopyInto(hb, &writer.writer, track->impl.descriptor,
203                              track->impl.descriptor_size);
204   PerfettoHeapBufferDestroy(hb, &writer.writer);
205 }
206 
207 // Registers a counter track named `name` with and `parent_uuid` into `track`.
PerfettoTeCounterTrackRegister(struct PerfettoTeRegisteredTrack * track,const char * name,uint64_t parent_track_uuid)208 static inline void PerfettoTeCounterTrackRegister(
209     struct PerfettoTeRegisteredTrack* track,
210     const char* name,
211     uint64_t parent_track_uuid) {
212   uint64_t uuid;
213   struct PerfettoPbMsgWriter writer;
214   struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
215   struct perfetto_protos_TrackDescriptor desc;
216   PerfettoPbMsgInit(&desc.msg, &writer);
217 
218   uuid = PerfettoTeCounterTrackUuid(name, parent_track_uuid);
219 
220   PerfettoTeCounterTrackFillDesc(&desc, name, parent_track_uuid, uuid);
221 
222   track->impl.descriptor_size =
223       PerfettoStreamWriterGetWrittenSize(&writer.writer);
224   track->impl.descriptor = malloc(track->impl.descriptor_size);
225   track->impl.uuid = uuid;
226   PerfettoHeapBufferCopyInto(hb, &writer.writer, track->impl.descriptor,
227                              track->impl.descriptor_size);
228   PerfettoHeapBufferDestroy(hb, &writer.writer);
229 }
230 
231 // Unregisters the previously registered track `track`.
PerfettoTeRegisteredTrackUnregister(struct PerfettoTeRegisteredTrack * track)232 static inline void PerfettoTeRegisteredTrackUnregister(
233     struct PerfettoTeRegisteredTrack* track) {
234   free(track->impl.descriptor);
235   track->impl.descriptor = PERFETTO_NULL;
236   track->impl.descriptor_size = 0;
237 }
238 
239 // Identifies a flow: a link between two events.
240 struct PerfettoTeFlow {
241   uint64_t id;
242 };
243 
244 // Returns a flow that's scoped to this process. It can be used to link events
245 // inside this process.
PerfettoTeProcessScopedFlow(uint64_t id)246 static inline struct PerfettoTeFlow PerfettoTeProcessScopedFlow(uint64_t id) {
247   struct PerfettoTeFlow ret;
248   ret.id = id ^ perfetto_te_process_track_uuid;
249   return ret;
250 }
251 
252 // Returns a global flow. It can be used to link events between different
253 // processes.
PerfettoTeGlobalFlow(uint64_t id)254 static inline struct PerfettoTeFlow PerfettoTeGlobalFlow(uint64_t id) {
255   struct PerfettoTeFlow ret;
256   ret.id = id;
257   return ret;
258 }
259 
260 // Returns a static-category-like object used when dynamic categories are passed
261 // as extra parameters.
PerfettoTeRegisteredDynamicCategory(void)262 static inline struct PerfettoTeCategory PerfettoTeRegisteredDynamicCategory(
263     void) {
264   struct PerfettoTeCategory ret = {
265       perfetto_te_any_categories_enabled,
266       perfetto_te_any_categories,
267       {PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL, 0},
268       0};
269   return ret;
270 }
271 
272 // Iterator for all the active instances (on this thread) of a data source type.
273 struct PerfettoTeLlIterator {
274   struct PerfettoTeLlImplIterator impl;
275 };
276 
PerfettoTeLlBeginSlowPath(struct PerfettoTeCategory * cat,struct PerfettoTeTimestamp ts)277 static inline struct PerfettoTeLlIterator PerfettoTeLlBeginSlowPath(
278     struct PerfettoTeCategory* cat,
279     struct PerfettoTeTimestamp ts) {
280   struct PerfettoTeLlIterator ret;
281   ret.impl = PerfettoTeLlImplBegin(cat->impl, ts);
282   return ret;
283 }
284 
PerfettoTeLlNext(struct PerfettoTeCategory * cat,struct PerfettoTeTimestamp ts,struct PerfettoTeLlIterator * iterator)285 static inline void PerfettoTeLlNext(struct PerfettoTeCategory* cat,
286                                     struct PerfettoTeTimestamp ts,
287                                     struct PerfettoTeLlIterator* iterator) {
288   PerfettoTeLlImplNext(cat->impl, ts, &iterator->impl);
289 }
290 
PerfettoTeLlBreak(struct PerfettoTeCategory * cat,struct PerfettoTeLlIterator * iterator)291 static inline void PerfettoTeLlBreak(struct PerfettoTeCategory* cat,
292                                      struct PerfettoTeLlIterator* iterator) {
293   if (iterator->impl.ds.tracer) {
294     PerfettoTeLlImplBreak(cat->impl, &iterator->impl);
295   }
296 }
297 
298 // Checks if the category descriptor `dyn_cat` is enabled in the current active
299 // instance pointed by `iterator`.
PerfettoTeLlDynCatEnabled(struct PerfettoTeLlIterator * iterator,const struct PerfettoTeCategoryDescriptor * dyn_cat)300 static inline bool PerfettoTeLlDynCatEnabled(
301     struct PerfettoTeLlIterator* iterator,
302     const struct PerfettoTeCategoryDescriptor* dyn_cat) {
303   return PerfettoTeLlImplDynCatEnabled(iterator->impl.ds.tracer,
304                                        iterator->impl.ds.inst_id, dyn_cat);
305 }
306 
307 // Initializes `root` to write a new packet to the data source instance pointed
308 // by `iterator`.
PerfettoTeLlPacketBegin(struct PerfettoTeLlIterator * iterator,struct PerfettoDsRootTracePacket * root)309 static inline void PerfettoTeLlPacketBegin(
310     struct PerfettoTeLlIterator* iterator,
311     struct PerfettoDsRootTracePacket* root) {
312   root->writer.writer =
313       PerfettoDsTracerImplPacketBegin(iterator->impl.ds.tracer);
314   PerfettoPbMsgInit(&root->msg.msg, &root->writer);
315 }
316 
317 // Finishes writing the packet pointed by `root` on the data source instance
318 // pointer by `iterator`.
PerfettoTeLlPacketEnd(struct PerfettoTeLlIterator * iterator,struct PerfettoDsRootTracePacket * root)319 static inline void PerfettoTeLlPacketEnd(
320     struct PerfettoTeLlIterator* iterator,
321     struct PerfettoDsRootTracePacket* root) {
322   PerfettoPbMsgFinalize(&root->msg.msg);
323   PerfettoDsTracerImplPacketEnd(iterator->impl.ds.tracer, &root->writer.writer);
324 }
325 
PerfettoTeLlFlushPacket(struct PerfettoTeLlIterator * iterator)326 static inline void PerfettoTeLlFlushPacket(
327     struct PerfettoTeLlIterator* iterator) {
328   PerfettoDsTracerImplFlush(iterator->impl.ds.tracer, PERFETTO_NULL,
329                             PERFETTO_NULL);
330 }
331 
332 // Returns true if the track event incremental state has already seen in the
333 // past a track with `uuid` as track UUID.
PerfettoTeLlTrackSeen(struct PerfettoTeLlImplIncr * incr,uint64_t uuid)334 static inline bool PerfettoTeLlTrackSeen(struct PerfettoTeLlImplIncr* incr,
335                                          uint64_t uuid) {
336   return PerfettoTeLlImplTrackSeen(incr, uuid);
337 }
338 
339 // Interning:
340 //
341 // it's possible to avoid repeating the same data over and over in a trace by
342 // using "interning".
343 //
344 // `type` is a field id in the `perfetto.protos.InternedData` protobuf message.
345 // `data` and `data_size` point to the raw data that is potentially repeated.
346 // The function returns an integer (the iid) that can be used instead of
347 // serializing the data directly in the packet. `*seen` is set to false if this
348 // is the first time the library observed this data for this specific type
349 // (therefore it allocated a new iid).
PerfettoTeLlIntern(struct PerfettoTeLlImplIncr * incr,int32_t type,const void * data,size_t data_size,bool * seen)350 static inline uint64_t PerfettoTeLlIntern(struct PerfettoTeLlImplIncr* incr,
351                                           int32_t type,
352                                           const void* data,
353                                           size_t data_size,
354                                           bool* seen) {
355   return PerfettoTeLlImplIntern(incr, type, data, data_size, seen);
356 }
357 
358 // Used to lazily start, only if required, a nested InternedData submessage for
359 // a TracePacket `tp`. `incr` is the incremental state ABI pointer received from
360 // PerfettoTeLlIterator.
361 struct PerfettoTeLlInternContext {
362   struct PerfettoTeLlImplIncr* incr;
363   struct perfetto_protos_TracePacket* tp;
364   struct perfetto_protos_InternedData interned;
365   // true if the nested `interned` submessage has been started, false otherwise.
366   bool started;
367 };
368 
PerfettoTeLlInternContextInit(struct PerfettoTeLlInternContext * ctx,struct PerfettoTeLlImplIncr * incr,struct perfetto_protos_TracePacket * tp)369 static inline void PerfettoTeLlInternContextInit(
370     struct PerfettoTeLlInternContext* ctx,
371     struct PerfettoTeLlImplIncr* incr,
372     struct perfetto_protos_TracePacket* tp) {
373   ctx->incr = incr;
374   ctx->tp = tp;
375   ctx->started = false;
376 }
377 
PerfettoTeLlInternContextStartIfNeeded(struct PerfettoTeLlInternContext * ctx)378 static inline void PerfettoTeLlInternContextStartIfNeeded(
379     struct PerfettoTeLlInternContext* ctx) {
380   if (!ctx->started) {
381     ctx->started = true;
382     perfetto_protos_TracePacket_begin_interned_data(ctx->tp, &ctx->interned);
383   }
384 }
385 
PerfettoTeLlInternContextDestroy(struct PerfettoTeLlInternContext * ctx)386 static inline void PerfettoTeLlInternContextDestroy(
387     struct PerfettoTeLlInternContext* ctx) {
388   if (ctx->started) {
389     perfetto_protos_TracePacket_end_interned_data(ctx->tp, &ctx->interned);
390   }
391 }
392 
PerfettoTeLlInternRegisteredCat(struct PerfettoTeLlInternContext * ctx,struct PerfettoTeCategory * reg_cat)393 static inline void PerfettoTeLlInternRegisteredCat(
394     struct PerfettoTeLlInternContext* ctx,
395     struct PerfettoTeCategory* reg_cat) {
396   uint64_t iid = reg_cat->cat_iid;
397   bool seen;
398 
399   if (!iid) {
400     return;
401   }
402   PerfettoTeLlIntern(ctx->incr,
403                      perfetto_protos_InternedData_event_categories_field_number,
404                      &iid, sizeof(iid), &seen);
405   if (!seen) {
406     struct perfetto_protos_EventCategory event_category;
407     PerfettoTeLlInternContextStartIfNeeded(ctx);
408 
409     perfetto_protos_InternedData_begin_event_categories(&ctx->interned,
410                                                         &event_category);
411     perfetto_protos_EventCategory_set_iid(&event_category, iid);
412     perfetto_protos_EventCategory_set_cstr_name(&event_category,
413                                                 reg_cat->desc.name);
414     perfetto_protos_InternedData_end_event_categories(&ctx->interned,
415                                                       &event_category);
416   }
417 }
418 
PerfettoTeLlWriteRegisteredCat(struct perfetto_protos_TrackEvent * te,struct PerfettoTeCategory * reg_cat)419 static inline void PerfettoTeLlWriteRegisteredCat(
420     struct perfetto_protos_TrackEvent* te,
421     struct PerfettoTeCategory* reg_cat) {
422   if (reg_cat->cat_iid) {
423     perfetto_protos_TrackEvent_set_category_iids(te, reg_cat->cat_iid);
424   } else if (reg_cat->desc.name) {
425     perfetto_protos_TrackEvent_set_cstr_categories(te, reg_cat->desc.name);
426   }
427 }
428 
PerfettoTeLlWriteDynamicCat(struct perfetto_protos_TrackEvent * te,struct PerfettoTeCategoryDescriptor * dyn_cat,int32_t type)429 static inline void PerfettoTeLlWriteDynamicCat(
430     struct perfetto_protos_TrackEvent* te,
431     struct PerfettoTeCategoryDescriptor* dyn_cat,
432     int32_t type) {
433   if (dyn_cat && type != PERFETTO_TE_TYPE_SLICE_END &&
434       type != PERFETTO_TE_TYPE_COUNTER) {
435     perfetto_protos_TrackEvent_set_cstr_categories(te, dyn_cat->name);
436   }
437 }
438 
PerfettoTeLlInternEventName(struct PerfettoTeLlInternContext * ctx,const char * name)439 static inline uint64_t PerfettoTeLlInternEventName(
440     struct PerfettoTeLlInternContext* ctx,
441     const char* name) {
442   uint64_t iid = 0;
443   if (name) {
444     bool seen;
445     iid = PerfettoTeLlIntern(
446         ctx->incr, perfetto_protos_InternedData_event_names_field_number, name,
447         strlen(name), &seen);
448     if (!seen) {
449       struct perfetto_protos_EventName event_name;
450       PerfettoTeLlInternContextStartIfNeeded(ctx);
451       perfetto_protos_InternedData_begin_event_names(&ctx->interned,
452                                                      &event_name);
453       perfetto_protos_EventName_set_iid(&event_name, iid);
454       perfetto_protos_EventName_set_cstr_name(&event_name, name);
455       perfetto_protos_InternedData_end_event_names(&ctx->interned, &event_name);
456     }
457   }
458   return iid;
459 }
460 
PerfettoTeLlWriteEventName(struct perfetto_protos_TrackEvent * te,const char * name)461 static inline void PerfettoTeLlWriteEventName(
462     struct perfetto_protos_TrackEvent* te,
463     const char* name) {
464   if (name) {
465     perfetto_protos_TrackEvent_set_cstr_name(te, name);
466   }
467 }
468 
PerfettoTeLlWriteInternedEventName(struct perfetto_protos_TrackEvent * te,uint64_t iid)469 static inline void PerfettoTeLlWriteInternedEventName(
470     struct perfetto_protos_TrackEvent* te,
471     uint64_t iid) {
472   if (iid != 0) {
473     perfetto_protos_TrackEvent_set_name_iid(te, iid);
474   }
475 }
476 
PerfettoTeLlWriteTimestamp(struct perfetto_protos_TracePacket * tp,const struct PerfettoTeTimestamp * ts)477 static inline void PerfettoTeLlWriteTimestamp(
478     struct perfetto_protos_TracePacket* tp,
479     const struct PerfettoTeTimestamp* ts) {
480   uint32_t clock_id = ts->clock_id;
481   perfetto_protos_TracePacket_set_timestamp(tp, ts->value);
482   perfetto_protos_TracePacket_set_timestamp_clock_id(tp, clock_id);
483 }
484 
PerfettoTeLlInternDbgArgName(struct PerfettoTeLlInternContext * ctx,const char * name)485 static inline uint64_t PerfettoTeLlInternDbgArgName(
486     struct PerfettoTeLlInternContext* ctx,
487     const char* name) {
488   uint64_t iid = 0;
489   if (name) {
490     bool seen;
491     iid = PerfettoTeLlIntern(
492         ctx->incr,
493         perfetto_protos_InternedData_debug_annotation_names_field_number, name,
494         strlen(name), &seen);
495     if (!seen) {
496       struct perfetto_protos_EventName event_name;
497       PerfettoTeLlInternContextStartIfNeeded(ctx);
498       perfetto_protos_InternedData_begin_event_names(&ctx->interned,
499                                                      &event_name);
500       perfetto_protos_EventName_set_iid(&event_name, iid);
501       perfetto_protos_EventName_set_cstr_name(&event_name, name);
502       perfetto_protos_InternedData_end_event_names(&ctx->interned, &event_name);
503     }
504   }
505   return iid;
506 }
507 
508 #endif  // INCLUDE_PERFETTO_PUBLIC_TRACK_EVENT_H_
509