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