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]
1491macro_rules! flow_begin {
1492 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1493 {
1494 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1495 use $crate::AsTraceStrRef;
1496 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1497 $crate::flow_begin(&context, $name, $flow_id,
1498 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1499 }
1500 }
1501 }
1502}
1503
1504#[macro_export]
1519macro_rules! flow_step {
1520 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1521 {
1522 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1523 use $crate::AsTraceStrRef;
1524 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1525 $crate::flow_step(&context, $name, $flow_id,
1526 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1527 }
1528 }
1529 }
1530}
1531
1532#[macro_export]
1547macro_rules! flow_end {
1548 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1549 {
1550 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1551 use $crate::AsTraceStrRef;
1552 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1553 $crate::flow_end(&context, $name, $flow_id,
1554 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1555 }
1556 }
1557 }
1558}
1559
1560pub fn flow_begin<S: AsTraceStrRef>(
1579 context: &TraceCategoryContext,
1580 name: S,
1581 flow_id: Id,
1582 args: &[Arg<'_>],
1583) {
1584 let ticks = zx::BootTicks::get();
1585 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1586
1587 let name_ref = name.as_trace_str_ref(context);
1588 context.write_flow_begin(ticks, name_ref, flow_id, args);
1589}
1590
1591pub fn flow_end<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_end(ticks, name_ref, flow_id, args);
1618}
1619
1620pub fn flow_step<S: AsTraceStrRef>(
1637 context: &TraceCategoryContext,
1638 name: S,
1639 flow_id: Id,
1640 args: &[Arg<'_>],
1641) {
1642 let ticks = zx::BootTicks::get();
1643 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1644
1645 let name_ref = name.as_trace_str_ref(context);
1646 context.write_flow_step(ticks, name_ref, flow_id, args);
1647}
1648
1649#[macro_export]
1663macro_rules! instaflow_begin {
1664 (
1665 $category:expr,
1666 $flow_name:expr,
1667 $step_name:expr,
1668 $flow_id:expr
1669 $(, $key:expr => $val:expr)*
1670 ) => {
1671 {
1672 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1673 use $crate::AsTraceStrRef;
1674 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1675 $crate::instaflow_begin(
1676 &context,
1677 $flow_name,
1678 $step_name,
1679 $flow_id,
1680 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1681 )
1682 }
1683 }
1684 }
1685}
1686
1687#[macro_export]
1701macro_rules! instaflow_end {
1702 (
1703 $category:expr,
1704 $flow_name:expr,
1705 $step_name:expr,
1706 $flow_id:expr
1707 $(, $key:expr => $val:expr)*
1708 ) => {
1709 {
1710 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1711 use $crate::AsTraceStrRef;
1712 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1713 $crate::instaflow_end(
1714 &context,
1715 $flow_name,
1716 $step_name,
1717 $flow_id,
1718 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1719 )
1720 }
1721 }
1722 }
1723}
1724
1725#[macro_export]
1739macro_rules! instaflow_step {
1740 (
1741 $category:expr,
1742 $flow_name:expr,
1743 $step_name:expr,
1744 $flow_id:expr
1745 $(, $key:expr => $val:expr)*
1746 ) => {
1747 {
1748 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1749 use $crate::AsTraceStrRef;
1750 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1751 $crate::instaflow_step(
1752 &context,
1753 $flow_name,
1754 $step_name,
1755 $flow_id,
1756 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1757 )
1758 }
1759 }
1760 }
1761}
1762
1763pub fn instaflow_begin<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1775 context: &TraceCategoryContext,
1776 flow_name: S1,
1777 step_name: S2,
1778 flow_id: Id,
1779 args: &[Arg<'_>],
1780) {
1781 let ticks = zx::BootTicks::get();
1782 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1783
1784 let flow_name_ref = flow_name.as_trace_str_ref(context);
1785 let step_name_ref = step_name.as_trace_str_ref(context);
1786
1787 context.write_duration_begin(ticks, step_name_ref, args);
1788 context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1789 context.write_duration_end(ticks, step_name_ref, args);
1790}
1791
1792pub fn instaflow_end<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1804 context: &TraceCategoryContext,
1805 flow_name: S1,
1806 step_name: S2,
1807 flow_id: Id,
1808 args: &[Arg<'_>],
1809) {
1810 let ticks = zx::BootTicks::get();
1811 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1812
1813 let flow_name_ref = flow_name.as_trace_str_ref(context);
1814 let step_name_ref = step_name.as_trace_str_ref(context);
1815
1816 context.write_duration_begin(ticks, step_name_ref, args);
1817 context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1818 context.write_duration_end(ticks, step_name_ref, args);
1819}
1820
1821pub fn instaflow_step<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1833 context: &TraceCategoryContext,
1834 flow_name: S1,
1835 step_name: S2,
1836 flow_id: Id,
1837 args: &[Arg<'_>],
1838) {
1839 let ticks = zx::BootTicks::get();
1840 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1841
1842 let flow_name_ref = flow_name.as_trace_str_ref(context);
1843 let step_name_ref = step_name.as_trace_str_ref(context);
1844
1845 context.write_duration_begin(ticks, step_name_ref, args);
1846 context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1847 context.write_duration_end(ticks, step_name_ref, args);
1848}
1849
1850const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1852 sys::trace_string_ref_t {
1853 encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1854 inline_string: ptr::null(),
1855 }
1856}
1857
1858#[inline]
1859fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1860 let mut len = string.len();
1861 if string.len() > max_len {
1862 len = max_len;
1866 while len > 0 {
1867 if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1868 break;
1869 }
1870 len -= 1;
1871 }
1872 }
1873 &string.as_bytes()[0..len]
1874}
1875
1876#[inline]
1879fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1880 let len = string.len() as u16;
1881 if len == 0 {
1882 return trace_make_empty_string_ref();
1883 }
1884
1885 let string = trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH);
1886
1887 sys::trace_string_ref_t {
1888 encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1889 inline_string: string.as_ptr() as *const libc::c_char,
1890 }
1891}
1892
1893pub struct TraceCategoryContext {
1895 context: Context,
1896 category_ref: sys::trace_string_ref_t,
1897}
1898
1899impl TraceCategoryContext {
1900 #[inline]
1901 pub fn acquire_cached<C: CategoryString>(
1902 category: C,
1903 site: &sys::trace_site_t,
1904 ) -> Option<TraceCategoryContext> {
1905 category.acquire_context_cached(site)
1906 }
1907
1908 pub fn acquire<C: CategoryString>(category: C) -> Option<TraceCategoryContext> {
1909 category.acquire_context()
1910 }
1911
1912 #[inline]
1913 pub fn register_string_literal<T: CategoryString>(&self, name: T) -> sys::trace_string_ref_t {
1914 name.register(&self.context)
1915 }
1916
1917 #[inline]
1918 #[cfg(fuchsia_api_level_at_least = "27")]
1919 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1920 unsafe {
1921 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1922 sys::trace_context_register_bytestring(
1923 self.context.raw,
1924 name.as_ptr().cast::<libc::c_char>(),
1925 name.len(),
1926 name_ref.as_mut_ptr(),
1927 );
1928 name_ref.assume_init()
1929 }
1930 }
1931 #[inline]
1932 #[cfg(not(fuchsia_api_level_at_least = "27"))]
1933 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1934 trace_make_inline_string_ref(name)
1935 }
1936
1937 #[inline]
1938 fn register_current_thread(&self) -> sys::trace_thread_ref_t {
1939 unsafe {
1940 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1941 sys::trace_context_register_current_thread(self.context.raw, thread_ref.as_mut_ptr());
1942 thread_ref.assume_init()
1943 }
1944 }
1945
1946 #[cfg(fuchsia_api_level_at_least = "31")]
1947 #[inline]
1948 fn register_vthread<S: AsTraceStrRef>(
1949 &self,
1950 name: &S,
1951 id: sys::trace_vthread_id_t,
1952 process_koid: zx::sys::zx_koid_t,
1953 ) -> sys::trace_thread_ref_t {
1954 let name_ref = name.as_trace_str_ref(self);
1955 unsafe {
1956 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1957 sys::trace_context_register_vthread_by_ref(
1958 self.context.raw,
1959 process_koid,
1960 &name_ref,
1961 id,
1962 thread_ref.as_mut_ptr(),
1963 );
1964 thread_ref.assume_init()
1965 }
1966 }
1967
1968 #[inline]
1969 pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
1970 let ticks = zx::BootTicks::get();
1971 let thread_ref = self.register_current_thread();
1972 unsafe {
1973 sys::trace_context_write_instant_event_record(
1974 self.context.raw,
1975 ticks.into_raw(),
1976 &thread_ref,
1977 &self.category_ref,
1978 &name_ref,
1979 scope.into_raw(),
1980 args.as_ptr() as *const sys::trace_arg_t,
1981 args.len(),
1982 );
1983 }
1984 }
1985
1986 pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
1987 let name_ref = trace_make_inline_string_ref(name);
1988 self.write_instant(name_ref, scope, args)
1989 }
1990
1991 fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
1992 let ticks = zx::BootTicks::get();
1993 let thread_ref = self.register_current_thread();
1994 unsafe {
1995 sys::trace_context_write_counter_event_record(
1996 self.context.raw,
1997 ticks.into_raw(),
1998 &thread_ref,
1999 &self.category_ref,
2000 &name_ref,
2001 counter_id,
2002 args.as_ptr() as *const sys::trace_arg_t,
2003 args.len(),
2004 );
2005 }
2006 }
2007
2008 pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
2009 let name_ref = trace_make_inline_string_ref(name);
2010 self.write_counter(name_ref, counter_id, args);
2011 }
2012
2013 fn write_duration(
2014 &self,
2015 name_ref: sys::trace_string_ref_t,
2016 start_time: zx::BootTicks,
2017 args: &[Arg<'_>],
2018 ) {
2019 let ticks = zx::BootTicks::get();
2020 let thread_ref = self.register_current_thread();
2021 unsafe {
2022 sys::trace_context_write_duration_event_record(
2023 self.context.raw,
2024 start_time.into_raw(),
2025 ticks.into_raw(),
2026 &thread_ref,
2027 &self.category_ref,
2028 &name_ref,
2029 args.as_ptr() as *const sys::trace_arg_t,
2030 args.len(),
2031 );
2032 }
2033 }
2034
2035 pub fn write_duration_with_inline_name(
2036 &self,
2037 name: &str,
2038 start_time: zx::BootTicks,
2039 args: &[Arg<'_>],
2040 ) {
2041 let name_ref = trace_make_inline_string_ref(name);
2042 self.write_duration(name_ref, start_time, args);
2043 }
2044
2045 fn write_duration_begin(
2046 &self,
2047 ticks: zx::BootTicks,
2048 name_ref: sys::trace_string_ref_t,
2049 args: &[Arg<'_>],
2050 ) {
2051 let thread_ref = self.register_current_thread();
2052 unsafe {
2053 sys::trace_context_write_duration_begin_event_record(
2054 self.context.raw,
2055 ticks.into_raw(),
2056 &thread_ref,
2057 &self.category_ref,
2058 &name_ref,
2059 args.as_ptr() as *const sys::trace_arg_t,
2060 args.len(),
2061 );
2062 }
2063 }
2064
2065 #[cfg(fuchsia_api_level_at_least = "31")]
2066 fn write_vthread_duration_begin<S: AsTraceStrRef>(
2067 &self,
2068 ticks: zx::BootTicks,
2069 name_ref: sys::trace_string_ref_t,
2070 vthread: &VThread<S>,
2071 args: &[Arg<'_>],
2072 ) {
2073 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2074 unsafe {
2075 sys::trace_context_write_duration_begin_event_record(
2076 self.context.raw,
2077 ticks.into_raw(),
2078 &thread_ref,
2079 &self.category_ref,
2080 &name_ref,
2081 args.as_ptr() as *const sys::trace_arg_t,
2082 args.len(),
2083 );
2084 }
2085 }
2086
2087 pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
2088 let name_ref = trace_make_inline_string_ref(name);
2089 self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
2090 }
2091
2092 fn write_duration_end(
2093 &self,
2094 ticks: zx::BootTicks,
2095 name_ref: sys::trace_string_ref_t,
2096 args: &[Arg<'_>],
2097 ) {
2098 let thread_ref = self.register_current_thread();
2099 unsafe {
2100 sys::trace_context_write_duration_end_event_record(
2101 self.context.raw,
2102 ticks.into_raw(),
2103 &thread_ref,
2104 &self.category_ref,
2105 &name_ref,
2106 args.as_ptr() as *const sys::trace_arg_t,
2107 args.len(),
2108 );
2109 }
2110 }
2111
2112 #[cfg(fuchsia_api_level_at_least = "31")]
2113 fn write_vthread_duration_end<S: AsTraceStrRef>(
2114 &self,
2115 ticks: zx::BootTicks,
2116 name_ref: sys::trace_string_ref_t,
2117 vthread: &VThread<S>,
2118 args: &[Arg<'_>],
2119 ) {
2120 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2121 unsafe {
2122 sys::trace_context_write_duration_end_event_record(
2123 self.context.raw,
2124 ticks.into_raw(),
2125 &thread_ref,
2126 &self.category_ref,
2127 &name_ref,
2128 args.as_ptr() as *const sys::trace_arg_t,
2129 args.len(),
2130 );
2131 }
2132 }
2133
2134 #[cfg(fuchsia_api_level_at_least = "31")]
2135 fn write_vthread_instant<S: AsTraceStrRef>(
2136 &self,
2137 ticks: zx::BootTicks,
2138 name_ref: sys::trace_string_ref_t,
2139 vthread: &VThread<S>,
2140 scope: Scope,
2141 args: &[Arg<'_>],
2142 ) {
2143 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2144 unsafe {
2147 sys::trace_context_write_instant_event_record(
2148 self.context.raw,
2149 ticks.into_raw(),
2150 &thread_ref,
2151 &self.category_ref,
2152 &name_ref,
2153 scope.into_raw(),
2154 args.as_ptr() as *const sys::trace_arg_t,
2155 args.len(),
2156 );
2157 }
2158 }
2159
2160 #[cfg(fuchsia_api_level_at_least = "31")]
2161 fn write_vthread_duration<S: AsTraceStrRef>(
2162 &self,
2163 start_time: zx::BootTicks,
2164 ticks: zx::BootTicks,
2165 name_ref: sys::trace_string_ref_t,
2166 vthread: &VThread<S>,
2167 args: &[Arg<'_>],
2168 ) {
2169 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2170 unsafe {
2173 sys::trace_context_write_duration_event_record(
2174 self.context.raw,
2175 start_time.into_raw(),
2176 ticks.into_raw(),
2177 &thread_ref,
2178 &self.category_ref,
2179 &name_ref,
2180 args.as_ptr() as *const sys::trace_arg_t,
2181 args.len(),
2182 );
2183 }
2184 }
2185
2186 pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
2187 let name_ref = trace_make_inline_string_ref(name);
2188 self.write_duration_end(zx::BootTicks::get(), name_ref, args);
2189 }
2190
2191 fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2192 let ticks = zx::BootTicks::get();
2193 let thread_ref = self.register_current_thread();
2194 unsafe {
2195 sys::trace_context_write_async_begin_event_record(
2196 self.context.raw,
2197 ticks.into_raw(),
2198 &thread_ref,
2199 &self.category_ref,
2200 &name_ref,
2201 id.into(),
2202 args.as_ptr() as *const sys::trace_arg_t,
2203 args.len(),
2204 );
2205 }
2206 }
2207
2208 pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
2209 let name_ref = trace_make_inline_string_ref(name);
2210 self.write_async_begin(id, name_ref, args);
2211 }
2212
2213 fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2214 let ticks = zx::BootTicks::get();
2215 let thread_ref = self.register_current_thread();
2216 unsafe {
2217 sys::trace_context_write_async_end_event_record(
2218 self.context.raw,
2219 ticks.into_raw(),
2220 &thread_ref,
2221 &self.category_ref,
2222 &name_ref,
2223 id.into(),
2224 args.as_ptr() as *const sys::trace_arg_t,
2225 args.len(),
2226 );
2227 }
2228 }
2229
2230 pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
2231 let name_ref = trace_make_inline_string_ref(name);
2232 self.write_async_end(id, name_ref, args);
2233 }
2234
2235 fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2236 let ticks = zx::BootTicks::get();
2237 let thread_ref = self.register_current_thread();
2238 unsafe {
2239 sys::trace_context_write_async_instant_event_record(
2240 self.context.raw,
2241 ticks.into_raw(),
2242 &thread_ref,
2243 &self.category_ref,
2244 &name_ref,
2245 id.into(),
2246 args.as_ptr() as *const sys::trace_arg_t,
2247 args.len(),
2248 );
2249 }
2250 }
2251
2252 fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
2253 let ticks = zx::BootTicks::get();
2254 let thread_ref = self.register_current_thread();
2255 unsafe {
2256 sys::trace_context_write_blob_event_record(
2257 self.context.raw,
2258 ticks.into_raw(),
2259 &thread_ref,
2260 &self.category_ref,
2261 &name_ref,
2262 bytes.as_ptr() as *const core::ffi::c_void,
2263 bytes.len(),
2264 args.as_ptr() as *const sys::trace_arg_t,
2265 args.len(),
2266 );
2267 }
2268 }
2269
2270 fn write_flow_begin(
2271 &self,
2272 ticks: zx::BootTicks,
2273 name_ref: sys::trace_string_ref_t,
2274 flow_id: Id,
2275 args: &[Arg<'_>],
2276 ) {
2277 let thread_ref = self.register_current_thread();
2278 unsafe {
2279 sys::trace_context_write_flow_begin_event_record(
2280 self.context.raw,
2281 ticks.into_raw(),
2282 &thread_ref,
2283 &self.category_ref,
2284 &name_ref,
2285 flow_id.into(),
2286 args.as_ptr() as *const sys::trace_arg_t,
2287 args.len(),
2288 );
2289 }
2290 }
2291
2292 fn write_flow_end(
2293 &self,
2294 ticks: zx::BootTicks,
2295 name_ref: sys::trace_string_ref_t,
2296 flow_id: Id,
2297 args: &[Arg<'_>],
2298 ) {
2299 let thread_ref = self.register_current_thread();
2300 unsafe {
2301 sys::trace_context_write_flow_end_event_record(
2302 self.context.raw,
2303 ticks.into_raw(),
2304 &thread_ref,
2305 &self.category_ref,
2306 &name_ref,
2307 flow_id.into(),
2308 args.as_ptr() as *const sys::trace_arg_t,
2309 args.len(),
2310 );
2311 }
2312 }
2313
2314 fn write_flow_step(
2315 &self,
2316 ticks: zx::BootTicks,
2317 name_ref: sys::trace_string_ref_t,
2318 flow_id: Id,
2319 args: &[Arg<'_>],
2320 ) {
2321 let thread_ref = self.register_current_thread();
2322 unsafe {
2323 sys::trace_context_write_flow_step_event_record(
2324 self.context.raw,
2325 ticks.into_raw(),
2326 &thread_ref,
2327 &self.category_ref,
2328 &name_ref,
2329 flow_id.into(),
2330 args.as_ptr() as *const sys::trace_arg_t,
2331 args.len(),
2332 );
2333 }
2334 }
2335}
2336
2337pub struct Context {
2339 raw: *const sys::trace_context_t,
2340}
2341
2342impl Context {
2343 #[inline]
2344 pub fn acquire() -> Option<Self> {
2345 let context = unsafe { sys::trace_acquire_context() };
2346 if context.is_null() { None } else { Some(Self { raw: context }) }
2347 }
2348
2349 #[inline]
2350 pub fn register_string_literal<T: CategoryString>(&self, s: T) -> sys::trace_string_ref_t {
2351 s.register(self)
2352 }
2353
2354 pub fn write_blob_record(
2355 &self,
2356 type_: sys::trace_blob_type_t,
2357 name_ref: &sys::trace_string_ref_t,
2358 data: &[u8],
2359 ) {
2360 unsafe {
2361 sys::trace_context_write_blob_record(
2362 self.raw,
2363 type_,
2364 name_ref as *const sys::trace_string_ref_t,
2365 data.as_ptr() as *const libc::c_void,
2366 data.len(),
2367 );
2368 }
2369 }
2370
2371 pub fn copy_record(&self, buffer: &[u64]) -> Option<usize> {
2375 unsafe {
2376 let ptr = sys::trace_context_alloc_record(self.raw, 8 * buffer.len() as libc::size_t);
2377 if ptr == std::ptr::null_mut() {
2378 return None;
2379 }
2380 ptr.cast::<u64>().copy_from(buffer.as_ptr(), buffer.len());
2381 };
2382 Some(buffer.len())
2383 }
2384
2385 pub fn buffering_mode(&self) -> BufferingMode {
2386 match unsafe { sys::trace_context_get_buffering_mode(self.raw) } {
2387 sys::TRACE_BUFFERING_MODE_ONESHOT => BufferingMode::OneShot,
2388 sys::TRACE_BUFFERING_MODE_CIRCULAR => BufferingMode::Circular,
2389 sys::TRACE_BUFFERING_MODE_STREAMING => BufferingMode::Streaming,
2390 m => panic!("Unknown trace buffering mode: {:?}", m),
2391 }
2392 }
2393}
2394
2395impl std::ops::Drop for Context {
2396 fn drop(&mut self) {
2397 unsafe { sys::trace_release_context(self.raw) }
2398 }
2399}
2400
2401pub struct ProlongedContext {
2402 context: *const sys::trace_prolonged_context_t,
2403}
2404
2405impl ProlongedContext {
2406 pub fn acquire() -> Option<Self> {
2407 let context = unsafe { sys::trace_acquire_prolonged_context() };
2408 if context.is_null() { None } else { Some(Self { context }) }
2409 }
2410}
2411
2412impl Drop for ProlongedContext {
2413 fn drop(&mut self) {
2414 unsafe { sys::trace_release_prolonged_context(self.context) }
2415 }
2416}
2417
2418unsafe impl Send for ProlongedContext {}
2419
2420mod sys {
2421 #![allow(non_camel_case_types, unused)]
2422 use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
2423
2424 pub type trace_ticks_t = zx_ticks_t;
2425 pub type trace_counter_id_t = u64;
2426 pub type trace_async_id_t = u64;
2427 pub type trace_flow_id_t = u64;
2428 pub type trace_vthread_id_t = u64;
2429 pub type trace_thread_state_t = u32;
2430 pub type trace_cpu_number_t = u32;
2431 pub type trace_string_index_t = u32;
2432 pub type trace_thread_index_t = u32;
2433 pub type trace_context_t = libc::c_void;
2434 pub type trace_prolonged_context_t = libc::c_void;
2435
2436 pub type trace_encoded_string_ref_t = u16;
2437 pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
2438 pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
2439 pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
2440 pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: usize = 32000;
2441 pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
2442 pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
2443
2444 pub type trace_encoded_thread_ref_t = u32;
2445 pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
2446 pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
2447 pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
2448
2449 pub type trace_state_t = libc::c_int;
2450 pub const TRACE_STOPPED: trace_state_t = 0;
2451 pub const TRACE_STARTED: trace_state_t = 1;
2452 pub const TRACE_STOPPING: trace_state_t = 2;
2453
2454 pub type trace_scope_t = libc::c_int;
2455 pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
2456 pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
2457 pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
2458
2459 pub type trace_blob_type_t = libc::c_int;
2460 pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
2461 pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
2462 pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
2463
2464 pub type trace_buffering_mode_t = libc::c_int;
2465 pub const TRACE_BUFFERING_MODE_ONESHOT: trace_buffering_mode_t = 0;
2466 pub const TRACE_BUFFERING_MODE_CIRCULAR: trace_buffering_mode_t = 1;
2467 pub const TRACE_BUFFERING_MODE_STREAMING: trace_buffering_mode_t = 2;
2468
2469 #[repr(C)]
2470 #[derive(Copy, Clone)]
2471 pub struct trace_string_ref_t {
2472 pub encoded_value: trace_encoded_string_ref_t,
2473 pub inline_string: *const libc::c_char,
2474 }
2475
2476 pub type trace_site_t = std::sync::atomic::AtomicU64;
2480
2481 unsafe impl Send for trace_string_ref_t {}
2491 unsafe impl Sync for trace_string_ref_t {}
2492
2493 #[repr(C)]
2494 pub struct trace_thread_ref_t {
2495 pub encoded_value: trace_encoded_thread_ref_t,
2496 pub inline_process_koid: zx_koid_t,
2497 pub inline_thread_koid: zx_koid_t,
2498 }
2499
2500 #[repr(C)]
2501 pub struct trace_arg_t {
2502 pub name_ref: trace_string_ref_t,
2503 pub value: trace_arg_value_t,
2504 }
2505
2506 #[repr(C)]
2507 pub union trace_arg_union_t {
2508 pub int32_value: i32,
2509 pub uint32_value: u32,
2510 pub int64_value: i64,
2511 pub uint64_value: u64,
2512 pub double_value: libc::c_double,
2513 pub string_value_ref: trace_string_ref_t,
2514 pub pointer_value: libc::uintptr_t,
2515 pub koid_value: zx_koid_t,
2516 pub bool_value: bool,
2517 pub reserved_for_future_expansion: [libc::uintptr_t; 2],
2518 }
2519
2520 pub type trace_arg_type_t = libc::c_int;
2521 pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
2522 pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
2523 pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
2524 pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
2525 pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
2526 pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
2527 pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
2528 pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
2529 pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
2530 pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
2531
2532 #[repr(C)]
2533 pub struct trace_arg_value_t {
2534 pub type_: trace_arg_type_t,
2535 pub value: trace_arg_union_t,
2536 }
2537
2538 #[repr(C)]
2539 pub struct trace_handler_ops_t {
2540 pub is_category_enabled:
2541 unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
2542 pub trace_started: unsafe fn(handler: *const trace_handler_t),
2543 pub trace_stopped: unsafe fn(
2544 handler: *const trace_handler_t,
2545 async_ptr: *const (), disposition: zx_status_t,
2547 buffer_bytes_written: libc::size_t,
2548 ),
2549 pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
2550 }
2551
2552 #[repr(C)]
2553 pub struct trace_handler_t {
2554 pub ops: *const trace_handler_ops_t,
2555 }
2556
2557 unsafe extern "C" {
2559 pub fn trace_context_is_category_enabled(
2562 context: *const trace_context_t,
2563 category_literal: *const libc::c_char,
2564 ) -> bool;
2565
2566 pub fn trace_context_register_string_literal(
2567 context: *const trace_context_t,
2568 string_literal: *const libc::c_char,
2569 out_ref: *mut trace_string_ref_t,
2570 );
2571
2572 #[cfg(fuchsia_api_level_at_least = "27")]
2573 pub fn trace_context_register_bytestring(
2574 context: *const trace_context_t,
2575 string_literal: *const libc::c_char,
2576 length: libc::size_t,
2577 out_ref: *mut trace_string_ref_t,
2578 );
2579
2580 pub fn trace_context_register_category_literal(
2581 context: *const trace_context_t,
2582 category_literal: *const libc::c_char,
2583 out_ref: *mut trace_string_ref_t,
2584 ) -> bool;
2585
2586 pub fn trace_context_register_current_thread(
2587 context: *const trace_context_t,
2588 out_ref: *mut trace_thread_ref_t,
2589 );
2590
2591 pub fn trace_context_register_thread(
2592 context: *const trace_context_t,
2593 process_koid: zx_koid_t,
2594 thread_koid: zx_koid_t,
2595 out_ref: *mut trace_thread_ref_t,
2596 );
2597
2598 #[cfg(fuchsia_api_level_at_least = "31")]
2599 pub fn trace_context_register_vthread_by_ref(
2600 context: *const trace_context_t,
2601 process_koid: zx_koid_t,
2602 vthread_name: *const trace_string_ref_t,
2603 vthread_id: trace_vthread_id_t,
2604 out_ref: *mut trace_thread_ref_t,
2605 );
2606
2607 pub fn trace_context_write_kernel_object_record(
2608 context: *const trace_context_t,
2609 koid: zx_koid_t,
2610 type_: zx_obj_type_t,
2611 args: *const trace_arg_t,
2612 num_args: libc::size_t,
2613 );
2614
2615 pub fn trace_context_write_kernel_object_record_for_handle(
2616 context: *const trace_context_t,
2617 handle: zx_handle_t,
2618 args: *const trace_arg_t,
2619 num_args: libc::size_t,
2620 );
2621
2622 pub fn trace_context_write_process_info_record(
2623 context: *const trace_context_t,
2624 process_koid: zx_koid_t,
2625 process_name_ref: *const trace_string_ref_t,
2626 );
2627
2628 pub fn trace_context_write_thread_info_record(
2629 context: *const trace_context_t,
2630 process_koid: zx_koid_t,
2631 thread_koid: zx_koid_t,
2632 thread_name_ref: *const trace_string_ref_t,
2633 );
2634
2635 pub fn trace_context_write_context_switch_record(
2636 context: *const trace_context_t,
2637 event_time: trace_ticks_t,
2638 cpu_number: trace_cpu_number_t,
2639 outgoing_thread_state: trace_thread_state_t,
2640 outgoing_thread_ref: *const trace_thread_ref_t,
2641 incoming_thread_ref: *const trace_thread_ref_t,
2642 );
2643
2644 pub fn trace_context_write_log_record(
2645 context: *const trace_context_t,
2646 event_time: trace_ticks_t,
2647 thread_ref: *const trace_thread_ref_t,
2648 log_message: *const libc::c_char,
2649 log_message_length: libc::size_t,
2650 );
2651
2652 pub fn trace_context_write_instant_event_record(
2653 context: *const trace_context_t,
2654 event_time: trace_ticks_t,
2655 thread_ref: *const trace_thread_ref_t,
2656 category_ref: *const trace_string_ref_t,
2657 name_ref: *const trace_string_ref_t,
2658 scope: trace_scope_t,
2659 args: *const trace_arg_t,
2660 num_args: libc::size_t,
2661 );
2662
2663 pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
2664
2665 #[cfg(fuchsia_api_level_at_least = "27")]
2666 pub fn trace_context_send_alert_bytestring(
2667 context: *const trace_context_t,
2668 name: *const u8,
2669 length: usize,
2670 );
2671
2672 pub fn trace_context_write_counter_event_record(
2673 context: *const trace_context_t,
2674 event_time: trace_ticks_t,
2675 thread_ref: *const trace_thread_ref_t,
2676 category_ref: *const trace_string_ref_t,
2677 name_ref: *const trace_string_ref_t,
2678 counter_id: trace_counter_id_t,
2679 args: *const trace_arg_t,
2680 num_args: libc::size_t,
2681 );
2682
2683 pub fn trace_context_write_duration_event_record(
2684 context: *const trace_context_t,
2685 start_time: trace_ticks_t,
2686 end_time: trace_ticks_t,
2687 thread_ref: *const trace_thread_ref_t,
2688 category_ref: *const trace_string_ref_t,
2689 name_ref: *const trace_string_ref_t,
2690 args: *const trace_arg_t,
2691 num_args: libc::size_t,
2692 );
2693
2694 pub fn trace_context_write_blob_event_record(
2695 context: *const trace_context_t,
2696 event_time: trace_ticks_t,
2697 thread_ref: *const trace_thread_ref_t,
2698 category_ref: *const trace_string_ref_t,
2699 name_ref: *const trace_string_ref_t,
2700 blob: *const libc::c_void,
2701 blob_size: libc::size_t,
2702 args: *const trace_arg_t,
2703 num_args: libc::size_t,
2704 );
2705
2706 pub fn trace_context_write_duration_begin_event_record(
2707 context: *const trace_context_t,
2708 event_time: trace_ticks_t,
2709 thread_ref: *const trace_thread_ref_t,
2710 category_ref: *const trace_string_ref_t,
2711 name_ref: *const trace_string_ref_t,
2712 args: *const trace_arg_t,
2713 num_args: libc::size_t,
2714 );
2715
2716 pub fn trace_context_write_duration_end_event_record(
2717 context: *const trace_context_t,
2718 event_time: trace_ticks_t,
2719 thread_ref: *const trace_thread_ref_t,
2720 category_ref: *const trace_string_ref_t,
2721 name_ref: *const trace_string_ref_t,
2722 args: *const trace_arg_t,
2723 num_args: libc::size_t,
2724 );
2725
2726 pub fn trace_context_write_async_begin_event_record(
2727 context: *const trace_context_t,
2728 event_time: trace_ticks_t,
2729 thread_ref: *const trace_thread_ref_t,
2730 category_ref: *const trace_string_ref_t,
2731 name_ref: *const trace_string_ref_t,
2732 async_id: trace_async_id_t,
2733 args: *const trace_arg_t,
2734 num_args: libc::size_t,
2735 );
2736
2737 pub fn trace_context_write_async_instant_event_record(
2738 context: *const trace_context_t,
2739 event_time: trace_ticks_t,
2740 thread_ref: *const trace_thread_ref_t,
2741 category_ref: *const trace_string_ref_t,
2742 name_ref: *const trace_string_ref_t,
2743 async_id: trace_async_id_t,
2744 args: *const trace_arg_t,
2745 num_args: libc::size_t,
2746 );
2747
2748 pub fn trace_context_write_async_end_event_record(
2749 context: *const trace_context_t,
2750 event_time: trace_ticks_t,
2751 thread_ref: *const trace_thread_ref_t,
2752 category_ref: *const trace_string_ref_t,
2753 name_ref: *const trace_string_ref_t,
2754 async_id: trace_async_id_t,
2755 args: *const trace_arg_t,
2756 num_args: libc::size_t,
2757 );
2758
2759 pub fn trace_context_write_flow_begin_event_record(
2760 context: *const trace_context_t,
2761 event_time: trace_ticks_t,
2762 thread_ref: *const trace_thread_ref_t,
2763 category_ref: *const trace_string_ref_t,
2764 name_ref: *const trace_string_ref_t,
2765 flow_id: trace_flow_id_t,
2766 args: *const trace_arg_t,
2767 num_args: libc::size_t,
2768 );
2769
2770 pub fn trace_context_write_flow_step_event_record(
2771 context: *const trace_context_t,
2772 event_time: trace_ticks_t,
2773 thread_ref: *const trace_thread_ref_t,
2774 category_ref: *const trace_string_ref_t,
2775 name_ref: *const trace_string_ref_t,
2776 flow_id: trace_flow_id_t,
2777 args: *const trace_arg_t,
2778 num_args: libc::size_t,
2779 );
2780
2781 pub fn trace_context_write_flow_end_event_record(
2782 context: *const trace_context_t,
2783 event_time: trace_ticks_t,
2784 thread_ref: *const trace_thread_ref_t,
2785 category_ref: *const trace_string_ref_t,
2786 name_ref: *const trace_string_ref_t,
2787 flow_id: trace_flow_id_t,
2788 args: *const trace_arg_t,
2789 num_args: libc::size_t,
2790 );
2791
2792 pub fn trace_context_write_initialization_record(
2793 context: *const trace_context_t,
2794 ticks_per_second: u64,
2795 );
2796
2797 pub fn trace_context_write_string_record(
2798 context: *const trace_context_t,
2799 index: trace_string_index_t,
2800 string: *const libc::c_char,
2801 length: libc::size_t,
2802 );
2803
2804 pub fn trace_context_write_thread_record(
2805 context: *const trace_context_t,
2806 index: trace_thread_index_t,
2807 procss_koid: zx_koid_t,
2808 thread_koid: zx_koid_t,
2809 );
2810
2811 pub fn trace_context_write_blob_record(
2812 context: *const trace_context_t,
2813 type_: trace_blob_type_t,
2814 name_ref: *const trace_string_ref_t,
2815 data: *const libc::c_void,
2816 size: libc::size_t,
2817 );
2818
2819 pub fn trace_context_alloc_record(
2820 context: *const trace_context_t,
2821 num_bytes: libc::size_t,
2822 ) -> *mut libc::c_void;
2823
2824 pub fn trace_state() -> trace_state_t;
2826
2827 #[cfg(fuchsia_api_level_at_least = "27")]
2828 pub fn trace_is_category_bytestring_enabled(
2829 category_literal: *const u8,
2830 length: usize,
2831 ) -> bool;
2832
2833 pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2834
2835 pub fn trace_acquire_context() -> *const trace_context_t;
2836
2837 pub fn trace_acquire_context_for_category(
2838 category_literal: *const libc::c_char,
2839 out_ref: *mut trace_string_ref_t,
2840 ) -> *const trace_context_t;
2841
2842 pub fn trace_acquire_context_for_category_cached(
2843 category_literal: *const libc::c_char,
2844 trace_site: *const u64,
2845 out_ref: *mut trace_string_ref_t,
2846 ) -> *const trace_context_t;
2847
2848 #[cfg(fuchsia_api_level_at_least = "27")]
2849 pub fn trace_acquire_context_for_category_bytestring(
2850 bytes: *const u8,
2851 length: usize,
2852 out_ref: *mut trace_string_ref_t,
2853 ) -> *const trace_context_t;
2854
2855 #[cfg(fuchsia_api_level_at_least = "27")]
2856 pub fn trace_acquire_context_for_category_bytestring_cached(
2857 bytes: *const u8,
2858 length: usize,
2859 trace_site: *const u64,
2860 out_ref: *mut trace_string_ref_t,
2861 ) -> *const trace_context_t;
2862
2863 pub fn trace_release_context(context: *const trace_context_t);
2864
2865 pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2866
2867 pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2868
2869 pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2870
2871 pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2872
2873 pub fn trace_notify_observer_updated(event: zx_handle_t);
2874
2875 pub fn trace_context_get_buffering_mode(
2876 context: *const trace_context_t,
2877 ) -> trace_buffering_mode_t;
2878 }
2879}
2880
2881pub struct TraceFutureArgs<'a, C: CategoryString, S: AsTraceStrRef> {
2884 pub category: C,
2885 pub name: S,
2886
2887 pub args: Box<[Arg<'a>]>,
2890
2891 pub flow_id: Option<Id>,
2894
2895 pub _use_trace_future_args: (),
2897}
2898
2899#[doc(hidden)]
2900#[macro_export]
2901macro_rules! __impl_trace_future_args {
2902 ($category:expr, $name:expr, $flow_id:expr) => {
2905 $crate::TraceFutureArgs {
2906 category: $category,
2907 name: $name,
2908 args: ::std::boxed::Box::new([]),
2909 flow_id: $flow_id,
2910 _use_trace_future_args: (),
2911 }
2912 };
2913 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2914 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2915 use $crate::AsTraceStrRef;
2916 let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2917 let args: ::std::boxed::Box<[$crate::Arg<'_>]> = if let Some(context) = context {
2918 ::std::boxed::Box::new(
2919 [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
2920 )
2921 } else {
2922 ::std::boxed::Box::new([])
2923 };
2924 $crate::TraceFutureArgs {
2925 category: $category,
2926 name: $name,
2927 args: args,
2928 flow_id: $flow_id,
2929 _use_trace_future_args: (),
2930 }
2931 }};
2932}
2933
2934#[macro_export]
2946macro_rules! trace_future_args {
2947 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
2948 $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
2949 };
2950 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
2951 $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
2952 };
2953}
2954
2955pub trait TraceFutureExt: Future + Sized {
2957 #[inline(always)]
2971 fn trace<'a, C: CategoryString, S: AsTraceStrRef>(
2972 self,
2973 args: TraceFutureArgs<'a, C, S>,
2974 ) -> TraceFuture<'a, Self, C, S> {
2975 TraceFuture::new(args, self)
2976 }
2977}
2978
2979impl<T: Future + Sized> TraceFutureExt for T {}
2980
2981#[pin_project]
2984pub struct TraceFuture<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> {
2985 #[pin]
2987 future: Fut,
2988 category: C,
2989 name: S,
2990 args: Box<[Arg<'a>]>,
2992 flow_id: Option<Id>,
2993 poll_count: u64,
2994}
2995
2996impl<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> TraceFuture<'a, Fut, C, S> {
2997 #[inline(always)]
2998 pub fn new(args: TraceFutureArgs<'a, C, S>, future: Fut) -> Self {
2999 Self {
3000 future,
3001 category: args.category,
3002 name: args.name,
3003 args: args.args,
3004 flow_id: args.flow_id,
3005 poll_count: 0,
3006 }
3007 }
3008
3009 #[cold]
3010 fn trace_poll(
3011 self: Pin<&mut Self>,
3012 context: &TraceCategoryContext,
3013 cx: &mut std::task::Context<'_>,
3014 ) -> Poll<Fut::Output> {
3015 let start_time = zx::BootTicks::get();
3016 let this = self.project();
3017 *this.poll_count = this.poll_count.saturating_add(1);
3018 let name_ref = this.name.as_trace_str_ref(context);
3019 context.write_duration_begin(start_time, name_ref, &this.args);
3020
3021 let result = this.future.poll(cx);
3022
3023 let flow_id = this.flow_id.get_or_insert_with(Id::new);
3024 let result_str: sys::trace_string_ref_t = if result.is_pending() {
3025 if *this.poll_count == 1 {
3026 context.write_flow_begin(start_time, name_ref, *flow_id, &[]);
3027 } else {
3028 context.write_flow_step(start_time, name_ref, *flow_id, &[]);
3029 }
3030 context.register_str("pending")
3031 } else {
3032 if *this.poll_count != 1 {
3033 context.write_flow_end(start_time, name_ref, *flow_id, &[]);
3034 }
3035 context.register_str("ready")
3036 };
3037 context.write_duration_end(
3038 zx::BootTicks::get(),
3039 name_ref,
3040 &[
3041 ArgValue::of_registered(context.register_str("poll-state"), result_str),
3042 ArgValue::of_registered(context.register_str("poll-count"), *this.poll_count),
3043 ],
3044 );
3045 result
3046 }
3047}
3048
3049impl<Fut: Future, C: CategoryString, S: AsTraceStrRef> Future for TraceFuture<'_, Fut, C, S> {
3050 type Output = Fut::Output;
3051 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
3052 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
3053 self.trace_poll(&context, cx)
3054 } else {
3055 self.project().future.poll(cx)
3056 }
3057 }
3058}
3059
3060#[cfg(test)]
3061mod test {
3062 use super::{Id, trim_to_last_char_boundary};
3063
3064 #[test]
3065 fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
3066 assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
3067 assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
3068 assert_eq!(b"", trim_to_last_char_boundary("x", 0));
3069 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
3070 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
3071 assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
3072
3073 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
3074 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
3075 assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
3076 }
3077
3078 #[test]
3082 fn test_id_new() {
3083 assert_ne!(Id::new(), Id::new());
3084 }
3085}