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