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#[cfg(fuchsia_api_level_at_least = "31")]
73#[inline]
74pub fn flush_buffer() -> Result<(), zx::Status> {
75 let status = unsafe { sys::trace_engine_flush_buffer() };
91 zx::Status::ok(status)
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
95#[repr(i32)]
96pub enum BufferingMode {
97 OneShot = sys::TRACE_BUFFERING_MODE_ONESHOT,
98 Circular = sys::TRACE_BUFFERING_MODE_CIRCULAR,
99 Streaming = sys::TRACE_BUFFERING_MODE_STREAMING,
100}
101
102#[repr(transparent)]
104#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
105pub struct Id(u64);
106
107impl Id {
108 pub fn new() -> Self {
110 let ts = zx::BootInstant::get().into_nanos() as u64;
113 let high_order = ts << 16;
114 let low_order = rand::random::<u16>() as u64;
115 Self(high_order | low_order)
116 }
117}
118
119impl From<u64> for Id {
120 fn from(u: u64) -> Self {
121 Self(u)
122 }
123}
124
125impl From<Id> for u64 {
126 fn from(id: Id) -> Self {
127 id.0
128 }
129}
130
131pub trait CategoryString: Copy {
132 fn register(&self, context: &Context) -> sys::trace_string_ref_t;
134
135 fn acquire_context(&self) -> Option<TraceCategoryContext>;
138
139 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext>;
141
142 fn is_category_enabled(&self) -> bool;
144}
145
146impl CategoryString for &'static CStr {
147 fn register(&self, context: &Context) -> sys::trace_string_ref_t {
148 unsafe {
149 let mut self_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
150 sys::trace_context_register_string_literal(
151 context.raw,
152 self.as_ptr(),
153 self_ref.as_mut_ptr(),
154 );
155 self_ref.assume_init()
156 }
157 }
158
159 fn acquire_context(&self) -> Option<TraceCategoryContext> {
160 unsafe {
161 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
162 let raw =
163 sys::trace_acquire_context_for_category(self.as_ptr(), category_ref.as_mut_ptr());
164 if raw != ptr::null() {
165 Some(TraceCategoryContext {
166 context: Context { raw },
167 category_ref: category_ref.assume_init(),
168 })
169 } else {
170 None
171 }
172 }
173 }
174
175 #[inline]
176 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext> {
177 let current_state = site.load(Ordering::Relaxed);
178 if (current_state & 1) != 0 {
181 return None;
182 }
183 unsafe {
184 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
189 let raw = sys::trace_acquire_context_for_category_cached(
190 self.as_ptr(),
191 site.as_ptr(),
192 category_ref.as_mut_ptr(),
193 );
194 if raw != ptr::null() {
195 Some(TraceCategoryContext {
196 context: Context { raw },
197 category_ref: category_ref.assume_init(),
198 })
199 } else {
200 None
201 }
202 }
203 }
204
205 fn is_category_enabled(&self) -> bool {
206 unsafe { sys::trace_is_category_enabled(self.as_ptr()) }
207 }
208}
209
210#[cfg(fuchsia_api_level_at_least = "27")]
211impl CategoryString for &'static str {
212 fn register(&self, context: &Context) -> sys::trace_string_ref_t {
213 unsafe {
214 let mut self_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
215 sys::trace_context_register_bytestring(
216 context.raw,
217 self.as_ptr().cast::<libc::c_char>(),
218 self.len(),
219 self_ref.as_mut_ptr(),
220 );
221 self_ref.assume_init()
222 }
223 }
224
225 fn acquire_context(&self) -> Option<TraceCategoryContext> {
226 unsafe {
227 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
228 let raw = sys::trace_acquire_context_for_category_bytestring(
229 self.as_ptr(),
230 self.len(),
231 category_ref.as_mut_ptr(),
232 );
233 if raw != ptr::null() {
234 Some(TraceCategoryContext {
235 context: Context { raw },
236 category_ref: category_ref.assume_init(),
237 })
238 } else {
239 None
240 }
241 }
242 }
243
244 #[inline]
245 fn acquire_context_cached(&self, site: &sys::trace_site_t) -> Option<TraceCategoryContext> {
246 let current_state = site.load(Ordering::Relaxed);
247 if (current_state & 1) != 0 {
250 return None;
251 }
252 unsafe {
253 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
258 let raw = sys::trace_acquire_context_for_category_bytestring_cached(
259 self.as_ptr(),
260 self.len(),
261 site.as_ptr(),
262 category_ref.as_mut_ptr(),
263 );
264 if raw != ptr::null() {
265 Some(TraceCategoryContext {
266 context: Context { raw },
267 category_ref: category_ref.assume_init(),
268 })
269 } else {
270 None
271 }
272 }
273 }
274
275 fn is_category_enabled(&self) -> bool {
276 unsafe { sys::trace_is_category_bytestring_enabled(self.as_ptr(), self.len()) }
277 }
278}
279
280pub trait AlertString {
281 fn send_alert(&self, context: &Context);
283}
284
285impl AlertString for &CStr {
286 fn send_alert(&self, context: &Context) {
287 unsafe {
288 sys::trace_context_send_alert(context.raw, self.as_ptr());
289 }
290 }
291}
292
293#[cfg(fuchsia_api_level_at_least = "27")]
294impl AlertString for &str {
295 fn send_alert(&self, context: &Context) {
296 unsafe {
297 sys::trace_context_send_alert_bytestring(context.raw, self.as_ptr(), self.len());
298 }
299 }
300}
301
302#[cfg(fuchsia_api_level_at_least = "27")]
303impl AlertString for &String {
304 fn send_alert(&self, context: &Context) {
305 unsafe {
306 sys::trace_context_send_alert_bytestring(context.raw, self.as_ptr(), self.len());
307 }
308 }
309}
310
311pub trait AsTraceStrRef {
312 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t;
313}
314
315impl AsTraceStrRef for &'static CStr {
316 #[inline]
317 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
318 context.register_string_literal(*self)
319 }
320}
321
322impl AsTraceStrRef for &'static str {
326 #[inline]
327 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
328 context.register_str(self)
329 }
330}
331
332impl AsTraceStrRef for String {
333 #[inline]
334 fn as_trace_str_ref(&self, _context: &TraceCategoryContext) -> sys::trace_string_ref_t {
335 trace_make_inline_string_ref(self.as_str())
336 }
337}
338
339impl AsTraceStrRef for std::borrow::Cow<'static, str> {
340 #[inline]
341 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
342 match self {
343 std::borrow::Cow::Borrowed(s) => s.as_trace_str_ref(context),
344 std::borrow::Cow::Owned(s) => s.as_trace_str_ref(context),
345 }
346 }
347}
348
349impl<T: AsTraceStrRef> AsTraceStrRef for &T {
351 #[inline]
352 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
353 (*self).as_trace_str_ref(context)
354 }
355}
356
357#[repr(transparent)]
359pub struct Arg<'a>(sys::trace_arg_t, PhantomData<&'a ()>);
360
361pub trait ArgValue {
367 fn of<'a>(key: &'a str, value: Self) -> Arg<'a>
368 where
369 Self: 'a;
370 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, value: Self) -> Arg<'a>
371 where
372 Self: 'a;
373}
374
375macro_rules! arg_from {
381 ($valname:ident, $(($type:ty, $tag:expr, $value:expr))*) => {
382 $(
383 impl ArgValue for $type {
384 #[inline]
385 fn of<'a>(key: &'a str, $valname: Self) -> Arg<'a>
386 where Self: 'a
387 {
388 #[allow(unused)]
389 let $valname = $valname;
390
391 Arg(sys::trace_arg_t {
392 name_ref: trace_make_inline_string_ref(key),
393 value: sys::trace_arg_value_t {
394 type_: $tag,
395 value: $value,
396 },
397 }, PhantomData)
398 }
399 #[inline]
400 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, $valname: Self) -> Arg<'a>
401 where Self: 'a
402 {
403 #[allow(unused)]
404 let $valname = $valname;
405
406 Arg(sys::trace_arg_t {
407 name_ref,
408 value: sys::trace_arg_value_t {
409 type_: $tag,
410 value: $value,
411 },
412 }, PhantomData)
413 }
414 }
415 )*
416 }
417}
418
419#[rustfmt::skip]
421arg_from!(val,
422 ((), sys::TRACE_ARG_NULL, sys::trace_arg_union_t { int32_value: 0 })
423 (bool, sys::TRACE_ARG_BOOL, sys::trace_arg_union_t { bool_value: val })
424 (i32, sys::TRACE_ARG_INT32, sys::trace_arg_union_t { int32_value: val })
425 (u32, sys::TRACE_ARG_UINT32, sys::trace_arg_union_t { uint32_value: val })
426 (i64, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val })
427 (u64, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val })
428 (isize, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val as i64 })
429 (usize, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val as u64 })
430 (f64, sys::TRACE_ARG_DOUBLE, sys::trace_arg_union_t { double_value: val })
431 (zx::Koid, sys::TRACE_ARG_KOID, sys::trace_arg_union_t { koid_value: val.raw_koid() })
432);
433
434impl<T> ArgValue for *const T {
435 #[inline]
436 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
437 where
438 Self: 'a,
439 {
440 Arg(
441 sys::trace_arg_t {
442 name_ref: trace_make_inline_string_ref(key),
443 value: sys::trace_arg_value_t {
444 type_: sys::TRACE_ARG_POINTER,
445 value: sys::trace_arg_union_t { pointer_value: val as usize },
446 },
447 },
448 PhantomData,
449 )
450 }
451 #[inline]
452 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
453 where
454 Self: 'a,
455 {
456 Arg(
457 sys::trace_arg_t {
458 name_ref,
459 value: sys::trace_arg_value_t {
460 type_: sys::TRACE_ARG_POINTER,
461 value: sys::trace_arg_union_t { pointer_value: val as usize },
462 },
463 },
464 PhantomData,
465 )
466 }
467}
468
469impl<T> ArgValue for *mut T {
470 #[inline]
471 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
472 where
473 Self: 'a,
474 {
475 Arg(
476 sys::trace_arg_t {
477 name_ref: trace_make_inline_string_ref(key),
478 value: sys::trace_arg_value_t {
479 type_: sys::TRACE_ARG_POINTER,
480 value: sys::trace_arg_union_t { pointer_value: val as usize },
481 },
482 },
483 PhantomData,
484 )
485 }
486 #[inline]
487 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
488 where
489 Self: 'a,
490 {
491 Arg(
492 sys::trace_arg_t {
493 name_ref,
494 value: sys::trace_arg_value_t {
495 type_: sys::TRACE_ARG_POINTER,
496 value: sys::trace_arg_union_t { pointer_value: val as usize },
497 },
498 },
499 PhantomData,
500 )
501 }
502}
503
504impl<'a> ArgValue for &'a str {
505 #[inline]
506 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
507 where
508 Self: 'b,
509 {
510 Arg(
511 sys::trace_arg_t {
512 name_ref: trace_make_inline_string_ref(key),
513 value: sys::trace_arg_value_t {
514 type_: sys::TRACE_ARG_STRING,
515 value: sys::trace_arg_union_t {
516 string_value_ref: trace_make_inline_string_ref(val),
517 },
518 },
519 },
520 PhantomData,
521 )
522 }
523 #[inline]
524 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
525 where
526 Self: 'b,
527 {
528 Arg(
529 sys::trace_arg_t {
530 name_ref,
531 value: sys::trace_arg_value_t {
532 type_: sys::TRACE_ARG_STRING,
533 value: sys::trace_arg_union_t {
534 string_value_ref: trace_make_inline_string_ref(val),
535 },
536 },
537 },
538 PhantomData,
539 )
540 }
541}
542
543impl<'a> ArgValue for sys::trace_string_ref_t {
544 #[inline]
545 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
546 where
547 Self: 'b,
548 {
549 Arg(
550 sys::trace_arg_t {
551 name_ref: trace_make_inline_string_ref(key),
552 value: sys::trace_arg_value_t {
553 type_: sys::TRACE_ARG_STRING,
554 value: sys::trace_arg_union_t { string_value_ref: val },
555 },
556 },
557 PhantomData,
558 )
559 }
560 #[inline]
561 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
562 where
563 Self: 'b,
564 {
565 Arg(
566 sys::trace_arg_t {
567 name_ref,
568 value: sys::trace_arg_value_t {
569 type_: sys::TRACE_ARG_STRING,
570 value: sys::trace_arg_union_t { string_value_ref: val },
571 },
572 },
573 PhantomData,
574 )
575 }
576}
577
578#[macro_export]
600macro_rules! instant {
601 ($category:expr, $name:expr, $scope:expr $(, $key:expr => $val:expr)*) => {
602 {
603 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
604 use $crate::AsTraceStrRef;
605 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
606 $crate::instant(&context, $name, $scope, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
607 }
608 }
609 }
610}
611
612#[inline]
615pub fn instant<S: AsTraceStrRef>(
616 context: &TraceCategoryContext,
617 name: S,
618 scope: Scope,
619 args: &[Arg<'_>],
620) {
621 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
622
623 let name_ref = name.as_trace_str_ref(context);
624 context.write_instant(name_ref, scope, args);
625}
626
627#[macro_export]
641macro_rules! alert {
642 ($category:expr, $name:expr) => {
643 $crate::alert($category, $name)
644 };
645}
646
647pub fn alert<C: CategoryString, S: AlertString>(category: C, name: S) {
649 if let Some(context) = category.acquire_context() {
650 name.send_alert(&context.context);
651 }
652}
653
654#[macro_export]
671macro_rules! counter {
672 ($category:expr, $name:expr, $counter_id:expr $(, $key:expr => $val:expr)*) => {
673 {
674 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
675 use $crate::AsTraceStrRef;
676 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
677 $crate::counter(&context, $name, $counter_id,
678 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
679 }
680 }
681 }
682}
683
684pub fn counter<S: AsTraceStrRef>(
694 context: &TraceCategoryContext,
695 name: S,
696 counter_id: u64,
697 args: &[Arg<'_>],
698) {
699 assert!(args.len() >= 1, "trace counter args must include at least one numeric argument");
700 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
701
702 let name_ref = name.as_trace_str_ref(context);
703 context.write_counter(name_ref, counter_id, args);
704}
705
706#[must_use = "DurationScope must be `end`ed to be recorded"]
709pub struct DurationScope<'a, C: CategoryString, S: AsTraceStrRef> {
710 category: C,
711 name: S,
712 args: &'a [Arg<'a>],
713 start_time: zx::BootTicks,
714}
715
716impl<'a, C: CategoryString, S: AsTraceStrRef> DurationScope<'a, C, S> {
717 pub fn begin(category: C, name: S, args: &'a [Arg<'_>]) -> Self {
720 let start_time = zx::BootTicks::get();
721 Self { category, name, args, start_time }
722 }
723}
724
725impl<'a, C: CategoryString, S: AsTraceStrRef> Drop for DurationScope<'a, C, S> {
726 fn drop(&mut self) {
727 if let Some(context) = TraceCategoryContext::acquire(self.category) {
728 let name_ref = self.name.as_trace_str_ref(&context);
729 context.write_duration(name_ref, self.start_time, self.args);
730 }
731 }
732}
733
734pub fn complete_duration<C: CategoryString, S: AsTraceStrRef>(
736 category: C,
737 name: S,
738 start_time: zx::BootTicks,
739 args: &[Arg<'_>],
740) {
741 if let Some(context) = TraceCategoryContext::acquire(category) {
742 let name_ref = name.as_trace_str_ref(&context);
743 context.write_duration(name_ref, start_time, args);
744 }
745}
746
747#[macro_export]
782macro_rules! duration {
783 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
784 let mut args;
785 let _scope = {
786 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
787 use $crate::AsTraceStrRef;
794 if let Some(context) =
795 $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
796 args = [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*];
797 Some($crate::duration($category, $name, &args))
798 } else {
799 None
800 }
801 };
802 }
803}
804
805pub fn duration<'a, C: CategoryString, S: AsTraceStrRef>(
817 category: C,
818 name: S,
819 args: &'a [Arg<'_>],
820) -> DurationScope<'a, C, S> {
821 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
822 DurationScope::begin(category, name, args)
823}
824
825#[macro_export]
839macro_rules! duration_begin {
840 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
841 {
842 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
843 use $crate::AsTraceStrRef;
844 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
845 $crate::duration_begin(&context, $name,
846 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
847 }
848 }
849 };
850}
851
852#[cfg(fuchsia_api_level_at_least = "31")]
868#[macro_export]
869macro_rules! vthread_duration_begin {
870 ($category:expr, $name:expr, $vthread_name:expr, $vthread_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
871 {
872 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
873 let vthread = $crate::VThread::new($vthread_name, $vthread_id);
874 use $crate::AsTraceStrRef;
875 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
876 $crate::vthread_duration_begin(
877 &context,
878 $name,
879 &vthread,
880 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
881 )
882 }
883 }
884 };
885}
886
887#[macro_export]
901macro_rules! duration_end {
902 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
903 {
904 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
905 use $crate::AsTraceStrRef;
906 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
907 $crate::duration_end(&context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
908 }
909 }
910 };
911}
912
913#[cfg(fuchsia_api_level_at_least = "31")]
929#[macro_export]
930macro_rules! vthread_duration_end {
931 ($category:expr, $name:expr, $vthread_name:expr, $vthread_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
932 {
933 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
934 let vthread = $crate::VThread::new($vthread_name, $vthread_id);
935 use $crate::AsTraceStrRef;
936 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
937 $crate::vthread_duration_end(
938 &context,
939 $name,
940 &vthread,
941 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
942 )
943 }
944 }
945 };
946}
947
948#[cfg(fuchsia_api_level_at_least = "31")]
953#[macro_export]
954macro_rules! track_instant {
955 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
956 {
957 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
958 use $crate::AsTraceStrRef;
959 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
960 $crate::track_instant(
961 &context,
962 $name,
963 &$track,
964 $crate::Scope::Thread,
965 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
966 )
967 }
968 }
969 };
970}
971
972#[cfg(fuchsia_api_level_at_least = "31")]
974#[macro_export]
975macro_rules! track_duration_begin {
976 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
977 {
978 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
979 use $crate::AsTraceStrRef;
980 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
981 $crate::track_duration_begin(
982 &context,
983 $name,
984 &$track,
985 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
986 )
987 }
988 }
989 };
990}
991
992#[cfg(fuchsia_api_level_at_least = "31")]
994#[macro_export]
995macro_rules! track_duration_end {
996 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
997 {
998 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
999 use $crate::AsTraceStrRef;
1000 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1001 $crate::track_duration_end(
1002 &context,
1003 $name,
1004 &$track,
1005 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
1006 )
1007 }
1008 }
1009 };
1010}
1011
1012#[cfg(fuchsia_api_level_at_least = "31")]
1019#[macro_export]
1020macro_rules! track_duration {
1021 ($category:expr, $track:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
1022 let mut args;
1028 let _scope = {
1029 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1030 use $crate::AsTraceStrRef;
1031 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1032 args = [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*];
1033 Some($crate::track_duration($category, $name, &$track, &args))
1034 } else {
1035 None
1036 }
1037 };
1038 };
1039}
1040
1041pub fn duration_begin<S: AsTraceStrRef>(context: &TraceCategoryContext, name: S, args: &[Arg<'_>]) {
1052 let ticks = zx::BootTicks::get();
1053 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1054
1055 let name_ref = name.as_trace_str_ref(&context);
1056 context.write_duration_begin(ticks, name_ref, args);
1057}
1058
1059#[cfg(fuchsia_api_level_at_least = "31")]
1060#[derive(Clone, Debug)]
1061pub struct VThread<S: AsTraceStrRef = &'static str> {
1062 name: S,
1063 id: sys::trace_vthread_id_t,
1064 process_koid: zx::sys::zx_koid_t,
1065}
1066
1067#[cfg(fuchsia_api_level_at_least = "31")]
1068impl<S: AsTraceStrRef> VThread<S> {
1069 pub fn new(name: S, id: sys::trace_vthread_id_t) -> Self {
1070 Self { name, id, process_koid: zx::sys::ZX_KOID_INVALID }
1071 }
1072
1073 pub fn new_with_process_koid(
1074 name: S,
1075 id: sys::trace_vthread_id_t,
1076 process_koid: zx::sys::zx_koid_t,
1077 ) -> Self {
1078 Self { name, id, process_koid }
1079 }
1080}
1081
1082#[cfg(fuchsia_api_level_at_least = "31")]
1084pub fn vthread_duration_begin<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1085 context: &TraceCategoryContext,
1086 name: S1,
1087 vthread: &VThread<S2>,
1088 args: &[Arg<'_>],
1089) {
1090 let ticks = zx::BootTicks::get();
1091 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1092
1093 let name_ref = name.as_trace_str_ref(context);
1094 context.write_vthread_duration_begin(ticks, name_ref, vthread, args);
1095}
1096
1097pub fn duration_end<S: AsTraceStrRef>(context: &TraceCategoryContext, name: S, args: &[Arg<'_>]) {
1107 let ticks = zx::BootTicks::get();
1108 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1109
1110 let name_ref = name.as_trace_str_ref(&context);
1111 context.write_duration_end(ticks, name_ref, args);
1112}
1113
1114#[cfg(fuchsia_api_level_at_least = "31")]
1116pub fn vthread_duration_end<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1117 context: &TraceCategoryContext,
1118 name: S1,
1119 vthread: &VThread<S2>,
1120 args: &[Arg<'_>],
1121) {
1122 let ticks = zx::BootTicks::get();
1123 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1124
1125 let name_ref = name.as_trace_str_ref(context);
1126 context.write_vthread_duration_end(ticks, name_ref, vthread, args);
1127}
1128
1129#[cfg(fuchsia_api_level_at_least = "31")]
1131pub fn vthread_instant<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1132 context: &TraceCategoryContext,
1133 name: S1,
1134 vthread: &VThread<S2>,
1135 scope: Scope,
1136 args: &[Arg<'_>],
1137) {
1138 let ticks = zx::BootTicks::get();
1139 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1140
1141 let name_ref = name.as_trace_str_ref(context);
1142 context.write_vthread_instant(ticks, name_ref, vthread, scope, args);
1143}
1144
1145#[cfg(fuchsia_api_level_at_least = "31")]
1153#[derive(Clone, Debug)]
1154pub struct Track {
1155 pub(crate) vthread: VThread<&'static str>,
1156}
1157
1158#[cfg(fuchsia_api_level_at_least = "31")]
1159impl Track {
1160 pub fn new(name: &'static str) -> Self {
1168 let id = Id::new();
1169 let process_koid = fuchsia_runtime::process_self()
1170 .koid()
1171 .map(|k| k.raw_koid())
1172 .unwrap_or(zx::sys::ZX_KOID_INVALID);
1173 Self { vthread: VThread::new_with_process_koid(name, id.into(), process_koid) }
1174 }
1175}
1176
1177#[cfg(fuchsia_api_level_at_least = "31")]
1183pub fn track_instant<S1: AsTraceStrRef>(
1184 context: &TraceCategoryContext,
1185 name: S1,
1186 track: &Track,
1187 scope: Scope,
1188 args: &[Arg<'_>],
1189) {
1190 vthread_instant(context, name, &track.vthread, scope, args);
1191}
1192
1193#[cfg(fuchsia_api_level_at_least = "31")]
1195pub fn track_duration_begin<S1: AsTraceStrRef>(
1196 context: &TraceCategoryContext,
1197 name: S1,
1198 track: &Track,
1199 args: &[Arg<'_>],
1200) {
1201 vthread_duration_begin(context, name, &track.vthread, args);
1202}
1203
1204#[cfg(fuchsia_api_level_at_least = "31")]
1206pub fn track_duration_end<S1: AsTraceStrRef>(
1207 context: &TraceCategoryContext,
1208 name: S1,
1209 track: &Track,
1210 args: &[Arg<'_>],
1211) {
1212 vthread_duration_end(context, name, &track.vthread, args);
1213}
1214
1215#[cfg(fuchsia_api_level_at_least = "31")]
1223#[must_use = "TrackDurationScope must be held to be recorded"]
1224pub struct TrackDurationScope<'a, C: CategoryString, S: AsTraceStrRef> {
1225 category: C,
1226 name: S,
1227 track: &'a Track,
1228 args: &'a [Arg<'a>],
1229 start_time: zx::BootTicks,
1230}
1231
1232#[cfg(fuchsia_api_level_at_least = "31")]
1233impl<'a, C: CategoryString, S: AsTraceStrRef> TrackDurationScope<'a, C, S> {
1234 pub fn begin(category: C, name: S, track: &'a Track, args: &'a [Arg<'_>]) -> Self {
1236 let start_time = zx::BootTicks::get();
1237 Self { category, name, track, args, start_time }
1238 }
1239}
1240
1241#[cfg(fuchsia_api_level_at_least = "31")]
1242impl<'a, C: CategoryString, S: AsTraceStrRef> Drop for TrackDurationScope<'a, C, S> {
1243 fn drop(&mut self) {
1244 if let Some(context) = TraceCategoryContext::acquire(self.category) {
1245 let name_ref = self.name.as_trace_str_ref(&context);
1246 context.write_vthread_duration(
1247 self.start_time,
1248 zx::BootTicks::get(),
1249 name_ref,
1250 &self.track.vthread,
1251 self.args,
1252 );
1253 }
1254 }
1255}
1256
1257#[cfg(fuchsia_api_level_at_least = "31")]
1262pub fn track_duration<'a, C: CategoryString, S: AsTraceStrRef>(
1263 category: C,
1264 name: S,
1265 track: &'a Track,
1266 args: &'a [Arg<'_>],
1267) -> TrackDurationScope<'a, C, S> {
1268 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1269 TrackDurationScope::begin(category, name, track, args)
1270}
1271
1272#[must_use = "emits an end event when dropped, so if dropped immediately creates an essentially \
1275 zero length duration that should just be an instant instead"]
1276pub struct AsyncScope<C: CategoryString = &'static CStr, S: AsTraceStrRef = &'static CStr> {
1277 id: Id,
1280 category: C,
1281 name: S,
1282}
1283
1284impl<C: CategoryString, S: AsTraceStrRef> AsyncScope<C, S> {
1285 pub fn begin(id: Id, category: C, name: S, args: &[Arg<'_>]) -> Self {
1288 async_begin(id, category, &name, args);
1289 Self { id, category, name }
1290 }
1291
1292 pub fn end(self, args: &[Arg<'_>]) {
1295 async_end(self.id, self.category, &self.name, args);
1296 std::mem::forget(self);
1297 }
1298}
1299
1300impl<C: CategoryString, S: AsTraceStrRef> Drop for AsyncScope<C, S> {
1301 fn drop(&mut self) {
1302 async_end(self.id, self.category, &self.name, &[]);
1306 }
1307}
1308
1309pub fn async_enter<C: CategoryString, S: AsTraceStrRef>(
1318 id: Id,
1319 category: C,
1320 name: S,
1321 args: &[Arg<'_>],
1322) -> AsyncScope<C, S> {
1323 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1324 AsyncScope::begin(id, category, name, args)
1325}
1326
1327#[macro_export]
1358macro_rules! async_enter {
1359 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
1360 {
1361 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1362 use $crate::AsTraceStrRef;
1363 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1364 Some($crate::AsyncScope::begin($id, $category, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]))
1365 } else {
1366 None
1367 }
1368 }
1369 }
1370}
1371
1372#[macro_export]
1396macro_rules! async_instant {
1397 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
1398 {
1399 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1400 use $crate::AsTraceStrRef;
1401 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1402 $crate::async_instant($id, &context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
1403 }
1404 }
1405 }
1406}
1407
1408pub fn async_begin<C: CategoryString, S: AsTraceStrRef>(
1420 id: Id,
1421 category: C,
1422 name: S,
1423 args: &[Arg<'_>],
1424) {
1425 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1426
1427 if let Some(context) = TraceCategoryContext::acquire(category) {
1428 let name_ref = name.as_trace_str_ref(&context);
1429 context.write_async_begin(id, name_ref, args);
1430 }
1431}
1432
1433pub fn async_end<C: CategoryString, S: AsTraceStrRef>(
1445 id: Id,
1446 category: C,
1447 name: S,
1448 args: &[Arg<'_>],
1449) {
1450 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1451
1452 if let Some(context) = TraceCategoryContext::acquire(category) {
1453 let name_ref = name.as_trace_str_ref(&context);
1454 context.write_async_end(id, name_ref, args);
1455 }
1456}
1457
1458pub fn async_instant<S: AsTraceStrRef>(
1470 id: Id,
1471 context: &TraceCategoryContext,
1472 name: S,
1473 args: &[Arg<'_>],
1474) {
1475 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1476
1477 let name_ref = name.as_trace_str_ref(context);
1478 context.write_async_instant(id, name_ref, args);
1479}
1480
1481#[macro_export]
1482macro_rules! blob {
1483 ($category:expr, $name:expr, $bytes:expr $(, $key:expr => $val:expr)*) => {
1484 {
1485 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1486 use $crate::AsTraceStrRef;
1487 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1488 $crate::blob_fn(&context, $name, $bytes, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1489 }
1490 }
1491 }
1492}
1493pub fn blob_fn<S: AsTraceStrRef>(
1494 context: &TraceCategoryContext,
1495 name: S,
1496 bytes: &[u8],
1497 args: &[Arg<'_>],
1498) {
1499 let name_ref = name.as_trace_str_ref(context);
1500 context.write_blob(name_ref, bytes, args);
1501}
1502
1503#[macro_export]
1527macro_rules! flow_begin {
1528 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1529 {
1530 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1531 use $crate::AsTraceStrRef;
1532 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1533 $crate::flow_begin(&context, $name, $flow_id,
1534 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1535 }
1536 }
1537 }
1538}
1539
1540#[macro_export]
1564macro_rules! flow_step {
1565 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1566 {
1567 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1568 use $crate::AsTraceStrRef;
1569 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1570 $crate::flow_step(&context, $name, $flow_id,
1571 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1572 }
1573 }
1574 }
1575}
1576
1577#[macro_export]
1601macro_rules! flow_end {
1602 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
1603 {
1604 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1605 use $crate::AsTraceStrRef;
1606 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1607 $crate::flow_end(&context, $name, $flow_id,
1608 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1609 }
1610 }
1611 }
1612}
1613
1614pub fn flow_begin<S: AsTraceStrRef>(
1635 context: &TraceCategoryContext,
1636 name: S,
1637 flow_id: Id,
1638 args: &[Arg<'_>],
1639) {
1640 let ticks = zx::BootTicks::get();
1641 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1642
1643 let name_ref = name.as_trace_str_ref(context);
1644 context.write_flow_begin(ticks, name_ref, flow_id, args);
1645}
1646
1647pub fn flow_end<S: AsTraceStrRef>(
1666 context: &TraceCategoryContext,
1667 name: S,
1668 flow_id: Id,
1669 args: &[Arg<'_>],
1670) {
1671 let ticks = zx::BootTicks::get();
1672 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1673
1674 let name_ref = name.as_trace_str_ref(context);
1675 context.write_flow_end(ticks, name_ref, flow_id, args);
1676}
1677
1678pub fn flow_step<S: AsTraceStrRef>(
1697 context: &TraceCategoryContext,
1698 name: S,
1699 flow_id: Id,
1700 args: &[Arg<'_>],
1701) {
1702 let ticks = zx::BootTicks::get();
1703 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1704
1705 let name_ref = name.as_trace_str_ref(context);
1706 context.write_flow_step(ticks, name_ref, flow_id, args);
1707}
1708
1709#[macro_export]
1723macro_rules! instaflow_begin {
1724 (
1725 $category:expr,
1726 $flow_name:expr,
1727 $step_name:expr,
1728 $flow_id:expr
1729 $(, $key:expr => $val:expr)*
1730 ) => {
1731 {
1732 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1733 use $crate::AsTraceStrRef;
1734 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1735 $crate::instaflow_begin(
1736 &context,
1737 $flow_name,
1738 $step_name,
1739 $flow_id,
1740 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1741 )
1742 }
1743 }
1744 }
1745}
1746
1747#[macro_export]
1761macro_rules! instaflow_end {
1762 (
1763 $category:expr,
1764 $flow_name:expr,
1765 $step_name:expr,
1766 $flow_id:expr
1767 $(, $key:expr => $val:expr)*
1768 ) => {
1769 {
1770 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1771 use $crate::AsTraceStrRef;
1772 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1773 $crate::instaflow_end(
1774 &context,
1775 $flow_name,
1776 $step_name,
1777 $flow_id,
1778 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1779 )
1780 }
1781 }
1782 }
1783}
1784
1785#[macro_export]
1799macro_rules! instaflow_step {
1800 (
1801 $category:expr,
1802 $flow_name:expr,
1803 $step_name:expr,
1804 $flow_id:expr
1805 $(, $key:expr => $val:expr)*
1806 ) => {
1807 {
1808 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1809 use $crate::AsTraceStrRef;
1810 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1811 $crate::instaflow_step(
1812 &context,
1813 $flow_name,
1814 $step_name,
1815 $flow_id,
1816 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1817 )
1818 }
1819 }
1820 }
1821}
1822
1823pub fn instaflow_begin<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1837 context: &TraceCategoryContext,
1838 flow_name: S1,
1839 step_name: S2,
1840 flow_id: Id,
1841 args: &[Arg<'_>],
1842) {
1843 let ticks = zx::BootTicks::get();
1844 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1845
1846 let flow_name_ref = flow_name.as_trace_str_ref(context);
1847 let step_name_ref = step_name.as_trace_str_ref(context);
1848
1849 context.write_duration_begin(ticks, step_name_ref, args);
1850 context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1851 context.write_duration_end(ticks, step_name_ref, args);
1852}
1853
1854pub fn instaflow_end<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1868 context: &TraceCategoryContext,
1869 flow_name: S1,
1870 step_name: S2,
1871 flow_id: Id,
1872 args: &[Arg<'_>],
1873) {
1874 let ticks = zx::BootTicks::get();
1875 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1876
1877 let flow_name_ref = flow_name.as_trace_str_ref(context);
1878 let step_name_ref = step_name.as_trace_str_ref(context);
1879
1880 context.write_duration_begin(ticks, step_name_ref, args);
1881 context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1882 context.write_duration_end(ticks, step_name_ref, args);
1883}
1884
1885pub fn instaflow_step<S1: AsTraceStrRef, S2: AsTraceStrRef>(
1899 context: &TraceCategoryContext,
1900 flow_name: S1,
1901 step_name: S2,
1902 flow_id: Id,
1903 args: &[Arg<'_>],
1904) {
1905 let ticks = zx::BootTicks::get();
1906 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1907
1908 let flow_name_ref = flow_name.as_trace_str_ref(context);
1909 let step_name_ref = step_name.as_trace_str_ref(context);
1910
1911 context.write_duration_begin(ticks, step_name_ref, args);
1912 context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1913 context.write_duration_end(ticks, step_name_ref, args);
1914}
1915
1916const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1918 sys::trace_string_ref_t {
1919 encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1920 inline_string: ptr::null(),
1921 }
1922}
1923
1924#[inline]
1925fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1926 let mut len = string.len();
1927 if string.len() > max_len {
1928 len = max_len;
1932 while len > 0 {
1933 if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1934 break;
1935 }
1936 len -= 1;
1937 }
1938 }
1939 &string.as_bytes()[0..len]
1940}
1941
1942#[inline]
1945fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1946 let len = string.len() as u16;
1947 if len == 0 {
1948 return trace_make_empty_string_ref();
1949 }
1950
1951 let string = trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH);
1952
1953 sys::trace_string_ref_t {
1954 encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1955 inline_string: string.as_ptr() as *const libc::c_char,
1956 }
1957}
1958
1959pub struct TraceCategoryContext {
1961 context: Context,
1962 category_ref: sys::trace_string_ref_t,
1963}
1964
1965impl TraceCategoryContext {
1966 #[inline]
1967 pub fn acquire_cached<C: CategoryString>(
1968 category: C,
1969 site: &sys::trace_site_t,
1970 ) -> Option<TraceCategoryContext> {
1971 category.acquire_context_cached(site)
1972 }
1973
1974 pub fn acquire<C: CategoryString>(category: C) -> Option<TraceCategoryContext> {
1975 category.acquire_context()
1976 }
1977
1978 #[inline]
1979 pub fn register_string_literal<T: CategoryString>(&self, name: T) -> sys::trace_string_ref_t {
1980 name.register(&self.context)
1981 }
1982
1983 #[inline]
1984 #[cfg(fuchsia_api_level_at_least = "27")]
1985 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1986 unsafe {
1987 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1988 sys::trace_context_register_bytestring(
1989 self.context.raw,
1990 name.as_ptr().cast::<libc::c_char>(),
1991 name.len(),
1992 name_ref.as_mut_ptr(),
1993 );
1994 name_ref.assume_init()
1995 }
1996 }
1997 #[inline]
1998 #[cfg(not(fuchsia_api_level_at_least = "27"))]
1999 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
2000 trace_make_inline_string_ref(name)
2001 }
2002
2003 #[inline]
2004 fn register_current_thread(&self) -> sys::trace_thread_ref_t {
2005 unsafe {
2006 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
2007 sys::trace_context_register_current_thread(self.context.raw, thread_ref.as_mut_ptr());
2008 thread_ref.assume_init()
2009 }
2010 }
2011
2012 #[cfg(fuchsia_api_level_at_least = "31")]
2013 #[inline]
2014 fn register_vthread<S: AsTraceStrRef>(
2015 &self,
2016 name: &S,
2017 id: sys::trace_vthread_id_t,
2018 process_koid: zx::sys::zx_koid_t,
2019 ) -> sys::trace_thread_ref_t {
2020 let name_ref = name.as_trace_str_ref(self);
2021 unsafe {
2022 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
2023 sys::trace_context_register_vthread_by_ref(
2024 self.context.raw,
2025 process_koid,
2026 &name_ref,
2027 id,
2028 thread_ref.as_mut_ptr(),
2029 );
2030 thread_ref.assume_init()
2031 }
2032 }
2033
2034 #[inline]
2035 pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
2036 let ticks = zx::BootTicks::get();
2037 let thread_ref = self.register_current_thread();
2038 unsafe {
2039 sys::trace_context_write_instant_event_record(
2040 self.context.raw,
2041 ticks.into_raw(),
2042 &thread_ref,
2043 &self.category_ref,
2044 &name_ref,
2045 scope.into_raw(),
2046 args.as_ptr() as *const sys::trace_arg_t,
2047 args.len(),
2048 );
2049 }
2050 }
2051
2052 pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
2053 let name_ref = trace_make_inline_string_ref(name);
2054 self.write_instant(name_ref, scope, args)
2055 }
2056
2057 fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
2058 let ticks = zx::BootTicks::get();
2059 let thread_ref = self.register_current_thread();
2060 unsafe {
2061 sys::trace_context_write_counter_event_record(
2062 self.context.raw,
2063 ticks.into_raw(),
2064 &thread_ref,
2065 &self.category_ref,
2066 &name_ref,
2067 counter_id,
2068 args.as_ptr() as *const sys::trace_arg_t,
2069 args.len(),
2070 );
2071 }
2072 }
2073
2074 pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
2075 let name_ref = trace_make_inline_string_ref(name);
2076 self.write_counter(name_ref, counter_id, args);
2077 }
2078
2079 fn write_duration(
2080 &self,
2081 name_ref: sys::trace_string_ref_t,
2082 start_time: zx::BootTicks,
2083 args: &[Arg<'_>],
2084 ) {
2085 let ticks = zx::BootTicks::get();
2086 let thread_ref = self.register_current_thread();
2087 unsafe {
2088 sys::trace_context_write_duration_event_record(
2089 self.context.raw,
2090 start_time.into_raw(),
2091 ticks.into_raw(),
2092 &thread_ref,
2093 &self.category_ref,
2094 &name_ref,
2095 args.as_ptr() as *const sys::trace_arg_t,
2096 args.len(),
2097 );
2098 }
2099 }
2100
2101 pub fn write_duration_with_inline_name(
2102 &self,
2103 name: &str,
2104 start_time: zx::BootTicks,
2105 args: &[Arg<'_>],
2106 ) {
2107 let name_ref = trace_make_inline_string_ref(name);
2108 self.write_duration(name_ref, start_time, args);
2109 }
2110
2111 fn write_duration_begin(
2112 &self,
2113 ticks: zx::BootTicks,
2114 name_ref: sys::trace_string_ref_t,
2115 args: &[Arg<'_>],
2116 ) {
2117 let thread_ref = self.register_current_thread();
2118 unsafe {
2119 sys::trace_context_write_duration_begin_event_record(
2120 self.context.raw,
2121 ticks.into_raw(),
2122 &thread_ref,
2123 &self.category_ref,
2124 &name_ref,
2125 args.as_ptr() as *const sys::trace_arg_t,
2126 args.len(),
2127 );
2128 }
2129 }
2130
2131 #[cfg(fuchsia_api_level_at_least = "31")]
2132 fn write_vthread_duration_begin<S: AsTraceStrRef>(
2133 &self,
2134 ticks: zx::BootTicks,
2135 name_ref: sys::trace_string_ref_t,
2136 vthread: &VThread<S>,
2137 args: &[Arg<'_>],
2138 ) {
2139 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2140 unsafe {
2141 sys::trace_context_write_duration_begin_event_record(
2142 self.context.raw,
2143 ticks.into_raw(),
2144 &thread_ref,
2145 &self.category_ref,
2146 &name_ref,
2147 args.as_ptr() as *const sys::trace_arg_t,
2148 args.len(),
2149 );
2150 }
2151 }
2152
2153 pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
2154 let name_ref = trace_make_inline_string_ref(name);
2155 self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
2156 }
2157
2158 fn write_duration_end(
2159 &self,
2160 ticks: zx::BootTicks,
2161 name_ref: sys::trace_string_ref_t,
2162 args: &[Arg<'_>],
2163 ) {
2164 let thread_ref = self.register_current_thread();
2165 unsafe {
2166 sys::trace_context_write_duration_end_event_record(
2167 self.context.raw,
2168 ticks.into_raw(),
2169 &thread_ref,
2170 &self.category_ref,
2171 &name_ref,
2172 args.as_ptr() as *const sys::trace_arg_t,
2173 args.len(),
2174 );
2175 }
2176 }
2177
2178 #[cfg(fuchsia_api_level_at_least = "31")]
2179 fn write_vthread_duration_end<S: AsTraceStrRef>(
2180 &self,
2181 ticks: zx::BootTicks,
2182 name_ref: sys::trace_string_ref_t,
2183 vthread: &VThread<S>,
2184 args: &[Arg<'_>],
2185 ) {
2186 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2187 unsafe {
2188 sys::trace_context_write_duration_end_event_record(
2189 self.context.raw,
2190 ticks.into_raw(),
2191 &thread_ref,
2192 &self.category_ref,
2193 &name_ref,
2194 args.as_ptr() as *const sys::trace_arg_t,
2195 args.len(),
2196 );
2197 }
2198 }
2199
2200 #[cfg(fuchsia_api_level_at_least = "31")]
2201 fn write_vthread_instant<S: AsTraceStrRef>(
2202 &self,
2203 ticks: zx::BootTicks,
2204 name_ref: sys::trace_string_ref_t,
2205 vthread: &VThread<S>,
2206 scope: Scope,
2207 args: &[Arg<'_>],
2208 ) {
2209 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2210 unsafe {
2213 sys::trace_context_write_instant_event_record(
2214 self.context.raw,
2215 ticks.into_raw(),
2216 &thread_ref,
2217 &self.category_ref,
2218 &name_ref,
2219 scope.into_raw(),
2220 args.as_ptr() as *const sys::trace_arg_t,
2221 args.len(),
2222 );
2223 }
2224 }
2225
2226 #[cfg(fuchsia_api_level_at_least = "31")]
2227 fn write_vthread_duration<S: AsTraceStrRef>(
2228 &self,
2229 start_time: zx::BootTicks,
2230 ticks: zx::BootTicks,
2231 name_ref: sys::trace_string_ref_t,
2232 vthread: &VThread<S>,
2233 args: &[Arg<'_>],
2234 ) {
2235 let thread_ref = self.register_vthread(&vthread.name, vthread.id, vthread.process_koid);
2236 unsafe {
2239 sys::trace_context_write_duration_event_record(
2240 self.context.raw,
2241 start_time.into_raw(),
2242 ticks.into_raw(),
2243 &thread_ref,
2244 &self.category_ref,
2245 &name_ref,
2246 args.as_ptr() as *const sys::trace_arg_t,
2247 args.len(),
2248 );
2249 }
2250 }
2251
2252 pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
2253 let name_ref = trace_make_inline_string_ref(name);
2254 self.write_duration_end(zx::BootTicks::get(), name_ref, args);
2255 }
2256
2257 fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2258 let ticks = zx::BootTicks::get();
2259 let thread_ref = self.register_current_thread();
2260 unsafe {
2261 sys::trace_context_write_async_begin_event_record(
2262 self.context.raw,
2263 ticks.into_raw(),
2264 &thread_ref,
2265 &self.category_ref,
2266 &name_ref,
2267 id.into(),
2268 args.as_ptr() as *const sys::trace_arg_t,
2269 args.len(),
2270 );
2271 }
2272 }
2273
2274 pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
2275 let name_ref = trace_make_inline_string_ref(name);
2276 self.write_async_begin(id, name_ref, args);
2277 }
2278
2279 fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2280 let ticks = zx::BootTicks::get();
2281 let thread_ref = self.register_current_thread();
2282 unsafe {
2283 sys::trace_context_write_async_end_event_record(
2284 self.context.raw,
2285 ticks.into_raw(),
2286 &thread_ref,
2287 &self.category_ref,
2288 &name_ref,
2289 id.into(),
2290 args.as_ptr() as *const sys::trace_arg_t,
2291 args.len(),
2292 );
2293 }
2294 }
2295
2296 pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
2297 let name_ref = trace_make_inline_string_ref(name);
2298 self.write_async_end(id, name_ref, args);
2299 }
2300
2301 fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
2302 let ticks = zx::BootTicks::get();
2303 let thread_ref = self.register_current_thread();
2304 unsafe {
2305 sys::trace_context_write_async_instant_event_record(
2306 self.context.raw,
2307 ticks.into_raw(),
2308 &thread_ref,
2309 &self.category_ref,
2310 &name_ref,
2311 id.into(),
2312 args.as_ptr() as *const sys::trace_arg_t,
2313 args.len(),
2314 );
2315 }
2316 }
2317
2318 fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
2319 let ticks = zx::BootTicks::get();
2320 let thread_ref = self.register_current_thread();
2321 unsafe {
2322 sys::trace_context_write_blob_event_record(
2323 self.context.raw,
2324 ticks.into_raw(),
2325 &thread_ref,
2326 &self.category_ref,
2327 &name_ref,
2328 bytes.as_ptr() as *const core::ffi::c_void,
2329 bytes.len(),
2330 args.as_ptr() as *const sys::trace_arg_t,
2331 args.len(),
2332 );
2333 }
2334 }
2335
2336 fn write_flow_begin(
2337 &self,
2338 ticks: zx::BootTicks,
2339 name_ref: sys::trace_string_ref_t,
2340 flow_id: Id,
2341 args: &[Arg<'_>],
2342 ) {
2343 let thread_ref = self.register_current_thread();
2344 unsafe {
2345 sys::trace_context_write_flow_begin_event_record(
2346 self.context.raw,
2347 ticks.into_raw(),
2348 &thread_ref,
2349 &self.category_ref,
2350 &name_ref,
2351 flow_id.into(),
2352 args.as_ptr() as *const sys::trace_arg_t,
2353 args.len(),
2354 );
2355 }
2356 }
2357
2358 fn write_flow_end(
2359 &self,
2360 ticks: zx::BootTicks,
2361 name_ref: sys::trace_string_ref_t,
2362 flow_id: Id,
2363 args: &[Arg<'_>],
2364 ) {
2365 let thread_ref = self.register_current_thread();
2366 unsafe {
2367 sys::trace_context_write_flow_end_event_record(
2368 self.context.raw,
2369 ticks.into_raw(),
2370 &thread_ref,
2371 &self.category_ref,
2372 &name_ref,
2373 flow_id.into(),
2374 args.as_ptr() as *const sys::trace_arg_t,
2375 args.len(),
2376 );
2377 }
2378 }
2379
2380 fn write_flow_step(
2381 &self,
2382 ticks: zx::BootTicks,
2383 name_ref: sys::trace_string_ref_t,
2384 flow_id: Id,
2385 args: &[Arg<'_>],
2386 ) {
2387 let thread_ref = self.register_current_thread();
2388 unsafe {
2389 sys::trace_context_write_flow_step_event_record(
2390 self.context.raw,
2391 ticks.into_raw(),
2392 &thread_ref,
2393 &self.category_ref,
2394 &name_ref,
2395 flow_id.into(),
2396 args.as_ptr() as *const sys::trace_arg_t,
2397 args.len(),
2398 );
2399 }
2400 }
2401}
2402
2403pub struct Context {
2405 raw: *const sys::trace_context_t,
2406}
2407
2408impl Context {
2409 #[inline]
2410 pub fn acquire() -> Option<Self> {
2411 let context = unsafe { sys::trace_acquire_context() };
2412 if context.is_null() { None } else { Some(Self { raw: context }) }
2413 }
2414
2415 #[inline]
2416 pub fn register_string_literal<T: CategoryString>(&self, s: T) -> sys::trace_string_ref_t {
2417 s.register(self)
2418 }
2419
2420 pub fn write_blob_record(
2421 &self,
2422 type_: sys::trace_blob_type_t,
2423 name_ref: &sys::trace_string_ref_t,
2424 data: &[u8],
2425 ) {
2426 unsafe {
2427 sys::trace_context_write_blob_record(
2428 self.raw,
2429 type_,
2430 name_ref as *const sys::trace_string_ref_t,
2431 data.as_ptr() as *const libc::c_void,
2432 data.len(),
2433 );
2434 }
2435 }
2436
2437 pub fn copy_record(&self, buffer: &[u64]) -> Option<usize> {
2441 unsafe {
2442 let ptr = sys::trace_context_alloc_record(self.raw, 8 * buffer.len() as libc::size_t);
2443 if ptr == std::ptr::null_mut() {
2444 return None;
2445 }
2446 ptr.cast::<u64>().copy_from(buffer.as_ptr(), buffer.len());
2447 };
2448 Some(buffer.len())
2449 }
2450
2451 pub fn buffering_mode(&self) -> BufferingMode {
2452 match unsafe { sys::trace_context_get_buffering_mode(self.raw) } {
2453 sys::TRACE_BUFFERING_MODE_ONESHOT => BufferingMode::OneShot,
2454 sys::TRACE_BUFFERING_MODE_CIRCULAR => BufferingMode::Circular,
2455 sys::TRACE_BUFFERING_MODE_STREAMING => BufferingMode::Streaming,
2456 m => panic!("Unknown trace buffering mode: {:?}", m),
2457 }
2458 }
2459}
2460
2461impl std::ops::Drop for Context {
2462 fn drop(&mut self) {
2463 unsafe { sys::trace_release_context(self.raw) }
2464 }
2465}
2466
2467pub struct ProlongedContext {
2468 context: *const sys::trace_prolonged_context_t,
2469}
2470
2471impl ProlongedContext {
2472 pub fn acquire() -> Option<Self> {
2473 let context = unsafe { sys::trace_acquire_prolonged_context() };
2474 if context.is_null() { None } else { Some(Self { context }) }
2475 }
2476}
2477
2478impl Drop for ProlongedContext {
2479 fn drop(&mut self) {
2480 unsafe { sys::trace_release_prolonged_context(self.context) }
2481 }
2482}
2483
2484unsafe impl Send for ProlongedContext {}
2485
2486mod sys {
2487 #![allow(non_camel_case_types, unused)]
2488 use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
2489
2490 pub type trace_ticks_t = zx_ticks_t;
2491 pub type trace_counter_id_t = u64;
2492 pub type trace_async_id_t = u64;
2493 pub type trace_flow_id_t = u64;
2494 pub type trace_vthread_id_t = u64;
2495 pub type trace_thread_state_t = u32;
2496 pub type trace_cpu_number_t = u32;
2497 pub type trace_string_index_t = u32;
2498 pub type trace_thread_index_t = u32;
2499 pub type trace_context_t = libc::c_void;
2500 pub type trace_prolonged_context_t = libc::c_void;
2501
2502 pub type trace_encoded_string_ref_t = u16;
2503 pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
2504 pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
2505 pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
2506 pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: usize = 32000;
2507 pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
2508 pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
2509
2510 pub type trace_encoded_thread_ref_t = u32;
2511 pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
2512 pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
2513 pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
2514
2515 pub type trace_state_t = libc::c_int;
2516 pub const TRACE_STOPPED: trace_state_t = 0;
2517 pub const TRACE_STARTED: trace_state_t = 1;
2518 pub const TRACE_STOPPING: trace_state_t = 2;
2519
2520 pub type trace_scope_t = libc::c_int;
2521 pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
2522 pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
2523 pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
2524
2525 pub type trace_blob_type_t = libc::c_int;
2526 pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
2527 pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
2528 pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
2529
2530 pub type trace_buffering_mode_t = libc::c_int;
2531 pub const TRACE_BUFFERING_MODE_ONESHOT: trace_buffering_mode_t = 0;
2532 pub const TRACE_BUFFERING_MODE_CIRCULAR: trace_buffering_mode_t = 1;
2533 pub const TRACE_BUFFERING_MODE_STREAMING: trace_buffering_mode_t = 2;
2534
2535 #[repr(C)]
2536 #[derive(Copy, Clone)]
2537 pub struct trace_string_ref_t {
2538 pub encoded_value: trace_encoded_string_ref_t,
2539 pub inline_string: *const libc::c_char,
2540 }
2541
2542 pub type trace_site_t = std::sync::atomic::AtomicU64;
2546
2547 unsafe impl Send for trace_string_ref_t {}
2557 unsafe impl Sync for trace_string_ref_t {}
2558
2559 #[repr(C)]
2560 pub struct trace_thread_ref_t {
2561 pub encoded_value: trace_encoded_thread_ref_t,
2562 pub inline_process_koid: zx_koid_t,
2563 pub inline_thread_koid: zx_koid_t,
2564 }
2565
2566 #[repr(C)]
2567 pub struct trace_arg_t {
2568 pub name_ref: trace_string_ref_t,
2569 pub value: trace_arg_value_t,
2570 }
2571
2572 #[repr(C)]
2573 pub union trace_arg_union_t {
2574 pub int32_value: i32,
2575 pub uint32_value: u32,
2576 pub int64_value: i64,
2577 pub uint64_value: u64,
2578 pub double_value: libc::c_double,
2579 pub string_value_ref: trace_string_ref_t,
2580 pub pointer_value: libc::uintptr_t,
2581 pub koid_value: zx_koid_t,
2582 pub bool_value: bool,
2583 pub reserved_for_future_expansion: [libc::uintptr_t; 2],
2584 }
2585
2586 pub type trace_arg_type_t = libc::c_int;
2587 pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
2588 pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
2589 pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
2590 pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
2591 pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
2592 pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
2593 pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
2594 pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
2595 pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
2596 pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
2597
2598 #[repr(C)]
2599 pub struct trace_arg_value_t {
2600 pub type_: trace_arg_type_t,
2601 pub value: trace_arg_union_t,
2602 }
2603
2604 #[repr(C)]
2605 pub struct trace_handler_ops_t {
2606 pub is_category_enabled:
2607 unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
2608 pub trace_started: unsafe fn(handler: *const trace_handler_t),
2609 pub trace_stopped: unsafe fn(
2610 handler: *const trace_handler_t,
2611 async_ptr: *const (), disposition: zx_status_t,
2613 buffer_bytes_written: libc::size_t,
2614 ),
2615 pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
2616 }
2617
2618 #[repr(C)]
2619 pub struct trace_handler_t {
2620 pub ops: *const trace_handler_ops_t,
2621 }
2622
2623 unsafe extern "C" {
2625 pub fn trace_context_is_category_enabled(
2628 context: *const trace_context_t,
2629 category_literal: *const libc::c_char,
2630 ) -> bool;
2631
2632 pub fn trace_context_register_string_literal(
2633 context: *const trace_context_t,
2634 string_literal: *const libc::c_char,
2635 out_ref: *mut trace_string_ref_t,
2636 );
2637
2638 #[cfg(fuchsia_api_level_at_least = "27")]
2639 pub fn trace_context_register_bytestring(
2640 context: *const trace_context_t,
2641 string_literal: *const libc::c_char,
2642 length: libc::size_t,
2643 out_ref: *mut trace_string_ref_t,
2644 );
2645
2646 pub fn trace_context_register_category_literal(
2647 context: *const trace_context_t,
2648 category_literal: *const libc::c_char,
2649 out_ref: *mut trace_string_ref_t,
2650 ) -> bool;
2651
2652 pub fn trace_context_register_current_thread(
2653 context: *const trace_context_t,
2654 out_ref: *mut trace_thread_ref_t,
2655 );
2656
2657 pub fn trace_context_register_thread(
2658 context: *const trace_context_t,
2659 process_koid: zx_koid_t,
2660 thread_koid: zx_koid_t,
2661 out_ref: *mut trace_thread_ref_t,
2662 );
2663
2664 #[cfg(fuchsia_api_level_at_least = "31")]
2665 pub fn trace_context_register_vthread_by_ref(
2666 context: *const trace_context_t,
2667 process_koid: zx_koid_t,
2668 vthread_name: *const trace_string_ref_t,
2669 vthread_id: trace_vthread_id_t,
2670 out_ref: *mut trace_thread_ref_t,
2671 );
2672
2673 pub fn trace_context_write_kernel_object_record(
2674 context: *const trace_context_t,
2675 koid: zx_koid_t,
2676 type_: zx_obj_type_t,
2677 args: *const trace_arg_t,
2678 num_args: libc::size_t,
2679 );
2680
2681 pub fn trace_context_write_kernel_object_record_for_handle(
2682 context: *const trace_context_t,
2683 handle: zx_handle_t,
2684 args: *const trace_arg_t,
2685 num_args: libc::size_t,
2686 );
2687
2688 pub fn trace_context_write_process_info_record(
2689 context: *const trace_context_t,
2690 process_koid: zx_koid_t,
2691 process_name_ref: *const trace_string_ref_t,
2692 );
2693
2694 pub fn trace_context_write_thread_info_record(
2695 context: *const trace_context_t,
2696 process_koid: zx_koid_t,
2697 thread_koid: zx_koid_t,
2698 thread_name_ref: *const trace_string_ref_t,
2699 );
2700
2701 pub fn trace_context_write_context_switch_record(
2702 context: *const trace_context_t,
2703 event_time: trace_ticks_t,
2704 cpu_number: trace_cpu_number_t,
2705 outgoing_thread_state: trace_thread_state_t,
2706 outgoing_thread_ref: *const trace_thread_ref_t,
2707 incoming_thread_ref: *const trace_thread_ref_t,
2708 );
2709
2710 pub fn trace_context_write_log_record(
2711 context: *const trace_context_t,
2712 event_time: trace_ticks_t,
2713 thread_ref: *const trace_thread_ref_t,
2714 log_message: *const libc::c_char,
2715 log_message_length: libc::size_t,
2716 );
2717
2718 pub fn trace_context_write_instant_event_record(
2719 context: *const trace_context_t,
2720 event_time: trace_ticks_t,
2721 thread_ref: *const trace_thread_ref_t,
2722 category_ref: *const trace_string_ref_t,
2723 name_ref: *const trace_string_ref_t,
2724 scope: trace_scope_t,
2725 args: *const trace_arg_t,
2726 num_args: libc::size_t,
2727 );
2728
2729 pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
2730
2731 #[cfg(fuchsia_api_level_at_least = "27")]
2732 pub fn trace_context_send_alert_bytestring(
2733 context: *const trace_context_t,
2734 name: *const u8,
2735 length: usize,
2736 );
2737
2738 pub fn trace_context_write_counter_event_record(
2739 context: *const trace_context_t,
2740 event_time: trace_ticks_t,
2741 thread_ref: *const trace_thread_ref_t,
2742 category_ref: *const trace_string_ref_t,
2743 name_ref: *const trace_string_ref_t,
2744 counter_id: trace_counter_id_t,
2745 args: *const trace_arg_t,
2746 num_args: libc::size_t,
2747 );
2748
2749 pub fn trace_context_write_duration_event_record(
2750 context: *const trace_context_t,
2751 start_time: trace_ticks_t,
2752 end_time: trace_ticks_t,
2753 thread_ref: *const trace_thread_ref_t,
2754 category_ref: *const trace_string_ref_t,
2755 name_ref: *const trace_string_ref_t,
2756 args: *const trace_arg_t,
2757 num_args: libc::size_t,
2758 );
2759
2760 pub fn trace_context_write_blob_event_record(
2761 context: *const trace_context_t,
2762 event_time: trace_ticks_t,
2763 thread_ref: *const trace_thread_ref_t,
2764 category_ref: *const trace_string_ref_t,
2765 name_ref: *const trace_string_ref_t,
2766 blob: *const libc::c_void,
2767 blob_size: libc::size_t,
2768 args: *const trace_arg_t,
2769 num_args: libc::size_t,
2770 );
2771
2772 pub fn trace_context_write_duration_begin_event_record(
2773 context: *const trace_context_t,
2774 event_time: trace_ticks_t,
2775 thread_ref: *const trace_thread_ref_t,
2776 category_ref: *const trace_string_ref_t,
2777 name_ref: *const trace_string_ref_t,
2778 args: *const trace_arg_t,
2779 num_args: libc::size_t,
2780 );
2781
2782 pub fn trace_context_write_duration_end_event_record(
2783 context: *const trace_context_t,
2784 event_time: trace_ticks_t,
2785 thread_ref: *const trace_thread_ref_t,
2786 category_ref: *const trace_string_ref_t,
2787 name_ref: *const trace_string_ref_t,
2788 args: *const trace_arg_t,
2789 num_args: libc::size_t,
2790 );
2791
2792 pub fn trace_context_write_async_begin_event_record(
2793 context: *const trace_context_t,
2794 event_time: trace_ticks_t,
2795 thread_ref: *const trace_thread_ref_t,
2796 category_ref: *const trace_string_ref_t,
2797 name_ref: *const trace_string_ref_t,
2798 async_id: trace_async_id_t,
2799 args: *const trace_arg_t,
2800 num_args: libc::size_t,
2801 );
2802
2803 pub fn trace_context_write_async_instant_event_record(
2804 context: *const trace_context_t,
2805 event_time: trace_ticks_t,
2806 thread_ref: *const trace_thread_ref_t,
2807 category_ref: *const trace_string_ref_t,
2808 name_ref: *const trace_string_ref_t,
2809 async_id: trace_async_id_t,
2810 args: *const trace_arg_t,
2811 num_args: libc::size_t,
2812 );
2813
2814 pub fn trace_context_write_async_end_event_record(
2815 context: *const trace_context_t,
2816 event_time: trace_ticks_t,
2817 thread_ref: *const trace_thread_ref_t,
2818 category_ref: *const trace_string_ref_t,
2819 name_ref: *const trace_string_ref_t,
2820 async_id: trace_async_id_t,
2821 args: *const trace_arg_t,
2822 num_args: libc::size_t,
2823 );
2824
2825 pub fn trace_context_write_flow_begin_event_record(
2826 context: *const trace_context_t,
2827 event_time: trace_ticks_t,
2828 thread_ref: *const trace_thread_ref_t,
2829 category_ref: *const trace_string_ref_t,
2830 name_ref: *const trace_string_ref_t,
2831 flow_id: trace_flow_id_t,
2832 args: *const trace_arg_t,
2833 num_args: libc::size_t,
2834 );
2835
2836 pub fn trace_context_write_flow_step_event_record(
2837 context: *const trace_context_t,
2838 event_time: trace_ticks_t,
2839 thread_ref: *const trace_thread_ref_t,
2840 category_ref: *const trace_string_ref_t,
2841 name_ref: *const trace_string_ref_t,
2842 flow_id: trace_flow_id_t,
2843 args: *const trace_arg_t,
2844 num_args: libc::size_t,
2845 );
2846
2847 pub fn trace_context_write_flow_end_event_record(
2848 context: *const trace_context_t,
2849 event_time: trace_ticks_t,
2850 thread_ref: *const trace_thread_ref_t,
2851 category_ref: *const trace_string_ref_t,
2852 name_ref: *const trace_string_ref_t,
2853 flow_id: trace_flow_id_t,
2854 args: *const trace_arg_t,
2855 num_args: libc::size_t,
2856 );
2857
2858 pub fn trace_context_write_initialization_record(
2859 context: *const trace_context_t,
2860 ticks_per_second: u64,
2861 );
2862
2863 pub fn trace_context_write_string_record(
2864 context: *const trace_context_t,
2865 index: trace_string_index_t,
2866 string: *const libc::c_char,
2867 length: libc::size_t,
2868 );
2869
2870 pub fn trace_context_write_thread_record(
2871 context: *const trace_context_t,
2872 index: trace_thread_index_t,
2873 procss_koid: zx_koid_t,
2874 thread_koid: zx_koid_t,
2875 );
2876
2877 pub fn trace_context_write_blob_record(
2878 context: *const trace_context_t,
2879 type_: trace_blob_type_t,
2880 name_ref: *const trace_string_ref_t,
2881 data: *const libc::c_void,
2882 size: libc::size_t,
2883 );
2884
2885 pub fn trace_context_alloc_record(
2886 context: *const trace_context_t,
2887 num_bytes: libc::size_t,
2888 ) -> *mut libc::c_void;
2889
2890 pub fn trace_state() -> trace_state_t;
2892
2893 #[cfg(fuchsia_api_level_at_least = "27")]
2894 pub fn trace_is_category_bytestring_enabled(
2895 category_literal: *const u8,
2896 length: usize,
2897 ) -> bool;
2898
2899 pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2900
2901 pub fn trace_acquire_context() -> *const trace_context_t;
2902
2903 pub fn trace_acquire_context_for_category(
2904 category_literal: *const libc::c_char,
2905 out_ref: *mut trace_string_ref_t,
2906 ) -> *const trace_context_t;
2907
2908 pub fn trace_acquire_context_for_category_cached(
2909 category_literal: *const libc::c_char,
2910 trace_site: *const u64,
2911 out_ref: *mut trace_string_ref_t,
2912 ) -> *const trace_context_t;
2913
2914 #[cfg(fuchsia_api_level_at_least = "27")]
2915 pub fn trace_acquire_context_for_category_bytestring(
2916 bytes: *const u8,
2917 length: usize,
2918 out_ref: *mut trace_string_ref_t,
2919 ) -> *const trace_context_t;
2920
2921 #[cfg(fuchsia_api_level_at_least = "27")]
2922 pub fn trace_acquire_context_for_category_bytestring_cached(
2923 bytes: *const u8,
2924 length: usize,
2925 trace_site: *const u64,
2926 out_ref: *mut trace_string_ref_t,
2927 ) -> *const trace_context_t;
2928
2929 pub fn trace_release_context(context: *const trace_context_t);
2930
2931 pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2932
2933 pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2934
2935 pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2936
2937 pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2938
2939 pub fn trace_notify_observer_updated(event: zx_handle_t);
2940
2941 pub fn trace_context_get_buffering_mode(
2942 context: *const trace_context_t,
2943 ) -> trace_buffering_mode_t;
2944
2945 #[cfg(fuchsia_api_level_at_least = "31")]
2946 pub fn trace_engine_flush_buffer() -> zx_status_t;
2947 }
2948}
2949
2950pub struct TraceFutureArgs<'a, C: CategoryString, S: AsTraceStrRef> {
2953 pub category: C,
2954 pub name: S,
2955
2956 pub args: Box<[Arg<'a>]>,
2959
2960 pub flow_id: Option<Id>,
2963
2964 pub _use_trace_future_args: (),
2966}
2967
2968#[doc(hidden)]
2969#[macro_export]
2970macro_rules! __impl_trace_future_args {
2971 ($category:expr, $name:expr, $flow_id:expr) => {
2974 $crate::TraceFutureArgs {
2975 category: $category,
2976 name: $name,
2977 args: ::std::boxed::Box::new([]),
2978 flow_id: $flow_id,
2979 _use_trace_future_args: (),
2980 }
2981 };
2982 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2983 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2984 use $crate::AsTraceStrRef;
2985 let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2986 let args: ::std::boxed::Box<[$crate::Arg<'_>]> = if let Some(context) = context {
2987 ::std::boxed::Box::new(
2988 [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
2989 )
2990 } else {
2991 ::std::boxed::Box::new([])
2992 };
2993 $crate::TraceFutureArgs {
2994 category: $category,
2995 name: $name,
2996 args: args,
2997 flow_id: $flow_id,
2998 _use_trace_future_args: (),
2999 }
3000 }};
3001}
3002
3003#[macro_export]
3015macro_rules! trace_future_args {
3016 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
3017 $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
3018 };
3019 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)* $(,)?) => {
3020 $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
3021 };
3022}
3023
3024pub trait TraceFutureExt: Future + Sized {
3026 #[inline(always)]
3040 fn trace<'a, C: CategoryString, S: AsTraceStrRef>(
3041 self,
3042 args: TraceFutureArgs<'a, C, S>,
3043 ) -> TraceFuture<'a, Self, C, S> {
3044 TraceFuture::new(args, self)
3045 }
3046}
3047
3048impl<T: Future + Sized> TraceFutureExt for T {}
3049
3050#[pin_project]
3053pub struct TraceFuture<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> {
3054 #[pin]
3056 future: Fut,
3057 category: C,
3058 name: S,
3059 args: Box<[Arg<'a>]>,
3061 flow_id: Option<Id>,
3062 poll_count: u64,
3063}
3064
3065impl<'a, Fut: Future, C: CategoryString, S: AsTraceStrRef> TraceFuture<'a, Fut, C, S> {
3066 #[inline(always)]
3067 pub fn new(args: TraceFutureArgs<'a, C, S>, future: Fut) -> Self {
3068 Self {
3069 future,
3070 category: args.category,
3071 name: args.name,
3072 args: args.args,
3073 flow_id: args.flow_id,
3074 poll_count: 0,
3075 }
3076 }
3077
3078 #[cold]
3079 fn trace_poll(
3080 self: Pin<&mut Self>,
3081 context: &TraceCategoryContext,
3082 cx: &mut std::task::Context<'_>,
3083 ) -> Poll<Fut::Output> {
3084 let start_time = zx::BootTicks::get();
3085 let this = self.project();
3086 *this.poll_count = this.poll_count.saturating_add(1);
3087 let name_ref = this.name.as_trace_str_ref(context);
3088 context.write_duration_begin(start_time, name_ref, &this.args);
3089
3090 let result = this.future.poll(cx);
3091
3092 let flow_id = this.flow_id.get_or_insert_with(Id::new);
3093 let result_str: sys::trace_string_ref_t = if result.is_pending() {
3094 if *this.poll_count == 1 {
3095 context.write_flow_begin(start_time, name_ref, *flow_id, &[]);
3096 } else {
3097 context.write_flow_step(start_time, name_ref, *flow_id, &[]);
3098 }
3099 context.register_str("pending")
3100 } else {
3101 if *this.poll_count != 1 {
3102 context.write_flow_end(start_time, name_ref, *flow_id, &[]);
3103 }
3104 context.register_str("ready")
3105 };
3106 context.write_duration_end(
3107 zx::BootTicks::get(),
3108 name_ref,
3109 &[
3110 ArgValue::of_registered(context.register_str("poll-state"), result_str),
3111 ArgValue::of_registered(context.register_str("poll-count"), *this.poll_count),
3112 ],
3113 );
3114 result
3115 }
3116}
3117
3118impl<Fut: Future, C: CategoryString, S: AsTraceStrRef> Future for TraceFuture<'_, Fut, C, S> {
3119 type Output = Fut::Output;
3120 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
3121 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
3122 self.trace_poll(&context, cx)
3123 } else {
3124 self.project().future.poll(cx)
3125 }
3126 }
3127}
3128
3129#[cfg(test)]
3130mod test {
3131 use super::{Id, trim_to_last_char_boundary};
3132
3133 #[test]
3134 fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
3135 assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
3136 assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
3137 assert_eq!(b"", trim_to_last_char_boundary("x", 0));
3138 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
3139 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
3140 assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
3141
3142 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
3143 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
3144 assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
3145 }
3146
3147 #[test]
3151 fn test_id_new() {
3152 assert_ne!(Id::new(), Id::new());
3153 }
3154}