1#[cfg(not(fuchsia_api_level_at_least = "31"))]
6use fuchsia_runtime as _;
7use pin_project::pin_project;
8use std::ffi::CStr;
9use std::future::Future;
10use std::marker::PhantomData;
11use std::pin::Pin;
12use std::sync::atomic::Ordering;
13use std::task::Poll;
14use std::{mem, ptr};
15
16pub use sys::{
17 TRACE_BLOB_TYPE_DATA, TRACE_BLOB_TYPE_LAST_BRANCH, TRACE_BLOB_TYPE_PERFETTO, trace_site_t,
18 trace_string_ref_t,
19};
20
21#[derive(Copy, Clone)]
23pub enum Scope {
24 Thread,
25 Process,
26 Global,
27}
28
29impl Scope {
30 fn into_raw(self) -> sys::trace_scope_t {
31 match self {
32 Scope::Thread => sys::TRACE_SCOPE_THREAD,
33 Scope::Process => sys::TRACE_SCOPE_PROCESS,
34 Scope::Global => sys::TRACE_SCOPE_GLOBAL,
35 }
36 }
37}
38
39#[inline]
41pub fn is_enabled() -> bool {
42 unsafe { sys::trace_state() != sys::TRACE_STOPPED }
44}
45
46pub fn category_enabled<S: CategoryString>(category: S) -> bool {
48 category.is_category_enabled()
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub enum TraceState {
53 Stopped,
54 Started,
55 Stopping,
56}
57
58pub fn trace_state() -> TraceState {
59 match unsafe { sys::trace_state() } {
60 sys::TRACE_STOPPED => TraceState::Stopped,
61 sys::TRACE_STARTED => TraceState::Started,
62 sys::TRACE_STOPPING => TraceState::Stopping,
63 s => panic!("Unknown trace state {:?}", s),
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68#[repr(i32)]
69pub enum BufferingMode {
70 OneShot = sys::TRACE_BUFFERING_MODE_ONESHOT,
71 Circular = sys::TRACE_BUFFERING_MODE_CIRCULAR,
72 Streaming = sys::TRACE_BUFFERING_MODE_STREAMING,
73}
74
75#[repr(transparent)]
77#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub struct Id(u64);
79
80impl Id {
81 pub fn new() -> Self {
83 let ts = zx::BootInstant::get().into_nanos() as u64;
86 let high_order = ts << 16;
87 let low_order = rand::random::<u16>() as u64;
88 Self(high_order | low_order)
89 }
90}
91
92impl From<u64> for Id {
93 fn from(u: u64) -> Self {
94 Self(u)
95 }
96}
97
98impl From<Id> for u64 {
99 fn from(id: Id) -> Self {
100 id.0
101 }
102}
103
104pub trait CategoryString: Copy {
105 fn register(&self, context: &Context) -> sys::trace_string_ref_t;
107
108 fn acquire_context(&self) -> Option<TraceCategoryContext>;
111
112 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext>;
114
115 fn is_category_enabled(&self) -> bool;
117}
118
119impl CategoryString for &'static CStr {
120 fn register(&self, context: &Context) -> sys::trace_string_ref_t {
121 unsafe {
122 let mut self_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
123 sys::trace_context_register_string_literal(
124 context.raw,
125 self.as_ptr(),
126 self_ref.as_mut_ptr(),
127 );
128 self_ref.assume_init()
129 }
130 }
131
132 fn acquire_context(&self) -> Option<TraceCategoryContext> {
133 unsafe {
134 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
135 let raw =
136 sys::trace_acquire_context_for_category(self.as_ptr(), category_ref.as_mut_ptr());
137 if raw != ptr::null() {
138 Some(TraceCategoryContext {
139 context: Context { raw },
140 category_ref: category_ref.assume_init(),
141 })
142 } else {
143 None
144 }
145 }
146 }
147
148 #[inline]
149 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext> {
150 let current_state = site.load(Ordering::Relaxed);
151 if (current_state & 1) != 0 {
154 return None;
155 }
156 unsafe {
157 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
162 let raw = sys::trace_acquire_context_for_category_cached(
163 self.as_ptr(),
164 site.as_ptr(),
165 category_ref.as_mut_ptr(),
166 );
167 if raw != ptr::null() {
168 Some(TraceCategoryContext {
169 context: Context { raw },
170 category_ref: category_ref.assume_init(),
171 })
172 } else {
173 None
174 }
175 }
176 }
177
178 fn is_category_enabled(&self) -> bool {
179 unsafe { sys::trace_is_category_enabled(self.as_ptr()) }
180 }
181}
182
183#[cfg(fuchsia_api_level_at_least = "27")]
184impl CategoryString for &'static str {
185 fn register(&self, context: &Context) -> sys::trace_string_ref_t {
186 unsafe {
187 let mut self_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
188 sys::trace_context_register_bytestring(
189 context.raw,
190 self.as_ptr().cast::<libc::c_char>(),
191 self.len(),
192 self_ref.as_mut_ptr(),
193 );
194 self_ref.assume_init()
195 }
196 }
197
198 fn acquire_context(&self) -> Option<TraceCategoryContext> {
199 unsafe {
200 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
201 let raw = sys::trace_acquire_context_for_category_bytestring(
202 self.as_ptr(),
203 self.len(),
204 category_ref.as_mut_ptr(),
205 );
206 if raw != ptr::null() {
207 Some(TraceCategoryContext {
208 context: Context { raw },
209 category_ref: category_ref.assume_init(),
210 })
211 } else {
212 None
213 }
214 }
215 }
216
217 #[inline]
218 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext> {
219 let current_state = site.load(Ordering::Relaxed);
220 if (current_state & 1) != 0 {
223 return None;
224 }
225 unsafe {
226 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 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 #[inline]
290 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
291 context.register_string_literal(*self)
292 }
293}
294
295impl AsTraceStrRef for &'static str {
299 #[inline]
300 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
301 context.register_str(self)
302 }
303}
304
305impl AsTraceStrRef for String {
306 #[inline]
307 fn as_trace_str_ref(&self, _context: &TraceCategoryContext) -> sys::trace_string_ref_t {
308 trace_make_inline_string_ref(self.as_str())
309 }
310}
311
312impl AsTraceStrRef for std::borrow::Cow<'static, str> {
313 #[inline]
314 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
315 match self {
316 std::borrow::Cow::Borrowed(s) => s.as_trace_str_ref(context),
317 std::borrow::Cow::Owned(s) => s.as_trace_str_ref(context),
318 }
319 }
320}
321
322impl<T: AsTraceStrRef> AsTraceStrRef for &T {
324 #[inline]
325 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
326 (*self).as_trace_str_ref(context)
327 }
328}
329
330#[repr(transparent)]
332pub struct Arg<'a>(sys::trace_arg_t, PhantomData<&'a ()>);
333
334pub trait ArgValue {
340 fn of<'a>(key: &'a str, value: Self) -> Arg<'a>
341 where
342 Self: 'a;
343 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, value: Self) -> Arg<'a>
344 where
345 Self: 'a;
346}
347
348macro_rules! arg_from {
354 ($valname:ident, $(($type:ty, $tag:expr, $value:expr))*) => {
355 $(
356 impl ArgValue for $type {
357 #[inline]
358 fn of<'a>(key: &'a str, $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: trace_make_inline_string_ref(key),
366 value: sys::trace_arg_value_t {
367 type_: $tag,
368 value: $value,
369 },
370 }, PhantomData)
371 }
372 #[inline]
373 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, $valname: Self) -> Arg<'a>
374 where Self: 'a
375 {
376 #[allow(unused)]
377 let $valname = $valname;
378
379 Arg(sys::trace_arg_t {
380 name_ref,
381 value: sys::trace_arg_value_t {
382 type_: $tag,
383 value: $value,
384 },
385 }, PhantomData)
386 }
387 }
388 )*
389 }
390}
391
392#[rustfmt::skip]
394arg_from!(val,
395 ((), sys::TRACE_ARG_NULL, sys::trace_arg_union_t { int32_value: 0 })
396 (bool, sys::TRACE_ARG_BOOL, sys::trace_arg_union_t { bool_value: val })
397 (i32, sys::TRACE_ARG_INT32, sys::trace_arg_union_t { int32_value: val })
398 (u32, sys::TRACE_ARG_UINT32, sys::trace_arg_union_t { uint32_value: val })
399 (i64, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val })
400 (u64, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val })
401 (isize, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val as i64 })
402 (usize, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val as u64 })
403 (f64, sys::TRACE_ARG_DOUBLE, sys::trace_arg_union_t { double_value: val })
404 (zx::Koid, sys::TRACE_ARG_KOID, sys::trace_arg_union_t { koid_value: val.raw_koid() })
405);
406
407impl<T> ArgValue for *const T {
408 #[inline]
409 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
410 where
411 Self: 'a,
412 {
413 Arg(
414 sys::trace_arg_t {
415 name_ref: trace_make_inline_string_ref(key),
416 value: sys::trace_arg_value_t {
417 type_: sys::TRACE_ARG_POINTER,
418 value: sys::trace_arg_union_t { pointer_value: val as usize },
419 },
420 },
421 PhantomData,
422 )
423 }
424 #[inline]
425 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
426 where
427 Self: 'a,
428 {
429 Arg(
430 sys::trace_arg_t {
431 name_ref,
432 value: sys::trace_arg_value_t {
433 type_: sys::TRACE_ARG_POINTER,
434 value: sys::trace_arg_union_t { pointer_value: val as usize },
435 },
436 },
437 PhantomData,
438 )
439 }
440}
441
442impl<T> ArgValue for *mut T {
443 #[inline]
444 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
445 where
446 Self: 'a,
447 {
448 Arg(
449 sys::trace_arg_t {
450 name_ref: trace_make_inline_string_ref(key),
451 value: sys::trace_arg_value_t {
452 type_: sys::TRACE_ARG_POINTER,
453 value: sys::trace_arg_union_t { pointer_value: val as usize },
454 },
455 },
456 PhantomData,
457 )
458 }
459 #[inline]
460 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
461 where
462 Self: 'a,
463 {
464 Arg(
465 sys::trace_arg_t {
466 name_ref,
467 value: sys::trace_arg_value_t {
468 type_: sys::TRACE_ARG_POINTER,
469 value: sys::trace_arg_union_t { pointer_value: val as usize },
470 },
471 },
472 PhantomData,
473 )
474 }
475}
476
477impl<'a> ArgValue for &'a str {
478 #[inline]
479 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
480 where
481 Self: 'b,
482 {
483 Arg(
484 sys::trace_arg_t {
485 name_ref: trace_make_inline_string_ref(key),
486 value: sys::trace_arg_value_t {
487 type_: sys::TRACE_ARG_STRING,
488 value: sys::trace_arg_union_t {
489 string_value_ref: trace_make_inline_string_ref(val),
490 },
491 },
492 },
493 PhantomData,
494 )
495 }
496 #[inline]
497 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
498 where
499 Self: 'b,
500 {
501 Arg(
502 sys::trace_arg_t {
503 name_ref,
504 value: sys::trace_arg_value_t {
505 type_: sys::TRACE_ARG_STRING,
506 value: sys::trace_arg_union_t {
507 string_value_ref: trace_make_inline_string_ref(val),
508 },
509 },
510 },
511 PhantomData,
512 )
513 }
514}
515
516impl<'a> ArgValue for sys::trace_string_ref_t {
517 #[inline]
518 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
519 where
520 Self: 'b,
521 {
522 Arg(
523 sys::trace_arg_t {
524 name_ref: trace_make_inline_string_ref(key),
525 value: sys::trace_arg_value_t {
526 type_: sys::TRACE_ARG_STRING,
527 value: sys::trace_arg_union_t { string_value_ref: val },
528 },
529 },
530 PhantomData,
531 )
532 }
533 #[inline]
534 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
535 where
536 Self: 'b,
537 {
538 Arg(
539 sys::trace_arg_t {
540 name_ref,
541 value: sys::trace_arg_value_t {
542 type_: sys::TRACE_ARG_STRING,
543 value: sys::trace_arg_union_t { string_value_ref: val },
544 },
545 },
546 PhantomData,
547 )
548 }
549}
550
551#[macro_export]
573macro_rules! instant {
574 ($category:expr, $name:expr, $scope:expr $(, $key:expr => $val:expr)*) => {
575 {
576 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
577 use $crate::AsTraceStrRef;
578 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
579 $crate::instant(&context, $name, $scope, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
580 }
581 }
582 }
583}
584
585#[inline]
588pub fn instant<S: AsTraceStrRef>(
589 context: &TraceCategoryContext,
590 name: S,
591 scope: Scope,
592 args: &[Arg<'_>],
593) {
594 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
595
596 let name_ref = name.as_trace_str_ref(context);
597 context.write_instant(name_ref, scope, args);
598}
599
600#[macro_export]
614macro_rules! alert {
615 ($category:expr, $name:expr) => {
616 $crate::alert($category, $name)
617 };
618}
619
620pub fn alert<C: CategoryString, S: AlertString>(category: C, name: S) {
622 if let Some(context) = category.acquire_context() {
623 name.send_alert(&context.context);
624 }
625}
626
627#[macro_export]
644macro_rules! counter {
645 ($category:expr, $name:expr, $counter_id:expr $(, $key:expr => $val:expr)*) => {
646 {
647 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
648 use $crate::AsTraceStrRef;
649 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
650 $crate::counter(&context, $name, $counter_id,
651 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
652 }
653 }
654 }
655}
656
657pub fn counter<S: AsTraceStrRef>(
667 context: &TraceCategoryContext,
668 name: S,
669 counter_id: u64,
670 args: &[Arg<'_>],
671) {
672 assert!(args.len() >= 1, "trace counter args must include at least one numeric argument");
673 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
674
675 let name_ref = name.as_trace_str_ref(context);
676 context.write_counter(name_ref, counter_id, args);
677}
678
679#[must_use = "DurationScope must be `end`ed to be recorded"]
682pub struct DurationScope<'a, C: CategoryString, S: AsTraceStrRef> {
683 category: C,
684 name: S,
685 args: &'a [Arg<'a>],
686 start_time: zx::BootTicks,
687}
688
689impl<'a, C: CategoryString, S: AsTraceStrRef> DurationScope<'a, C, S> {
690 pub fn begin(category: C, name: S, args: &'a [Arg<'_>]) -> Self {
693 let start_time = zx::BootTicks::get();
694 Self { category, name, args, start_time }
695 }
696}
697
698impl<'a, C: CategoryString, S: AsTraceStrRef> Drop for DurationScope<'a, C, S> {
699 fn drop(&mut self) {
700 if let Some(context) = TraceCategoryContext::acquire(self.category) {
701 let name_ref = self.name.as_trace_str_ref(&context);
702 context.write_duration(name_ref, self.start_time, self.args);
703 }
704 }
705}
706
707pub fn complete_duration<C: CategoryString, S: AsTraceStrRef>(
709 category: C,
710 name: S,
711 start_time: zx::BootTicks,
712 args: &[Arg<'_>],
713) {
714 if let Some(context) = TraceCategoryContext::acquire(category) {
715 let name_ref = name.as_trace_str_ref(&context);
716 context.write_duration(name_ref, start_time, args);
717 }
718}
719
720#[macro_export]
755macro_rules! duration {
756 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
757 let mut args;
758 let _scope = {
759 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
760 use $crate::AsTraceStrRef;
767 if let Some(context) =
768 $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
769 args = [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*];
770 Some($crate::duration($category, $name, &args))
771 } else {
772 None
773 }
774 };
775 }
776}
777
778pub fn duration<'a, C: CategoryString, S: AsTraceStrRef>(
790 category: C,
791 name: S,
792 args: &'a [Arg<'_>],
793) -> DurationScope<'a, C, S> {
794 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
795 DurationScope::begin(category, name, args)
796}
797
798#[macro_export]
812macro_rules! duration_begin {
813 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
814 {
815 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
816 use $crate::AsTraceStrRef;
817 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
818 $crate::duration_begin(&context, $name,
819 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
820 }
821 }
822 };
823}
824
825#[cfg(fuchsia_api_level_at_least = "31")]
841#[macro_export]
842macro_rules! vthread_duration_begin {
843 ($category:expr, $name:expr, $vthread_name:expr, $vthread_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
844 {
845 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
846 let vthread = $crate::VThread::new($vthread_name, $vthread_id);
847 use $crate::AsTraceStrRef;
848 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
849 $crate::vthread_duration_begin(
850 &context,
851 $name,
852 &vthread,
853 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
854 )
855 }
856 }
857 };
858}
859
860#[macro_export]
874macro_rules! duration_end {
875 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
876 {
877 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
878 use $crate::AsTraceStrRef;
879 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
880 $crate::duration_end(&context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
881 }
882 }
883 };
884}
885
886#[cfg(fuchsia_api_level_at_least = "31")]
902#[macro_export]
903macro_rules! vthread_duration_end {
904 ($category:expr, $name:expr, $vthread_name:expr, $vthread_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
905 {
906 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
907 let vthread = $crate::VThread::new($vthread_name, $vthread_id);
908 use $crate::AsTraceStrRef;
909 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
910 $crate::vthread_duration_end(
911 &context,
912 $name,
913 &vthread,
914 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
915 )
916 }
917 }
918 };
919}
920
921#[cfg(fuchsia_api_level_at_least = "31")]
926#[macro_export]
927macro_rules! track_instant {
928 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
929 {
930 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
931 use $crate::AsTraceStrRef;
932 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
933 $crate::track_instant(
934 &context,
935 $name,
936 &$track,
937 $crate::Scope::Thread,
938 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
939 )
940 }
941 }
942 };
943}
944
945#[cfg(fuchsia_api_level_at_least = "31")]
947#[macro_export]
948macro_rules! track_duration_begin {
949 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
950 {
951 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
952 use $crate::AsTraceStrRef;
953 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
954 $crate::track_duration_begin(
955 &context,
956 $name,
957 &$track,
958 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
959 )
960 }
961 }
962 };
963}
964
965#[cfg(fuchsia_api_level_at_least = "31")]
967#[macro_export]
968macro_rules! track_duration_end {
969 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
970 {
971 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
972 use $crate::AsTraceStrRef;
973 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
974 $crate::track_duration_end(
975 &context,
976 $name,
977 &$track,
978 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
979 )
980 }
981 }
982 };
983}
984
985#[cfg(fuchsia_api_level_at_least = "31")]
992#[macro_export]
993macro_rules! track_duration {
994 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
995 let mut args;
1001 let _scope = {
1002 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1003 use $crate::AsTraceStrRef;
1004 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1005 args = [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*];
1006 Some($crate::track_duration($category, $name, &$track, &args))
1007 } else {
1008 None
1009 }
1010 };
1011 };
1012}
1013
1014pub fn duration_begin<S: AsTraceStrRef>(context: &TraceCategoryContext, name: S, args: &[Arg<'_>]) {
1025 let ticks = zx::BootTicks::get();
1026 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1027
1028 let name_ref = name.as_trace_str_ref(&context);
1029 context.write_duration_begin(ticks, name_ref, args);
1030}
1031
1032#[cfg(fuchsia_api_level_at_least = "31")]
1033#[derive(Clone, Debug)]
1034pub struct VThread<S: AsTraceStrRef = &'static str> {
1035 name: S,
1036 id: sys::trace_vthread_id_t,
1037 process_koid: zx::sys::zx_koid_t,
1038}
1039
1040#[cfg(fuchsia_api_level_at_least = "31")]
1041impl<S: AsTraceStrRef> VThread<S> {
1042 pub fn new(name: S, id: sys::trace_vthread_id_t) -> Self {
1043 Self { name, id, process_koid: zx::sys::ZX_KOID_INVALID }
1044 }
1045
1046 pub fn new_with_process_koid(
1047 name: S,
1048 id: sys::trace_vthread_id_t,
1049 process_koid: zx::sys::zx_koid_t,
1050 ) -> Self {
1051 Self { name, id, process_koid }
1052 }
1053}
1054
1055#[cfg(fuchsia_api_level_at_least = "31")]
1057pub fn vthread_duration_begin<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1058 context: &TraceCategoryContext,
1059 name: S1,
1060 vthread: &VThread<S2>,
1061 args: &[Arg<'_>],
1062) {
1063 let ticks = zx::BootTicks::get();
1064 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1065
1066 let name_ref = name.as_trace_str_ref(context);
1067 context.write_vthread_duration_begin(ticks, name_ref, vthread, args);
1068}
1069
1070pub fn duration_end<S: AsTraceStrRef>(context: &TraceCategoryContext, name: S, args: &[Arg<'_>]) {
1080 let ticks = zx::BootTicks::get();
1081 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1082
1083 let name_ref = name.as_trace_str_ref(&context);
1084 context.write_duration_end(ticks, name_ref, args);
1085}
1086
1087#[cfg(fuchsia_api_level_at_least = "31")]
1089pub fn vthread_duration_end<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1090 context: &TraceCategoryContext,
1091 name: S1,
1092 vthread: &VThread<S2>,
1093 args: &[Arg<'_>],
1094) {
1095 let ticks = zx::BootTicks::get();
1096 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1097
1098 let name_ref = name.as_trace_str_ref(context);
1099 context.write_vthread_duration_end(ticks, name_ref, vthread, args);
1100}
1101
1102#[cfg(fuchsia_api_level_at_least = "31")]
1104pub fn vthread_instant<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1105 context: &TraceCategoryContext,
1106 name: S1,
1107 vthread: &VThread<S2>,
1108 scope: Scope,
1109 args: &[Arg<'_>],
1110) {
1111 let ticks = zx::BootTicks::get();
1112 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1113
1114 let name_ref = name.as_trace_str_ref(context);
1115 context.write_vthread_instant(ticks, name_ref, vthread, scope, args);
1116}
1117
1118#[cfg(fuchsia_api_level_at_least = "31")]
1126#[derive(Clone, Debug)]
1127pub struct Track {
1128 pub(crate) vthread: VThread<&'static str>,
1129}
1130
1131#[cfg(fuchsia_api_level_at_least = "31")]
1132impl Track {
1133 pub fn new(name: &'static str) -> Self {
1141 let id = Id::new();
1142 let process_koid = fuchsia_runtime::process_self()
1143 .koid()
1144 .map(|k| k.raw_koid())
1145 .unwrap_or(zx::sys::ZX_KOID_INVALID);
1146 Self { vthread: VThread::new_with_process_koid(name, id.into(), process_koid) }
1147 }
1148}
1149
1150#[cfg(fuchsia_api_level_at_least = "31")]
1156pub fn track_instant<S1: AsTraceStrRef>(
1157 context: &TraceCategoryContext,
1158 name: S1,
1159 track: &Track,
1160 scope: Scope,
1161 args: &[Arg<'_>],
1162) {
1163 vthread_instant(context, name, &track.vthread, scope, args);
1164}
1165
1166#[cfg(fuchsia_api_level_at_least = "31")]
1168pub fn track_duration_begin<S1: AsTraceStrRef>(
1169 context: &TraceCategoryContext,
1170 name: S1,
1171 track: &Track,
1172 args: &[Arg<'_>],
1173) {
1174 vthread_duration_begin(context, name, &track.vthread, args);
1175}
1176
1177#[cfg(fuchsia_api_level_at_least = "31")]
1179pub fn track_duration_end<S1: AsTraceStrRef>(
1180 context: &TraceCategoryContext,
1181 name: S1,
1182 track: &Track,
1183 args: &[Arg<'_>],
1184) {
1185 vthread_duration_end(context, name, &track.vthread, args);
1186}
1187
1188#[cfg(fuchsia_api_level_at_least = "31")]
1196#[must_use = "TrackDurationScope must be held to be recorded"]
1197pub struct TrackDurationScope<'a, C: CategoryString, S: AsTraceStrRef> {
1198 category: C,
1199 name: S,
1200 track: &'a Track,
1201 args: &'a [Arg<'a>],
1202 start_time: zx::BootTicks,
1203}
1204
1205#[cfg(fuchsia_api_level_at_least = "31")]
1206impl<'a, C: CategoryString, S: AsTraceStrRef> TrackDurationScope<'a, C, S> {
1207 pub fn begin(category: C, name: S, track: &'a Track, args: &'a [Arg<'_>]) -> Self {
1209 let start_time = zx::BootTicks::get();
1210 Self { category, name, track, args, start_time }
1211 }
1212}
1213
1214#[cfg(fuchsia_api_level_at_least = "31")]
1215impl<'a, C: CategoryString, S: AsTraceStrRef> Drop for TrackDurationScope<'a, C, S> {
1216 fn drop(&mut self) {
1217 if let Some(context) = TraceCategoryContext::acquire(self.category) {
1218 let name_ref = self.name.as_trace_str_ref(&context);
1219 context.write_vthread_duration(
1220 self.start_time,
1221 zx::BootTicks::get(),
1222 name_ref,
1223 &self.track.vthread,
1224 self.args,
1225 );
1226 }
1227 }
1228}
1229
1230#[cfg(fuchsia_api_level_at_least = "31")]
1235pub fn track_duration<'a, C: CategoryString, S: AsTraceStrRef>(
1236 category: C,
1237 name: S,
1238 track: &'a Track,
1239 args: &'a [Arg<'_>],
1240) -> TrackDurationScope<'a, C, S> {
1241 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1242 TrackDurationScope::begin(category, name, track, args)
1243}
1244
1245#[must_use = "emits an end event when dropped, so if dropped immediately creates an essentially \
1248 zero length duration that should just be an instant instead"]
1249pub struct AsyncScope<C: CategoryString = &'static CStr, S: AsTraceStrRef = &'static CStr> {
1250 id: Id,
1253 category: C,
1254 name: S,
1255}
1256
1257impl<C: CategoryString, S: AsTraceStrRef> AsyncScope<C, S> {
1258 pub fn begin(id: Id, category: C, name: S, args: &[Arg<'_>]) -> Self {
1261 async_begin(id, category, &name, args);
1262 Self { id, category, name }
1263 }
1264
1265 pub fn end(self, args: &[Arg<'_>]) {
1268 async_end(self.id, self.category, &self.name, args);
1269 std::mem::forget(self);
1270 }
1271}
1272
1273impl<C: CategoryString, S: AsTraceStrRef> Drop for AsyncScope<C, S> {
1274 fn drop(&mut self) {
1275 async_end(self.id, self.category, &self.name, &[]);
1279 }
1280}
1281
1282pub fn async_enter<C: CategoryString, S: AsTraceStrRef>(
1291 id: Id,
1292 category: C,
1293 name: S,
1294 args: &[Arg<'_>],
1295) -> AsyncScope<C, S> {
1296 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1297 AsyncScope::begin(id, category, name, args)
1298}
1299
1300#[macro_export]
1331macro_rules! async_enter {
1332 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
1333 {
1334 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1335 use $crate::AsTraceStrRef;
1336 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1337 Some($crate::AsyncScope::begin($id, $category, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]))
1338 } else {
1339 None
1340 }
1341 }
1342 }
1343}
1344
1345#[macro_export]
1369macro_rules! async_instant {
1370 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
1371 {
1372 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1373 use $crate::AsTraceStrRef;
1374 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1375 $crate::async_instant($id, &context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
1376 }
1377 }
1378 }
1379}
1380
1381pub fn async_begin<C: CategoryString, S: AsTraceStrRef>(
1393 id: Id,
1394 category: C,
1395 name: S,
1396 args: &[Arg<'_>],
1397) {
1398 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1399
1400 if let Some(context) = TraceCategoryContext::acquire(category) {
1401 let name_ref = name.as_trace_str_ref(&context);
1402 context.write_async_begin(id, name_ref, args);
1403 }
1404}
1405
1406pub fn async_end<C: CategoryString, S: AsTraceStrRef>(
1418 id: Id,
1419 category: C,
1420 name: S,
1421 args: &[Arg<'_>],
1422) {
1423 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1424
1425 if let Some(context) = TraceCategoryContext::acquire(category) {
1426 let name_ref = name.as_trace_str_ref(&context);
1427 context.write_async_end(id, name_ref, args);
1428 }
1429}
1430
1431pub fn async_instant<S: AsTraceStrRef>(
1443 id: Id,
1444 context: &TraceCategoryContext,
1445 name: S,
1446 args: &[Arg<'_>],
1447) {
1448 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1449
1450 let name_ref = name.as_trace_str_ref(context);
1451 context.write_async_instant(id, name_ref, args);
1452}
1453
1454#[macro_export]
1455macro_rules! blob {
1456 ($category:expr, $name:expr, $bytes:expr $(, $key:expr => $val:expr)*) => {
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::blob_fn(&context, $name, $bytes, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1462 }
1463 }
1464 }
1465}
1466pub fn blob_fn<S: AsTraceStrRef>(
1467 context: &TraceCategoryContext,
1468 name: S,
1469 bytes: &[u8],
1470 args: &[Arg<'_>],
1471) {
1472 let name_ref = name.as_trace_str_ref(context);
1473 context.write_blob(name_ref, bytes, args);
1474}
1475
1476#[macro_export]
1500macro_rules! flow_begin {
1501 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1502 {
1503 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1504 use $crate::AsTraceStrRef;
1505 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1506 $crate::flow_begin(&context, $name, $flow_id,
1507 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1508 }
1509 }
1510 }
1511}
1512
1513#[macro_export]
1537macro_rules! flow_step {
1538 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1539 {
1540 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1541 use $crate::AsTraceStrRef;
1542 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1543 $crate::flow_step(&context, $name, $flow_id,
1544 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1545 }
1546 }
1547 }
1548}
1549
1550#[macro_export]
1574macro_rules! flow_end {
1575 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1576 {
1577 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1578 use $crate::AsTraceStrRef;
1579 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1580 $crate::flow_end(&context, $name, $flow_id,
1581 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1582 }
1583 }
1584 }
1585}
1586
1587pub fn flow_begin<S: AsTraceStrRef>(
1608 context: &TraceCategoryContext,
1609 name: S,
1610 flow_id: Id,
1611 args: &[Arg<'_>],
1612) {
1613 let ticks = zx::BootTicks::get();
1614 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1615
1616 let name_ref = name.as_trace_str_ref(context);
1617 context.write_flow_begin(ticks, name_ref, flow_id, args);
1618}
1619
1620pub fn flow_end<S: AsTraceStrRef>(
1639 context: &TraceCategoryContext,
1640 name: S,
1641 flow_id: Id,
1642 args: &[Arg<'_>],
1643) {
1644 let ticks = zx::BootTicks::get();
1645 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1646
1647 let name_ref = name.as_trace_str_ref(context);
1648 context.write_flow_end(ticks, name_ref, flow_id, args);
1649}
1650
1651pub fn flow_step<S: AsTraceStrRef>(
1670 context: &TraceCategoryContext,
1671 name: S,
1672 flow_id: Id,
1673 args: &[Arg<'_>],
1674) {
1675 let ticks = zx::BootTicks::get();
1676 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1677
1678 let name_ref = name.as_trace_str_ref(context);
1679 context.write_flow_step(ticks, name_ref, flow_id, args);
1680}
1681
1682#[macro_export]
1696macro_rules! instaflow_begin {
1697 (
1698 $category:expr,
1699 $flow_name:expr,
1700 $step_name:expr,
1701 $flow_id:expr
1702 $(, $key:expr => $val:expr)*
1703 ) => {
1704 {
1705 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1706 use $crate::AsTraceStrRef;
1707 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1708 $crate::instaflow_begin(
1709 &context,
1710 $flow_name,
1711 $step_name,
1712 $flow_id,
1713 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1714 )
1715 }
1716 }
1717 }
1718}
1719
1720#[macro_export]
1734macro_rules! instaflow_end {
1735 (
1736 $category:expr,
1737 $flow_name:expr,
1738 $step_name:expr,
1739 $flow_id:expr
1740 $(, $key:expr => $val:expr)*
1741 ) => {
1742 {
1743 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1744 use $crate::AsTraceStrRef;
1745 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1746 $crate::instaflow_end(
1747 &context,
1748 $flow_name,
1749 $step_name,
1750 $flow_id,
1751 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1752 )
1753 }
1754 }
1755 }
1756}
1757
1758#[macro_export]
1772macro_rules! instaflow_step {
1773 (
1774 $category:expr,
1775 $flow_name:expr,
1776 $step_name:expr,
1777 $flow_id:expr
1778 $(, $key:expr => $val:expr)*
1779 ) => {
1780 {
1781 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1782 use $crate::AsTraceStrRef;
1783 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1784 $crate::instaflow_step(
1785 &context,
1786 $flow_name,
1787 $step_name,
1788 $flow_id,
1789 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1790 )
1791 }
1792 }
1793 }
1794}
1795
1796pub fn instaflow_begin<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1810 context: &TraceCategoryContext,
1811 flow_name: S1,
1812 step_name: S2,
1813 flow_id: Id,
1814 args: &[Arg<'_>],
1815) {
1816 let ticks = zx::BootTicks::get();
1817 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1818
1819 let flow_name_ref = flow_name.as_trace_str_ref(context);
1820 let step_name_ref = step_name.as_trace_str_ref(context);
1821
1822 context.write_duration_begin(ticks, step_name_ref, args);
1823 context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1824 context.write_duration_end(ticks, step_name_ref, args);
1825}
1826
1827pub fn instaflow_end<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1841 context: &TraceCategoryContext,
1842 flow_name: S1,
1843 step_name: S2,
1844 flow_id: Id,
1845 args: &[Arg<'_>],
1846) {
1847 let ticks = zx::BootTicks::get();
1848 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1849
1850 let flow_name_ref = flow_name.as_trace_str_ref(context);
1851 let step_name_ref = step_name.as_trace_str_ref(context);
1852
1853 context.write_duration_begin(ticks, step_name_ref, args);
1854 context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1855 context.write_duration_end(ticks, step_name_ref, args);
1856}
1857
1858pub fn instaflow_step<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1872 context: &TraceCategoryContext,
1873 flow_name: S1,
1874 step_name: S2,
1875 flow_id: Id,
1876 args: &[Arg<'_>],
1877) {
1878 let ticks = zx::BootTicks::get();
1879 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1880
1881 let flow_name_ref = flow_name.as_trace_str_ref(context);
1882 let step_name_ref = step_name.as_trace_str_ref(context);
1883
1884 context.write_duration_begin(ticks, step_name_ref, args);
1885 context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1886 context.write_duration_end(ticks, step_name_ref, args);
1887}
1888
1889const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1891 sys::trace_string_ref_t {
1892 encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1893 inline_string: ptr::null(),
1894 }
1895}
1896
1897#[inline]
1898fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1899 let mut len = string.len();
1900 if string.len() > max_len {
1901 len = max_len;
1905 while len > 0 {
1906 if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1907 break;
1908 }
1909 len -= 1;
1910 }
1911 }
1912 &string.as_bytes()[0..len]
1913}
1914
1915#[inline]
1918fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1919 let len = string.len() as u16;
1920 if len == 0 {
1921 return trace_make_empty_string_ref();
1922 }
1923
1924 let string = trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH);
1925
1926 sys::trace_string_ref_t {
1927 encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1928 inline_string: string.as_ptr() as *const libc::c_char,
1929 }
1930}
1931
1932pub struct TraceCategoryContext {
1934 context: Context,
1935 category_ref: sys::trace_string_ref_t,
1936}
1937
1938impl TraceCategoryContext {
1939 #[inline]
1940 pub fn acquire_cached<C: CategoryString>(
1941 category: C,
1942 site: &sys::trace_site_t,
1943 ) -> Option<TraceCategoryContext> {
1944 category.acquire_context_cached(site)
1945 }
1946
1947 pub fn acquire<C: CategoryString>(category: C) -> Option<TraceCategoryContext> {
1948 category.acquire_context()
1949 }
1950
1951 #[inline]
1952 pub fn register_string_literal<T: CategoryString>(&self, name: T) -> sys::trace_string_ref_t {
1953 name.register(&self.context)
1954 }
1955
1956 #[inline]
1957 #[cfg(fuchsia_api_level_at_least = "27")]
1958 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1959 unsafe {
1960 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1961 sys::trace_context_register_bytestring(
1962 self.context.raw,
1963 name.as_ptr().cast::<libc::c_char>(),
1964 name.len(),
1965 name_ref.as_mut_ptr(),
1966 );
1967 name_ref.assume_init()
1968 }
1969 }
1970 #[inline]
1971 #[cfg(not(fuchsia_api_level_at_least = "27"))]
1972 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1973 trace_make_inline_string_ref(name)
1974 }
1975
1976 #[inline]
1977 fn register_current_thread(&self) -> sys::trace_thread_ref_t {
1978 unsafe {
1979 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1980 sys::trace_context_register_current_thread(self.context.raw, thread_ref.as_mut_ptr());
1981 thread_ref.assume_init()
1982 }
1983 }
1984
1985 #[cfg(fuchsia_api_level_at_least = "31")]
1986 #[inline]
1987 fn register_vthread<S: AsTraceStrRef>(
1988 &self,
1989 name: &S,
1990 id: sys::trace_vthread_id_t,
1991 process_koid: zx::sys::zx_koid_t,
1992 ) -> sys::trace_thread_ref_t {
1993 let name_ref = name.as_trace_str_ref(self);
1994 unsafe {
1995 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1996 sys::trace_context_register_vthread_by_ref(
1997 self.context.raw,
1998 process_koid,
1999 &name_ref,
2000 id,
2001 thread_ref.as_mut_ptr(),
2002 );
2003 thread_ref.assume_init()
2004 }
2005 }
2006
2007 #[inline]
2008 pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
2009 let ticks = zx::BootTicks::get();
2010 let thread_ref = self.register_current_thread();
2011 unsafe {
2012 sys::trace_context_write_instant_event_record(
2013 self.context.raw,
2014 ticks.into_raw(),
2015 &thread_ref,
2016 &self.category_ref,
2017 &name_ref,
2018 scope.into_raw(),
2019 args.as_ptr() as *const sys::trace_arg_t,
2020 args.len(),
2021 );
2022 }
2023 }
2024
2025 pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
2026 let name_ref = trace_make_inline_string_ref(name);
2027 self.write_instant(name_ref, scope, args)
2028 }
2029
2030 fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
2031 let ticks = zx::BootTicks::get();
2032 let thread_ref = self.register_current_thread();
2033 unsafe {
2034 sys::trace_context_write_counter_event_record(
2035 self.context.raw,
2036 ticks.into_raw(),
2037 &thread_ref,
2038 &self.category_ref,
2039 &name_ref,
2040 counter_id,
2041 args.as_ptr() as *const sys::trace_arg_t,
2042 args.len(),
2043 );
2044 }
2045 }
2046
2047 pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
2048 let name_ref = trace_make_inline_string_ref(name);
2049 self.write_counter(name_ref, counter_id, args);
2050 }
2051
2052 fn write_duration(
2053 &self,
2054 name_ref: sys::trace_string_ref_t,
2055 start_time: zx::BootTicks,
2056 args: &[Arg<'_>],
2057 ) {
2058 let ticks = zx::BootTicks::get();
2059 let thread_ref = self.register_current_thread();
2060 unsafe {
2061 sys::trace_context_write_duration_event_record(
2062 self.context.raw,
2063 start_time.into_raw(),
2064 ticks.into_raw(),
2065 &thread_ref,
2066 &self.category_ref,
2067 &name_ref,
2068 args.as_ptr() as *const sys::trace_arg_t,
2069 args.len(),
2070 );
2071 }
2072 }
2073
2074 pub fn write_duration_with_inline_name(
2075 &self,
2076 name: &str,
2077 start_time: zx::BootTicks,
2078 args: &[Arg<'_>],
2079 ) {
2080 let name_ref = trace_make_inline_string_ref(name);
2081 self.write_duration(name_ref, start_time, args);
2082 }
2083
2084 fn write_duration_begin(
2085 &self,
2086 ticks: zx::BootTicks,
2087 name_ref: sys::trace_string_ref_t,
2088 args: &[Arg<'_>],
2089 ) {
2090 let thread_ref = self.register_current_thread();
2091 unsafe {
2092 sys::trace_context_write_duration_begin_event_record(
2093 self.context.raw,
2094 ticks.into_raw(),
2095 &thread_ref,
2096 &self.category_ref,
2097 &name_ref,
2098 args.as_ptr() as *const sys::trace_arg_t,
2099 args.len(),
2100 );
2101 }
2102 }
2103
2104 #[cfg(fuchsia_api_level_at_least = "31")]
2105 fn write_vthread_duration_begin<S: AsTraceStrRef>(
2106 &self,
2107 ticks: zx::BootTicks,
2108 name_ref: sys::trace_string_ref_t,
2109 vthread: &VThread<S>,
2110 args: &[Arg<'_>],
2111 ) {
2112 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2113 unsafe {
2114 sys::trace_context_write_duration_begin_event_record(
2115 self.context.raw,
2116 ticks.into_raw(),
2117 &thread_ref,
2118 &self.category_ref,
2119 &name_ref,
2120 args.as_ptr() as *const sys::trace_arg_t,
2121 args.len(),
2122 );
2123 }
2124 }
2125
2126 pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
2127 let name_ref = trace_make_inline_string_ref(name);
2128 self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
2129 }
2130
2131 fn write_duration_end(
2132 &self,
2133 ticks: zx::BootTicks,
2134 name_ref: sys::trace_string_ref_t,
2135 args: &[Arg<'_>],
2136 ) {
2137 let thread_ref = self.register_current_thread();
2138 unsafe {
2139 sys::trace_context_write_duration_end_event_record(
2140 self.context.raw,
2141 ticks.into_raw(),
2142 &thread_ref,
2143 &self.category_ref,
2144 &name_ref,
2145 args.as_ptr() as *const sys::trace_arg_t,
2146 args.len(),
2147 );
2148 }
2149 }
2150
2151 #[cfg(fuchsia_api_level_at_least = "31")]
2152 fn write_vthread_duration_end<S: AsTraceStrRef>(
2153 &self,
2154 ticks: zx::BootTicks,
2155 name_ref: sys::trace_string_ref_t,
2156 vthread: &VThread<S>,
2157 args: &[Arg<'_>],
2158 ) {
2159 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2160 unsafe {
2161 sys::trace_context_write_duration_end_event_record(
2162 self.context.raw,
2163 ticks.into_raw(),
2164 &thread_ref,
2165 &self.category_ref,
2166 &name_ref,
2167 args.as_ptr() as *const sys::trace_arg_t,
2168 args.len(),
2169 );
2170 }
2171 }
2172
2173 #[cfg(fuchsia_api_level_at_least = "31")]
2174 fn write_vthread_instant<S: AsTraceStrRef>(
2175 &self,
2176 ticks: zx::BootTicks,
2177 name_ref: sys::trace_string_ref_t,
2178 vthread: &VThread<S>,
2179 scope: Scope,
2180 args: &[Arg<'_>],
2181 ) {
2182 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2183 unsafe {
2186 sys::trace_context_write_instant_event_record(
2187 self.context.raw,
2188 ticks.into_raw(),
2189 &thread_ref,
2190 &self.category_ref,
2191 &name_ref,
2192 scope.into_raw(),
2193 args.as_ptr() as *const sys::trace_arg_t,
2194 args.len(),
2195 );
2196 }
2197 }
2198
2199 #[cfg(fuchsia_api_level_at_least = "31")]
2200 fn write_vthread_duration<S: AsTraceStrRef>(
2201 &self,
2202 start_time: zx::BootTicks,
2203 ticks: zx::BootTicks,
2204 name_ref: sys::trace_string_ref_t,
2205 vthread: &VThread<S>,
2206 args: &[Arg<'_>],
2207 ) {
2208 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2209 unsafe {
2212 sys::trace_context_write_duration_event_record(
2213 self.context.raw,
2214 start_time.into_raw(),
2215 ticks.into_raw(),
2216 &thread_ref,
2217 &self.category_ref,
2218 &name_ref,
2219 args.as_ptr() as *const sys::trace_arg_t,
2220 args.len(),
2221 );
2222 }
2223 }
2224
2225 pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
2226 let name_ref = trace_make_inline_string_ref(name);
2227 self.write_duration_end(zx::BootTicks::get(), name_ref, args);
2228 }
2229
2230 fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2231 let ticks = zx::BootTicks::get();
2232 let thread_ref = self.register_current_thread();
2233 unsafe {
2234 sys::trace_context_write_async_begin_event_record(
2235 self.context.raw,
2236 ticks.into_raw(),
2237 &thread_ref,
2238 &self.category_ref,
2239 &name_ref,
2240 id.into(),
2241 args.as_ptr() as *const sys::trace_arg_t,
2242 args.len(),
2243 );
2244 }
2245 }
2246
2247 pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
2248 let name_ref = trace_make_inline_string_ref(name);
2249 self.write_async_begin(id, name_ref, args);
2250 }
2251
2252 fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2253 let ticks = zx::BootTicks::get();
2254 let thread_ref = self.register_current_thread();
2255 unsafe {
2256 sys::trace_context_write_async_end_event_record(
2257 self.context.raw,
2258 ticks.into_raw(),
2259 &thread_ref,
2260 &self.category_ref,
2261 &name_ref,
2262 id.into(),
2263 args.as_ptr() as *const sys::trace_arg_t,
2264 args.len(),
2265 );
2266 }
2267 }
2268
2269 pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
2270 let name_ref = trace_make_inline_string_ref(name);
2271 self.write_async_end(id, name_ref, args);
2272 }
2273
2274 fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2275 let ticks = zx::BootTicks::get();
2276 let thread_ref = self.register_current_thread();
2277 unsafe {
2278 sys::trace_context_write_async_instant_event_record(
2279 self.context.raw,
2280 ticks.into_raw(),
2281 &thread_ref,
2282 &self.category_ref,
2283 &name_ref,
2284 id.into(),
2285 args.as_ptr() as *const sys::trace_arg_t,
2286 args.len(),
2287 );
2288 }
2289 }
2290
2291 fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
2292 let ticks = zx::BootTicks::get();
2293 let thread_ref = self.register_current_thread();
2294 unsafe {
2295 sys::trace_context_write_blob_event_record(
2296 self.context.raw,
2297 ticks.into_raw(),
2298 &thread_ref,
2299 &self.category_ref,
2300 &name_ref,
2301 bytes.as_ptr() as *const core::ffi::c_void,
2302 bytes.len(),
2303 args.as_ptr() as *const sys::trace_arg_t,
2304 args.len(),
2305 );
2306 }
2307 }
2308
2309 fn write_flow_begin(
2310 &self,
2311 ticks: zx::BootTicks,
2312 name_ref: sys::trace_string_ref_t,
2313 flow_id: Id,
2314 args: &[Arg<'_>],
2315 ) {
2316 let thread_ref = self.register_current_thread();
2317 unsafe {
2318 sys::trace_context_write_flow_begin_event_record(
2319 self.context.raw,
2320 ticks.into_raw(),
2321 &thread_ref,
2322 &self.category_ref,
2323 &name_ref,
2324 flow_id.into(),
2325 args.as_ptr() as *const sys::trace_arg_t,
2326 args.len(),
2327 );
2328 }
2329 }
2330
2331 fn write_flow_end(
2332 &self,
2333 ticks: zx::BootTicks,
2334 name_ref: sys::trace_string_ref_t,
2335 flow_id: Id,
2336 args: &[Arg<'_>],
2337 ) {
2338 let thread_ref = self.register_current_thread();
2339 unsafe {
2340 sys::trace_context_write_flow_end_event_record(
2341 self.context.raw,
2342 ticks.into_raw(),
2343 &thread_ref,
2344 &self.category_ref,
2345 &name_ref,
2346 flow_id.into(),
2347 args.as_ptr() as *const sys::trace_arg_t,
2348 args.len(),
2349 );
2350 }
2351 }
2352
2353 fn write_flow_step(
2354 &self,
2355 ticks: zx::BootTicks,
2356 name_ref: sys::trace_string_ref_t,
2357 flow_id: Id,
2358 args: &[Arg<'_>],
2359 ) {
2360 let thread_ref = self.register_current_thread();
2361 unsafe {
2362 sys::trace_context_write_flow_step_event_record(
2363 self.context.raw,
2364 ticks.into_raw(),
2365 &thread_ref,
2366 &self.category_ref,
2367 &name_ref,
2368 flow_id.into(),
2369 args.as_ptr() as *const sys::trace_arg_t,
2370 args.len(),
2371 );
2372 }
2373 }
2374}
2375
2376pub struct Context {
2378 raw: *const sys::trace_context_t,
2379}
2380
2381impl Context {
2382 #[inline]
2383 pub fn acquire() -> Option<Self> {
2384 let context = unsafe { sys::trace_acquire_context() };
2385 if context.is_null() { None } else { Some(Self { raw: context }) }
2386 }
2387
2388 #[inline]
2389 pub fn register_string_literal<T: CategoryString>(&self, s: T) -> sys::trace_string_ref_t {
2390 s.register(self)
2391 }
2392
2393 pub fn write_blob_record(
2394 &self,
2395 type_: sys::trace_blob_type_t,
2396 name_ref: &sys::trace_string_ref_t,
2397 data: &[u8],
2398 ) {
2399 unsafe {
2400 sys::trace_context_write_blob_record(
2401 self.raw,
2402 type_,
2403 name_ref as *const sys::trace_string_ref_t,
2404 data.as_ptr() as *const libc::c_void,
2405 data.len(),
2406 );
2407 }
2408 }
2409
2410 pub fn copy_record(&self, buffer: &[u64]) -> Option<usize> {
2414 unsafe {
2415 let ptr = sys::trace_context_alloc_record(self.raw, 8 * buffer.len() as libc::size_t);
2416 if ptr == std::ptr::null_mut() {
2417 return None;
2418 }
2419 ptr.cast::<u64>().copy_from(buffer.as_ptr(), buffer.len());
2420 };
2421 Some(buffer.len())
2422 }
2423
2424 pub fn buffering_mode(&self) -> BufferingMode {
2425 match unsafe { sys::trace_context_get_buffering_mode(self.raw) } {
2426 sys::TRACE_BUFFERING_MODE_ONESHOT => BufferingMode::OneShot,
2427 sys::TRACE_BUFFERING_MODE_CIRCULAR => BufferingMode::Circular,
2428 sys::TRACE_BUFFERING_MODE_STREAMING => BufferingMode::Streaming,
2429 m => panic!("Unknown trace buffering mode: {:?}", m),
2430 }
2431 }
2432}
2433
2434impl std::ops::Drop for Context {
2435 fn drop(&mut self) {
2436 unsafe { sys::trace_release_context(self.raw) }
2437 }
2438}
2439
2440pub struct ProlongedContext {
2441 context: *const sys::trace_prolonged_context_t,
2442}
2443
2444impl ProlongedContext {
2445 pub fn acquire() -> Option<Self> {
2446 let context = unsafe { sys::trace_acquire_prolonged_context() };
2447 if context.is_null() { None } else { Some(Self { context }) }
2448 }
2449}
2450
2451impl Drop for ProlongedContext {
2452 fn drop(&mut self) {
2453 unsafe { sys::trace_release_prolonged_context(self.context) }
2454 }
2455}
2456
2457unsafe impl Send for ProlongedContext {}
2458
2459mod sys {
2460 #![allow(non_camel_case_types, unused)]
2461 use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
2462
2463 pub type trace_ticks_t = zx_ticks_t;
2464 pub type trace_counter_id_t = u64;
2465 pub type trace_async_id_t = u64;
2466 pub type trace_flow_id_t = u64;
2467 pub type trace_vthread_id_t = u64;
2468 pub type trace_thread_state_t = u32;
2469 pub type trace_cpu_number_t = u32;
2470 pub type trace_string_index_t = u32;
2471 pub type trace_thread_index_t = u32;
2472 pub type trace_context_t = libc::c_void;
2473 pub type trace_prolonged_context_t = libc::c_void;
2474
2475 pub type trace_encoded_string_ref_t = u16;
2476 pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
2477 pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
2478 pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
2479 pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: usize = 32000;
2480 pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
2481 pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
2482
2483 pub type trace_encoded_thread_ref_t = u32;
2484 pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
2485 pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
2486 pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
2487
2488 pub type trace_state_t = libc::c_int;
2489 pub const TRACE_STOPPED: trace_state_t = 0;
2490 pub const TRACE_STARTED: trace_state_t = 1;
2491 pub const TRACE_STOPPING: trace_state_t = 2;
2492
2493 pub type trace_scope_t = libc::c_int;
2494 pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
2495 pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
2496 pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
2497
2498 pub type trace_blob_type_t = libc::c_int;
2499 pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
2500 pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
2501 pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
2502
2503 pub type trace_buffering_mode_t = libc::c_int;
2504 pub const TRACE_BUFFERING_MODE_ONESHOT: trace_buffering_mode_t = 0;
2505 pub const TRACE_BUFFERING_MODE_CIRCULAR: trace_buffering_mode_t = 1;
2506 pub const TRACE_BUFFERING_MODE_STREAMING: trace_buffering_mode_t = 2;
2507
2508 #[repr(C)]
2509 #[derive(Copy, Clone)]
2510 pub struct trace_string_ref_t {
2511 pub encoded_value: trace_encoded_string_ref_t,
2512 pub inline_string: *const libc::c_char,
2513 }
2514
2515 pub type trace_site_t = std::sync::atomic::AtomicU64;
2519
2520 unsafe impl Send for trace_string_ref_t {}
2530 unsafe impl Sync for trace_string_ref_t {}
2531
2532 #[repr(C)]
2533 pub struct trace_thread_ref_t {
2534 pub encoded_value: trace_encoded_thread_ref_t,
2535 pub inline_process_koid: zx_koid_t,
2536 pub inline_thread_koid: zx_koid_t,
2537 }
2538
2539 #[repr(C)]
2540 pub struct trace_arg_t {
2541 pub name_ref: trace_string_ref_t,
2542 pub value: trace_arg_value_t,
2543 }
2544
2545 #[repr(C)]
2546 pub union trace_arg_union_t {
2547 pub int32_value: i32,
2548 pub uint32_value: u32,
2549 pub int64_value: i64,
2550 pub uint64_value: u64,
2551 pub double_value: libc::c_double,
2552 pub string_value_ref: trace_string_ref_t,
2553 pub pointer_value: libc::uintptr_t,
2554 pub koid_value: zx_koid_t,
2555 pub bool_value: bool,
2556 pub reserved_for_future_expansion: [libc::uintptr_t; 2],
2557 }
2558
2559 pub type trace_arg_type_t = libc::c_int;
2560 pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
2561 pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
2562 pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
2563 pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
2564 pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
2565 pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
2566 pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
2567 pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
2568 pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
2569 pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
2570
2571 #[repr(C)]
2572 pub struct trace_arg_value_t {
2573 pub type_: trace_arg_type_t,
2574 pub value: trace_arg_union_t,
2575 }
2576
2577 #[repr(C)]
2578 pub struct trace_handler_ops_t {
2579 pub is_category_enabled:
2580 unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
2581 pub trace_started: unsafe fn(handler: *const trace_handler_t),
2582 pub trace_stopped: unsafe fn(
2583 handler: *const trace_handler_t,
2584 async_ptr: *const (), disposition: zx_status_t,
2586 buffer_bytes_written: libc::size_t,
2587 ),
2588 pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
2589 }
2590
2591 #[repr(C)]
2592 pub struct trace_handler_t {
2593 pub ops: *const trace_handler_ops_t,
2594 }
2595
2596 unsafe extern "C" {
2598 pub fn trace_context_is_category_enabled(
2601 context: *const trace_context_t,
2602 category_literal: *const libc::c_char,
2603 ) -> bool;
2604
2605 pub fn trace_context_register_string_literal(
2606 context: *const trace_context_t,
2607 string_literal: *const libc::c_char,
2608 out_ref: *mut trace_string_ref_t,
2609 );
2610
2611 #[cfg(fuchsia_api_level_at_least = "27")]
2612 pub fn trace_context_register_bytestring(
2613 context: *const trace_context_t,
2614 string_literal: *const libc::c_char,
2615 length: libc::size_t,
2616 out_ref: *mut trace_string_ref_t,
2617 );
2618
2619 pub fn trace_context_register_category_literal(
2620 context: *const trace_context_t,
2621 category_literal: *const libc::c_char,
2622 out_ref: *mut trace_string_ref_t,
2623 ) -> bool;
2624
2625 pub fn trace_context_register_current_thread(
2626 context: *const trace_context_t,
2627 out_ref: *mut trace_thread_ref_t,
2628 );
2629
2630 pub fn trace_context_register_thread(
2631 context: *const trace_context_t,
2632 process_koid: zx_koid_t,
2633 thread_koid: zx_koid_t,
2634 out_ref: *mut trace_thread_ref_t,
2635 );
2636
2637 #[cfg(fuchsia_api_level_at_least = "31")]
2638 pub fn trace_context_register_vthread_by_ref(
2639 context: *const trace_context_t,
2640 process_koid: zx_koid_t,
2641 vthread_name: *const trace_string_ref_t,
2642 vthread_id: trace_vthread_id_t,
2643 out_ref: *mut trace_thread_ref_t,
2644 );
2645
2646 pub fn trace_context_write_kernel_object_record(
2647 context: *const trace_context_t,
2648 koid: zx_koid_t,
2649 type_: zx_obj_type_t,
2650 args: *const trace_arg_t,
2651 num_args: libc::size_t,
2652 );
2653
2654 pub fn trace_context_write_kernel_object_record_for_handle(
2655 context: *const trace_context_t,
2656 handle: zx_handle_t,
2657 args: *const trace_arg_t,
2658 num_args: libc::size_t,
2659 );
2660
2661 pub fn trace_context_write_process_info_record(
2662 context: *const trace_context_t,
2663 process_koid: zx_koid_t,
2664 process_name_ref: *const trace_string_ref_t,
2665 );
2666
2667 pub fn trace_context_write_thread_info_record(
2668 context: *const trace_context_t,
2669 process_koid: zx_koid_t,
2670 thread_koid: zx_koid_t,
2671 thread_name_ref: *const trace_string_ref_t,
2672 );
2673
2674 pub fn trace_context_write_context_switch_record(
2675 context: *const trace_context_t,
2676 event_time: trace_ticks_t,
2677 cpu_number: trace_cpu_number_t,
2678 outgoing_thread_state: trace_thread_state_t,
2679 outgoing_thread_ref: *const trace_thread_ref_t,
2680 incoming_thread_ref: *const trace_thread_ref_t,
2681 );
2682
2683 pub fn trace_context_write_log_record(
2684 context: *const trace_context_t,
2685 event_time: trace_ticks_t,
2686 thread_ref: *const trace_thread_ref_t,
2687 log_message: *const libc::c_char,
2688 log_message_length: libc::size_t,
2689 );
2690
2691 pub fn trace_context_write_instant_event_record(
2692 context: *const trace_context_t,
2693 event_time: trace_ticks_t,
2694 thread_ref: *const trace_thread_ref_t,
2695 category_ref: *const trace_string_ref_t,
2696 name_ref: *const trace_string_ref_t,
2697 scope: trace_scope_t,
2698 args: *const trace_arg_t,
2699 num_args: libc::size_t,
2700 );
2701
2702 pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
2703
2704 #[cfg(fuchsia_api_level_at_least = "27")]
2705 pub fn trace_context_send_alert_bytestring(
2706 context: *const trace_context_t,
2707 name: *const u8,
2708 length: usize,
2709 );
2710
2711 pub fn trace_context_write_counter_event_record(
2712 context: *const trace_context_t,
2713 event_time: trace_ticks_t,
2714 thread_ref: *const trace_thread_ref_t,
2715 category_ref: *const trace_string_ref_t,
2716 name_ref: *const trace_string_ref_t,
2717 counter_id: trace_counter_id_t,
2718 args: *const trace_arg_t,
2719 num_args: libc::size_t,
2720 );
2721
2722 pub fn trace_context_write_duration_event_record(
2723 context: *const trace_context_t,
2724 start_time: trace_ticks_t,
2725 end_time: trace_ticks_t,
2726 thread_ref: *const trace_thread_ref_t,
2727 category_ref: *const trace_string_ref_t,
2728 name_ref: *const trace_string_ref_t,
2729 args: *const trace_arg_t,
2730 num_args: libc::size_t,
2731 );
2732
2733 pub fn trace_context_write_blob_event_record(
2734 context: *const trace_context_t,
2735 event_time: trace_ticks_t,
2736 thread_ref: *const trace_thread_ref_t,
2737 category_ref: *const trace_string_ref_t,
2738 name_ref: *const trace_string_ref_t,
2739 blob: *const libc::c_void,
2740 blob_size: libc::size_t,
2741 args: *const trace_arg_t,
2742 num_args: libc::size_t,
2743 );
2744
2745 pub fn trace_context_write_duration_begin_event_record(
2746 context: *const trace_context_t,
2747 event_time: trace_ticks_t,
2748 thread_ref: *const trace_thread_ref_t,
2749 category_ref: *const trace_string_ref_t,
2750 name_ref: *const trace_string_ref_t,
2751 args: *const trace_arg_t,
2752 num_args: libc::size_t,
2753 );
2754
2755 pub fn trace_context_write_duration_end_event_record(
2756 context: *const trace_context_t,
2757 event_time: trace_ticks_t,
2758 thread_ref: *const trace_thread_ref_t,
2759 category_ref: *const trace_string_ref_t,
2760 name_ref: *const trace_string_ref_t,
2761 args: *const trace_arg_t,
2762 num_args: libc::size_t,
2763 );
2764
2765 pub fn trace_context_write_async_begin_event_record(
2766 context: *const trace_context_t,
2767 event_time: trace_ticks_t,
2768 thread_ref: *const trace_thread_ref_t,
2769 category_ref: *const trace_string_ref_t,
2770 name_ref: *const trace_string_ref_t,
2771 async_id: trace_async_id_t,
2772 args: *const trace_arg_t,
2773 num_args: libc::size_t,
2774 );
2775
2776 pub fn trace_context_write_async_instant_event_record(
2777 context: *const trace_context_t,
2778 event_time: trace_ticks_t,
2779 thread_ref: *const trace_thread_ref_t,
2780 category_ref: *const trace_string_ref_t,
2781 name_ref: *const trace_string_ref_t,
2782 async_id: trace_async_id_t,
2783 args: *const trace_arg_t,
2784 num_args: libc::size_t,
2785 );
2786
2787 pub fn trace_context_write_async_end_event_record(
2788 context: *const trace_context_t,
2789 event_time: trace_ticks_t,
2790 thread_ref: *const trace_thread_ref_t,
2791 category_ref: *const trace_string_ref_t,
2792 name_ref: *const trace_string_ref_t,
2793 async_id: trace_async_id_t,
2794 args: *const trace_arg_t,
2795 num_args: libc::size_t,
2796 );
2797
2798 pub fn trace_context_write_flow_begin_event_record(
2799 context: *const trace_context_t,
2800 event_time: trace_ticks_t,
2801 thread_ref: *const trace_thread_ref_t,
2802 category_ref: *const trace_string_ref_t,
2803 name_ref: *const trace_string_ref_t,
2804 flow_id: trace_flow_id_t,
2805 args: *const trace_arg_t,
2806 num_args: libc::size_t,
2807 );
2808
2809 pub fn trace_context_write_flow_step_event_record(
2810 context: *const trace_context_t,
2811 event_time: trace_ticks_t,
2812 thread_ref: *const trace_thread_ref_t,
2813 category_ref: *const trace_string_ref_t,
2814 name_ref: *const trace_string_ref_t,
2815 flow_id: trace_flow_id_t,
2816 args: *const trace_arg_t,
2817 num_args: libc::size_t,
2818 );
2819
2820 pub fn trace_context_write_flow_end_event_record(
2821 context: *const trace_context_t,
2822 event_time: trace_ticks_t,
2823 thread_ref: *const trace_thread_ref_t,
2824 category_ref: *const trace_string_ref_t,
2825 name_ref: *const trace_string_ref_t,
2826 flow_id: trace_flow_id_t,
2827 args: *const trace_arg_t,
2828 num_args: libc::size_t,
2829 );
2830
2831 pub fn trace_context_write_initialization_record(
2832 context: *const trace_context_t,
2833 ticks_per_second: u64,
2834 );
2835
2836 pub fn trace_context_write_string_record(
2837 context: *const trace_context_t,
2838 index: trace_string_index_t,
2839 string: *const libc::c_char,
2840 length: libc::size_t,
2841 );
2842
2843 pub fn trace_context_write_thread_record(
2844 context: *const trace_context_t,
2845 index: trace_thread_index_t,
2846 procss_koid: zx_koid_t,
2847 thread_koid: zx_koid_t,
2848 );
2849
2850 pub fn trace_context_write_blob_record(
2851 context: *const trace_context_t,
2852 type_: trace_blob_type_t,
2853 name_ref: *const trace_string_ref_t,
2854 data: *const libc::c_void,
2855 size: libc::size_t,
2856 );
2857
2858 pub fn trace_context_alloc_record(
2859 context: *const trace_context_t,
2860 num_bytes: libc::size_t,
2861 ) -> *mut libc::c_void;
2862
2863 pub fn trace_state() -> trace_state_t;
2865
2866 #[cfg(fuchsia_api_level_at_least = "27")]
2867 pub fn trace_is_category_bytestring_enabled(
2868 category_literal: *const u8,
2869 length: usize,
2870 ) -> bool;
2871
2872 pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2873
2874 pub fn trace_acquire_context() -> *const trace_context_t;
2875
2876 pub fn trace_acquire_context_for_category(
2877 category_literal: *const libc::c_char,
2878 out_ref: *mut trace_string_ref_t,
2879 ) -> *const trace_context_t;
2880
2881 pub fn trace_acquire_context_for_category_cached(
2882 category_literal: *const libc::c_char,
2883 trace_site: *const u64,
2884 out_ref: *mut trace_string_ref_t,
2885 ) -> *const trace_context_t;
2886
2887 #[cfg(fuchsia_api_level_at_least = "27")]
2888 pub fn trace_acquire_context_for_category_bytestring(
2889 bytes: *const u8,
2890 length: usize,
2891 out_ref: *mut trace_string_ref_t,
2892 ) -> *const trace_context_t;
2893
2894 #[cfg(fuchsia_api_level_at_least = "27")]
2895 pub fn trace_acquire_context_for_category_bytestring_cached(
2896 bytes: *const u8,
2897 length: usize,
2898 trace_site: *const u64,
2899 out_ref: *mut trace_string_ref_t,
2900 ) -> *const trace_context_t;
2901
2902 pub fn trace_release_context(context: *const trace_context_t);
2903
2904 pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2905
2906 pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2907
2908 pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2909
2910 pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2911
2912 pub fn trace_notify_observer_updated(event: zx_handle_t);
2913
2914 pub fn trace_context_get_buffering_mode(
2915 context: *const trace_context_t,
2916 ) -> trace_buffering_mode_t;
2917 }
2918}
2919
2920pub struct TraceFutureArgs<'a, C: CategoryString, S: AsTraceStrRef> {
2923 pub category: C,
2924 pub name: S,
2925
2926 pub args: Box<[Arg<'a>]>,
2929
2930 pub flow_id: Option<Id>,
2933
2934 pub _use_trace_future_args: (),
2936}
2937
2938#[doc(hidden)]
2939#[macro_export]
2940macro_rules! __impl_trace_future_args {
2941 ($category:expr, $name:expr, $flow_id:expr) => {
2944 $crate::TraceFutureArgs {
2945 category: $category,
2946 name: $name,
2947 args: ::std::boxed::Box::new([]),
2948 flow_id: $flow_id,
2949 _use_trace_future_args: (),
2950 }
2951 };
2952 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2953 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2954 use $crate::AsTraceStrRef;
2955 let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2956 let args: ::std::boxed::Box<[$crate::Arg<'_>]> = if let Some(context) = context {
2957 ::std::boxed::Box::new(
2958 [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
2959 )
2960 } else {
2961 ::std::boxed::Box::new([])
2962 };
2963 $crate::TraceFutureArgs {
2964 category: $category,
2965 name: $name,
2966 args: args,
2967 flow_id: $flow_id,
2968 _use_trace_future_args: (),
2969 }
2970 }};
2971}
2972
2973#[macro_export]
2985macro_rules! trace_future_args {
2986 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
2987 $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
2988 };
2989 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
2990 $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
2991 };
2992}
2993
2994pub trait TraceFutureExt: Future + Sized {
2996 #[inline(always)]
3010 fn trace<'a, C: CategoryString, S: AsTraceStrRef>(
3011 self,
3012 args: TraceFutureArgs<'a, C, S>,
3013 ) -> TraceFuture<'a, Self, C, S> {
3014 TraceFuture::new(args, self)
3015 }
3016}
3017
3018impl<T: Future + Sized> TraceFutureExt for T {}
3019
3020#[pin_project]
3023pub struct TraceFuture<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> {
3024 #[pin]
3026 future: Fut,
3027 category: C,
3028 name: S,
3029 args: Box<[Arg<'a>]>,
3031 flow_id: Option<Id>,
3032 poll_count: u64,
3033}
3034
3035impl<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> TraceFuture<'a, Fut, C, S> {
3036 #[inline(always)]
3037 pub fn new(args: TraceFutureArgs<'a, C, S>, future: Fut) -> Self {
3038 Self {
3039 future,
3040 category: args.category,
3041 name: args.name,
3042 args: args.args,
3043 flow_id: args.flow_id,
3044 poll_count: 0,
3045 }
3046 }
3047
3048 #[cold]
3049 fn trace_poll(
3050 self: Pin<&mut Self>,
3051 context: &TraceCategoryContext,
3052 cx: &mut std::task::Context<'_>,
3053 ) -> Poll<Fut::Output> {
3054 let start_time = zx::BootTicks::get();
3055 let this = self.project();
3056 *this.poll_count = this.poll_count.saturating_add(1);
3057 let name_ref = this.name.as_trace_str_ref(context);
3058 context.write_duration_begin(start_time, name_ref, &this.args);
3059
3060 let result = this.future.poll(cx);
3061
3062 let flow_id = this.flow_id.get_or_insert_with(Id::new);
3063 let result_str: sys::trace_string_ref_t = if result.is_pending() {
3064 if *this.poll_count == 1 {
3065 context.write_flow_begin(start_time, name_ref, *flow_id, &[]);
3066 } else {
3067 context.write_flow_step(start_time, name_ref, *flow_id, &[]);
3068 }
3069 context.register_str("pending")
3070 } else {
3071 if *this.poll_count != 1 {
3072 context.write_flow_end(start_time, name_ref, *flow_id, &[]);
3073 }
3074 context.register_str("ready")
3075 };
3076 context.write_duration_end(
3077 zx::BootTicks::get(),
3078 name_ref,
3079 &[
3080 ArgValue::of_registered(context.register_str("poll-state"), result_str),
3081 ArgValue::of_registered(context.register_str("poll-count"), *this.poll_count),
3082 ],
3083 );
3084 result
3085 }
3086}
3087
3088impl<Fut: Future, C: CategoryString, S: AsTraceStrRef> Future for TraceFuture<'_, Fut, C, S> {
3089 type Output = Fut::Output;
3090 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
3091 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
3092 self.trace_poll(&context, cx)
3093 } else {
3094 self.project().future.poll(cx)
3095 }
3096 }
3097}
3098
3099#[cfg(test)]
3100mod test {
3101 use super::{Id, trim_to_last_char_boundary};
3102
3103 #[test]
3104 fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
3105 assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
3106 assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
3107 assert_eq!(b"", trim_to_last_char_boundary("x", 0));
3108 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
3109 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
3110 assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
3111
3112 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
3113 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
3114 assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
3115 }
3116
3117 #[test]
3121 fn test_id_new() {
3122 assert_ne!(Id::new(), Id::new());
3123 }
3124}