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