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