fuchsia_trace/
lib.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use pin_project::pin_project;
6use std::boxed::Box;
7use std::ffi::CStr;
8use std::future::Future;
9use std::marker::PhantomData;
10use std::pin::Pin;
11use std::task::Poll;
12use std::{mem, ptr};
13
14pub use sys::{
15    trace_site_t, TRACE_BLOB_TYPE_DATA, TRACE_BLOB_TYPE_LAST_BRANCH, TRACE_BLOB_TYPE_PERFETTO,
16};
17
18/// `Scope` represents the scope of a trace event.
19#[derive(Copy, Clone)]
20pub enum Scope {
21    Thread,
22    Process,
23    Global,
24}
25
26impl Scope {
27    fn into_raw(self) -> sys::trace_scope_t {
28        match self {
29            Scope::Thread => sys::TRACE_SCOPE_THREAD,
30            Scope::Process => sys::TRACE_SCOPE_PROCESS,
31            Scope::Global => sys::TRACE_SCOPE_GLOBAL,
32        }
33    }
34}
35
36/// Returns true if tracing is enabled.
37#[inline]
38pub fn is_enabled() -> bool {
39    // Trivial no-argument function that will not race
40    unsafe { sys::trace_state() != sys::TRACE_STOPPED }
41}
42
43/// Returns true if tracing has been enabled for the given category.
44pub fn category_enabled(category: &'static CStr) -> bool {
45    // Function requires a pointer to a static null-terminated string literal,
46    // which `&'static CStr` is.
47    unsafe { sys::trace_is_category_enabled(category.as_ptr()) }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub enum TraceState {
52    Stopped,
53    Started,
54    Stopping,
55}
56
57pub fn trace_state() -> TraceState {
58    match unsafe { sys::trace_state() } {
59        sys::TRACE_STOPPED => TraceState::Stopped,
60        sys::TRACE_STARTED => TraceState::Started,
61        sys::TRACE_STOPPING => TraceState::Stopping,
62        s => panic!("Unknown trace state {:?}", s),
63    }
64}
65
66/// An identifier for flows and async spans.
67#[repr(transparent)]
68#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
69pub struct Id(u64);
70
71impl Id {
72    /// Creates a new `Id`. `Id`s created by separate calls to `new` in the same process are
73    /// guaranteed to be distinct.
74    ///
75    /// WARNING: `Id::new` is likely to hit the UI bug where UIs group async
76    /// durations with the same trace id but different process ids. Use
77    /// `Id::random` instead. (Until https://fxbug.dev/42054669 is fixed.)
78    pub fn new() -> Self {
79        // Trivial no-argument function that cannot race.
80        Self(unsafe { sys::trace_generate_nonce() })
81    }
82
83    /// Creates a new `Id` based on the current montonic time and a random `u16` to, with high
84    /// probability, avoid the bug where UIs group async durations with the same trace id but
85    /// different process ids.
86    /// `Id::new` is likely to hit the UI bug because it (per process) generates trace ids
87    /// consecutively starting from 1.
88    /// https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/trace-engine/nonce.cc;l=15-17;drc=b1c2f508a59e6c87c617852ed3e424693a392646
89    /// TODO(https://fxbug.dev/42054669) Delete this and migrate clients to `Id::new` once UIs stop grouping
90    /// async durations with the same trace id but different process ids.
91    pub fn random() -> Self {
92        let ts = zx::BootInstant::get().into_nanos() as u64;
93        let high_order = ts << 16;
94        let low_order = rand::random::<u16>() as u64;
95        Self(high_order | low_order)
96    }
97}
98
99impl From<u64> for Id {
100    fn from(u: u64) -> Self {
101        Self(u)
102    }
103}
104
105impl From<Id> for u64 {
106    fn from(id: Id) -> Self {
107        id.0
108    }
109}
110
111/// `Arg` holds an argument to a tracing function, which can be one of many types.
112#[repr(transparent)]
113pub struct Arg<'a>(sys::trace_arg_t, PhantomData<&'a ()>);
114
115/// A trait for types that can be the values of an argument set.
116///
117/// This trait is not implementable by users of the library.
118/// Users should instead use one of the common types which implements
119/// `ArgValue`, such as `i32`, `f64`, or `&str`.
120pub trait ArgValue {
121    fn of<'a>(key: &'a str, value: Self) -> Arg<'a>
122    where
123        Self: 'a;
124}
125
126// Implements `arg_from` for many types.
127// $valname is the name to which to bind the `Self` value in the $value expr
128// $ty is the type
129// $tag is the union tag indicating the variant of trace_arg_union_t being used
130// $value is the union value for that particular type
131macro_rules! arg_from {
132    ($valname:ident, $(($type:ty, $tag:expr, $value:expr))*) => {
133        $(
134            impl ArgValue for $type {
135                #[inline]
136                fn of<'a>(key: &'a str, $valname: Self) -> Arg<'a>
137                    where Self: 'a
138                {
139                    #[allow(unused)]
140                    let $valname = $valname;
141
142                    Arg(sys::trace_arg_t {
143                        name_ref: trace_make_inline_string_ref(key),
144                        value: sys::trace_arg_value_t {
145                            type_: $tag,
146                            value: $value,
147                        },
148                    }, PhantomData)
149                }
150            }
151        )*
152    }
153}
154
155// Implement ArgFrom for a variety of types
156#[rustfmt::skip]
157arg_from!(val,
158    ((), sys::TRACE_ARG_NULL, sys::trace_arg_union_t { int32_value: 0 })
159    (bool, sys::TRACE_ARG_BOOL, sys::trace_arg_union_t { bool_value: val })
160    (i32, sys::TRACE_ARG_INT32, sys::trace_arg_union_t { int32_value: val })
161    (u32, sys::TRACE_ARG_UINT32, sys::trace_arg_union_t { uint32_value: val })
162    (i64, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val })
163    (u64, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val })
164    (isize, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val as i64 })
165    (usize, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val as u64 })
166    (f64, sys::TRACE_ARG_DOUBLE, sys::trace_arg_union_t { double_value: val })
167    (zx::Koid, sys::TRACE_ARG_KOID, sys::trace_arg_union_t { koid_value: val.raw_koid() })
168);
169
170impl<T> ArgValue for *const T {
171    #[inline]
172    fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
173    where
174        Self: 'a,
175    {
176        Arg(
177            sys::trace_arg_t {
178                name_ref: trace_make_inline_string_ref(key),
179                value: sys::trace_arg_value_t {
180                    type_: sys::TRACE_ARG_POINTER,
181                    value: sys::trace_arg_union_t { pointer_value: val as usize },
182                },
183            },
184            PhantomData,
185        )
186    }
187}
188
189impl<T> ArgValue for *mut T {
190    #[inline]
191    fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
192    where
193        Self: 'a,
194    {
195        Arg(
196            sys::trace_arg_t {
197                name_ref: trace_make_inline_string_ref(key),
198                value: sys::trace_arg_value_t {
199                    type_: sys::TRACE_ARG_POINTER,
200                    value: sys::trace_arg_union_t { pointer_value: val as usize },
201                },
202            },
203            PhantomData,
204        )
205    }
206}
207
208impl<'a> ArgValue for &'a str {
209    #[inline]
210    fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
211    where
212        Self: 'b,
213    {
214        Arg(
215            sys::trace_arg_t {
216                name_ref: trace_make_inline_string_ref(key),
217                value: sys::trace_arg_value_t {
218                    type_: sys::TRACE_ARG_STRING,
219                    value: sys::trace_arg_union_t {
220                        string_value_ref: trace_make_inline_string_ref(val),
221                    },
222                },
223            },
224            PhantomData,
225        )
226    }
227}
228
229/// Convenience macro for the `instant` function.
230///
231/// Example:
232///
233/// ```rust
234/// instant!(c"foo", c"bar", Scope::Process, "x" => 5, "y" => "boo");
235/// ```
236///
237/// is equivalent to
238///
239/// ```rust
240/// instant(c"foo", c"bar", Scope::Process,
241///     &[ArgValue::of("x", 5), ArgValue::of("y", "boo")]);
242/// ```
243/// or
244/// ```rust
245/// const FOO: &'static CStr = c"foo";
246/// const BAR: &'static CStr = c"bar";
247/// instant(FOO, BAR, Scope::Process,
248///     &[ArgValue::of("x", 5), ArgValue::of("y", "boo")]);
249/// ```
250#[macro_export]
251macro_rules! instant {
252    ($category:expr, $name:expr, $scope:expr $(, $key:expr => $val:expr)*) => {
253        {
254            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
255            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
256                $crate::instant(&context, $name, $scope, &[$($crate::ArgValue::of($key, $val)),*]);
257            }
258        }
259    }
260}
261
262/// Writes an instant event representing a single moment in time.
263/// The number of `args` must not be greater than 15.
264#[inline]
265pub fn instant(
266    context: &TraceCategoryContext,
267    name: &'static CStr,
268    scope: Scope,
269    args: &[Arg<'_>],
270) {
271    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
272
273    let name_ref = context.register_string_literal(name);
274    context.write_instant(name_ref, scope, args);
275}
276
277/// Convenience macro for the `alert` function.
278///
279/// Example:
280///
281/// ```rust
282/// alert!(c"foo", c"bar");
283/// ```
284///
285/// is equivalent to
286///
287/// ```rust
288/// alert(c"foo", c"bar");
289/// ```
290#[macro_export]
291macro_rules! alert {
292    ($category:expr, $name:expr) => {
293        $crate::alert($category, $name)
294    };
295}
296
297/// Sends an alert, which can be mapped to an action.
298pub fn alert(category: &'static CStr, name: &'static CStr) {
299    // trace_context_write_xxx functions require that:
300    // - category and name are static null-terminated strings (`&'static CStr).
301    // - the refs must be valid for the given call
302    unsafe {
303        let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
304        let context =
305            sys::trace_acquire_context_for_category(category.as_ptr(), category_ref.as_mut_ptr());
306        if context != ptr::null() {
307            sys::trace_context_send_alert(context, name.as_ptr());
308            sys::trace_release_context(context);
309        }
310    }
311}
312
313/// Convenience macro for the `counter` function.
314///
315/// Example:
316///
317/// ```rust
318/// let id = 555;
319/// counter!(c"foo", c"bar", id, "x" => 5, "y" => 10);
320/// ```
321///
322/// is equivalent to
323///
324/// ```rust
325/// let id = 555;
326/// counter(c"foo", c"bar", id,
327///     &[ArgValue::of("x", 5), ArgValue::of("y", 10)]);
328/// ```
329#[macro_export]
330macro_rules! counter {
331    ($category:expr, $name:expr, $counter_id:expr $(, $key:expr => $val:expr)*) => {
332        {
333            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
334            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
335                $crate::counter(&context, $name, $counter_id,
336                    &[$($crate::ArgValue::of($key, $val)),*])
337            }
338        }
339    }
340}
341
342/// Writes a counter event with the specified id.
343///
344/// The arguments to this event are numeric samples and are typically
345/// represented by the visualizer as a stacked area chart. The id serves to
346/// distinguish multiple instances of counters which share the same category
347/// and name within the same process.
348///
349/// 1 to 15 numeric arguments can be associated with an event, each of which is
350/// interpreted as a distinct time series.
351pub fn counter(
352    context: &TraceCategoryContext,
353    name: &'static CStr,
354    counter_id: u64,
355    args: &[Arg<'_>],
356) {
357    assert!(args.len() >= 1, "trace counter args must include at least one numeric argument");
358    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
359
360    let name_ref = context.register_string_literal(name);
361    context.write_counter(name_ref, counter_id, args);
362}
363
364/// The scope of a duration event, returned by the `duration` function and the `duration!` macro.
365/// The duration will be `end'ed` when this object is dropped.
366#[must_use = "DurationScope must be `end`ed to be recorded"]
367pub struct DurationScope<'a> {
368    category: &'static CStr,
369    name: &'static CStr,
370    args: &'a [Arg<'a>],
371    start_time: zx::BootTicks,
372}
373
374impl<'a> DurationScope<'a> {
375    /// Starts a new duration scope that starts now and will be end'ed when
376    /// this object is dropped.
377    pub fn begin(category: &'static CStr, name: &'static CStr, args: &'a [Arg<'_>]) -> Self {
378        let start_time = zx::BootTicks::get();
379        Self { category, name, args, start_time }
380    }
381}
382
383impl<'a> Drop for DurationScope<'a> {
384    fn drop(&mut self) {
385        if let Some(context) = TraceCategoryContext::acquire(self.category) {
386            let name_ref = context.register_string_literal(self.name);
387            context.write_duration(name_ref, self.start_time, self.args);
388        }
389    }
390}
391
392/// Write a "duration complete" record representing both the beginning and end of a duration.
393pub fn complete_duration(
394    category: &'static CStr,
395    name: &'static CStr,
396    start_time: zx::BootTicks,
397    args: &[Arg<'_>],
398) {
399    if let Some(context) = TraceCategoryContext::acquire(category) {
400        let name_ref = context.register_string_literal(name);
401        context.write_duration(name_ref, start_time, args);
402    }
403}
404
405/// Convenience macro for the `duration` function that can be used to trace
406/// the duration of a scope. If you need finer grained control over when a
407/// duration starts and stops, see `duration_begin` and `duration_end`.
408///
409/// Example:
410///
411/// ```rust
412///   {
413///       duration!(c"foo", c"bar", "x" => 5, "y" => 10);
414///       ...
415///       ...
416///       // event will be recorded on drop.
417///   }
418/// ```
419///
420/// is equivalent to
421///
422/// ```rust
423///   {
424///       let mut args;
425///       let _scope =  {
426///           static CACHE: trace_site_t = trace_site_t::new(0);
427///           if let Some(_context) = TraceCategoryContext::acquire_cached(c"foo", &CACHE) {
428///               args = [ArgValue::of("x", 5), ArgValue::of("y", 10)];
429///               Some($crate::duration(c"foo", c"bar", &args))
430///           } else {
431///               None
432///           }
433///       };
434///       ...
435///       ...
436///       // event will be recorded on drop.
437///   }
438/// ```
439#[macro_export]
440macro_rules! duration {
441    ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
442        let mut args;
443        let _scope =  {
444            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
445            // NB: It is intentional that _context is not used here.  This cached context is used to
446            // elide the expensive context lookup if tracing is disabled.  When the duration ends,
447            // it will do a second lookup, but this cost is dwarfed by the cost of writing the trace
448            // event, so this second lookup is irrelevant.  Retaining the context for the lifetime
449            // of the DurationScope to avoid this second lookup would prevent the trace buffers from
450            // flushing until the DurationScope is dropped.
451            if let Some(_context) =
452                    $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
453                args = [$($crate::ArgValue::of($key, $val)),*];
454                Some($crate::duration($category, $name, &args))
455            } else {
456                None
457            }
458        };
459    }
460}
461
462/// Writes a duration event which ends when the current scope exits, or the
463/// `end` method is manually called.
464///
465/// Durations describe work which is happening synchronously on one thread.
466/// They can be nested to represent a control flow stack.
467///
468/// 0 to 15 arguments can be associated with the event, each of which is used
469/// to annotate the duration with additional information.
470///
471/// NOTE: For performance reasons, it is advisable to create a cached context scope, which will
472/// avoid expensive lookups when tracing is disabled.  See the example in the `duration!` macro.
473pub fn duration<'a>(
474    category: &'static CStr,
475    name: &'static CStr,
476    args: &'a [Arg<'_>],
477) -> DurationScope<'a> {
478    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
479    DurationScope::begin(category, name, args)
480}
481
482/// Convenience macro for the `duration_begin` function.
483///
484/// Examples:
485///
486/// ```rust
487/// duration_begin!(c"foo", c"bar", "x" => 5, "y" => "boo");
488/// ```
489///
490/// ```rust
491/// const FOO: &'static CStr = c"foo";
492/// const BAR: &'static CStr = c"bar";
493/// duration_begin!(FOO, BAR, "x" => 5, "y" => "boo");
494/// ```
495#[macro_export]
496macro_rules! duration_begin {
497    ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
498        {
499            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
500            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
501                $crate::duration_begin(&context, $name,
502                                       &[$($crate::ArgValue::of($key, $val)),*])
503            }
504        }
505    };
506}
507
508/// Convenience macro for the `duration_end` function.
509///
510/// Examples:
511///
512/// ```rust
513/// duration_end!(c"foo", c"bar", "x" => 5, "y" => "boo");
514/// ```
515///
516/// ```rust
517/// const FOO: &'static CStr = c"foo";
518/// const BAR: &'static CStr = c"bar";
519/// duration_end!(FOO, BAR, "x" => 5, "y" => "boo");
520/// ```
521#[macro_export]
522macro_rules! duration_end {
523    ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
524        {
525            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
526            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
527                $crate::duration_end(&context, $name, &[$($crate::ArgValue::of($key, $val)),*])
528            }
529        }
530    };
531}
532
533/// Writes a duration begin event only.
534/// This event must be matched by a duration end event with the same category and name.
535///
536/// Durations describe work which is happening synchronously on one thread.
537/// They can be nested to represent a control flow stack.
538///
539/// 0 to 15 arguments can be associated with the event, each of which is used
540/// to annotate the duration with additional information.  The arguments provided
541/// to matching duration begin and duration end events are combined together in
542/// the trace; it is not necessary to repeat them.
543pub fn duration_begin(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
544    let ticks = zx::BootTicks::get();
545    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
546
547    let name_ref = context.register_string_literal(name);
548    context.write_duration_begin(ticks, name_ref, args);
549}
550
551/// Writes a duration end event only.
552///
553/// Durations describe work which is happening synchronously on one thread.
554/// They can be nested to represent a control flow stack.
555///
556/// 0 to 15 arguments can be associated with the event, each of which is used
557/// to annotate the duration with additional information.  The arguments provided
558/// to matching duration begin and duration end events are combined together in
559/// the trace; it is not necessary to repeat them.
560pub fn duration_end(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
561    let ticks = zx::BootTicks::get();
562    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
563
564    let name_ref = context.register_string_literal(name);
565    context.write_duration_end(ticks, name_ref, args);
566}
567
568/// AsyncScope maintains state around the context of async events generated via the
569/// async_enter! macro.
570#[must_use = "emits an end event when dropped, so if dropped immediately creates an essentially \
571              zero length duration that should just be an instant instead"]
572pub struct AsyncScope {
573    // AsyncScope::end uses std::mem::forget to bypass AsyncScope's Drop impl, so if any fields
574    // with Drop impls are added, AsyncScope::end should be updated.
575    id: Id,
576    category: &'static CStr,
577    name: &'static CStr,
578}
579impl AsyncScope {
580    /// Starts a new async event scope, generating a begin event now, and ended when the
581    /// object is dropped.
582    pub fn begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) -> Self {
583        async_begin(id, category, name, args);
584        Self { id, category, name }
585    }
586
587    /// Manually end the async event scope with `args` instead of waiting until the guard is
588    /// dropped (which would end the event scope with an empty `args`).
589    pub fn end(self, args: &[Arg<'_>]) {
590        let Self { id, category, name } = self;
591        async_end(id, category, name, args);
592        std::mem::forget(self);
593    }
594}
595
596impl Drop for AsyncScope {
597    fn drop(&mut self) {
598        // AsyncScope::end uses std::mem::forget to bypass this Drop impl (to avoid emitting
599        // extraneous end events), so any logic added to this Drop impl (or any fields added to
600        // AsyncScope that have Drop impls) should addressed (if necessary) in AsyncScope::end.
601        let Self { id, category, name } = *self;
602        async_end(id, category, name, &[]);
603    }
604}
605
606/// Writes an async event which ends when the current scope exits, or the `end` method is is
607/// manually called.
608///
609/// Async events describe concurrently-scheduled work items that may migrate between threads. They
610/// may be nested by sharing id, and are otherwise differentiated by their id.
611///
612/// 0 to 15 arguments can be associated with the event, each of which is used to annotate the
613/// duration with additional information.
614pub fn async_enter(
615    id: Id,
616    category: &'static CStr,
617    name: &'static CStr,
618    args: &[Arg<'_>],
619) -> AsyncScope {
620    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
621    AsyncScope::begin(id, category, name, args)
622}
623
624/// Convenience macro for the `async_enter` function, which can be used to trace the duration of a
625/// scope containing async code. This macro returns the drop guard, which the caller may then
626/// choose to manage.
627///
628/// Example:
629///
630/// ```rust
631/// {
632///     let id = Id::new();
633///     let _guard = async_enter!(id, c"foo", c"bar", "x" => 5, "y" => 10);
634///     ...
635///     ...
636///     // event recorded on drop
637/// }
638/// ```
639///
640/// is equivalent to
641///
642/// ```rust
643/// {
644///     let id = Id::new();
645///     let _guard = AsyncScope::begin(id, c"foo", c"bar", &[ArgValue::of("x", 5),
646///         ArgValue::of("y", 10)]);
647///     ...
648///     ...
649///     // event recorded on drop
650/// }
651/// ```
652///
653/// Calls to async_enter! may be nested.
654#[macro_export]
655macro_rules! async_enter {
656    ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
657        {
658            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
659            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
660                Some($crate::AsyncScope::begin($id, $category, $name, &[$($crate::ArgValue::of($key, $val)),*]))
661            } else {
662                None
663            }
664        }
665    }
666}
667
668/// Convenience macro for the `async_instant` function, which can be used to emit an async instant
669/// event.
670///
671/// Example:
672///
673/// ```rust
674/// {
675///     let id = Id::new();
676///     async_instant!(id, c"foo", c"bar", "x" => 5, "y" => 10);
677/// }
678/// ```
679///
680/// is equivalent to
681///
682/// ```rust
683/// {
684///     let id = Id::new();
685///     async_instant(
686///         id, c"foo", c"bar",
687///         &[ArgValue::of(c"x", 5), ArgValue::of("y", 10)]
688///     );
689/// }
690/// ```
691#[macro_export]
692macro_rules! async_instant {
693    ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
694        {
695            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
696            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
697                $crate::async_instant($id, &context, $name, &[$($crate::ArgValue::of($key, $val)),*]);
698            }
699        }
700    }
701}
702
703/// Writes an async begin event. This event must be matched by an async end event with the same
704/// id, category, and name. This function is intended to be called through use of the
705/// `async_enter!` macro.
706///
707/// Async events describe concurrent work that may or may not migrate threads, or be otherwise
708/// interleaved with other work on the same thread. They can be nested to represent a control
709/// flow stack.
710///
711/// 0 to 15 arguments can be associated with the event, each of which is used to annotate the
712/// async event with additional information. Arguments provided in matching async begin and end
713/// events are combined together in the trace; it is not necessary to repeat them.
714pub fn async_begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
715    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
716
717    if let Some(context) = TraceCategoryContext::acquire(category) {
718        let name_ref = context.register_string_literal(name);
719        context.write_async_begin(id, name_ref, args);
720    }
721}
722
723/// Writes an async end event. This event must be associated with a prior async begin event
724/// with the same id, category, and name. This function is intended to be called implicitly
725/// when the `AsyncScope` object created through use of the `async_enter!` macro is dropped.
726///
727/// Async events describe concurrent work that may or may not migrate threads, or be otherwise
728/// interleaved with other work on the same thread. They can be nested to represent a control
729/// flow stack.
730///
731/// 0 to 15 arguments can be associated with the event, each of which is used to annotate the
732/// async event with additional information. Arguments provided in matching async begin and end
733/// events are combined together in the trace; it is not necessary to repeat them.
734pub fn async_end(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
735    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
736
737    if let Some(context) = TraceCategoryContext::acquire(category) {
738        let name_ref = context.register_string_literal(name);
739        context.write_async_end(id, name_ref, args);
740    }
741}
742
743/// Writes an async instant event with the specified id.
744///
745/// Asynchronous events describe work that is happening asynchronously and that
746/// may span multiple threads.  Asynchronous events do not nest.  The id serves
747/// to correlate the progress of distinct asynchronous operations that share
748/// the same category and name within the same process.
749///
750/// 0 to 15 arguments can be associated with the event, each of which is used
751/// to annotate the asynchronous operation with additional information.  The
752/// arguments provided to matching async begin, async instant, and async end
753/// events are combined together in the trace; it is not necessary to repeat them.
754pub fn async_instant(
755    id: Id,
756    context: &TraceCategoryContext,
757    name: &'static CStr,
758    args: &[Arg<'_>],
759) {
760    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
761
762    let name_ref = context.register_string_literal(name);
763    context.write_async_instant(id, name_ref, args);
764}
765
766#[macro_export]
767macro_rules! blob {
768    ($category:expr, $name:expr, $bytes:expr $(, $key:expr => $val:expr)*) => {
769        {
770            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
771            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
772                $crate::blob_fn(&context, $name, $bytes, &[$($crate::ArgValue::of($key, $val)),*])
773            }
774        }
775    }
776}
777pub fn blob_fn(
778    context: &TraceCategoryContext,
779    name: &'static CStr,
780    bytes: &[u8],
781    args: &[Arg<'_>],
782) {
783    let name_ref = context.register_string_literal(name);
784    context.write_blob(name_ref, bytes, args);
785}
786
787/// Convenience macro for the `flow_begin` function.
788///
789/// Example:
790///
791/// ```rust
792/// let flow_id = 1234;
793/// flow_begin!(c"foo", c"bar", flow_id, "x" => 5, "y" => "boo");
794/// ```
795///
796/// ```rust
797/// const FOO: &'static CStr = c"foo";
798/// const BAR: &'static CStr = c"bar";
799/// flow_begin!(c"foo", c"bar", flow_id);
800/// ```
801#[macro_export]
802macro_rules! flow_begin {
803    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
804        {
805            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
806            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
807                $crate::flow_begin(&context, $name, $flow_id,
808                                   &[$($crate::ArgValue::of($key, $val)),*])
809            }
810        }
811    }
812}
813
814/// Convenience macro for the `flow_step` function.
815///
816/// Example:
817///
818/// ```rust
819/// let flow_id = 1234;
820/// flow_step!(c"foo", c"bar", flow_id, "x" => 5, "y" => "boo");
821/// ```
822///
823/// ```rust
824/// const FOO: &'static CStr = c"foo";
825/// const BAR: &'static CStr = c"bar";
826/// flow_step!(c"foo", c"bar", flow_id);
827/// ```
828#[macro_export]
829macro_rules! flow_step {
830    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
831        {
832            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
833            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
834                $crate::flow_step(&context, $name, $flow_id,
835                                  &[$($crate::ArgValue::of($key, $val)),*])
836            }
837        }
838    }
839}
840
841/// Convenience macro for the `flow_end` function.
842///
843/// Example:
844///
845/// ```rust
846/// let flow_id = 1234;
847/// flow_end!(c"foo", c"bar", flow_id, "x" => 5, "y" => "boo");
848/// ```
849///
850/// ```rust
851/// const FOO: &'static CStr = c"foo";
852/// const BAR: &'static CStr = c"bar";
853/// flow_end!(c"foo", c"bar", flow_id);
854/// ```
855#[macro_export]
856macro_rules! flow_end {
857    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
858        {
859            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
860            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
861                $crate::flow_end(&context, $name, $flow_id,
862                                 &[$($crate::ArgValue::of($key, $val)),*])
863            }
864        }
865    }
866}
867
868/// Writes a flow begin event with the specified id.
869/// This event may be followed by flow steps events and must be matched by
870/// a flow end event with the same category, name, and id.
871///
872/// Flow events describe control flow handoffs between threads or across processes.
873/// They are typically represented as arrows in a visualizer.  Flow arrows are
874/// from the end of the duration event which encloses the beginning of the flow
875/// to the beginning of the duration event which encloses the next step or the
876/// end of the flow.  The id serves to correlate flows which share the same
877/// category and name across processes.
878///
879/// This event must be enclosed in a duration event which represents where
880/// the flow handoff occurs.
881///
882/// 0 to 15 arguments can be associated with the event, each of which is used
883/// to annotate the flow with additional information.  The arguments provided
884/// to matching flow begin, flow step, and flow end events are combined together
885/// in the trace; it is not necessary to repeat them.
886pub fn flow_begin(
887    context: &TraceCategoryContext,
888    name: &'static CStr,
889    flow_id: Id,
890    args: &[Arg<'_>],
891) {
892    let ticks = zx::BootTicks::get();
893    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
894
895    let name_ref = context.register_string_literal(name);
896    context.write_flow_begin(ticks, name_ref, flow_id, args);
897}
898
899/// Writes a flow end event with the specified id.
900///
901/// Flow events describe control flow handoffs between threads or across processes.
902/// They are typically represented as arrows in a visualizer.  Flow arrows are
903/// from the end of the duration event which encloses the beginning of the flow
904/// to the beginning of the duration event which encloses the next step or the
905/// end of the flow.  The id serves to correlate flows which share the same
906/// category and name across processes.
907///
908/// This event must be enclosed in a duration event which represents where
909/// the flow handoff occurs.
910///
911/// 0 to 15 arguments can be associated with the event, each of which is used
912/// to annotate the flow with additional information.  The arguments provided
913/// to matching flow begin, flow step, and flow end events are combined together
914/// in the trace; it is not necessary to repeat them.
915pub fn flow_end(
916    context: &TraceCategoryContext,
917    name: &'static CStr,
918    flow_id: Id,
919    args: &[Arg<'_>],
920) {
921    let ticks = zx::BootTicks::get();
922    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
923
924    let name_ref = context.register_string_literal(name);
925    context.write_flow_end(ticks, name_ref, flow_id, args);
926}
927
928/// Writes a flow step event with the specified id.
929///
930/// Flow events describe control flow handoffs between threads or across processes.
931/// They are typically represented as arrows in a visualizer.  Flow arrows are
932/// from the end of the duration event which encloses the beginning of the flow
933/// to the beginning of the duration event which encloses the next step or the
934/// end of the flow.  The id serves to correlate flows which share the same
935/// category and name across processes.
936///
937/// This event must be enclosed in a duration event which represents where
938/// the flow handoff occurs.
939///
940/// 0 to 15 arguments can be associated with the event, each of which is used
941/// to annotate the flow with additional information.  The arguments provided
942/// to matching flow begin, flow step, and flow end events are combined together
943/// in the trace; it is not necessary to repeat them.
944pub fn flow_step(
945    context: &TraceCategoryContext,
946    name: &'static CStr,
947    flow_id: Id,
948    args: &[Arg<'_>],
949) {
950    let ticks = zx::BootTicks::get();
951    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
952
953    let name_ref = context.register_string_literal(name);
954    context.write_flow_step(ticks, name_ref, flow_id, args);
955}
956
957/// Convenience macro to emit the beginning of a flow attached to an instant event.
958///
959/// Flows must be attached to a duration event. This can be awkward when there isn't an obvious
960/// duration event to attach to, or the relevant duration is very small, which makes visualizing
961/// difficult. This emits a flow event wrapped in a self contained instant event that is also easy
962/// to see in the tracing UI.
963///
964/// Example:
965///
966/// ```rust
967/// let flow_id = 1234;
968/// instaflow_begin!(c"category", c"event", c"flow", flow_id, "x" => 5, "y" => "boo");
969/// ```
970#[macro_export]
971macro_rules! instaflow_begin {
972    (
973        $category:expr,
974        $event_name:expr,
975        $flow_name:expr,
976        $flow_id:expr
977        $(, $key:expr => $val:expr)*
978    ) => {
979        {
980            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
981            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
982                $crate::instaflow_begin(
983                    &context,
984                    $event_name,
985                    $flow_name,
986                    $flow_id,
987                    &[$($crate::ArgValue::of($key, $val)),*],
988                )
989            }
990        }
991    }
992}
993
994/// Convenience macro to emit the end of a flow attached to an instant event.
995///
996/// Flows must be attached to a duration event. This can be awkward when there isn't an obvious
997/// duration event to attach to, or the relevant duration is very small, which makes visualizing
998/// difficult. This emits a flow event wrapped in a self contained instant event that is also easy
999/// to see in the tracing UI.
1000///
1001/// Example:
1002///
1003/// ```rust
1004/// let flow_id = 1234;
1005/// instaflow_end!(c"category", c"event", c"flow", flow_id, "x" => 5, "y" => "boo");
1006/// ```
1007#[macro_export]
1008macro_rules! instaflow_end {
1009    (
1010        $category:expr,
1011        $event_name:expr,
1012        $flow_name:expr,
1013        $flow_id:expr
1014        $(, $key:expr => $val:expr)*
1015    ) => {
1016        {
1017            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1018            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1019                $crate::instaflow_end(
1020                    &context,
1021                    $event_name,
1022                    $flow_name,
1023                    $flow_id,
1024                    &[$($crate::ArgValue::of($key, $val)),*],
1025                )
1026            }
1027        }
1028    }
1029}
1030
1031/// Convenience macro to emit a step in a flow attached to an instant event.
1032///
1033/// Flows must be attached to a duration event. This can be awkward when there isn't an obvious
1034/// duration event to attach to, or the relevant duration is very small, which makes visualizing
1035/// difficult. This emits a flow event wrapped in a self contained instant event that is also easy
1036/// to see in the tracing UI.
1037///
1038/// Example:
1039///
1040/// ```rust
1041/// let flow_id = 1234;
1042/// instaflow_step!(c"category", c"event", c"flow", flow_id, "x" => 5, "y" => "boo");
1043/// ```
1044#[macro_export]
1045macro_rules! instaflow_step {
1046    (
1047        $category:expr,
1048        $event_name:expr,
1049        $flow_name:expr,
1050        $flow_id:expr
1051        $(, $key:expr => $val:expr)*
1052    ) => {
1053        {
1054            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1055            if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1056                $crate::instaflow_step(
1057                    &context,
1058                    $event_name,
1059                    $flow_name,
1060                    $flow_id,
1061                    &[$($crate::ArgValue::of($key, $val)),*],
1062                )
1063            }
1064        }
1065    }
1066}
1067
1068/// Convenience function to emit the beginning of a flow attached to an instant event.
1069///
1070/// Flow events describe control flow handoffs between threads or across processes. They are
1071/// typically represented as arrows in a visualizer. Flow arrows are from the end of the duration
1072/// event which encloses the beginning of the flow to the beginning of the duration event which
1073/// encloses the next step or the end of the flow. The id serves to correlate flows which share the
1074/// same category and name across processes.
1075///
1076/// 0 to 15 arguments can be associated with the event, each of which is used to annotate the flow
1077/// with additional information. The arguments provided to matching flow begin, flow step, and flow
1078/// end events are combined together in the trace; it is not necessary to repeat them.
1079pub fn instaflow_begin(
1080    context: &TraceCategoryContext,
1081    event_name: &'static CStr,
1082    flow_name: &'static CStr,
1083    flow_id: Id,
1084    args: &[Arg<'_>],
1085) {
1086    let ticks = zx::BootTicks::get();
1087    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1088
1089    let event_name_ref = context.register_string_literal(event_name);
1090    let flow_name_ref = context.register_string_literal(flow_name);
1091
1092    context.write_duration_begin(ticks, event_name_ref, args);
1093    context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1094    context.write_duration_end(ticks, event_name_ref, args);
1095}
1096
1097/// Convenience function to the end of a flow attached to an instant event.
1098///
1099/// Flow events describe control flow handoffs between threads or across processes. They are
1100/// typically represented as arrows in a visualizer. Flow arrows are from the end of the duration
1101/// event which encloses the beginning of the flow to the beginning of the duration event which
1102/// encloses the next step or the end of the flow. The id serves to correlate flows which share the
1103/// same category and name across processes.
1104///
1105/// 0 to 15 arguments can be associated with the event, each of which is used to annotate the flow
1106/// with additional information. The arguments provided to matching flow begin, flow step, and flow
1107/// end events are combined together in the trace; it is not necessary to repeat them.
1108pub fn instaflow_end(
1109    context: &TraceCategoryContext,
1110    event_name: &'static CStr,
1111    flow_name: &'static CStr,
1112    flow_id: Id,
1113    args: &[Arg<'_>],
1114) {
1115    let ticks = zx::BootTicks::get();
1116    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1117
1118    let event_name_ref = context.register_string_literal(event_name);
1119    let flow_name_ref = context.register_string_literal(flow_name);
1120
1121    context.write_duration_begin(ticks, event_name_ref, args);
1122    context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1123    context.write_duration_end(ticks, event_name_ref, args);
1124}
1125
1126/// Convenience function to emit a step in a flow attached to an instant event.
1127///
1128/// Flow events describe control flow handoffs between threads or across processes. They are
1129/// typically represented as arrows in a visualizer. Flow arrows are from the end of the duration
1130/// event which encloses the beginning of the flow to the beginning of the duration event which
1131/// encloses the next step or the end of the flow. The id serves to correlate flows which share the
1132/// same category and name across processes.
1133///
1134/// 0 to 15 arguments can be associated with the event, each of which is used to annotate the flow
1135/// with additional information. The arguments provided to matching flow begin, flow step, and flow
1136/// end events are combined together in the trace; it is not necessary to repeat them.
1137pub fn instaflow_step(
1138    context: &TraceCategoryContext,
1139    event_name: &'static CStr,
1140    flow_name: &'static CStr,
1141    flow_id: Id,
1142    args: &[Arg<'_>],
1143) {
1144    let ticks = zx::BootTicks::get();
1145    assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1146
1147    let event_name_ref = context.register_string_literal(event_name);
1148    let flow_name_ref = context.register_string_literal(flow_name);
1149
1150    context.write_duration_begin(ticks, event_name_ref, args);
1151    context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1152    context.write_duration_end(ticks, event_name_ref, args);
1153}
1154
1155// translated from trace-engine/types.h for inlining
1156const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1157    sys::trace_string_ref_t {
1158        encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1159        inline_string: ptr::null(),
1160    }
1161}
1162
1163#[inline]
1164fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1165    let mut len = string.len();
1166    if string.len() > max_len {
1167        // Trim to the last unicode character that fits within the max length.
1168        // We search for the last character boundary that is immediately followed
1169        // by another character boundary (end followed by beginning).
1170        len = max_len;
1171        while len > 0 {
1172            if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1173                break;
1174            }
1175            len -= 1;
1176        }
1177    }
1178    &string.as_bytes()[0..len]
1179}
1180
1181// translated from trace-engine/types.h for inlining
1182// The resulting `trace_string_ref_t` only lives as long as the input `string`.
1183#[inline]
1184fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1185    let len = string.len() as u32;
1186    if len == 0 {
1187        return trace_make_empty_string_ref();
1188    }
1189
1190    let string =
1191        trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH as usize);
1192
1193    sys::trace_string_ref_t {
1194        encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1195        inline_string: string.as_ptr() as *const libc::c_char,
1196    }
1197}
1198
1199/// RAII wrapper for a trace context for a specific category.
1200pub struct TraceCategoryContext {
1201    raw: *const sys::trace_context_t,
1202    category_ref: sys::trace_string_ref_t,
1203}
1204
1205impl TraceCategoryContext {
1206    #[inline]
1207    pub fn acquire_cached(
1208        category: &'static CStr,
1209        site: &sys::trace_site_t,
1210    ) -> Option<TraceCategoryContext> {
1211        unsafe {
1212            // SAFETY: The call to `trace_acquire_context_for_category_cached` is sound because
1213            // all arguments are live and non-null. If this function returns a non-null
1214            // pointer then it also guarantees that `category_ref` will have been initialized.
1215            // Internally, it uses relaxed atomic semantics to load and store site.
1216            let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1217            let raw = sys::trace_acquire_context_for_category_cached(
1218                category.as_ptr(),
1219                site.as_ptr(),
1220                category_ref.as_mut_ptr(),
1221            );
1222            if raw != ptr::null() {
1223                Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1224            } else {
1225                None
1226            }
1227        }
1228    }
1229
1230    pub fn acquire(category: &'static CStr) -> Option<TraceCategoryContext> {
1231        unsafe {
1232            let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1233            let raw = sys::trace_acquire_context_for_category(
1234                category.as_ptr(),
1235                category_ref.as_mut_ptr(),
1236            );
1237            if raw != ptr::null() {
1238                Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1239            } else {
1240                None
1241            }
1242        }
1243    }
1244
1245    #[inline]
1246    pub fn register_string_literal(&self, name: &'static CStr) -> sys::trace_string_ref_t {
1247        unsafe {
1248            let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1249            sys::trace_context_register_string_literal(
1250                self.raw,
1251                name.as_ptr(),
1252                name_ref.as_mut_ptr(),
1253            );
1254            name_ref.assume_init()
1255        }
1256    }
1257
1258    #[inline]
1259    fn register_current_thread(&self) -> sys::trace_thread_ref_t {
1260        unsafe {
1261            let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1262            sys::trace_context_register_current_thread(self.raw, thread_ref.as_mut_ptr());
1263            thread_ref.assume_init()
1264        }
1265    }
1266
1267    #[inline]
1268    pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
1269        let ticks = zx::BootTicks::get();
1270        let thread_ref = self.register_current_thread();
1271        unsafe {
1272            sys::trace_context_write_instant_event_record(
1273                self.raw,
1274                ticks.into_raw(),
1275                &thread_ref,
1276                &self.category_ref,
1277                &name_ref,
1278                scope.into_raw(),
1279                args.as_ptr() as *const sys::trace_arg_t,
1280                args.len(),
1281            );
1282        }
1283    }
1284
1285    pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
1286        let name_ref = trace_make_inline_string_ref(name);
1287        self.write_instant(name_ref, scope, args)
1288    }
1289
1290    fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
1291        let ticks = zx::BootTicks::get();
1292        let thread_ref = self.register_current_thread();
1293        unsafe {
1294            sys::trace_context_write_counter_event_record(
1295                self.raw,
1296                ticks.into_raw(),
1297                &thread_ref,
1298                &self.category_ref,
1299                &name_ref,
1300                counter_id,
1301                args.as_ptr() as *const sys::trace_arg_t,
1302                args.len(),
1303            );
1304        }
1305    }
1306
1307    pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
1308        let name_ref = trace_make_inline_string_ref(name);
1309        self.write_counter(name_ref, counter_id, args);
1310    }
1311
1312    fn write_duration(
1313        &self,
1314        name_ref: sys::trace_string_ref_t,
1315        start_time: zx::BootTicks,
1316        args: &[Arg<'_>],
1317    ) {
1318        let ticks = zx::BootTicks::get();
1319        let thread_ref = self.register_current_thread();
1320        unsafe {
1321            sys::trace_context_write_duration_event_record(
1322                self.raw,
1323                start_time.into_raw(),
1324                ticks.into_raw(),
1325                &thread_ref,
1326                &self.category_ref,
1327                &name_ref,
1328                args.as_ptr() as *const sys::trace_arg_t,
1329                args.len(),
1330            );
1331        }
1332    }
1333
1334    pub fn write_duration_with_inline_name(
1335        &self,
1336        name: &str,
1337        start_time: zx::BootTicks,
1338        args: &[Arg<'_>],
1339    ) {
1340        let name_ref = trace_make_inline_string_ref(name);
1341        self.write_duration(name_ref, start_time, args);
1342    }
1343
1344    fn write_duration_begin(
1345        &self,
1346        ticks: zx::BootTicks,
1347        name_ref: sys::trace_string_ref_t,
1348        args: &[Arg<'_>],
1349    ) {
1350        let thread_ref = self.register_current_thread();
1351        unsafe {
1352            sys::trace_context_write_duration_begin_event_record(
1353                self.raw,
1354                ticks.into_raw(),
1355                &thread_ref,
1356                &self.category_ref,
1357                &name_ref,
1358                args.as_ptr() as *const sys::trace_arg_t,
1359                args.len(),
1360            );
1361        }
1362    }
1363
1364    pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1365        let name_ref = trace_make_inline_string_ref(name);
1366        self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
1367    }
1368
1369    fn write_duration_end(
1370        &self,
1371        ticks: zx::BootTicks,
1372        name_ref: sys::trace_string_ref_t,
1373        args: &[Arg<'_>],
1374    ) {
1375        let thread_ref = self.register_current_thread();
1376        unsafe {
1377            sys::trace_context_write_duration_end_event_record(
1378                self.raw,
1379                ticks.into_raw(),
1380                &thread_ref,
1381                &self.category_ref,
1382                &name_ref,
1383                args.as_ptr() as *const sys::trace_arg_t,
1384                args.len(),
1385            );
1386        }
1387    }
1388
1389    pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1390        let name_ref = trace_make_inline_string_ref(name);
1391        self.write_duration_end(zx::BootTicks::get(), name_ref, args);
1392    }
1393
1394    fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1395        let ticks = zx::BootTicks::get();
1396        let thread_ref = self.register_current_thread();
1397        unsafe {
1398            sys::trace_context_write_async_begin_event_record(
1399                self.raw,
1400                ticks.into_raw(),
1401                &thread_ref,
1402                &self.category_ref,
1403                &name_ref,
1404                id.into(),
1405                args.as_ptr() as *const sys::trace_arg_t,
1406                args.len(),
1407            );
1408        }
1409    }
1410
1411    pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1412        let name_ref = trace_make_inline_string_ref(name);
1413        self.write_async_begin(id, name_ref, args);
1414    }
1415
1416    fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1417        let ticks = zx::BootTicks::get();
1418        let thread_ref = self.register_current_thread();
1419        unsafe {
1420            sys::trace_context_write_async_end_event_record(
1421                self.raw,
1422                ticks.into_raw(),
1423                &thread_ref,
1424                &self.category_ref,
1425                &name_ref,
1426                id.into(),
1427                args.as_ptr() as *const sys::trace_arg_t,
1428                args.len(),
1429            );
1430        }
1431    }
1432
1433    pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1434        let name_ref = trace_make_inline_string_ref(name);
1435        self.write_async_end(id, name_ref, args);
1436    }
1437
1438    fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1439        let ticks = zx::BootTicks::get();
1440        let thread_ref = self.register_current_thread();
1441        unsafe {
1442            sys::trace_context_write_async_instant_event_record(
1443                self.raw,
1444                ticks.into_raw(),
1445                &thread_ref,
1446                &self.category_ref,
1447                &name_ref,
1448                id.into(),
1449                args.as_ptr() as *const sys::trace_arg_t,
1450                args.len(),
1451            );
1452        }
1453    }
1454
1455    fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
1456        let ticks = zx::BootTicks::get();
1457        let thread_ref = self.register_current_thread();
1458        unsafe {
1459            sys::trace_context_write_blob_event_record(
1460                self.raw,
1461                ticks.into_raw(),
1462                &thread_ref,
1463                &self.category_ref,
1464                &name_ref,
1465                bytes.as_ptr() as *const core::ffi::c_void,
1466                bytes.len(),
1467                args.as_ptr() as *const sys::trace_arg_t,
1468                args.len(),
1469            );
1470        }
1471    }
1472
1473    fn write_flow_begin(
1474        &self,
1475        ticks: zx::BootTicks,
1476        name_ref: sys::trace_string_ref_t,
1477        flow_id: Id,
1478        args: &[Arg<'_>],
1479    ) {
1480        let thread_ref = self.register_current_thread();
1481        unsafe {
1482            sys::trace_context_write_flow_begin_event_record(
1483                self.raw,
1484                ticks.into_raw(),
1485                &thread_ref,
1486                &self.category_ref,
1487                &name_ref,
1488                flow_id.into(),
1489                args.as_ptr() as *const sys::trace_arg_t,
1490                args.len(),
1491            );
1492        }
1493    }
1494
1495    fn write_flow_end(
1496        &self,
1497        ticks: zx::BootTicks,
1498        name_ref: sys::trace_string_ref_t,
1499        flow_id: Id,
1500        args: &[Arg<'_>],
1501    ) {
1502        let thread_ref = self.register_current_thread();
1503        unsafe {
1504            sys::trace_context_write_flow_end_event_record(
1505                self.raw,
1506                ticks.into_raw(),
1507                &thread_ref,
1508                &self.category_ref,
1509                &name_ref,
1510                flow_id.into(),
1511                args.as_ptr() as *const sys::trace_arg_t,
1512                args.len(),
1513            );
1514        }
1515    }
1516
1517    fn write_flow_step(
1518        &self,
1519        ticks: zx::BootTicks,
1520        name_ref: sys::trace_string_ref_t,
1521        flow_id: Id,
1522        args: &[Arg<'_>],
1523    ) {
1524        let thread_ref = self.register_current_thread();
1525        unsafe {
1526            sys::trace_context_write_flow_step_event_record(
1527                self.raw,
1528                ticks.into_raw(),
1529                &thread_ref,
1530                &self.category_ref,
1531                &name_ref,
1532                flow_id.into(),
1533                args.as_ptr() as *const sys::trace_arg_t,
1534                args.len(),
1535            );
1536        }
1537    }
1538}
1539
1540impl std::ops::Drop for TraceCategoryContext {
1541    fn drop(&mut self) {
1542        unsafe {
1543            sys::trace_release_context(self.raw);
1544        }
1545    }
1546}
1547
1548/// RAII wrapper for trace contexts without a specific associated category.
1549pub struct Context {
1550    context: *const sys::trace_context_t,
1551}
1552
1553impl Context {
1554    #[inline]
1555    pub fn acquire() -> Option<Self> {
1556        let context = unsafe { sys::trace_acquire_context() };
1557        if context.is_null() {
1558            None
1559        } else {
1560            Some(Self { context })
1561        }
1562    }
1563
1564    #[inline]
1565    pub fn register_string_literal(&self, s: &'static CStr) -> sys::trace_string_ref_t {
1566        unsafe {
1567            let mut s_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1568            sys::trace_context_register_string_literal(
1569                self.context,
1570                s.as_ptr(),
1571                s_ref.as_mut_ptr(),
1572            );
1573            s_ref.assume_init()
1574        }
1575    }
1576
1577    pub fn write_blob_record(
1578        &self,
1579        type_: sys::trace_blob_type_t,
1580        name_ref: &sys::trace_string_ref_t,
1581        data: &[u8],
1582    ) {
1583        unsafe {
1584            sys::trace_context_write_blob_record(
1585                self.context,
1586                type_,
1587                name_ref as *const sys::trace_string_ref_t,
1588                data.as_ptr() as *const libc::c_void,
1589                data.len(),
1590            );
1591        }
1592    }
1593}
1594
1595impl std::ops::Drop for Context {
1596    fn drop(&mut self) {
1597        unsafe { sys::trace_release_context(self.context) }
1598    }
1599}
1600
1601pub struct ProlongedContext {
1602    context: *const sys::trace_prolonged_context_t,
1603}
1604
1605impl ProlongedContext {
1606    pub fn acquire() -> Option<Self> {
1607        let context = unsafe { sys::trace_acquire_prolonged_context() };
1608        if context.is_null() {
1609            None
1610        } else {
1611            Some(Self { context })
1612        }
1613    }
1614}
1615
1616impl Drop for ProlongedContext {
1617    fn drop(&mut self) {
1618        unsafe { sys::trace_release_prolonged_context(self.context) }
1619    }
1620}
1621
1622unsafe impl Send for ProlongedContext {}
1623
1624mod sys {
1625    #![allow(non_camel_case_types, unused)]
1626    use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
1627
1628    pub type trace_ticks_t = zx_ticks_t;
1629    pub type trace_counter_id_t = u64;
1630    pub type trace_async_id_t = u64;
1631    pub type trace_flow_id_t = u64;
1632    pub type trace_thread_state_t = u32;
1633    pub type trace_cpu_number_t = u32;
1634    pub type trace_string_index_t = u32;
1635    pub type trace_thread_index_t = u32;
1636    pub type trace_context_t = libc::c_void;
1637    pub type trace_prolonged_context_t = libc::c_void;
1638
1639    pub type trace_encoded_string_ref_t = u32;
1640    pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
1641    pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
1642    pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
1643    pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: trace_encoded_string_ref_t = 32000;
1644    pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
1645    pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
1646
1647    pub type trace_encoded_thread_ref_t = u32;
1648    pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
1649    pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
1650    pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
1651
1652    pub type trace_state_t = libc::c_int;
1653    pub const TRACE_STOPPED: trace_state_t = 0;
1654    pub const TRACE_STARTED: trace_state_t = 1;
1655    pub const TRACE_STOPPING: trace_state_t = 2;
1656
1657    pub type trace_scope_t = libc::c_int;
1658    pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
1659    pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
1660    pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
1661
1662    pub type trace_blob_type_t = libc::c_int;
1663    pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
1664    pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
1665    pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
1666
1667    #[repr(C)]
1668    #[derive(Copy, Clone)]
1669    pub struct trace_string_ref_t {
1670        pub encoded_value: trace_encoded_string_ref_t,
1671        pub inline_string: *const libc::c_char,
1672    }
1673
1674    // trace_site_t is an opaque type that trace-engine uses per callsite to cache if the trace
1675    // point is enabled. Internally, it is a 8 byte allocation accessed with relaxed atomic
1676    // semantics.
1677    pub type trace_site_t = std::sync::atomic::AtomicU64;
1678
1679    // A trace_string_ref_t object is created from a string slice.
1680    // The trace_string_ref_t object is contained inside an Arg object.
1681    // whose lifetime matches the string slice to ensure that the memory
1682    // cannot be de-allocated during the trace.
1683    //
1684    // trace_string_ref_t is safe for Send + Sync because the memory that
1685    // inline_string points to is guaranteed to be valid throughout the trace.
1686    //
1687    // For more information, see the ArgValue implementation for &str in this file.
1688    unsafe impl Send for trace_string_ref_t {}
1689    unsafe impl Sync for trace_string_ref_t {}
1690
1691    #[repr(C)]
1692    pub struct trace_thread_ref_t {
1693        pub encoded_value: trace_encoded_thread_ref_t,
1694        pub inline_process_koid: zx_koid_t,
1695        pub inline_thread_koid: zx_koid_t,
1696    }
1697
1698    #[repr(C)]
1699    pub struct trace_arg_t {
1700        pub name_ref: trace_string_ref_t,
1701        pub value: trace_arg_value_t,
1702    }
1703
1704    #[repr(C)]
1705    pub union trace_arg_union_t {
1706        pub int32_value: i32,
1707        pub uint32_value: u32,
1708        pub int64_value: i64,
1709        pub uint64_value: u64,
1710        pub double_value: libc::c_double,
1711        pub string_value_ref: trace_string_ref_t,
1712        pub pointer_value: libc::uintptr_t,
1713        pub koid_value: zx_koid_t,
1714        pub bool_value: bool,
1715        pub reserved_for_future_expansion: [libc::uintptr_t; 2],
1716    }
1717
1718    pub type trace_arg_type_t = libc::c_int;
1719    pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
1720    pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
1721    pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
1722    pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
1723    pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
1724    pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
1725    pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
1726    pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
1727    pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
1728    pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
1729
1730    #[repr(C)]
1731    pub struct trace_arg_value_t {
1732        pub type_: trace_arg_type_t,
1733        pub value: trace_arg_union_t,
1734    }
1735
1736    #[repr(C)]
1737    pub struct trace_handler_ops_t {
1738        pub is_category_enabled:
1739            unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
1740        pub trace_started: unsafe fn(handler: *const trace_handler_t),
1741        pub trace_stopped: unsafe fn(
1742            handler: *const trace_handler_t,
1743            async_ptr: *const (), //async_t,
1744            disposition: zx_status_t,
1745            buffer_bytes_written: libc::size_t,
1746        ),
1747        pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
1748    }
1749
1750    #[repr(C)]
1751    pub struct trace_handler_t {
1752        pub ops: *const trace_handler_ops_t,
1753    }
1754
1755    // From libtrace-engine.so
1756    extern "C" {
1757        // From trace-engine/context.h
1758
1759        pub fn trace_context_is_category_enabled(
1760            context: *const trace_context_t,
1761            category_literal: *const libc::c_char,
1762        ) -> bool;
1763
1764        pub fn trace_context_register_string_copy(
1765            context: *const trace_context_t,
1766            string: *const libc::c_char,
1767            length: libc::size_t,
1768            out_ref: *mut trace_string_ref_t,
1769        );
1770
1771        pub fn trace_context_register_string_literal(
1772            context: *const trace_context_t,
1773            string_literal: *const libc::c_char,
1774            out_ref: *mut trace_string_ref_t,
1775        );
1776
1777        pub fn trace_context_register_category_literal(
1778            context: *const trace_context_t,
1779            category_literal: *const libc::c_char,
1780            out_ref: *mut trace_string_ref_t,
1781        ) -> bool;
1782
1783        pub fn trace_context_register_current_thread(
1784            context: *const trace_context_t,
1785            out_ref: *mut trace_thread_ref_t,
1786        );
1787
1788        pub fn trace_context_register_thread(
1789            context: *const trace_context_t,
1790            process_koid: zx_koid_t,
1791            thread_koid: zx_koid_t,
1792            out_ref: *mut trace_thread_ref_t,
1793        );
1794
1795        pub fn trace_context_write_kernel_object_record(
1796            context: *const trace_context_t,
1797            koid: zx_koid_t,
1798            type_: zx_obj_type_t,
1799            args: *const trace_arg_t,
1800            num_args: libc::size_t,
1801        );
1802
1803        pub fn trace_context_write_kernel_object_record_for_handle(
1804            context: *const trace_context_t,
1805            handle: zx_handle_t,
1806            args: *const trace_arg_t,
1807            num_args: libc::size_t,
1808        );
1809
1810        pub fn trace_context_write_process_info_record(
1811            context: *const trace_context_t,
1812            process_koid: zx_koid_t,
1813            process_name_ref: *const trace_string_ref_t,
1814        );
1815
1816        pub fn trace_context_write_thread_info_record(
1817            context: *const trace_context_t,
1818            process_koid: zx_koid_t,
1819            thread_koid: zx_koid_t,
1820            thread_name_ref: *const trace_string_ref_t,
1821        );
1822
1823        pub fn trace_context_write_context_switch_record(
1824            context: *const trace_context_t,
1825            event_time: trace_ticks_t,
1826            cpu_number: trace_cpu_number_t,
1827            outgoing_thread_state: trace_thread_state_t,
1828            outgoing_thread_ref: *const trace_thread_ref_t,
1829            incoming_thread_ref: *const trace_thread_ref_t,
1830        );
1831
1832        pub fn trace_context_write_log_record(
1833            context: *const trace_context_t,
1834            event_time: trace_ticks_t,
1835            thread_ref: *const trace_thread_ref_t,
1836            log_message: *const libc::c_char,
1837            log_message_length: libc::size_t,
1838        );
1839
1840        pub fn trace_context_write_instant_event_record(
1841            context: *const trace_context_t,
1842            event_time: trace_ticks_t,
1843            thread_ref: *const trace_thread_ref_t,
1844            category_ref: *const trace_string_ref_t,
1845            name_ref: *const trace_string_ref_t,
1846            scope: trace_scope_t,
1847            args: *const trace_arg_t,
1848            num_args: libc::size_t,
1849        );
1850
1851        pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
1852
1853        pub fn trace_context_write_counter_event_record(
1854            context: *const trace_context_t,
1855            event_time: trace_ticks_t,
1856            thread_ref: *const trace_thread_ref_t,
1857            category_ref: *const trace_string_ref_t,
1858            name_ref: *const trace_string_ref_t,
1859            counter_id: trace_counter_id_t,
1860            args: *const trace_arg_t,
1861            num_args: libc::size_t,
1862        );
1863
1864        pub fn trace_context_write_duration_event_record(
1865            context: *const trace_context_t,
1866            start_time: trace_ticks_t,
1867            end_time: trace_ticks_t,
1868            thread_ref: *const trace_thread_ref_t,
1869            category_ref: *const trace_string_ref_t,
1870            name_ref: *const trace_string_ref_t,
1871            args: *const trace_arg_t,
1872            num_args: libc::size_t,
1873        );
1874
1875        pub fn trace_context_write_blob_event_record(
1876            context: *const trace_context_t,
1877            event_time: trace_ticks_t,
1878            thread_ref: *const trace_thread_ref_t,
1879            category_ref: *const trace_string_ref_t,
1880            name_ref: *const trace_string_ref_t,
1881            blob: *const libc::c_void,
1882            blob_size: libc::size_t,
1883            args: *const trace_arg_t,
1884            num_args: libc::size_t,
1885        );
1886
1887        pub fn trace_context_write_duration_begin_event_record(
1888            context: *const trace_context_t,
1889            event_time: trace_ticks_t,
1890            thread_ref: *const trace_thread_ref_t,
1891            category_ref: *const trace_string_ref_t,
1892            name_ref: *const trace_string_ref_t,
1893            args: *const trace_arg_t,
1894            num_args: libc::size_t,
1895        );
1896
1897        pub fn trace_context_write_duration_end_event_record(
1898            context: *const trace_context_t,
1899            event_time: trace_ticks_t,
1900            thread_ref: *const trace_thread_ref_t,
1901            category_ref: *const trace_string_ref_t,
1902            name_ref: *const trace_string_ref_t,
1903            args: *const trace_arg_t,
1904            num_args: libc::size_t,
1905        );
1906
1907        pub fn trace_context_write_async_begin_event_record(
1908            context: *const trace_context_t,
1909            event_time: trace_ticks_t,
1910            thread_ref: *const trace_thread_ref_t,
1911            category_ref: *const trace_string_ref_t,
1912            name_ref: *const trace_string_ref_t,
1913            async_id: trace_async_id_t,
1914            args: *const trace_arg_t,
1915            num_args: libc::size_t,
1916        );
1917
1918        pub fn trace_context_write_async_instant_event_record(
1919            context: *const trace_context_t,
1920            event_time: trace_ticks_t,
1921            thread_ref: *const trace_thread_ref_t,
1922            category_ref: *const trace_string_ref_t,
1923            name_ref: *const trace_string_ref_t,
1924            async_id: trace_async_id_t,
1925            args: *const trace_arg_t,
1926            num_args: libc::size_t,
1927        );
1928
1929        pub fn trace_context_write_async_end_event_record(
1930            context: *const trace_context_t,
1931            event_time: trace_ticks_t,
1932            thread_ref: *const trace_thread_ref_t,
1933            category_ref: *const trace_string_ref_t,
1934            name_ref: *const trace_string_ref_t,
1935            async_id: trace_async_id_t,
1936            args: *const trace_arg_t,
1937            num_args: libc::size_t,
1938        );
1939
1940        pub fn trace_context_write_flow_begin_event_record(
1941            context: *const trace_context_t,
1942            event_time: trace_ticks_t,
1943            thread_ref: *const trace_thread_ref_t,
1944            category_ref: *const trace_string_ref_t,
1945            name_ref: *const trace_string_ref_t,
1946            flow_id: trace_flow_id_t,
1947            args: *const trace_arg_t,
1948            num_args: libc::size_t,
1949        );
1950
1951        pub fn trace_context_write_flow_step_event_record(
1952            context: *const trace_context_t,
1953            event_time: trace_ticks_t,
1954            thread_ref: *const trace_thread_ref_t,
1955            category_ref: *const trace_string_ref_t,
1956            name_ref: *const trace_string_ref_t,
1957            flow_id: trace_flow_id_t,
1958            args: *const trace_arg_t,
1959            num_args: libc::size_t,
1960        );
1961
1962        pub fn trace_context_write_flow_end_event_record(
1963            context: *const trace_context_t,
1964            event_time: trace_ticks_t,
1965            thread_ref: *const trace_thread_ref_t,
1966            category_ref: *const trace_string_ref_t,
1967            name_ref: *const trace_string_ref_t,
1968            flow_id: trace_flow_id_t,
1969            args: *const trace_arg_t,
1970            num_args: libc::size_t,
1971        );
1972
1973        pub fn trace_context_write_initialization_record(
1974            context: *const trace_context_t,
1975            ticks_per_second: u64,
1976        );
1977
1978        pub fn trace_context_write_string_record(
1979            context: *const trace_context_t,
1980            index: trace_string_index_t,
1981            string: *const libc::c_char,
1982            length: libc::size_t,
1983        );
1984
1985        pub fn trace_context_write_thread_record(
1986            context: *const trace_context_t,
1987            index: trace_thread_index_t,
1988            procss_koid: zx_koid_t,
1989            thread_koid: zx_koid_t,
1990        );
1991
1992        pub fn trace_context_write_blob_record(
1993            context: *const trace_context_t,
1994            type_: trace_blob_type_t,
1995            name_ref: *const trace_string_ref_t,
1996            data: *const libc::c_void,
1997            size: libc::size_t,
1998        );
1999
2000        pub fn trace_context_alloc_record(
2001            context: *const trace_context_t,
2002            num_bytes: libc::size_t,
2003        ) -> *const libc::c_void;
2004
2005        // From trace-engine/handler.h
2006        /*
2007        pub fn trace_start_engine(
2008            async_ptr: *const async_t,
2009            handler: *const trace_handler_t,
2010            buffer: *const (),
2011            buffer_num_bytes: libc::size_t) -> zx_status_t;
2012            */
2013
2014        pub fn trace_stop_engine(disposition: zx_status_t) -> zx_status_t;
2015
2016        // From trace-engine/instrumentation.h
2017
2018        pub fn trace_generate_nonce() -> u64;
2019
2020        pub fn trace_state() -> trace_state_t;
2021
2022        pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2023
2024        pub fn trace_acquire_context() -> *const trace_context_t;
2025
2026        pub fn trace_acquire_context_for_category(
2027            category_literal: *const libc::c_char,
2028            out_ref: *mut trace_string_ref_t,
2029        ) -> *const trace_context_t;
2030
2031        pub fn trace_acquire_context_for_category_cached(
2032            category_literal: *const libc::c_char,
2033            trace_site: *const u64,
2034            out_ref: *mut trace_string_ref_t,
2035        ) -> *const trace_context_t;
2036
2037        pub fn trace_release_context(context: *const trace_context_t);
2038
2039        pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2040
2041        pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2042
2043        pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2044
2045        pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2046
2047        pub fn trace_notify_observer_updated(event: zx_handle_t);
2048    }
2049}
2050
2051/// Arguments for `TraceFuture` and `TraceFutureExt`. Use `trace_future_args!` to construct this
2052/// object.
2053pub struct TraceFutureArgs<'a> {
2054    pub category: &'static CStr,
2055    pub name: &'static CStr,
2056
2057    /// `TraceFuture::new` and `trace_future_args!` both check if the trace category is enabled. The
2058    /// trace context is acquired in `trace_future_args!` and is passed to `TraceFuture::new` to
2059    /// avoid acquiring it twice.
2060    pub context: Option<TraceCategoryContext>,
2061
2062    /// The trace arguments to appear in every duration event written by the `TraceFuture`. `args`
2063    /// should be empty if `context` is `None`.
2064    pub args: Vec<Arg<'a>>,
2065
2066    /// The flow id to use in the flow events that connect the duration events together. A flow id
2067    /// will be constructed with `Id::new()` if not provided.
2068    pub flow_id: Option<Id>,
2069
2070    /// Use `trace_future_args!` to construct this object.
2071    pub _use_trace_future_args: (),
2072}
2073
2074#[doc(hidden)]
2075#[macro_export]
2076macro_rules! __impl_trace_future_args {
2077    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2078        {
2079            static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2080            let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2081            let args = if context.is_some() {
2082                vec![$($crate::ArgValue::of($key, $val)),*]
2083            } else {
2084                vec![]
2085            };
2086            $crate::TraceFutureArgs {
2087                category: $category,
2088                name: $name,
2089                context: context,
2090                args: args,
2091                flow_id: $flow_id,
2092                _use_trace_future_args: (),
2093            }
2094        }
2095    }};
2096}
2097
2098/// Macro for constructing `TraceFutureArgs`. The trace arguments won't be constructed if the
2099/// category is not enabled. If the category becomes enabled while the `TraceFuture` is still alive
2100/// then the duration events will still be written but without the trace arguments.
2101///
2102/// Example:
2103///
2104/// ```
2105/// async move {
2106///     ....
2107/// }.trace(trace_future_args!(c"category", c"name", "x" => 5, "y" => 10)).await;
2108/// ```
2109#[macro_export]
2110macro_rules! trace_future_args {
2111    ($category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
2112        $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
2113    };
2114    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
2115        $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
2116    };
2117}
2118
2119/// Extension trait for tracing futures.
2120pub trait TraceFutureExt: Future + Sized {
2121    /// Wraps a `Future` in a `TraceFuture`.
2122    ///
2123    /// Example:
2124    ///
2125    /// ```rust
2126    /// future.trace(trace_future_args!(c"category", c"name")).await;
2127    /// ```
2128    ///
2129    /// Which is equivalent to:
2130    ///
2131    /// ```rust
2132    /// TraceFuture::new(trace_future_args!(c"category", c"name"), future).await;
2133    /// ```
2134    fn trace<'a>(self, args: TraceFutureArgs<'a>) -> TraceFuture<'a, Self> {
2135        TraceFuture::new(args, self)
2136    }
2137}
2138
2139impl<T: Future + Sized> TraceFutureExt for T {}
2140
2141/// Wraps a `Future` and writes duration events when the future is created, dropped, and every time
2142/// it's polled. The duration events are connected by flow events.
2143#[pin_project(PinnedDrop)]
2144pub struct TraceFuture<'a, Fut: Future> {
2145    category: &'static CStr,
2146    name: &'static CStr,
2147    args: Vec<Arg<'a>>,
2148    flow_id: Option<Id>,
2149    #[pin]
2150    // This future can be large (> 3000 bytes) so we Box it to avoid extra memcpy's when creating
2151    future: Pin<Box<Fut>>,
2152}
2153
2154impl<'a, Fut: Future> TraceFuture<'a, Fut> {
2155    pub fn new(args: TraceFutureArgs<'a>, future: Fut) -> Self {
2156        debug_assert!(
2157            args.context.is_some() || args.args.is_empty(),
2158            "There should not be any trace arguments when the category is disabled"
2159        );
2160        let mut this = Self {
2161            category: args.category,
2162            name: args.name,
2163            args: args.args,
2164            flow_id: args.flow_id,
2165            future: Box::pin(future),
2166        };
2167        if let Some(context) = args.context {
2168            this.trace_create(context);
2169        }
2170        this
2171    }
2172
2173    #[cold]
2174    fn trace_create(&mut self, context: TraceCategoryContext) {
2175        let name_ref = context.register_string_literal(self.name);
2176        let flow_id = self.flow_id.get_or_insert_with(Id::new);
2177        let duration_start = zx::BootTicks::get();
2178        context.write_flow_begin(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2179        self.args.push(ArgValue::of("state", "created"));
2180        context.write_duration(name_ref, duration_start, &self.args);
2181        self.args.pop();
2182    }
2183
2184    #[cold]
2185    fn trace_poll(
2186        self: Pin<&mut Self>,
2187        context: TraceCategoryContext,
2188        cx: &mut std::task::Context<'_>,
2189    ) -> Poll<Fut::Output> {
2190        let this = self.project();
2191        let name_ref = context.register_string_literal(this.name);
2192        let flow_id = this.flow_id.get_or_insert_with(Id::new);
2193        let duration_start = zx::BootTicks::get();
2194        context.write_flow_step(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2195        let result = this.future.poll(cx);
2196        let result_str: &'static str = if result.is_pending() { "pending" } else { "ready" };
2197        this.args.push(ArgValue::of("state", result_str));
2198        context.write_duration(name_ref, duration_start, &this.args);
2199        this.args.pop();
2200        result
2201    }
2202
2203    #[cold]
2204    fn trace_drop(self: Pin<&mut Self>, context: TraceCategoryContext) {
2205        let this = self.project();
2206        let name_ref = context.register_string_literal(this.name);
2207        let flow_id = this.flow_id.get_or_insert_with(Id::new);
2208        let duration_start = zx::BootTicks::get();
2209        context.write_flow_end(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2210        this.args.push(ArgValue::of("state", "dropped"));
2211        context.write_duration(name_ref, duration_start, &this.args);
2212        this.args.pop();
2213    }
2214}
2215
2216impl<Fut: Future> Future for TraceFuture<'_, Fut> {
2217    type Output = Fut::Output;
2218    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
2219        if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2220            self.trace_poll(context, cx)
2221        } else {
2222            self.project().future.poll(cx)
2223        }
2224    }
2225}
2226
2227#[pin_project::pinned_drop]
2228impl<Fut: Future> PinnedDrop for TraceFuture<'_, Fut> {
2229    fn drop(self: Pin<&mut Self>) {
2230        if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2231            self.trace_drop(context);
2232        }
2233    }
2234}
2235
2236#[cfg(test)]
2237mod test {
2238    use super::{trim_to_last_char_boundary, Id};
2239
2240    #[test]
2241    fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
2242        assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
2243        assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
2244        assert_eq!(b"", trim_to_last_char_boundary("x", 0));
2245        assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
2246        assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
2247        assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
2248
2249        assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
2250        assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
2251        assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
2252    }
2253
2254    // Here, we're looking to make sure that successive calls to the function generate distinct
2255    // values. How those values are distinct is not particularly meaningful; the current
2256    // implementation yields sequential values, but that's not a behavior to rely on.
2257    #[test]
2258    fn test_id_new() {
2259        assert_ne!(Id::new(), Id::new());
2260    }
2261}