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