1use 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#[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#[inline]
38pub fn is_enabled() -> bool {
39 unsafe { sys::trace_state() != sys::TRACE_STOPPED }
41}
42
43pub 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#[repr(transparent)]
74#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub struct Id(u64);
76
77impl Id {
78 pub fn new() -> Self {
80 let ts = zx::BootInstant::get().into_nanos() as u64;
83 let high_order = ts << 16;
84 let low_order = rand::random::<u16>() as u64;
85 Self(high_order | low_order)
86 }
87}
88
89impl From<u64> for Id {
90 fn from(u: u64) -> Self {
91 Self(u)
92 }
93}
94
95impl From<Id> for u64 {
96 fn from(id: Id) -> Self {
97 id.0
98 }
99}
100
101pub trait CategoryString: Copy {
102 fn register(&self, context: &Context) -> sys::trace_string_ref_t;
104
105 fn acquire_context(&self) -> Option<TraceCategoryContext>;
108
109 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext>;
111
112 fn is_category_enabled(&self) -> bool;
114}
115
116impl CategoryString for &'static CStr {
117 fn register(&self, context: &Context) -> sys::trace_string_ref_t {
118 unsafe {
119 let mut self_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
120 sys::trace_context_register_string_literal(
121 context.raw,
122 self.as_ptr(),
123 self_ref.as_mut_ptr(),
124 );
125 self_ref.assume_init()
126 }
127 }
128
129 fn acquire_context(&self) -> Option<TraceCategoryContext> {
130 unsafe {
131 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
132 let raw =
133 sys::trace_acquire_context_for_category(self.as_ptr(), category_ref.as_mut_ptr());
134 if raw != ptr::null() {
135 Some(TraceCategoryContext {
136 context: Context { raw },
137 category_ref: category_ref.assume_init(),
138 })
139 } else {
140 None
141 }
142 }
143 }
144
145 #[inline]
146 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext> {
147 unsafe {
148 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
153 let raw = sys::trace_acquire_context_for_category_cached(
154 self.as_ptr(),
155 site.as_ptr(),
156 category_ref.as_mut_ptr(),
157 );
158 if raw != ptr::null() {
159 Some(TraceCategoryContext {
160 context: Context { raw },
161 category_ref: category_ref.assume_init(),
162 })
163 } else {
164 None
165 }
166 }
167 }
168
169 fn is_category_enabled(&self) -> bool {
170 unsafe { sys::trace_is_category_enabled(self.as_ptr()) }
171 }
172}
173
174#[cfg(fuchsia_api_level_at_least = "27")]
175impl CategoryString for &'static str {
176 fn register(&self, context: &Context) -> sys::trace_string_ref_t {
177 unsafe {
178 let mut self_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
179 sys::trace_context_register_bytestring(
180 context.raw,
181 self.as_ptr().cast::<libc::c_char>(),
182 self.len(),
183 self_ref.as_mut_ptr(),
184 );
185 self_ref.assume_init()
186 }
187 }
188
189 fn acquire_context(&self) -> Option<TraceCategoryContext> {
190 unsafe {
191 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
192 let raw = sys::trace_acquire_context_for_category_bytestring(
193 self.as_ptr(),
194 self.len(),
195 category_ref.as_mut_ptr(),
196 );
197 if raw != ptr::null() {
198 Some(TraceCategoryContext {
199 context: Context { raw },
200 category_ref: category_ref.assume_init(),
201 })
202 } else {
203 None
204 }
205 }
206 }
207
208 #[inline]
209 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext> {
210 unsafe {
211 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
216 let raw = sys::trace_acquire_context_for_category_bytestring_cached(
217 self.as_ptr(),
218 self.len(),
219 site.as_ptr(),
220 category_ref.as_mut_ptr(),
221 );
222 if raw != ptr::null() {
223 Some(TraceCategoryContext {
224 context: Context { raw },
225 category_ref: category_ref.assume_init(),
226 })
227 } else {
228 None
229 }
230 }
231 }
232
233 fn is_category_enabled(&self) -> bool {
234 unsafe { sys::trace_is_category_bytestring_enabled(self.as_ptr(), self.len()) }
235 }
236}
237
238pub trait AlertString {
239 fn send_alert(&self, context: &Context);
241}
242
243impl AlertString for &CStr {
244 fn send_alert(&self, context: &Context) {
245 unsafe {
246 sys::trace_context_send_alert(context.raw, self.as_ptr());
247 }
248 }
249}
250
251#[cfg(fuchsia_api_level_at_least = "27")]
252impl AlertString for &str {
253 fn send_alert(&self, context: &Context) {
254 unsafe {
255 sys::trace_context_send_alert_bytestring(context.raw, self.as_ptr(), self.len());
256 }
257 }
258}
259
260#[cfg(fuchsia_api_level_at_least = "27")]
261impl AlertString for &String {
262 fn send_alert(&self, context: &Context) {
263 unsafe {
264 sys::trace_context_send_alert_bytestring(context.raw, self.as_ptr(), self.len());
265 }
266 }
267}
268
269pub trait AsTraceStrRef {
270 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t;
271}
272
273impl AsTraceStrRef for &'static CStr {
274 #[inline]
275 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
276 context.register_string_literal(*self)
277 }
278}
279
280impl AsTraceStrRef for &'static str {
284 #[inline]
285 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
286 context.register_str(self)
287 }
288}
289
290impl AsTraceStrRef for String {
291 #[inline]
292 fn as_trace_str_ref(&self, _context: &TraceCategoryContext) -> sys::trace_string_ref_t {
293 trace_make_inline_string_ref(self.as_str())
294 }
295}
296
297impl AsTraceStrRef for std::borrow::Cow<'static, str> {
298 #[inline]
299 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
300 match self {
301 std::borrow::Cow::Borrowed(s) => s.as_trace_str_ref(context),
302 std::borrow::Cow::Owned(s) => s.as_trace_str_ref(context),
303 }
304 }
305}
306
307impl<T: AsTraceStrRef> AsTraceStrRef for &T {
309 #[inline]
310 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
311 (*self).as_trace_str_ref(context)
312 }
313}
314
315#[repr(transparent)]
317pub struct Arg<'a>(sys::trace_arg_t, PhantomData<&'a ()>);
318
319pub trait ArgValue {
325 fn of<'a>(key: &'a str, value: Self) -> Arg<'a>
326 where
327 Self: 'a;
328 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, value: Self) -> Arg<'a>
329 where
330 Self: 'a;
331}
332
333macro_rules! arg_from {
339 ($valname:ident, $(($type:ty, $tag:expr, $value:expr))*) => {
340 $(
341 impl ArgValue for $type {
342 #[inline]
343 fn of<'a>(key: &'a str, $valname: Self) -> Arg<'a>
344 where Self: 'a
345 {
346 #[allow(unused)]
347 let $valname = $valname;
348
349 Arg(sys::trace_arg_t {
350 name_ref: trace_make_inline_string_ref(key),
351 value: sys::trace_arg_value_t {
352 type_: $tag,
353 value: $value,
354 },
355 }, PhantomData)
356 }
357 #[inline]
358 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, $valname: Self) -> Arg<'a>
359 where Self: 'a
360 {
361 #[allow(unused)]
362 let $valname = $valname;
363
364 Arg(sys::trace_arg_t {
365 name_ref,
366 value: sys::trace_arg_value_t {
367 type_: $tag,
368 value: $value,
369 },
370 }, PhantomData)
371 }
372 }
373 )*
374 }
375}
376
377#[rustfmt::skip]
379arg_from!(val,
380 ((), sys::TRACE_ARG_NULL, sys::trace_arg_union_t { int32_value: 0 })
381 (bool, sys::TRACE_ARG_BOOL, sys::trace_arg_union_t { bool_value: val })
382 (i32, sys::TRACE_ARG_INT32, sys::trace_arg_union_t { int32_value: val })
383 (u32, sys::TRACE_ARG_UINT32, sys::trace_arg_union_t { uint32_value: val })
384 (i64, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val })
385 (u64, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val })
386 (isize, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val as i64 })
387 (usize, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val as u64 })
388 (f64, sys::TRACE_ARG_DOUBLE, sys::trace_arg_union_t { double_value: val })
389 (zx::Koid, sys::TRACE_ARG_KOID, sys::trace_arg_union_t { koid_value: val.raw_koid() })
390);
391
392impl<T> ArgValue for *const T {
393 #[inline]
394 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
395 where
396 Self: 'a,
397 {
398 Arg(
399 sys::trace_arg_t {
400 name_ref: trace_make_inline_string_ref(key),
401 value: sys::trace_arg_value_t {
402 type_: sys::TRACE_ARG_POINTER,
403 value: sys::trace_arg_union_t { pointer_value: val as usize },
404 },
405 },
406 PhantomData,
407 )
408 }
409 #[inline]
410 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
411 where
412 Self: 'a,
413 {
414 Arg(
415 sys::trace_arg_t {
416 name_ref,
417 value: sys::trace_arg_value_t {
418 type_: sys::TRACE_ARG_POINTER,
419 value: sys::trace_arg_union_t { pointer_value: val as usize },
420 },
421 },
422 PhantomData,
423 )
424 }
425}
426
427impl<T> ArgValue for *mut T {
428 #[inline]
429 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
430 where
431 Self: 'a,
432 {
433 Arg(
434 sys::trace_arg_t {
435 name_ref: trace_make_inline_string_ref(key),
436 value: sys::trace_arg_value_t {
437 type_: sys::TRACE_ARG_POINTER,
438 value: sys::trace_arg_union_t { pointer_value: val as usize },
439 },
440 },
441 PhantomData,
442 )
443 }
444 #[inline]
445 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
446 where
447 Self: 'a,
448 {
449 Arg(
450 sys::trace_arg_t {
451 name_ref,
452 value: sys::trace_arg_value_t {
453 type_: sys::TRACE_ARG_POINTER,
454 value: sys::trace_arg_union_t { pointer_value: val as usize },
455 },
456 },
457 PhantomData,
458 )
459 }
460}
461
462impl<'a> ArgValue for &'a str {
463 #[inline]
464 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
465 where
466 Self: 'b,
467 {
468 Arg(
469 sys::trace_arg_t {
470 name_ref: trace_make_inline_string_ref(key),
471 value: sys::trace_arg_value_t {
472 type_: sys::TRACE_ARG_STRING,
473 value: sys::trace_arg_union_t {
474 string_value_ref: trace_make_inline_string_ref(val),
475 },
476 },
477 },
478 PhantomData,
479 )
480 }
481 #[inline]
482 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
483 where
484 Self: 'b,
485 {
486 Arg(
487 sys::trace_arg_t {
488 name_ref,
489 value: sys::trace_arg_value_t {
490 type_: sys::TRACE_ARG_STRING,
491 value: sys::trace_arg_union_t {
492 string_value_ref: trace_make_inline_string_ref(val),
493 },
494 },
495 },
496 PhantomData,
497 )
498 }
499}
500
501impl<'a> ArgValue for sys::trace_string_ref_t {
502 #[inline]
503 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
504 where
505 Self: 'b,
506 {
507 Arg(
508 sys::trace_arg_t {
509 name_ref: trace_make_inline_string_ref(key),
510 value: sys::trace_arg_value_t {
511 type_: sys::TRACE_ARG_STRING,
512 value: sys::trace_arg_union_t { string_value_ref: val },
513 },
514 },
515 PhantomData,
516 )
517 }
518 #[inline]
519 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
520 where
521 Self: 'b,
522 {
523 Arg(
524 sys::trace_arg_t {
525 name_ref,
526 value: sys::trace_arg_value_t {
527 type_: sys::TRACE_ARG_STRING,
528 value: sys::trace_arg_union_t { string_value_ref: val },
529 },
530 },
531 PhantomData,
532 )
533 }
534}
535
536#[macro_export]
558macro_rules! instant {
559 ($category:expr, $name:expr, $scope:expr $(, $key:expr => $val:expr)*) => {
560 {
561 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
562 use $crate::AsTraceStrRef;
563 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
564 $crate::instant(&context, $name, $scope, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
565 }
566 }
567 }
568}
569
570#[inline]
573pub fn instant<S: AsTraceStrRef>(
574 context: &TraceCategoryContext,
575 name: S,
576 scope: Scope,
577 args: &[Arg<'_>],
578) {
579 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
580
581 let name_ref = name.as_trace_str_ref(context);
582 context.write_instant(name_ref, scope, args);
583}
584
585#[macro_export]
599macro_rules! alert {
600 ($category:expr, $name:expr) => {
601 $crate::alert($category, $name)
602 };
603}
604
605pub fn alert<C: CategoryString, S: AlertString>(category: C, name: S) {
607 if let Some(context) = category.acquire_context() {
608 name.send_alert(&context.context);
609 }
610}
611
612#[macro_export]
629macro_rules! counter {
630 ($category:expr, $name:expr, $counter_id:expr $(, $key:expr => $val:expr)*) => {
631 {
632 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
633 use $crate::AsTraceStrRef;
634 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
635 $crate::counter(&context, $name, $counter_id,
636 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
637 }
638 }
639 }
640}
641
642pub fn counter<S: AsTraceStrRef>(
652 context: &TraceCategoryContext,
653 name: S,
654 counter_id: u64,
655 args: &[Arg<'_>],
656) {
657 assert!(args.len() >= 1, "trace counter args must include at least one numeric argument");
658 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
659
660 let name_ref = name.as_trace_str_ref(context);
661 context.write_counter(name_ref, counter_id, args);
662}
663
664#[must_use = "DurationScope must be `end`ed to be recorded"]
667pub struct DurationScope<'a, C: CategoryString, S: AsTraceStrRef> {
668 category: C,
669 name: S,
670 args: &'a [Arg<'a>],
671 start_time: zx::BootTicks,
672}
673
674impl<'a, C: CategoryString, S: AsTraceStrRef> DurationScope<'a, C, S> {
675 pub fn begin(category: C, name: S, args: &'a [Arg<'_>]) -> Self {
678 let start_time = zx::BootTicks::get();
679 Self { category, name, args, start_time }
680 }
681}
682
683impl<'a, C: CategoryString, S: AsTraceStrRef> Drop for DurationScope<'a, C, S> {
684 fn drop(&mut self) {
685 if let Some(context) = TraceCategoryContext::acquire(self.category) {
686 let name_ref = self.name.as_trace_str_ref(&context);
687 context.write_duration(name_ref, self.start_time, self.args);
688 }
689 }
690}
691
692pub fn complete_duration<C: CategoryString, S: AsTraceStrRef>(
694 category: C,
695 name: S,
696 start_time: zx::BootTicks,
697 args: &[Arg<'_>],
698) {
699 if let Some(context) = TraceCategoryContext::acquire(category) {
700 let name_ref = name.as_trace_str_ref(&context);
701 context.write_duration(name_ref, start_time, args);
702 }
703}
704
705#[macro_export]
740macro_rules! duration {
741 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
742 let mut args;
743 let _scope = {
744 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
745 use $crate::AsTraceStrRef;
752 if let Some(context) =
753 $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
754 args = [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*];
755 Some($crate::duration($category, $name, &args))
756 } else {
757 None
758 }
759 };
760 }
761}
762
763pub fn duration<'a, C: CategoryString, S: AsTraceStrRef>(
775 category: C,
776 name: S,
777 args: &'a [Arg<'_>],
778) -> DurationScope<'a, C, S> {
779 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
780 DurationScope::begin(category, name, args)
781}
782
783#[macro_export]
797macro_rules! duration_begin {
798 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
799 {
800 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
801 use $crate::AsTraceStrRef;
802 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
803 $crate::duration_begin(&context, $name,
804 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
805 }
806 }
807 };
808}
809
810#[cfg(fuchsia_api_level_at_least = "31")]
826#[macro_export]
827macro_rules! vthread_duration_begin {
828 ($category:expr, $name:expr, $vthread_name:expr, $vthread_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
829 {
830 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
831 let vthread = $crate::VThread::new($vthread_name, $vthread_id);
832 use $crate::AsTraceStrRef;
833 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
834 $crate::vthread_duration_begin(
835 &context,
836 $name,
837 &vthread,
838 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
839 )
840 }
841 }
842 };
843}
844
845#[macro_export]
859macro_rules! duration_end {
860 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
861 {
862 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
863 use $crate::AsTraceStrRef;
864 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
865 $crate::duration_end(&context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
866 }
867 }
868 };
869}
870
871#[cfg(fuchsia_api_level_at_least = "31")]
887#[macro_export]
888macro_rules! vthread_duration_end {
889 ($category:expr, $name:expr, $vthread_name:expr, $vthread_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
890 {
891 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
892 let vthread = $crate::VThread::new($vthread_name, $vthread_id);
893 use $crate::AsTraceStrRef;
894 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
895 $crate::vthread_duration_end(
896 &context,
897 $name,
898 &vthread,
899 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
900 )
901 }
902 }
903 };
904}
905
906pub fn duration_begin<S: AsTraceStrRef>(context: &TraceCategoryContext, name: S, args: &[Arg<'_>]) {
917 let ticks = zx::BootTicks::get();
918 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
919
920 let name_ref = name.as_trace_str_ref(&context);
921 context.write_duration_begin(ticks, name_ref, args);
922}
923
924#[cfg(fuchsia_api_level_at_least = "31")]
925pub struct VThread<S: AsTraceStrRef = &'static str> {
926 name: S,
927 id: sys::trace_vthread_id_t,
928 process_koid: zx::sys::zx_koid_t,
929}
930
931#[cfg(fuchsia_api_level_at_least = "31")]
932impl<S: AsTraceStrRef> VThread<S> {
933 pub fn new(name: S, id: sys::trace_vthread_id_t) -> Self {
934 Self { name, id, process_koid: zx::sys::ZX_KOID_INVALID }
935 }
936
937 pub fn new_with_process_koid(
938 name: S,
939 id: sys::trace_vthread_id_t,
940 process_koid: zx::sys::zx_koid_t,
941 ) -> Self {
942 Self { name, id, process_koid }
943 }
944}
945
946#[cfg(fuchsia_api_level_at_least = "31")]
948pub fn vthread_duration_begin<S1: AsTraceStrRef, S2: AsTraceStrRef>(
949 context: &TraceCategoryContext,
950 name: S1,
951 vthread: &VThread<S2>,
952 args: &[Arg<'_>],
953) {
954 let ticks = zx::BootTicks::get();
955 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
956
957 let name_ref = name.as_trace_str_ref(context);
958 context.write_vthread_duration_begin(ticks, name_ref, vthread, args);
959}
960
961pub fn duration_end<S: AsTraceStrRef>(context: &TraceCategoryContext, name: S, args: &[Arg<'_>]) {
971 let ticks = zx::BootTicks::get();
972 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
973
974 let name_ref = name.as_trace_str_ref(&context);
975 context.write_duration_end(ticks, name_ref, args);
976}
977
978#[cfg(fuchsia_api_level_at_least = "31")]
980pub fn vthread_duration_end<S1: AsTraceStrRef, S2: AsTraceStrRef>(
981 context: &TraceCategoryContext,
982 name: S1,
983 vthread: &VThread<S2>,
984 args: &[Arg<'_>],
985) {
986 let ticks = zx::BootTicks::get();
987 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
988
989 let name_ref = name.as_trace_str_ref(context);
990 context.write_vthread_duration_end(ticks, name_ref, vthread, args);
991}
992
993#[must_use = "emits an end event when dropped, so if dropped immediately creates an essentially \
996 zero length duration that should just be an instant instead"]
997pub struct AsyncScope<C: CategoryString = &'static CStr, S: AsTraceStrRef = &'static CStr> {
998 id: Id,
1001 category: C,
1002 name: S,
1003}
1004
1005impl<C: CategoryString, S: AsTraceStrRef> AsyncScope<C, S> {
1006 pub fn begin(id: Id, category: C, name: S, args: &[Arg<'_>]) -> Self {
1009 async_begin(id, category, &name, args);
1010 Self { id, category, name }
1011 }
1012
1013 pub fn end(self, args: &[Arg<'_>]) {
1016 async_end(self.id, self.category, &self.name, args);
1017 std::mem::forget(self);
1018 }
1019}
1020
1021impl<C: CategoryString, S: AsTraceStrRef> Drop for AsyncScope<C, S> {
1022 fn drop(&mut self) {
1023 async_end(self.id, self.category, &self.name, &[]);
1027 }
1028}
1029
1030pub fn async_enter<C: CategoryString, S: AsTraceStrRef>(
1039 id: Id,
1040 category: C,
1041 name: S,
1042 args: &[Arg<'_>],
1043) -> AsyncScope<C, S> {
1044 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1045 AsyncScope::begin(id, category, name, args)
1046}
1047
1048#[macro_export]
1079macro_rules! async_enter {
1080 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
1081 {
1082 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1083 use $crate::AsTraceStrRef;
1084 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1085 Some($crate::AsyncScope::begin($id, $category, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]))
1086 } else {
1087 None
1088 }
1089 }
1090 }
1091}
1092
1093#[macro_export]
1117macro_rules! async_instant {
1118 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
1119 {
1120 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1121 use $crate::AsTraceStrRef;
1122 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1123 $crate::async_instant($id, &context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
1124 }
1125 }
1126 }
1127}
1128
1129pub fn async_begin<C: CategoryString, S: AsTraceStrRef>(
1141 id: Id,
1142 category: C,
1143 name: S,
1144 args: &[Arg<'_>],
1145) {
1146 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1147
1148 if let Some(context) = TraceCategoryContext::acquire(category) {
1149 let name_ref = name.as_trace_str_ref(&context);
1150 context.write_async_begin(id, name_ref, args);
1151 }
1152}
1153
1154pub fn async_end<C: CategoryString, S: AsTraceStrRef>(
1166 id: Id,
1167 category: C,
1168 name: S,
1169 args: &[Arg<'_>],
1170) {
1171 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1172
1173 if let Some(context) = TraceCategoryContext::acquire(category) {
1174 let name_ref = name.as_trace_str_ref(&context);
1175 context.write_async_end(id, name_ref, args);
1176 }
1177}
1178
1179pub fn async_instant<S: AsTraceStrRef>(
1191 id: Id,
1192 context: &TraceCategoryContext,
1193 name: S,
1194 args: &[Arg<'_>],
1195) {
1196 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1197
1198 let name_ref = name.as_trace_str_ref(context);
1199 context.write_async_instant(id, name_ref, args);
1200}
1201
1202#[macro_export]
1203macro_rules! blob {
1204 ($category:expr, $name:expr, $bytes:expr $(, $key:expr => $val:expr)*) => {
1205 {
1206 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1207 use $crate::AsTraceStrRef;
1208 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1209 $crate::blob_fn(&context, $name, $bytes, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1210 }
1211 }
1212 }
1213}
1214pub fn blob_fn<S: AsTraceStrRef>(
1215 context: &TraceCategoryContext,
1216 name: S,
1217 bytes: &[u8],
1218 args: &[Arg<'_>],
1219) {
1220 let name_ref = name.as_trace_str_ref(context);
1221 context.write_blob(name_ref, bytes, args);
1222}
1223
1224#[macro_export]
1239macro_rules! flow_begin {
1240 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1241 {
1242 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1243 use $crate::AsTraceStrRef;
1244 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1245 $crate::flow_begin(&context, $name, $flow_id,
1246 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1247 }
1248 }
1249 }
1250}
1251
1252#[macro_export]
1267macro_rules! flow_step {
1268 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1269 {
1270 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1271 use $crate::AsTraceStrRef;
1272 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1273 $crate::flow_step(&context, $name, $flow_id,
1274 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1275 }
1276 }
1277 }
1278}
1279
1280#[macro_export]
1295macro_rules! flow_end {
1296 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1297 {
1298 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1299 use $crate::AsTraceStrRef;
1300 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1301 $crate::flow_end(&context, $name, $flow_id,
1302 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1303 }
1304 }
1305 }
1306}
1307
1308pub fn flow_begin<S: AsTraceStrRef>(
1327 context: &TraceCategoryContext,
1328 name: S,
1329 flow_id: Id,
1330 args: &[Arg<'_>],
1331) {
1332 let ticks = zx::BootTicks::get();
1333 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1334
1335 let name_ref = name.as_trace_str_ref(context);
1336 context.write_flow_begin(ticks, name_ref, flow_id, args);
1337}
1338
1339pub fn flow_end<S: AsTraceStrRef>(
1356 context: &TraceCategoryContext,
1357 name: S,
1358 flow_id: Id,
1359 args: &[Arg<'_>],
1360) {
1361 let ticks = zx::BootTicks::get();
1362 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1363
1364 let name_ref = name.as_trace_str_ref(context);
1365 context.write_flow_end(ticks, name_ref, flow_id, args);
1366}
1367
1368pub fn flow_step<S: AsTraceStrRef>(
1385 context: &TraceCategoryContext,
1386 name: S,
1387 flow_id: Id,
1388 args: &[Arg<'_>],
1389) {
1390 let ticks = zx::BootTicks::get();
1391 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1392
1393 let name_ref = name.as_trace_str_ref(context);
1394 context.write_flow_step(ticks, name_ref, flow_id, args);
1395}
1396
1397#[macro_export]
1411macro_rules! instaflow_begin {
1412 (
1413 $category:expr,
1414 $flow_name:expr,
1415 $step_name:expr,
1416 $flow_id:expr
1417 $(, $key:expr => $val:expr)*
1418 ) => {
1419 {
1420 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1421 use $crate::AsTraceStrRef;
1422 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1423 $crate::instaflow_begin(
1424 &context,
1425 $flow_name,
1426 $step_name,
1427 $flow_id,
1428 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1429 )
1430 }
1431 }
1432 }
1433}
1434
1435#[macro_export]
1449macro_rules! instaflow_end {
1450 (
1451 $category:expr,
1452 $flow_name:expr,
1453 $step_name:expr,
1454 $flow_id:expr
1455 $(, $key:expr => $val:expr)*
1456 ) => {
1457 {
1458 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1459 use $crate::AsTraceStrRef;
1460 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1461 $crate::instaflow_end(
1462 &context,
1463 $flow_name,
1464 $step_name,
1465 $flow_id,
1466 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1467 )
1468 }
1469 }
1470 }
1471}
1472
1473#[macro_export]
1487macro_rules! instaflow_step {
1488 (
1489 $category:expr,
1490 $flow_name:expr,
1491 $step_name:expr,
1492 $flow_id:expr
1493 $(, $key:expr => $val:expr)*
1494 ) => {
1495 {
1496 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1497 use $crate::AsTraceStrRef;
1498 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1499 $crate::instaflow_step(
1500 &context,
1501 $flow_name,
1502 $step_name,
1503 $flow_id,
1504 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1505 )
1506 }
1507 }
1508 }
1509}
1510
1511pub fn instaflow_begin<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1523 context: &TraceCategoryContext,
1524 flow_name: S1,
1525 step_name: S2,
1526 flow_id: Id,
1527 args: &[Arg<'_>],
1528) {
1529 let ticks = zx::BootTicks::get();
1530 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1531
1532 let flow_name_ref = flow_name.as_trace_str_ref(context);
1533 let step_name_ref = step_name.as_trace_str_ref(context);
1534
1535 context.write_duration_begin(ticks, step_name_ref, args);
1536 context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1537 context.write_duration_end(ticks, step_name_ref, args);
1538}
1539
1540pub fn instaflow_end<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1552 context: &TraceCategoryContext,
1553 flow_name: S1,
1554 step_name: S2,
1555 flow_id: Id,
1556 args: &[Arg<'_>],
1557) {
1558 let ticks = zx::BootTicks::get();
1559 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1560
1561 let flow_name_ref = flow_name.as_trace_str_ref(context);
1562 let step_name_ref = step_name.as_trace_str_ref(context);
1563
1564 context.write_duration_begin(ticks, step_name_ref, args);
1565 context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1566 context.write_duration_end(ticks, step_name_ref, args);
1567}
1568
1569pub fn instaflow_step<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1581 context: &TraceCategoryContext,
1582 flow_name: S1,
1583 step_name: S2,
1584 flow_id: Id,
1585 args: &[Arg<'_>],
1586) {
1587 let ticks = zx::BootTicks::get();
1588 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1589
1590 let flow_name_ref = flow_name.as_trace_str_ref(context);
1591 let step_name_ref = step_name.as_trace_str_ref(context);
1592
1593 context.write_duration_begin(ticks, step_name_ref, args);
1594 context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1595 context.write_duration_end(ticks, step_name_ref, args);
1596}
1597
1598const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1600 sys::trace_string_ref_t {
1601 encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1602 inline_string: ptr::null(),
1603 }
1604}
1605
1606#[inline]
1607fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1608 let mut len = string.len();
1609 if string.len() > max_len {
1610 len = max_len;
1614 while len > 0 {
1615 if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1616 break;
1617 }
1618 len -= 1;
1619 }
1620 }
1621 &string.as_bytes()[0..len]
1622}
1623
1624#[inline]
1627fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1628 let len = string.len() as u16;
1629 if len == 0 {
1630 return trace_make_empty_string_ref();
1631 }
1632
1633 let string = trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH);
1634
1635 sys::trace_string_ref_t {
1636 encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1637 inline_string: string.as_ptr() as *const libc::c_char,
1638 }
1639}
1640
1641pub struct TraceCategoryContext {
1643 context: Context,
1644 category_ref: sys::trace_string_ref_t,
1645}
1646
1647impl TraceCategoryContext {
1648 #[inline]
1649 pub fn acquire_cached<C: CategoryString>(
1650 category: C,
1651 site: &sys::trace_site_t,
1652 ) -> Option<TraceCategoryContext> {
1653 category.acquire_context_cached(site)
1654 }
1655
1656 pub fn acquire<C: CategoryString>(category: C) -> Option<TraceCategoryContext> {
1657 category.acquire_context()
1658 }
1659
1660 #[inline]
1661 pub fn register_string_literal<T: CategoryString>(&self, name: T) -> sys::trace_string_ref_t {
1662 name.register(&self.context)
1663 }
1664
1665 #[inline]
1666 #[cfg(fuchsia_api_level_at_least = "27")]
1667 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1668 unsafe {
1669 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1670 sys::trace_context_register_bytestring(
1671 self.context.raw,
1672 name.as_ptr().cast::<libc::c_char>(),
1673 name.len(),
1674 name_ref.as_mut_ptr(),
1675 );
1676 name_ref.assume_init()
1677 }
1678 }
1679 #[inline]
1680 #[cfg(not(fuchsia_api_level_at_least = "27"))]
1681 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1682 trace_make_inline_string_ref(name)
1683 }
1684
1685 #[inline]
1686 fn register_current_thread(&self) -> sys::trace_thread_ref_t {
1687 unsafe {
1688 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1689 sys::trace_context_register_current_thread(self.context.raw, thread_ref.as_mut_ptr());
1690 thread_ref.assume_init()
1691 }
1692 }
1693
1694 #[cfg(fuchsia_api_level_at_least = "31")]
1695 #[inline]
1696 fn register_vthread<S: AsTraceStrRef>(
1697 &self,
1698 name: &S,
1699 id: sys::trace_vthread_id_t,
1700 process_koid: zx::sys::zx_koid_t,
1701 ) -> sys::trace_thread_ref_t {
1702 let name_ref = name.as_trace_str_ref(self);
1703 unsafe {
1704 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1705 sys::trace_context_register_vthread_by_ref(
1706 self.context.raw,
1707 process_koid,
1708 &name_ref,
1709 id,
1710 thread_ref.as_mut_ptr(),
1711 );
1712 thread_ref.assume_init()
1713 }
1714 }
1715
1716 #[inline]
1717 pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
1718 let ticks = zx::BootTicks::get();
1719 let thread_ref = self.register_current_thread();
1720 unsafe {
1721 sys::trace_context_write_instant_event_record(
1722 self.context.raw,
1723 ticks.into_raw(),
1724 &thread_ref,
1725 &self.category_ref,
1726 &name_ref,
1727 scope.into_raw(),
1728 args.as_ptr() as *const sys::trace_arg_t,
1729 args.len(),
1730 );
1731 }
1732 }
1733
1734 pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
1735 let name_ref = trace_make_inline_string_ref(name);
1736 self.write_instant(name_ref, scope, args)
1737 }
1738
1739 fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
1740 let ticks = zx::BootTicks::get();
1741 let thread_ref = self.register_current_thread();
1742 unsafe {
1743 sys::trace_context_write_counter_event_record(
1744 self.context.raw,
1745 ticks.into_raw(),
1746 &thread_ref,
1747 &self.category_ref,
1748 &name_ref,
1749 counter_id,
1750 args.as_ptr() as *const sys::trace_arg_t,
1751 args.len(),
1752 );
1753 }
1754 }
1755
1756 pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
1757 let name_ref = trace_make_inline_string_ref(name);
1758 self.write_counter(name_ref, counter_id, args);
1759 }
1760
1761 fn write_duration(
1762 &self,
1763 name_ref: sys::trace_string_ref_t,
1764 start_time: zx::BootTicks,
1765 args: &[Arg<'_>],
1766 ) {
1767 let ticks = zx::BootTicks::get();
1768 let thread_ref = self.register_current_thread();
1769 unsafe {
1770 sys::trace_context_write_duration_event_record(
1771 self.context.raw,
1772 start_time.into_raw(),
1773 ticks.into_raw(),
1774 &thread_ref,
1775 &self.category_ref,
1776 &name_ref,
1777 args.as_ptr() as *const sys::trace_arg_t,
1778 args.len(),
1779 );
1780 }
1781 }
1782
1783 pub fn write_duration_with_inline_name(
1784 &self,
1785 name: &str,
1786 start_time: zx::BootTicks,
1787 args: &[Arg<'_>],
1788 ) {
1789 let name_ref = trace_make_inline_string_ref(name);
1790 self.write_duration(name_ref, start_time, args);
1791 }
1792
1793 fn write_duration_begin(
1794 &self,
1795 ticks: zx::BootTicks,
1796 name_ref: sys::trace_string_ref_t,
1797 args: &[Arg<'_>],
1798 ) {
1799 let thread_ref = self.register_current_thread();
1800 unsafe {
1801 sys::trace_context_write_duration_begin_event_record(
1802 self.context.raw,
1803 ticks.into_raw(),
1804 &thread_ref,
1805 &self.category_ref,
1806 &name_ref,
1807 args.as_ptr() as *const sys::trace_arg_t,
1808 args.len(),
1809 );
1810 }
1811 }
1812
1813 #[cfg(fuchsia_api_level_at_least = "31")]
1814 fn write_vthread_duration_begin<S: AsTraceStrRef>(
1815 &self,
1816 ticks: zx::BootTicks,
1817 name_ref: sys::trace_string_ref_t,
1818 vthread: &VThread<S>,
1819 args: &[Arg<'_>],
1820 ) {
1821 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
1822 unsafe {
1823 sys::trace_context_write_duration_begin_event_record(
1824 self.context.raw,
1825 ticks.into_raw(),
1826 &thread_ref,
1827 &self.category_ref,
1828 &name_ref,
1829 args.as_ptr() as *const sys::trace_arg_t,
1830 args.len(),
1831 );
1832 }
1833 }
1834
1835 pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1836 let name_ref = trace_make_inline_string_ref(name);
1837 self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
1838 }
1839
1840 fn write_duration_end(
1841 &self,
1842 ticks: zx::BootTicks,
1843 name_ref: sys::trace_string_ref_t,
1844 args: &[Arg<'_>],
1845 ) {
1846 let thread_ref = self.register_current_thread();
1847 unsafe {
1848 sys::trace_context_write_duration_end_event_record(
1849 self.context.raw,
1850 ticks.into_raw(),
1851 &thread_ref,
1852 &self.category_ref,
1853 &name_ref,
1854 args.as_ptr() as *const sys::trace_arg_t,
1855 args.len(),
1856 );
1857 }
1858 }
1859
1860 #[cfg(fuchsia_api_level_at_least = "31")]
1861 fn write_vthread_duration_end<S: AsTraceStrRef>(
1862 &self,
1863 ticks: zx::BootTicks,
1864 name_ref: sys::trace_string_ref_t,
1865 vthread: &VThread<S>,
1866 args: &[Arg<'_>],
1867 ) {
1868 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
1869 unsafe {
1870 sys::trace_context_write_duration_end_event_record(
1871 self.context.raw,
1872 ticks.into_raw(),
1873 &thread_ref,
1874 &self.category_ref,
1875 &name_ref,
1876 args.as_ptr() as *const sys::trace_arg_t,
1877 args.len(),
1878 );
1879 }
1880 }
1881
1882 pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1883 let name_ref = trace_make_inline_string_ref(name);
1884 self.write_duration_end(zx::BootTicks::get(), name_ref, args);
1885 }
1886
1887 fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1888 let ticks = zx::BootTicks::get();
1889 let thread_ref = self.register_current_thread();
1890 unsafe {
1891 sys::trace_context_write_async_begin_event_record(
1892 self.context.raw,
1893 ticks.into_raw(),
1894 &thread_ref,
1895 &self.category_ref,
1896 &name_ref,
1897 id.into(),
1898 args.as_ptr() as *const sys::trace_arg_t,
1899 args.len(),
1900 );
1901 }
1902 }
1903
1904 pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1905 let name_ref = trace_make_inline_string_ref(name);
1906 self.write_async_begin(id, name_ref, args);
1907 }
1908
1909 fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1910 let ticks = zx::BootTicks::get();
1911 let thread_ref = self.register_current_thread();
1912 unsafe {
1913 sys::trace_context_write_async_end_event_record(
1914 self.context.raw,
1915 ticks.into_raw(),
1916 &thread_ref,
1917 &self.category_ref,
1918 &name_ref,
1919 id.into(),
1920 args.as_ptr() as *const sys::trace_arg_t,
1921 args.len(),
1922 );
1923 }
1924 }
1925
1926 pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1927 let name_ref = trace_make_inline_string_ref(name);
1928 self.write_async_end(id, name_ref, args);
1929 }
1930
1931 fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1932 let ticks = zx::BootTicks::get();
1933 let thread_ref = self.register_current_thread();
1934 unsafe {
1935 sys::trace_context_write_async_instant_event_record(
1936 self.context.raw,
1937 ticks.into_raw(),
1938 &thread_ref,
1939 &self.category_ref,
1940 &name_ref,
1941 id.into(),
1942 args.as_ptr() as *const sys::trace_arg_t,
1943 args.len(),
1944 );
1945 }
1946 }
1947
1948 fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
1949 let ticks = zx::BootTicks::get();
1950 let thread_ref = self.register_current_thread();
1951 unsafe {
1952 sys::trace_context_write_blob_event_record(
1953 self.context.raw,
1954 ticks.into_raw(),
1955 &thread_ref,
1956 &self.category_ref,
1957 &name_ref,
1958 bytes.as_ptr() as *const core::ffi::c_void,
1959 bytes.len(),
1960 args.as_ptr() as *const sys::trace_arg_t,
1961 args.len(),
1962 );
1963 }
1964 }
1965
1966 fn write_flow_begin(
1967 &self,
1968 ticks: zx::BootTicks,
1969 name_ref: sys::trace_string_ref_t,
1970 flow_id: Id,
1971 args: &[Arg<'_>],
1972 ) {
1973 let thread_ref = self.register_current_thread();
1974 unsafe {
1975 sys::trace_context_write_flow_begin_event_record(
1976 self.context.raw,
1977 ticks.into_raw(),
1978 &thread_ref,
1979 &self.category_ref,
1980 &name_ref,
1981 flow_id.into(),
1982 args.as_ptr() as *const sys::trace_arg_t,
1983 args.len(),
1984 );
1985 }
1986 }
1987
1988 fn write_flow_end(
1989 &self,
1990 ticks: zx::BootTicks,
1991 name_ref: sys::trace_string_ref_t,
1992 flow_id: Id,
1993 args: &[Arg<'_>],
1994 ) {
1995 let thread_ref = self.register_current_thread();
1996 unsafe {
1997 sys::trace_context_write_flow_end_event_record(
1998 self.context.raw,
1999 ticks.into_raw(),
2000 &thread_ref,
2001 &self.category_ref,
2002 &name_ref,
2003 flow_id.into(),
2004 args.as_ptr() as *const sys::trace_arg_t,
2005 args.len(),
2006 );
2007 }
2008 }
2009
2010 fn write_flow_step(
2011 &self,
2012 ticks: zx::BootTicks,
2013 name_ref: sys::trace_string_ref_t,
2014 flow_id: Id,
2015 args: &[Arg<'_>],
2016 ) {
2017 let thread_ref = self.register_current_thread();
2018 unsafe {
2019 sys::trace_context_write_flow_step_event_record(
2020 self.context.raw,
2021 ticks.into_raw(),
2022 &thread_ref,
2023 &self.category_ref,
2024 &name_ref,
2025 flow_id.into(),
2026 args.as_ptr() as *const sys::trace_arg_t,
2027 args.len(),
2028 );
2029 }
2030 }
2031}
2032
2033pub struct Context {
2035 raw: *const sys::trace_context_t,
2036}
2037
2038impl Context {
2039 #[inline]
2040 pub fn acquire() -> Option<Self> {
2041 let context = unsafe { sys::trace_acquire_context() };
2042 if context.is_null() { None } else { Some(Self { raw: context }) }
2043 }
2044
2045 #[inline]
2046 pub fn register_string_literal<T: CategoryString>(&self, s: T) -> sys::trace_string_ref_t {
2047 s.register(self)
2048 }
2049
2050 pub fn write_blob_record(
2051 &self,
2052 type_: sys::trace_blob_type_t,
2053 name_ref: &sys::trace_string_ref_t,
2054 data: &[u8],
2055 ) {
2056 unsafe {
2057 sys::trace_context_write_blob_record(
2058 self.raw,
2059 type_,
2060 name_ref as *const sys::trace_string_ref_t,
2061 data.as_ptr() as *const libc::c_void,
2062 data.len(),
2063 );
2064 }
2065 }
2066
2067 pub fn copy_record(&self, buffer: &[u64]) -> Option<usize> {
2071 unsafe {
2072 let ptr = sys::trace_context_alloc_record(self.raw, 8 * buffer.len() as libc::size_t);
2073 if ptr == std::ptr::null_mut() {
2074 return None;
2075 }
2076 ptr.cast::<u64>().copy_from(buffer.as_ptr(), buffer.len());
2077 };
2078 Some(buffer.len())
2079 }
2080
2081 pub fn buffering_mode(&self) -> BufferingMode {
2082 match unsafe { sys::trace_context_get_buffering_mode(self.raw) } {
2083 sys::TRACE_BUFFERING_MODE_ONESHOT => BufferingMode::OneShot,
2084 sys::TRACE_BUFFERING_MODE_CIRCULAR => BufferingMode::Circular,
2085 sys::TRACE_BUFFERING_MODE_STREAMING => BufferingMode::Streaming,
2086 m => panic!("Unknown trace buffering mode: {:?}", m),
2087 }
2088 }
2089}
2090
2091impl std::ops::Drop for Context {
2092 fn drop(&mut self) {
2093 unsafe { sys::trace_release_context(self.raw) }
2094 }
2095}
2096
2097pub struct ProlongedContext {
2098 context: *const sys::trace_prolonged_context_t,
2099}
2100
2101impl ProlongedContext {
2102 pub fn acquire() -> Option<Self> {
2103 let context = unsafe { sys::trace_acquire_prolonged_context() };
2104 if context.is_null() { None } else { Some(Self { context }) }
2105 }
2106}
2107
2108impl Drop for ProlongedContext {
2109 fn drop(&mut self) {
2110 unsafe { sys::trace_release_prolonged_context(self.context) }
2111 }
2112}
2113
2114unsafe impl Send for ProlongedContext {}
2115
2116mod sys {
2117 #![allow(non_camel_case_types, unused)]
2118 use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
2119
2120 pub type trace_ticks_t = zx_ticks_t;
2121 pub type trace_counter_id_t = u64;
2122 pub type trace_async_id_t = u64;
2123 pub type trace_flow_id_t = u64;
2124 pub type trace_vthread_id_t = u64;
2125 pub type trace_thread_state_t = u32;
2126 pub type trace_cpu_number_t = u32;
2127 pub type trace_string_index_t = u32;
2128 pub type trace_thread_index_t = u32;
2129 pub type trace_context_t = libc::c_void;
2130 pub type trace_prolonged_context_t = libc::c_void;
2131
2132 pub type trace_encoded_string_ref_t = u16;
2133 pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
2134 pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
2135 pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
2136 pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: usize = 32000;
2137 pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
2138 pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
2139
2140 pub type trace_encoded_thread_ref_t = u32;
2141 pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
2142 pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
2143 pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
2144
2145 pub type trace_state_t = libc::c_int;
2146 pub const TRACE_STOPPED: trace_state_t = 0;
2147 pub const TRACE_STARTED: trace_state_t = 1;
2148 pub const TRACE_STOPPING: trace_state_t = 2;
2149
2150 pub type trace_scope_t = libc::c_int;
2151 pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
2152 pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
2153 pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
2154
2155 pub type trace_blob_type_t = libc::c_int;
2156 pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
2157 pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
2158 pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
2159
2160 pub type trace_buffering_mode_t = libc::c_int;
2161 pub const TRACE_BUFFERING_MODE_ONESHOT: trace_buffering_mode_t = 0;
2162 pub const TRACE_BUFFERING_MODE_CIRCULAR: trace_buffering_mode_t = 1;
2163 pub const TRACE_BUFFERING_MODE_STREAMING: trace_buffering_mode_t = 2;
2164
2165 #[repr(C)]
2166 #[derive(Copy, Clone)]
2167 pub struct trace_string_ref_t {
2168 pub encoded_value: trace_encoded_string_ref_t,
2169 pub inline_string: *const libc::c_char,
2170 }
2171
2172 pub type trace_site_t = std::sync::atomic::AtomicU64;
2176
2177 unsafe impl Send for trace_string_ref_t {}
2187 unsafe impl Sync for trace_string_ref_t {}
2188
2189 #[repr(C)]
2190 pub struct trace_thread_ref_t {
2191 pub encoded_value: trace_encoded_thread_ref_t,
2192 pub inline_process_koid: zx_koid_t,
2193 pub inline_thread_koid: zx_koid_t,
2194 }
2195
2196 #[repr(C)]
2197 pub struct trace_arg_t {
2198 pub name_ref: trace_string_ref_t,
2199 pub value: trace_arg_value_t,
2200 }
2201
2202 #[repr(C)]
2203 pub union trace_arg_union_t {
2204 pub int32_value: i32,
2205 pub uint32_value: u32,
2206 pub int64_value: i64,
2207 pub uint64_value: u64,
2208 pub double_value: libc::c_double,
2209 pub string_value_ref: trace_string_ref_t,
2210 pub pointer_value: libc::uintptr_t,
2211 pub koid_value: zx_koid_t,
2212 pub bool_value: bool,
2213 pub reserved_for_future_expansion: [libc::uintptr_t; 2],
2214 }
2215
2216 pub type trace_arg_type_t = libc::c_int;
2217 pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
2218 pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
2219 pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
2220 pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
2221 pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
2222 pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
2223 pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
2224 pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
2225 pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
2226 pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
2227
2228 #[repr(C)]
2229 pub struct trace_arg_value_t {
2230 pub type_: trace_arg_type_t,
2231 pub value: trace_arg_union_t,
2232 }
2233
2234 #[repr(C)]
2235 pub struct trace_handler_ops_t {
2236 pub is_category_enabled:
2237 unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
2238 pub trace_started: unsafe fn(handler: *const trace_handler_t),
2239 pub trace_stopped: unsafe fn(
2240 handler: *const trace_handler_t,
2241 async_ptr: *const (), disposition: zx_status_t,
2243 buffer_bytes_written: libc::size_t,
2244 ),
2245 pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
2246 }
2247
2248 #[repr(C)]
2249 pub struct trace_handler_t {
2250 pub ops: *const trace_handler_ops_t,
2251 }
2252
2253 unsafe extern "C" {
2255 pub fn trace_context_is_category_enabled(
2258 context: *const trace_context_t,
2259 category_literal: *const libc::c_char,
2260 ) -> bool;
2261
2262 pub fn trace_context_register_string_literal(
2263 context: *const trace_context_t,
2264 string_literal: *const libc::c_char,
2265 out_ref: *mut trace_string_ref_t,
2266 );
2267
2268 #[cfg(fuchsia_api_level_at_least = "27")]
2269 pub fn trace_context_register_bytestring(
2270 context: *const trace_context_t,
2271 string_literal: *const libc::c_char,
2272 length: libc::size_t,
2273 out_ref: *mut trace_string_ref_t,
2274 );
2275
2276 pub fn trace_context_register_category_literal(
2277 context: *const trace_context_t,
2278 category_literal: *const libc::c_char,
2279 out_ref: *mut trace_string_ref_t,
2280 ) -> bool;
2281
2282 pub fn trace_context_register_current_thread(
2283 context: *const trace_context_t,
2284 out_ref: *mut trace_thread_ref_t,
2285 );
2286
2287 pub fn trace_context_register_thread(
2288 context: *const trace_context_t,
2289 process_koid: zx_koid_t,
2290 thread_koid: zx_koid_t,
2291 out_ref: *mut trace_thread_ref_t,
2292 );
2293
2294 #[cfg(fuchsia_api_level_at_least = "31")]
2295 pub fn trace_context_register_vthread_by_ref(
2296 context: *const trace_context_t,
2297 process_koid: zx_koid_t,
2298 vthread_name: *const trace_string_ref_t,
2299 vthread_id: trace_vthread_id_t,
2300 out_ref: *mut trace_thread_ref_t,
2301 );
2302
2303 pub fn trace_context_write_kernel_object_record(
2304 context: *const trace_context_t,
2305 koid: zx_koid_t,
2306 type_: zx_obj_type_t,
2307 args: *const trace_arg_t,
2308 num_args: libc::size_t,
2309 );
2310
2311 pub fn trace_context_write_kernel_object_record_for_handle(
2312 context: *const trace_context_t,
2313 handle: zx_handle_t,
2314 args: *const trace_arg_t,
2315 num_args: libc::size_t,
2316 );
2317
2318 pub fn trace_context_write_process_info_record(
2319 context: *const trace_context_t,
2320 process_koid: zx_koid_t,
2321 process_name_ref: *const trace_string_ref_t,
2322 );
2323
2324 pub fn trace_context_write_thread_info_record(
2325 context: *const trace_context_t,
2326 process_koid: zx_koid_t,
2327 thread_koid: zx_koid_t,
2328 thread_name_ref: *const trace_string_ref_t,
2329 );
2330
2331 pub fn trace_context_write_context_switch_record(
2332 context: *const trace_context_t,
2333 event_time: trace_ticks_t,
2334 cpu_number: trace_cpu_number_t,
2335 outgoing_thread_state: trace_thread_state_t,
2336 outgoing_thread_ref: *const trace_thread_ref_t,
2337 incoming_thread_ref: *const trace_thread_ref_t,
2338 );
2339
2340 pub fn trace_context_write_log_record(
2341 context: *const trace_context_t,
2342 event_time: trace_ticks_t,
2343 thread_ref: *const trace_thread_ref_t,
2344 log_message: *const libc::c_char,
2345 log_message_length: libc::size_t,
2346 );
2347
2348 pub fn trace_context_write_instant_event_record(
2349 context: *const trace_context_t,
2350 event_time: trace_ticks_t,
2351 thread_ref: *const trace_thread_ref_t,
2352 category_ref: *const trace_string_ref_t,
2353 name_ref: *const trace_string_ref_t,
2354 scope: trace_scope_t,
2355 args: *const trace_arg_t,
2356 num_args: libc::size_t,
2357 );
2358
2359 pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
2360
2361 #[cfg(fuchsia_api_level_at_least = "27")]
2362 pub fn trace_context_send_alert_bytestring(
2363 context: *const trace_context_t,
2364 name: *const u8,
2365 length: usize,
2366 );
2367
2368 pub fn trace_context_write_counter_event_record(
2369 context: *const trace_context_t,
2370 event_time: trace_ticks_t,
2371 thread_ref: *const trace_thread_ref_t,
2372 category_ref: *const trace_string_ref_t,
2373 name_ref: *const trace_string_ref_t,
2374 counter_id: trace_counter_id_t,
2375 args: *const trace_arg_t,
2376 num_args: libc::size_t,
2377 );
2378
2379 pub fn trace_context_write_duration_event_record(
2380 context: *const trace_context_t,
2381 start_time: trace_ticks_t,
2382 end_time: trace_ticks_t,
2383 thread_ref: *const trace_thread_ref_t,
2384 category_ref: *const trace_string_ref_t,
2385 name_ref: *const trace_string_ref_t,
2386 args: *const trace_arg_t,
2387 num_args: libc::size_t,
2388 );
2389
2390 pub fn trace_context_write_blob_event_record(
2391 context: *const trace_context_t,
2392 event_time: trace_ticks_t,
2393 thread_ref: *const trace_thread_ref_t,
2394 category_ref: *const trace_string_ref_t,
2395 name_ref: *const trace_string_ref_t,
2396 blob: *const libc::c_void,
2397 blob_size: libc::size_t,
2398 args: *const trace_arg_t,
2399 num_args: libc::size_t,
2400 );
2401
2402 pub fn trace_context_write_duration_begin_event_record(
2403 context: *const trace_context_t,
2404 event_time: trace_ticks_t,
2405 thread_ref: *const trace_thread_ref_t,
2406 category_ref: *const trace_string_ref_t,
2407 name_ref: *const trace_string_ref_t,
2408 args: *const trace_arg_t,
2409 num_args: libc::size_t,
2410 );
2411
2412 pub fn trace_context_write_duration_end_event_record(
2413 context: *const trace_context_t,
2414 event_time: trace_ticks_t,
2415 thread_ref: *const trace_thread_ref_t,
2416 category_ref: *const trace_string_ref_t,
2417 name_ref: *const trace_string_ref_t,
2418 args: *const trace_arg_t,
2419 num_args: libc::size_t,
2420 );
2421
2422 pub fn trace_context_write_async_begin_event_record(
2423 context: *const trace_context_t,
2424 event_time: trace_ticks_t,
2425 thread_ref: *const trace_thread_ref_t,
2426 category_ref: *const trace_string_ref_t,
2427 name_ref: *const trace_string_ref_t,
2428 async_id: trace_async_id_t,
2429 args: *const trace_arg_t,
2430 num_args: libc::size_t,
2431 );
2432
2433 pub fn trace_context_write_async_instant_event_record(
2434 context: *const trace_context_t,
2435 event_time: trace_ticks_t,
2436 thread_ref: *const trace_thread_ref_t,
2437 category_ref: *const trace_string_ref_t,
2438 name_ref: *const trace_string_ref_t,
2439 async_id: trace_async_id_t,
2440 args: *const trace_arg_t,
2441 num_args: libc::size_t,
2442 );
2443
2444 pub fn trace_context_write_async_end_event_record(
2445 context: *const trace_context_t,
2446 event_time: trace_ticks_t,
2447 thread_ref: *const trace_thread_ref_t,
2448 category_ref: *const trace_string_ref_t,
2449 name_ref: *const trace_string_ref_t,
2450 async_id: trace_async_id_t,
2451 args: *const trace_arg_t,
2452 num_args: libc::size_t,
2453 );
2454
2455 pub fn trace_context_write_flow_begin_event_record(
2456 context: *const trace_context_t,
2457 event_time: trace_ticks_t,
2458 thread_ref: *const trace_thread_ref_t,
2459 category_ref: *const trace_string_ref_t,
2460 name_ref: *const trace_string_ref_t,
2461 flow_id: trace_flow_id_t,
2462 args: *const trace_arg_t,
2463 num_args: libc::size_t,
2464 );
2465
2466 pub fn trace_context_write_flow_step_event_record(
2467 context: *const trace_context_t,
2468 event_time: trace_ticks_t,
2469 thread_ref: *const trace_thread_ref_t,
2470 category_ref: *const trace_string_ref_t,
2471 name_ref: *const trace_string_ref_t,
2472 flow_id: trace_flow_id_t,
2473 args: *const trace_arg_t,
2474 num_args: libc::size_t,
2475 );
2476
2477 pub fn trace_context_write_flow_end_event_record(
2478 context: *const trace_context_t,
2479 event_time: trace_ticks_t,
2480 thread_ref: *const trace_thread_ref_t,
2481 category_ref: *const trace_string_ref_t,
2482 name_ref: *const trace_string_ref_t,
2483 flow_id: trace_flow_id_t,
2484 args: *const trace_arg_t,
2485 num_args: libc::size_t,
2486 );
2487
2488 pub fn trace_context_write_initialization_record(
2489 context: *const trace_context_t,
2490 ticks_per_second: u64,
2491 );
2492
2493 pub fn trace_context_write_string_record(
2494 context: *const trace_context_t,
2495 index: trace_string_index_t,
2496 string: *const libc::c_char,
2497 length: libc::size_t,
2498 );
2499
2500 pub fn trace_context_write_thread_record(
2501 context: *const trace_context_t,
2502 index: trace_thread_index_t,
2503 procss_koid: zx_koid_t,
2504 thread_koid: zx_koid_t,
2505 );
2506
2507 pub fn trace_context_write_blob_record(
2508 context: *const trace_context_t,
2509 type_: trace_blob_type_t,
2510 name_ref: *const trace_string_ref_t,
2511 data: *const libc::c_void,
2512 size: libc::size_t,
2513 );
2514
2515 pub fn trace_context_alloc_record(
2516 context: *const trace_context_t,
2517 num_bytes: libc::size_t,
2518 ) -> *mut libc::c_void;
2519
2520 pub fn trace_state() -> trace_state_t;
2522
2523 #[cfg(fuchsia_api_level_at_least = "27")]
2524 pub fn trace_is_category_bytestring_enabled(
2525 category_literal: *const u8,
2526 length: usize,
2527 ) -> bool;
2528
2529 pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2530
2531 pub fn trace_acquire_context() -> *const trace_context_t;
2532
2533 pub fn trace_acquire_context_for_category(
2534 category_literal: *const libc::c_char,
2535 out_ref: *mut trace_string_ref_t,
2536 ) -> *const trace_context_t;
2537
2538 pub fn trace_acquire_context_for_category_cached(
2539 category_literal: *const libc::c_char,
2540 trace_site: *const u64,
2541 out_ref: *mut trace_string_ref_t,
2542 ) -> *const trace_context_t;
2543
2544 #[cfg(fuchsia_api_level_at_least = "27")]
2545 pub fn trace_acquire_context_for_category_bytestring(
2546 bytes: *const u8,
2547 length: usize,
2548 out_ref: *mut trace_string_ref_t,
2549 ) -> *const trace_context_t;
2550
2551 #[cfg(fuchsia_api_level_at_least = "27")]
2552 pub fn trace_acquire_context_for_category_bytestring_cached(
2553 bytes: *const u8,
2554 length: usize,
2555 trace_site: *const u64,
2556 out_ref: *mut trace_string_ref_t,
2557 ) -> *const trace_context_t;
2558
2559 pub fn trace_release_context(context: *const trace_context_t);
2560
2561 pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2562
2563 pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2564
2565 pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2566
2567 pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2568
2569 pub fn trace_notify_observer_updated(event: zx_handle_t);
2570
2571 pub fn trace_context_get_buffering_mode(
2572 context: *const trace_context_t,
2573 ) -> trace_buffering_mode_t;
2574 }
2575}
2576
2577pub struct TraceFutureArgs<'a, C: CategoryString, S: AsTraceStrRef> {
2580 pub category: C,
2581 pub name: S,
2582
2583 pub args: Box<[Arg<'a>]>,
2586
2587 pub flow_id: Option<Id>,
2590
2591 pub _use_trace_future_args: (),
2593}
2594
2595#[doc(hidden)]
2596#[macro_export]
2597macro_rules! __impl_trace_future_args {
2598 ($category:expr, $name:expr, $flow_id:expr) => {
2601 $crate::TraceFutureArgs {
2602 category: $category,
2603 name: $name,
2604 args: ::std::boxed::Box::new([]),
2605 flow_id: $flow_id,
2606 _use_trace_future_args: (),
2607 }
2608 };
2609 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2610 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2611 use $crate::AsTraceStrRef;
2612 let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2613 let args: ::std::boxed::Box<[$crate::Arg<'_>]> = if let Some(context) = context {
2614 ::std::boxed::Box::new(
2615 [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
2616 )
2617 } else {
2618 ::std::boxed::Box::new([])
2619 };
2620 $crate::TraceFutureArgs {
2621 category: $category,
2622 name: $name,
2623 args: args,
2624 flow_id: $flow_id,
2625 _use_trace_future_args: (),
2626 }
2627 }};
2628}
2629
2630#[macro_export]
2642macro_rules! trace_future_args {
2643 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
2644 $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
2645 };
2646 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
2647 $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
2648 };
2649}
2650
2651pub trait TraceFutureExt: Future + Sized {
2653 #[inline(always)]
2667 fn trace<'a, C: CategoryString, S: AsTraceStrRef>(
2668 self,
2669 args: TraceFutureArgs<'a, C, S>,
2670 ) -> TraceFuture<'a, Self, C, S> {
2671 TraceFuture::new(args, self)
2672 }
2673}
2674
2675impl<T: Future + Sized> TraceFutureExt for T {}
2676
2677#[pin_project]
2680pub struct TraceFuture<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> {
2681 #[pin]
2683 future: Fut,
2684 category: C,
2685 name: S,
2686 args: Box<[Arg<'a>]>,
2688 flow_id: Option<Id>,
2689 poll_count: u64,
2690}
2691
2692impl<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> TraceFuture<'a, Fut, C, S> {
2693 #[inline(always)]
2694 pub fn new(args: TraceFutureArgs<'a, C, S>, future: Fut) -> Self {
2695 Self {
2696 future,
2697 category: args.category,
2698 name: args.name,
2699 args: args.args,
2700 flow_id: args.flow_id,
2701 poll_count: 0,
2702 }
2703 }
2704
2705 #[cold]
2706 fn trace_poll(
2707 self: Pin<&mut Self>,
2708 context: &TraceCategoryContext,
2709 cx: &mut std::task::Context<'_>,
2710 ) -> Poll<Fut::Output> {
2711 let start_time = zx::BootTicks::get();
2712 let this = self.project();
2713 *this.poll_count = this.poll_count.saturating_add(1);
2714 let name_ref = this.name.as_trace_str_ref(context);
2715 context.write_duration_begin(start_time, name_ref, &this.args);
2716
2717 let result = this.future.poll(cx);
2718
2719 let flow_id = this.flow_id.get_or_insert_with(Id::new);
2720 let result_str: sys::trace_string_ref_t = if result.is_pending() {
2721 if *this.poll_count == 1 {
2722 context.write_flow_begin(start_time, name_ref, *flow_id, &[]);
2723 } else {
2724 context.write_flow_step(start_time, name_ref, *flow_id, &[]);
2725 }
2726 context.register_str("pending")
2727 } else {
2728 if *this.poll_count != 1 {
2729 context.write_flow_end(start_time, name_ref, *flow_id, &[]);
2730 }
2731 context.register_str("ready")
2732 };
2733 context.write_duration_end(
2734 zx::BootTicks::get(),
2735 name_ref,
2736 &[
2737 ArgValue::of_registered(context.register_str("poll-state"), result_str),
2738 ArgValue::of_registered(context.register_str("poll-count"), *this.poll_count),
2739 ],
2740 );
2741 result
2742 }
2743}
2744
2745impl<Fut: Future, C: CategoryString, S: AsTraceStrRef> Future for TraceFuture<'_, Fut, C, S> {
2746 type Output = Fut::Output;
2747 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
2748 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2749 self.trace_poll(&context, cx)
2750 } else {
2751 self.project().future.poll(cx)
2752 }
2753 }
2754}
2755
2756#[cfg(test)]
2757mod test {
2758 use super::{Id, trim_to_last_char_boundary};
2759
2760 #[test]
2761 fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
2762 assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
2763 assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
2764 assert_eq!(b"", trim_to_last_char_boundary("x", 0));
2765 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
2766 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
2767 assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
2768
2769 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
2770 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
2771 assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
2772 }
2773
2774 #[test]
2778 fn test_id_new() {
2779 assert_ne!(Id::new(), Id::new());
2780 }
2781}