1use pin_project::pin_project;
6use std::boxed::Box;
7use std::ffi::CStr;
8use std::future::Future;
9use std::marker::PhantomData;
10use std::pin::Pin;
11use std::task::Poll;
12use std::{mem, ptr};
13
14pub use sys::{
15 trace_site_t, TRACE_BLOB_TYPE_DATA, TRACE_BLOB_TYPE_LAST_BRANCH, TRACE_BLOB_TYPE_PERFETTO,
16};
17
18#[derive(Copy, Clone)]
20pub enum Scope {
21 Thread,
22 Process,
23 Global,
24}
25
26impl Scope {
27 fn into_raw(self) -> sys::trace_scope_t {
28 match self {
29 Scope::Thread => sys::TRACE_SCOPE_THREAD,
30 Scope::Process => sys::TRACE_SCOPE_PROCESS,
31 Scope::Global => sys::TRACE_SCOPE_GLOBAL,
32 }
33 }
34}
35
36#[inline]
38pub fn is_enabled() -> bool {
39 unsafe { sys::trace_state() != sys::TRACE_STOPPED }
41}
42
43pub fn category_enabled(category: &'static CStr) -> bool {
45 unsafe { sys::trace_is_category_enabled(category.as_ptr()) }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub enum TraceState {
52 Stopped,
53 Started,
54 Stopping,
55}
56
57pub fn trace_state() -> TraceState {
58 match unsafe { sys::trace_state() } {
59 sys::TRACE_STOPPED => TraceState::Stopped,
60 sys::TRACE_STARTED => TraceState::Started,
61 sys::TRACE_STOPPING => TraceState::Stopping,
62 s => panic!("Unknown trace state {:?}", s),
63 }
64}
65
66#[repr(transparent)]
68#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
69pub struct Id(u64);
70
71impl Id {
72 pub fn new() -> Self {
79 Self(unsafe { sys::trace_generate_nonce() })
81 }
82
83 pub fn random() -> Self {
92 let ts = zx::BootInstant::get().into_nanos() as u64;
93 let high_order = ts << 16;
94 let low_order = rand::random::<u16>() as u64;
95 Self(high_order | low_order)
96 }
97}
98
99impl From<u64> for Id {
100 fn from(u: u64) -> Self {
101 Self(u)
102 }
103}
104
105impl From<Id> for u64 {
106 fn from(id: Id) -> Self {
107 id.0
108 }
109}
110
111#[repr(transparent)]
113pub struct Arg<'a>(sys::trace_arg_t, PhantomData<&'a ()>);
114
115pub trait ArgValue {
121 fn of<'a>(key: &'a str, value: Self) -> Arg<'a>
122 where
123 Self: 'a;
124}
125
126macro_rules! arg_from {
132 ($valname:ident, $(($type:ty, $tag:expr, $value:expr))*) => {
133 $(
134 impl ArgValue for $type {
135 #[inline]
136 fn of<'a>(key: &'a str, $valname: Self) -> Arg<'a>
137 where Self: 'a
138 {
139 #[allow(unused)]
140 let $valname = $valname;
141
142 Arg(sys::trace_arg_t {
143 name_ref: trace_make_inline_string_ref(key),
144 value: sys::trace_arg_value_t {
145 type_: $tag,
146 value: $value,
147 },
148 }, PhantomData)
149 }
150 }
151 )*
152 }
153}
154
155#[rustfmt::skip]
157arg_from!(val,
158 ((), sys::TRACE_ARG_NULL, sys::trace_arg_union_t { int32_value: 0 })
159 (bool, sys::TRACE_ARG_BOOL, sys::trace_arg_union_t { bool_value: val })
160 (i32, sys::TRACE_ARG_INT32, sys::trace_arg_union_t { int32_value: val })
161 (u32, sys::TRACE_ARG_UINT32, sys::trace_arg_union_t { uint32_value: val })
162 (i64, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val })
163 (u64, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val })
164 (isize, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val as i64 })
165 (usize, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val as u64 })
166 (f64, sys::TRACE_ARG_DOUBLE, sys::trace_arg_union_t { double_value: val })
167 (zx::Koid, sys::TRACE_ARG_KOID, sys::trace_arg_union_t { koid_value: val.raw_koid() })
168);
169
170impl<T> ArgValue for *const T {
171 #[inline]
172 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
173 where
174 Self: 'a,
175 {
176 Arg(
177 sys::trace_arg_t {
178 name_ref: trace_make_inline_string_ref(key),
179 value: sys::trace_arg_value_t {
180 type_: sys::TRACE_ARG_POINTER,
181 value: sys::trace_arg_union_t { pointer_value: val as usize },
182 },
183 },
184 PhantomData,
185 )
186 }
187}
188
189impl<T> ArgValue for *mut T {
190 #[inline]
191 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
192 where
193 Self: 'a,
194 {
195 Arg(
196 sys::trace_arg_t {
197 name_ref: trace_make_inline_string_ref(key),
198 value: sys::trace_arg_value_t {
199 type_: sys::TRACE_ARG_POINTER,
200 value: sys::trace_arg_union_t { pointer_value: val as usize },
201 },
202 },
203 PhantomData,
204 )
205 }
206}
207
208impl<'a> ArgValue for &'a str {
209 #[inline]
210 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
211 where
212 Self: 'b,
213 {
214 Arg(
215 sys::trace_arg_t {
216 name_ref: trace_make_inline_string_ref(key),
217 value: sys::trace_arg_value_t {
218 type_: sys::TRACE_ARG_STRING,
219 value: sys::trace_arg_union_t {
220 string_value_ref: trace_make_inline_string_ref(val),
221 },
222 },
223 },
224 PhantomData,
225 )
226 }
227}
228
229#[macro_export]
251macro_rules! instant {
252 ($category:expr, $name:expr, $scope:expr $(, $key:expr => $val:expr)*) => {
253 {
254 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
255 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
256 $crate::instant(&context, $name, $scope, &[$($crate::ArgValue::of($key, $val)),*]);
257 }
258 }
259 }
260}
261
262#[inline]
265pub fn instant(
266 context: &TraceCategoryContext,
267 name: &'static CStr,
268 scope: Scope,
269 args: &[Arg<'_>],
270) {
271 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
272
273 let name_ref = context.register_string_literal(name);
274 context.write_instant(name_ref, scope, args);
275}
276
277#[macro_export]
291macro_rules! alert {
292 ($category:expr, $name:expr) => {
293 $crate::alert($category, $name)
294 };
295}
296
297pub fn alert(category: &'static CStr, name: &'static CStr) {
299 unsafe {
303 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
304 let context =
305 sys::trace_acquire_context_for_category(category.as_ptr(), category_ref.as_mut_ptr());
306 if context != ptr::null() {
307 sys::trace_context_send_alert(context, name.as_ptr());
308 sys::trace_release_context(context);
309 }
310 }
311}
312
313#[macro_export]
330macro_rules! counter {
331 ($category:expr, $name:expr, $counter_id:expr $(, $key:expr => $val:expr)*) => {
332 {
333 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
334 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
335 $crate::counter(&context, $name, $counter_id,
336 &[$($crate::ArgValue::of($key, $val)),*])
337 }
338 }
339 }
340}
341
342pub fn counter(
352 context: &TraceCategoryContext,
353 name: &'static CStr,
354 counter_id: u64,
355 args: &[Arg<'_>],
356) {
357 assert!(args.len() >= 1, "trace counter args must include at least one numeric argument");
358 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
359
360 let name_ref = context.register_string_literal(name);
361 context.write_counter(name_ref, counter_id, args);
362}
363
364#[must_use = "DurationScope must be `end`ed to be recorded"]
367pub struct DurationScope<'a> {
368 category: &'static CStr,
369 name: &'static CStr,
370 args: &'a [Arg<'a>],
371 start_time: zx::BootTicks,
372}
373
374impl<'a> DurationScope<'a> {
375 pub fn begin(category: &'static CStr, name: &'static CStr, args: &'a [Arg<'_>]) -> Self {
378 let start_time = zx::BootTicks::get();
379 Self { category, name, args, start_time }
380 }
381}
382
383impl<'a> Drop for DurationScope<'a> {
384 fn drop(&mut self) {
385 if let Some(context) = TraceCategoryContext::acquire(self.category) {
386 let name_ref = context.register_string_literal(self.name);
387 context.write_duration(name_ref, self.start_time, self.args);
388 }
389 }
390}
391
392pub fn complete_duration(
394 category: &'static CStr,
395 name: &'static CStr,
396 start_time: zx::BootTicks,
397 args: &[Arg<'_>],
398) {
399 if let Some(context) = TraceCategoryContext::acquire(category) {
400 let name_ref = context.register_string_literal(name);
401 context.write_duration(name_ref, start_time, args);
402 }
403}
404
405#[macro_export]
440macro_rules! duration {
441 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
442 let mut args;
443 let _scope = {
444 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
445 if let Some(_context) =
452 $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
453 args = [$($crate::ArgValue::of($key, $val)),*];
454 Some($crate::duration($category, $name, &args))
455 } else {
456 None
457 }
458 };
459 }
460}
461
462pub fn duration<'a>(
474 category: &'static CStr,
475 name: &'static CStr,
476 args: &'a [Arg<'_>],
477) -> DurationScope<'a> {
478 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
479 DurationScope::begin(category, name, args)
480}
481
482#[macro_export]
496macro_rules! duration_begin {
497 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
498 {
499 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
500 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
501 $crate::duration_begin(&context, $name,
502 &[$($crate::ArgValue::of($key, $val)),*])
503 }
504 }
505 };
506}
507
508#[macro_export]
522macro_rules! duration_end {
523 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
524 {
525 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
526 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
527 $crate::duration_end(&context, $name, &[$($crate::ArgValue::of($key, $val)),*])
528 }
529 }
530 };
531}
532
533pub fn duration_begin(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
544 let ticks = zx::BootTicks::get();
545 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
546
547 let name_ref = context.register_string_literal(name);
548 context.write_duration_begin(ticks, name_ref, args);
549}
550
551pub fn duration_end(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
561 let ticks = zx::BootTicks::get();
562 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
563
564 let name_ref = context.register_string_literal(name);
565 context.write_duration_end(ticks, name_ref, args);
566}
567
568#[must_use = "emits an end event when dropped, so if dropped immediately creates an essentially \
571 zero length duration that should just be an instant instead"]
572pub struct AsyncScope {
573 id: Id,
576 category: &'static CStr,
577 name: &'static CStr,
578}
579impl AsyncScope {
580 pub fn begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) -> Self {
583 async_begin(id, category, name, args);
584 Self { id, category, name }
585 }
586
587 pub fn end(self, args: &[Arg<'_>]) {
590 let Self { id, category, name } = self;
591 async_end(id, category, name, args);
592 std::mem::forget(self);
593 }
594}
595
596impl Drop for AsyncScope {
597 fn drop(&mut self) {
598 let Self { id, category, name } = *self;
602 async_end(id, category, name, &[]);
603 }
604}
605
606pub fn async_enter(
615 id: Id,
616 category: &'static CStr,
617 name: &'static CStr,
618 args: &[Arg<'_>],
619) -> AsyncScope {
620 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
621 AsyncScope::begin(id, category, name, args)
622}
623
624#[macro_export]
655macro_rules! async_enter {
656 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
657 {
658 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
659 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
660 Some($crate::AsyncScope::begin($id, $category, $name, &[$($crate::ArgValue::of($key, $val)),*]))
661 } else {
662 None
663 }
664 }
665 }
666}
667
668#[macro_export]
692macro_rules! async_instant {
693 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
694 {
695 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
696 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
697 $crate::async_instant($id, &context, $name, &[$($crate::ArgValue::of($key, $val)),*]);
698 }
699 }
700 }
701}
702
703pub fn async_begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
715 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
716
717 if let Some(context) = TraceCategoryContext::acquire(category) {
718 let name_ref = context.register_string_literal(name);
719 context.write_async_begin(id, name_ref, args);
720 }
721}
722
723pub fn async_end(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
735 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
736
737 if let Some(context) = TraceCategoryContext::acquire(category) {
738 let name_ref = context.register_string_literal(name);
739 context.write_async_end(id, name_ref, args);
740 }
741}
742
743pub fn async_instant(
755 id: Id,
756 context: &TraceCategoryContext,
757 name: &'static CStr,
758 args: &[Arg<'_>],
759) {
760 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
761
762 let name_ref = context.register_string_literal(name);
763 context.write_async_instant(id, name_ref, args);
764}
765
766#[macro_export]
767macro_rules! blob {
768 ($category:expr, $name:expr, $bytes:expr $(, $key:expr => $val:expr)*) => {
769 {
770 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
771 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
772 $crate::blob_fn(&context, $name, $bytes, &[$($crate::ArgValue::of($key, $val)),*])
773 }
774 }
775 }
776}
777pub fn blob_fn(
778 context: &TraceCategoryContext,
779 name: &'static CStr,
780 bytes: &[u8],
781 args: &[Arg<'_>],
782) {
783 let name_ref = context.register_string_literal(name);
784 context.write_blob(name_ref, bytes, args);
785}
786
787#[macro_export]
802macro_rules! flow_begin {
803 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
804 {
805 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
806 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
807 $crate::flow_begin(&context, $name, $flow_id,
808 &[$($crate::ArgValue::of($key, $val)),*])
809 }
810 }
811 }
812}
813
814#[macro_export]
829macro_rules! flow_step {
830 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
831 {
832 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
833 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
834 $crate::flow_step(&context, $name, $flow_id,
835 &[$($crate::ArgValue::of($key, $val)),*])
836 }
837 }
838 }
839}
840
841#[macro_export]
856macro_rules! flow_end {
857 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
858 {
859 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
860 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
861 $crate::flow_end(&context, $name, $flow_id,
862 &[$($crate::ArgValue::of($key, $val)),*])
863 }
864 }
865 }
866}
867
868pub fn flow_begin(
887 context: &TraceCategoryContext,
888 name: &'static CStr,
889 flow_id: Id,
890 args: &[Arg<'_>],
891) {
892 let ticks = zx::BootTicks::get();
893 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
894
895 let name_ref = context.register_string_literal(name);
896 context.write_flow_begin(ticks, name_ref, flow_id, args);
897}
898
899pub fn flow_end(
916 context: &TraceCategoryContext,
917 name: &'static CStr,
918 flow_id: Id,
919 args: &[Arg<'_>],
920) {
921 let ticks = zx::BootTicks::get();
922 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
923
924 let name_ref = context.register_string_literal(name);
925 context.write_flow_end(ticks, name_ref, flow_id, args);
926}
927
928pub fn flow_step(
945 context: &TraceCategoryContext,
946 name: &'static CStr,
947 flow_id: Id,
948 args: &[Arg<'_>],
949) {
950 let ticks = zx::BootTicks::get();
951 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
952
953 let name_ref = context.register_string_literal(name);
954 context.write_flow_step(ticks, name_ref, flow_id, args);
955}
956
957#[macro_export]
971macro_rules! instaflow_begin {
972 (
973 $category:expr,
974 $event_name:expr,
975 $flow_name:expr,
976 $flow_id:expr
977 $(, $key:expr => $val:expr)*
978 ) => {
979 {
980 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
981 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
982 $crate::instaflow_begin(
983 &context,
984 $event_name,
985 $flow_name,
986 $flow_id,
987 &[$($crate::ArgValue::of($key, $val)),*],
988 )
989 }
990 }
991 }
992}
993
994#[macro_export]
1008macro_rules! instaflow_end {
1009 (
1010 $category:expr,
1011 $event_name:expr,
1012 $flow_name:expr,
1013 $flow_id:expr
1014 $(, $key:expr => $val:expr)*
1015 ) => {
1016 {
1017 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1018 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1019 $crate::instaflow_end(
1020 &context,
1021 $event_name,
1022 $flow_name,
1023 $flow_id,
1024 &[$($crate::ArgValue::of($key, $val)),*],
1025 )
1026 }
1027 }
1028 }
1029}
1030
1031#[macro_export]
1045macro_rules! instaflow_step {
1046 (
1047 $category:expr,
1048 $event_name:expr,
1049 $flow_name:expr,
1050 $flow_id:expr
1051 $(, $key:expr => $val:expr)*
1052 ) => {
1053 {
1054 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1055 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1056 $crate::instaflow_step(
1057 &context,
1058 $event_name,
1059 $flow_name,
1060 $flow_id,
1061 &[$($crate::ArgValue::of($key, $val)),*],
1062 )
1063 }
1064 }
1065 }
1066}
1067
1068pub fn instaflow_begin(
1080 context: &TraceCategoryContext,
1081 event_name: &'static CStr,
1082 flow_name: &'static CStr,
1083 flow_id: Id,
1084 args: &[Arg<'_>],
1085) {
1086 let ticks = zx::BootTicks::get();
1087 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1088
1089 let event_name_ref = context.register_string_literal(event_name);
1090 let flow_name_ref = context.register_string_literal(flow_name);
1091
1092 context.write_duration_begin(ticks, event_name_ref, args);
1093 context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1094 context.write_duration_end(ticks, event_name_ref, args);
1095}
1096
1097pub fn instaflow_end(
1109 context: &TraceCategoryContext,
1110 event_name: &'static CStr,
1111 flow_name: &'static CStr,
1112 flow_id: Id,
1113 args: &[Arg<'_>],
1114) {
1115 let ticks = zx::BootTicks::get();
1116 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1117
1118 let event_name_ref = context.register_string_literal(event_name);
1119 let flow_name_ref = context.register_string_literal(flow_name);
1120
1121 context.write_duration_begin(ticks, event_name_ref, args);
1122 context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1123 context.write_duration_end(ticks, event_name_ref, args);
1124}
1125
1126pub fn instaflow_step(
1138 context: &TraceCategoryContext,
1139 event_name: &'static CStr,
1140 flow_name: &'static CStr,
1141 flow_id: Id,
1142 args: &[Arg<'_>],
1143) {
1144 let ticks = zx::BootTicks::get();
1145 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1146
1147 let event_name_ref = context.register_string_literal(event_name);
1148 let flow_name_ref = context.register_string_literal(flow_name);
1149
1150 context.write_duration_begin(ticks, event_name_ref, args);
1151 context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1152 context.write_duration_end(ticks, event_name_ref, args);
1153}
1154
1155const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1157 sys::trace_string_ref_t {
1158 encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1159 inline_string: ptr::null(),
1160 }
1161}
1162
1163#[inline]
1164fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1165 let mut len = string.len();
1166 if string.len() > max_len {
1167 len = max_len;
1171 while len > 0 {
1172 if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1173 break;
1174 }
1175 len -= 1;
1176 }
1177 }
1178 &string.as_bytes()[0..len]
1179}
1180
1181#[inline]
1184fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1185 let len = string.len() as u32;
1186 if len == 0 {
1187 return trace_make_empty_string_ref();
1188 }
1189
1190 let string =
1191 trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH as usize);
1192
1193 sys::trace_string_ref_t {
1194 encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1195 inline_string: string.as_ptr() as *const libc::c_char,
1196 }
1197}
1198
1199pub struct TraceCategoryContext {
1201 raw: *const sys::trace_context_t,
1202 category_ref: sys::trace_string_ref_t,
1203}
1204
1205impl TraceCategoryContext {
1206 #[inline]
1207 pub fn acquire_cached(
1208 category: &'static CStr,
1209 site: &sys::trace_site_t,
1210 ) -> Option<TraceCategoryContext> {
1211 unsafe {
1212 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1217 let raw = sys::trace_acquire_context_for_category_cached(
1218 category.as_ptr(),
1219 site.as_ptr(),
1220 category_ref.as_mut_ptr(),
1221 );
1222 if raw != ptr::null() {
1223 Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1224 } else {
1225 None
1226 }
1227 }
1228 }
1229
1230 pub fn acquire(category: &'static CStr) -> Option<TraceCategoryContext> {
1231 unsafe {
1232 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1233 let raw = sys::trace_acquire_context_for_category(
1234 category.as_ptr(),
1235 category_ref.as_mut_ptr(),
1236 );
1237 if raw != ptr::null() {
1238 Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1239 } else {
1240 None
1241 }
1242 }
1243 }
1244
1245 #[inline]
1246 pub fn register_string_literal(&self, name: &'static CStr) -> sys::trace_string_ref_t {
1247 unsafe {
1248 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1249 sys::trace_context_register_string_literal(
1250 self.raw,
1251 name.as_ptr(),
1252 name_ref.as_mut_ptr(),
1253 );
1254 name_ref.assume_init()
1255 }
1256 }
1257
1258 #[inline]
1259 fn register_current_thread(&self) -> sys::trace_thread_ref_t {
1260 unsafe {
1261 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1262 sys::trace_context_register_current_thread(self.raw, thread_ref.as_mut_ptr());
1263 thread_ref.assume_init()
1264 }
1265 }
1266
1267 #[inline]
1268 pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
1269 let ticks = zx::BootTicks::get();
1270 let thread_ref = self.register_current_thread();
1271 unsafe {
1272 sys::trace_context_write_instant_event_record(
1273 self.raw,
1274 ticks.into_raw(),
1275 &thread_ref,
1276 &self.category_ref,
1277 &name_ref,
1278 scope.into_raw(),
1279 args.as_ptr() as *const sys::trace_arg_t,
1280 args.len(),
1281 );
1282 }
1283 }
1284
1285 pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
1286 let name_ref = trace_make_inline_string_ref(name);
1287 self.write_instant(name_ref, scope, args)
1288 }
1289
1290 fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
1291 let ticks = zx::BootTicks::get();
1292 let thread_ref = self.register_current_thread();
1293 unsafe {
1294 sys::trace_context_write_counter_event_record(
1295 self.raw,
1296 ticks.into_raw(),
1297 &thread_ref,
1298 &self.category_ref,
1299 &name_ref,
1300 counter_id,
1301 args.as_ptr() as *const sys::trace_arg_t,
1302 args.len(),
1303 );
1304 }
1305 }
1306
1307 pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
1308 let name_ref = trace_make_inline_string_ref(name);
1309 self.write_counter(name_ref, counter_id, args);
1310 }
1311
1312 fn write_duration(
1313 &self,
1314 name_ref: sys::trace_string_ref_t,
1315 start_time: zx::BootTicks,
1316 args: &[Arg<'_>],
1317 ) {
1318 let ticks = zx::BootTicks::get();
1319 let thread_ref = self.register_current_thread();
1320 unsafe {
1321 sys::trace_context_write_duration_event_record(
1322 self.raw,
1323 start_time.into_raw(),
1324 ticks.into_raw(),
1325 &thread_ref,
1326 &self.category_ref,
1327 &name_ref,
1328 args.as_ptr() as *const sys::trace_arg_t,
1329 args.len(),
1330 );
1331 }
1332 }
1333
1334 pub fn write_duration_with_inline_name(
1335 &self,
1336 name: &str,
1337 start_time: zx::BootTicks,
1338 args: &[Arg<'_>],
1339 ) {
1340 let name_ref = trace_make_inline_string_ref(name);
1341 self.write_duration(name_ref, start_time, args);
1342 }
1343
1344 fn write_duration_begin(
1345 &self,
1346 ticks: zx::BootTicks,
1347 name_ref: sys::trace_string_ref_t,
1348 args: &[Arg<'_>],
1349 ) {
1350 let thread_ref = self.register_current_thread();
1351 unsafe {
1352 sys::trace_context_write_duration_begin_event_record(
1353 self.raw,
1354 ticks.into_raw(),
1355 &thread_ref,
1356 &self.category_ref,
1357 &name_ref,
1358 args.as_ptr() as *const sys::trace_arg_t,
1359 args.len(),
1360 );
1361 }
1362 }
1363
1364 pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1365 let name_ref = trace_make_inline_string_ref(name);
1366 self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
1367 }
1368
1369 fn write_duration_end(
1370 &self,
1371 ticks: zx::BootTicks,
1372 name_ref: sys::trace_string_ref_t,
1373 args: &[Arg<'_>],
1374 ) {
1375 let thread_ref = self.register_current_thread();
1376 unsafe {
1377 sys::trace_context_write_duration_end_event_record(
1378 self.raw,
1379 ticks.into_raw(),
1380 &thread_ref,
1381 &self.category_ref,
1382 &name_ref,
1383 args.as_ptr() as *const sys::trace_arg_t,
1384 args.len(),
1385 );
1386 }
1387 }
1388
1389 pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1390 let name_ref = trace_make_inline_string_ref(name);
1391 self.write_duration_end(zx::BootTicks::get(), name_ref, args);
1392 }
1393
1394 fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1395 let ticks = zx::BootTicks::get();
1396 let thread_ref = self.register_current_thread();
1397 unsafe {
1398 sys::trace_context_write_async_begin_event_record(
1399 self.raw,
1400 ticks.into_raw(),
1401 &thread_ref,
1402 &self.category_ref,
1403 &name_ref,
1404 id.into(),
1405 args.as_ptr() as *const sys::trace_arg_t,
1406 args.len(),
1407 );
1408 }
1409 }
1410
1411 pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1412 let name_ref = trace_make_inline_string_ref(name);
1413 self.write_async_begin(id, name_ref, args);
1414 }
1415
1416 fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1417 let ticks = zx::BootTicks::get();
1418 let thread_ref = self.register_current_thread();
1419 unsafe {
1420 sys::trace_context_write_async_end_event_record(
1421 self.raw,
1422 ticks.into_raw(),
1423 &thread_ref,
1424 &self.category_ref,
1425 &name_ref,
1426 id.into(),
1427 args.as_ptr() as *const sys::trace_arg_t,
1428 args.len(),
1429 );
1430 }
1431 }
1432
1433 pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1434 let name_ref = trace_make_inline_string_ref(name);
1435 self.write_async_end(id, name_ref, args);
1436 }
1437
1438 fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1439 let ticks = zx::BootTicks::get();
1440 let thread_ref = self.register_current_thread();
1441 unsafe {
1442 sys::trace_context_write_async_instant_event_record(
1443 self.raw,
1444 ticks.into_raw(),
1445 &thread_ref,
1446 &self.category_ref,
1447 &name_ref,
1448 id.into(),
1449 args.as_ptr() as *const sys::trace_arg_t,
1450 args.len(),
1451 );
1452 }
1453 }
1454
1455 fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
1456 let ticks = zx::BootTicks::get();
1457 let thread_ref = self.register_current_thread();
1458 unsafe {
1459 sys::trace_context_write_blob_event_record(
1460 self.raw,
1461 ticks.into_raw(),
1462 &thread_ref,
1463 &self.category_ref,
1464 &name_ref,
1465 bytes.as_ptr() as *const core::ffi::c_void,
1466 bytes.len(),
1467 args.as_ptr() as *const sys::trace_arg_t,
1468 args.len(),
1469 );
1470 }
1471 }
1472
1473 fn write_flow_begin(
1474 &self,
1475 ticks: zx::BootTicks,
1476 name_ref: sys::trace_string_ref_t,
1477 flow_id: Id,
1478 args: &[Arg<'_>],
1479 ) {
1480 let thread_ref = self.register_current_thread();
1481 unsafe {
1482 sys::trace_context_write_flow_begin_event_record(
1483 self.raw,
1484 ticks.into_raw(),
1485 &thread_ref,
1486 &self.category_ref,
1487 &name_ref,
1488 flow_id.into(),
1489 args.as_ptr() as *const sys::trace_arg_t,
1490 args.len(),
1491 );
1492 }
1493 }
1494
1495 fn write_flow_end(
1496 &self,
1497 ticks: zx::BootTicks,
1498 name_ref: sys::trace_string_ref_t,
1499 flow_id: Id,
1500 args: &[Arg<'_>],
1501 ) {
1502 let thread_ref = self.register_current_thread();
1503 unsafe {
1504 sys::trace_context_write_flow_end_event_record(
1505 self.raw,
1506 ticks.into_raw(),
1507 &thread_ref,
1508 &self.category_ref,
1509 &name_ref,
1510 flow_id.into(),
1511 args.as_ptr() as *const sys::trace_arg_t,
1512 args.len(),
1513 );
1514 }
1515 }
1516
1517 fn write_flow_step(
1518 &self,
1519 ticks: zx::BootTicks,
1520 name_ref: sys::trace_string_ref_t,
1521 flow_id: Id,
1522 args: &[Arg<'_>],
1523 ) {
1524 let thread_ref = self.register_current_thread();
1525 unsafe {
1526 sys::trace_context_write_flow_step_event_record(
1527 self.raw,
1528 ticks.into_raw(),
1529 &thread_ref,
1530 &self.category_ref,
1531 &name_ref,
1532 flow_id.into(),
1533 args.as_ptr() as *const sys::trace_arg_t,
1534 args.len(),
1535 );
1536 }
1537 }
1538}
1539
1540impl std::ops::Drop for TraceCategoryContext {
1541 fn drop(&mut self) {
1542 unsafe {
1543 sys::trace_release_context(self.raw);
1544 }
1545 }
1546}
1547
1548pub struct Context {
1550 context: *const sys::trace_context_t,
1551}
1552
1553impl Context {
1554 #[inline]
1555 pub fn acquire() -> Option<Self> {
1556 let context = unsafe { sys::trace_acquire_context() };
1557 if context.is_null() {
1558 None
1559 } else {
1560 Some(Self { context })
1561 }
1562 }
1563
1564 #[inline]
1565 pub fn register_string_literal(&self, s: &'static CStr) -> sys::trace_string_ref_t {
1566 unsafe {
1567 let mut s_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1568 sys::trace_context_register_string_literal(
1569 self.context,
1570 s.as_ptr(),
1571 s_ref.as_mut_ptr(),
1572 );
1573 s_ref.assume_init()
1574 }
1575 }
1576
1577 pub fn write_blob_record(
1578 &self,
1579 type_: sys::trace_blob_type_t,
1580 name_ref: &sys::trace_string_ref_t,
1581 data: &[u8],
1582 ) {
1583 unsafe {
1584 sys::trace_context_write_blob_record(
1585 self.context,
1586 type_,
1587 name_ref as *const sys::trace_string_ref_t,
1588 data.as_ptr() as *const libc::c_void,
1589 data.len(),
1590 );
1591 }
1592 }
1593}
1594
1595impl std::ops::Drop for Context {
1596 fn drop(&mut self) {
1597 unsafe { sys::trace_release_context(self.context) }
1598 }
1599}
1600
1601pub struct ProlongedContext {
1602 context: *const sys::trace_prolonged_context_t,
1603}
1604
1605impl ProlongedContext {
1606 pub fn acquire() -> Option<Self> {
1607 let context = unsafe { sys::trace_acquire_prolonged_context() };
1608 if context.is_null() {
1609 None
1610 } else {
1611 Some(Self { context })
1612 }
1613 }
1614}
1615
1616impl Drop for ProlongedContext {
1617 fn drop(&mut self) {
1618 unsafe { sys::trace_release_prolonged_context(self.context) }
1619 }
1620}
1621
1622unsafe impl Send for ProlongedContext {}
1623
1624mod sys {
1625 #![allow(non_camel_case_types, unused)]
1626 use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
1627
1628 pub type trace_ticks_t = zx_ticks_t;
1629 pub type trace_counter_id_t = u64;
1630 pub type trace_async_id_t = u64;
1631 pub type trace_flow_id_t = u64;
1632 pub type trace_thread_state_t = u32;
1633 pub type trace_cpu_number_t = u32;
1634 pub type trace_string_index_t = u32;
1635 pub type trace_thread_index_t = u32;
1636 pub type trace_context_t = libc::c_void;
1637 pub type trace_prolonged_context_t = libc::c_void;
1638
1639 pub type trace_encoded_string_ref_t = u32;
1640 pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
1641 pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
1642 pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
1643 pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: trace_encoded_string_ref_t = 32000;
1644 pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
1645 pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
1646
1647 pub type trace_encoded_thread_ref_t = u32;
1648 pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
1649 pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
1650 pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
1651
1652 pub type trace_state_t = libc::c_int;
1653 pub const TRACE_STOPPED: trace_state_t = 0;
1654 pub const TRACE_STARTED: trace_state_t = 1;
1655 pub const TRACE_STOPPING: trace_state_t = 2;
1656
1657 pub type trace_scope_t = libc::c_int;
1658 pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
1659 pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
1660 pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
1661
1662 pub type trace_blob_type_t = libc::c_int;
1663 pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
1664 pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
1665 pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
1666
1667 #[repr(C)]
1668 #[derive(Copy, Clone)]
1669 pub struct trace_string_ref_t {
1670 pub encoded_value: trace_encoded_string_ref_t,
1671 pub inline_string: *const libc::c_char,
1672 }
1673
1674 pub type trace_site_t = std::sync::atomic::AtomicU64;
1678
1679 unsafe impl Send for trace_string_ref_t {}
1689 unsafe impl Sync for trace_string_ref_t {}
1690
1691 #[repr(C)]
1692 pub struct trace_thread_ref_t {
1693 pub encoded_value: trace_encoded_thread_ref_t,
1694 pub inline_process_koid: zx_koid_t,
1695 pub inline_thread_koid: zx_koid_t,
1696 }
1697
1698 #[repr(C)]
1699 pub struct trace_arg_t {
1700 pub name_ref: trace_string_ref_t,
1701 pub value: trace_arg_value_t,
1702 }
1703
1704 #[repr(C)]
1705 pub union trace_arg_union_t {
1706 pub int32_value: i32,
1707 pub uint32_value: u32,
1708 pub int64_value: i64,
1709 pub uint64_value: u64,
1710 pub double_value: libc::c_double,
1711 pub string_value_ref: trace_string_ref_t,
1712 pub pointer_value: libc::uintptr_t,
1713 pub koid_value: zx_koid_t,
1714 pub bool_value: bool,
1715 pub reserved_for_future_expansion: [libc::uintptr_t; 2],
1716 }
1717
1718 pub type trace_arg_type_t = libc::c_int;
1719 pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
1720 pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
1721 pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
1722 pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
1723 pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
1724 pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
1725 pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
1726 pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
1727 pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
1728 pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
1729
1730 #[repr(C)]
1731 pub struct trace_arg_value_t {
1732 pub type_: trace_arg_type_t,
1733 pub value: trace_arg_union_t,
1734 }
1735
1736 #[repr(C)]
1737 pub struct trace_handler_ops_t {
1738 pub is_category_enabled:
1739 unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
1740 pub trace_started: unsafe fn(handler: *const trace_handler_t),
1741 pub trace_stopped: unsafe fn(
1742 handler: *const trace_handler_t,
1743 async_ptr: *const (), disposition: zx_status_t,
1745 buffer_bytes_written: libc::size_t,
1746 ),
1747 pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
1748 }
1749
1750 #[repr(C)]
1751 pub struct trace_handler_t {
1752 pub ops: *const trace_handler_ops_t,
1753 }
1754
1755 extern "C" {
1757 pub fn trace_context_is_category_enabled(
1760 context: *const trace_context_t,
1761 category_literal: *const libc::c_char,
1762 ) -> bool;
1763
1764 pub fn trace_context_register_string_copy(
1765 context: *const trace_context_t,
1766 string: *const libc::c_char,
1767 length: libc::size_t,
1768 out_ref: *mut trace_string_ref_t,
1769 );
1770
1771 pub fn trace_context_register_string_literal(
1772 context: *const trace_context_t,
1773 string_literal: *const libc::c_char,
1774 out_ref: *mut trace_string_ref_t,
1775 );
1776
1777 pub fn trace_context_register_category_literal(
1778 context: *const trace_context_t,
1779 category_literal: *const libc::c_char,
1780 out_ref: *mut trace_string_ref_t,
1781 ) -> bool;
1782
1783 pub fn trace_context_register_current_thread(
1784 context: *const trace_context_t,
1785 out_ref: *mut trace_thread_ref_t,
1786 );
1787
1788 pub fn trace_context_register_thread(
1789 context: *const trace_context_t,
1790 process_koid: zx_koid_t,
1791 thread_koid: zx_koid_t,
1792 out_ref: *mut trace_thread_ref_t,
1793 );
1794
1795 pub fn trace_context_write_kernel_object_record(
1796 context: *const trace_context_t,
1797 koid: zx_koid_t,
1798 type_: zx_obj_type_t,
1799 args: *const trace_arg_t,
1800 num_args: libc::size_t,
1801 );
1802
1803 pub fn trace_context_write_kernel_object_record_for_handle(
1804 context: *const trace_context_t,
1805 handle: zx_handle_t,
1806 args: *const trace_arg_t,
1807 num_args: libc::size_t,
1808 );
1809
1810 pub fn trace_context_write_process_info_record(
1811 context: *const trace_context_t,
1812 process_koid: zx_koid_t,
1813 process_name_ref: *const trace_string_ref_t,
1814 );
1815
1816 pub fn trace_context_write_thread_info_record(
1817 context: *const trace_context_t,
1818 process_koid: zx_koid_t,
1819 thread_koid: zx_koid_t,
1820 thread_name_ref: *const trace_string_ref_t,
1821 );
1822
1823 pub fn trace_context_write_context_switch_record(
1824 context: *const trace_context_t,
1825 event_time: trace_ticks_t,
1826 cpu_number: trace_cpu_number_t,
1827 outgoing_thread_state: trace_thread_state_t,
1828 outgoing_thread_ref: *const trace_thread_ref_t,
1829 incoming_thread_ref: *const trace_thread_ref_t,
1830 );
1831
1832 pub fn trace_context_write_log_record(
1833 context: *const trace_context_t,
1834 event_time: trace_ticks_t,
1835 thread_ref: *const trace_thread_ref_t,
1836 log_message: *const libc::c_char,
1837 log_message_length: libc::size_t,
1838 );
1839
1840 pub fn trace_context_write_instant_event_record(
1841 context: *const trace_context_t,
1842 event_time: trace_ticks_t,
1843 thread_ref: *const trace_thread_ref_t,
1844 category_ref: *const trace_string_ref_t,
1845 name_ref: *const trace_string_ref_t,
1846 scope: trace_scope_t,
1847 args: *const trace_arg_t,
1848 num_args: libc::size_t,
1849 );
1850
1851 pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
1852
1853 pub fn trace_context_write_counter_event_record(
1854 context: *const trace_context_t,
1855 event_time: trace_ticks_t,
1856 thread_ref: *const trace_thread_ref_t,
1857 category_ref: *const trace_string_ref_t,
1858 name_ref: *const trace_string_ref_t,
1859 counter_id: trace_counter_id_t,
1860 args: *const trace_arg_t,
1861 num_args: libc::size_t,
1862 );
1863
1864 pub fn trace_context_write_duration_event_record(
1865 context: *const trace_context_t,
1866 start_time: trace_ticks_t,
1867 end_time: trace_ticks_t,
1868 thread_ref: *const trace_thread_ref_t,
1869 category_ref: *const trace_string_ref_t,
1870 name_ref: *const trace_string_ref_t,
1871 args: *const trace_arg_t,
1872 num_args: libc::size_t,
1873 );
1874
1875 pub fn trace_context_write_blob_event_record(
1876 context: *const trace_context_t,
1877 event_time: trace_ticks_t,
1878 thread_ref: *const trace_thread_ref_t,
1879 category_ref: *const trace_string_ref_t,
1880 name_ref: *const trace_string_ref_t,
1881 blob: *const libc::c_void,
1882 blob_size: libc::size_t,
1883 args: *const trace_arg_t,
1884 num_args: libc::size_t,
1885 );
1886
1887 pub fn trace_context_write_duration_begin_event_record(
1888 context: *const trace_context_t,
1889 event_time: trace_ticks_t,
1890 thread_ref: *const trace_thread_ref_t,
1891 category_ref: *const trace_string_ref_t,
1892 name_ref: *const trace_string_ref_t,
1893 args: *const trace_arg_t,
1894 num_args: libc::size_t,
1895 );
1896
1897 pub fn trace_context_write_duration_end_event_record(
1898 context: *const trace_context_t,
1899 event_time: trace_ticks_t,
1900 thread_ref: *const trace_thread_ref_t,
1901 category_ref: *const trace_string_ref_t,
1902 name_ref: *const trace_string_ref_t,
1903 args: *const trace_arg_t,
1904 num_args: libc::size_t,
1905 );
1906
1907 pub fn trace_context_write_async_begin_event_record(
1908 context: *const trace_context_t,
1909 event_time: trace_ticks_t,
1910 thread_ref: *const trace_thread_ref_t,
1911 category_ref: *const trace_string_ref_t,
1912 name_ref: *const trace_string_ref_t,
1913 async_id: trace_async_id_t,
1914 args: *const trace_arg_t,
1915 num_args: libc::size_t,
1916 );
1917
1918 pub fn trace_context_write_async_instant_event_record(
1919 context: *const trace_context_t,
1920 event_time: trace_ticks_t,
1921 thread_ref: *const trace_thread_ref_t,
1922 category_ref: *const trace_string_ref_t,
1923 name_ref: *const trace_string_ref_t,
1924 async_id: trace_async_id_t,
1925 args: *const trace_arg_t,
1926 num_args: libc::size_t,
1927 );
1928
1929 pub fn trace_context_write_async_end_event_record(
1930 context: *const trace_context_t,
1931 event_time: trace_ticks_t,
1932 thread_ref: *const trace_thread_ref_t,
1933 category_ref: *const trace_string_ref_t,
1934 name_ref: *const trace_string_ref_t,
1935 async_id: trace_async_id_t,
1936 args: *const trace_arg_t,
1937 num_args: libc::size_t,
1938 );
1939
1940 pub fn trace_context_write_flow_begin_event_record(
1941 context: *const trace_context_t,
1942 event_time: trace_ticks_t,
1943 thread_ref: *const trace_thread_ref_t,
1944 category_ref: *const trace_string_ref_t,
1945 name_ref: *const trace_string_ref_t,
1946 flow_id: trace_flow_id_t,
1947 args: *const trace_arg_t,
1948 num_args: libc::size_t,
1949 );
1950
1951 pub fn trace_context_write_flow_step_event_record(
1952 context: *const trace_context_t,
1953 event_time: trace_ticks_t,
1954 thread_ref: *const trace_thread_ref_t,
1955 category_ref: *const trace_string_ref_t,
1956 name_ref: *const trace_string_ref_t,
1957 flow_id: trace_flow_id_t,
1958 args: *const trace_arg_t,
1959 num_args: libc::size_t,
1960 );
1961
1962 pub fn trace_context_write_flow_end_event_record(
1963 context: *const trace_context_t,
1964 event_time: trace_ticks_t,
1965 thread_ref: *const trace_thread_ref_t,
1966 category_ref: *const trace_string_ref_t,
1967 name_ref: *const trace_string_ref_t,
1968 flow_id: trace_flow_id_t,
1969 args: *const trace_arg_t,
1970 num_args: libc::size_t,
1971 );
1972
1973 pub fn trace_context_write_initialization_record(
1974 context: *const trace_context_t,
1975 ticks_per_second: u64,
1976 );
1977
1978 pub fn trace_context_write_string_record(
1979 context: *const trace_context_t,
1980 index: trace_string_index_t,
1981 string: *const libc::c_char,
1982 length: libc::size_t,
1983 );
1984
1985 pub fn trace_context_write_thread_record(
1986 context: *const trace_context_t,
1987 index: trace_thread_index_t,
1988 procss_koid: zx_koid_t,
1989 thread_koid: zx_koid_t,
1990 );
1991
1992 pub fn trace_context_write_blob_record(
1993 context: *const trace_context_t,
1994 type_: trace_blob_type_t,
1995 name_ref: *const trace_string_ref_t,
1996 data: *const libc::c_void,
1997 size: libc::size_t,
1998 );
1999
2000 pub fn trace_context_alloc_record(
2001 context: *const trace_context_t,
2002 num_bytes: libc::size_t,
2003 ) -> *const libc::c_void;
2004
2005 pub fn trace_stop_engine(disposition: zx_status_t) -> zx_status_t;
2015
2016 pub fn trace_generate_nonce() -> u64;
2019
2020 pub fn trace_state() -> trace_state_t;
2021
2022 pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2023
2024 pub fn trace_acquire_context() -> *const trace_context_t;
2025
2026 pub fn trace_acquire_context_for_category(
2027 category_literal: *const libc::c_char,
2028 out_ref: *mut trace_string_ref_t,
2029 ) -> *const trace_context_t;
2030
2031 pub fn trace_acquire_context_for_category_cached(
2032 category_literal: *const libc::c_char,
2033 trace_site: *const u64,
2034 out_ref: *mut trace_string_ref_t,
2035 ) -> *const trace_context_t;
2036
2037 pub fn trace_release_context(context: *const trace_context_t);
2038
2039 pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2040
2041 pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2042
2043 pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2044
2045 pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2046
2047 pub fn trace_notify_observer_updated(event: zx_handle_t);
2048 }
2049}
2050
2051pub struct TraceFutureArgs<'a> {
2054 pub category: &'static CStr,
2055 pub name: &'static CStr,
2056
2057 pub context: Option<TraceCategoryContext>,
2061
2062 pub args: Vec<Arg<'a>>,
2065
2066 pub flow_id: Option<Id>,
2069
2070 pub _use_trace_future_args: (),
2072}
2073
2074#[doc(hidden)]
2075#[macro_export]
2076macro_rules! __impl_trace_future_args {
2077 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2078 {
2079 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2080 let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2081 let args = if context.is_some() {
2082 vec![$($crate::ArgValue::of($key, $val)),*]
2083 } else {
2084 vec![]
2085 };
2086 $crate::TraceFutureArgs {
2087 category: $category,
2088 name: $name,
2089 context: context,
2090 args: args,
2091 flow_id: $flow_id,
2092 _use_trace_future_args: (),
2093 }
2094 }
2095 }};
2096}
2097
2098#[macro_export]
2110macro_rules! trace_future_args {
2111 ($category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
2112 $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
2113 };
2114 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
2115 $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
2116 };
2117}
2118
2119pub trait TraceFutureExt: Future + Sized {
2121 fn trace<'a>(self, args: TraceFutureArgs<'a>) -> TraceFuture<'a, Self> {
2135 TraceFuture::new(args, self)
2136 }
2137}
2138
2139impl<T: Future + Sized> TraceFutureExt for T {}
2140
2141#[pin_project(PinnedDrop)]
2144pub struct TraceFuture<'a, Fut: Future> {
2145 category: &'static CStr,
2146 name: &'static CStr,
2147 args: Vec<Arg<'a>>,
2148 flow_id: Option<Id>,
2149 #[pin]
2150 future: Pin<Box<Fut>>,
2152}
2153
2154impl<'a, Fut: Future> TraceFuture<'a, Fut> {
2155 pub fn new(args: TraceFutureArgs<'a>, future: Fut) -> Self {
2156 debug_assert!(
2157 args.context.is_some() || args.args.is_empty(),
2158 "There should not be any trace arguments when the category is disabled"
2159 );
2160 let mut this = Self {
2161 category: args.category,
2162 name: args.name,
2163 args: args.args,
2164 flow_id: args.flow_id,
2165 future: Box::pin(future),
2166 };
2167 if let Some(context) = args.context {
2168 this.trace_create(context);
2169 }
2170 this
2171 }
2172
2173 #[cold]
2174 fn trace_create(&mut self, context: TraceCategoryContext) {
2175 let name_ref = context.register_string_literal(self.name);
2176 let flow_id = self.flow_id.get_or_insert_with(Id::new);
2177 let duration_start = zx::BootTicks::get();
2178 context.write_flow_begin(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2179 self.args.push(ArgValue::of("state", "created"));
2180 context.write_duration(name_ref, duration_start, &self.args);
2181 self.args.pop();
2182 }
2183
2184 #[cold]
2185 fn trace_poll(
2186 self: Pin<&mut Self>,
2187 context: TraceCategoryContext,
2188 cx: &mut std::task::Context<'_>,
2189 ) -> Poll<Fut::Output> {
2190 let this = self.project();
2191 let name_ref = context.register_string_literal(this.name);
2192 let flow_id = this.flow_id.get_or_insert_with(Id::new);
2193 let duration_start = zx::BootTicks::get();
2194 context.write_flow_step(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2195 let result = this.future.poll(cx);
2196 let result_str: &'static str = if result.is_pending() { "pending" } else { "ready" };
2197 this.args.push(ArgValue::of("state", result_str));
2198 context.write_duration(name_ref, duration_start, &this.args);
2199 this.args.pop();
2200 result
2201 }
2202
2203 #[cold]
2204 fn trace_drop(self: Pin<&mut Self>, context: TraceCategoryContext) {
2205 let this = self.project();
2206 let name_ref = context.register_string_literal(this.name);
2207 let flow_id = this.flow_id.get_or_insert_with(Id::new);
2208 let duration_start = zx::BootTicks::get();
2209 context.write_flow_end(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2210 this.args.push(ArgValue::of("state", "dropped"));
2211 context.write_duration(name_ref, duration_start, &this.args);
2212 this.args.pop();
2213 }
2214}
2215
2216impl<Fut: Future> Future for TraceFuture<'_, Fut> {
2217 type Output = Fut::Output;
2218 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
2219 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2220 self.trace_poll(context, cx)
2221 } else {
2222 self.project().future.poll(cx)
2223 }
2224 }
2225}
2226
2227#[pin_project::pinned_drop]
2228impl<Fut: Future> PinnedDrop for TraceFuture<'_, Fut> {
2229 fn drop(self: Pin<&mut Self>) {
2230 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2231 self.trace_drop(context);
2232 }
2233 }
2234}
2235
2236#[cfg(test)]
2237mod test {
2238 use super::{trim_to_last_char_boundary, Id};
2239
2240 #[test]
2241 fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
2242 assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
2243 assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
2244 assert_eq!(b"", trim_to_last_char_boundary("x", 0));
2245 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
2246 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
2247 assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
2248
2249 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
2250 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
2251 assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
2252 }
2253
2254 #[test]
2258 fn test_id_new() {
2259 assert_ne!(Id::new(), Id::new());
2260 }
2261}