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_string_ref_t, TRACE_BLOB_TYPE_DATA, TRACE_BLOB_TYPE_LAST_BRANCH,
16 TRACE_BLOB_TYPE_PERFETTO,
17};
18
19#[derive(Copy, Clone)]
21pub enum Scope {
22 Thread,
23 Process,
24 Global,
25}
26
27impl Scope {
28 fn into_raw(self) -> sys::trace_scope_t {
29 match self {
30 Scope::Thread => sys::TRACE_SCOPE_THREAD,
31 Scope::Process => sys::TRACE_SCOPE_PROCESS,
32 Scope::Global => sys::TRACE_SCOPE_GLOBAL,
33 }
34 }
35}
36
37#[inline]
39pub fn is_enabled() -> bool {
40 unsafe { sys::trace_state() != sys::TRACE_STOPPED }
42}
43
44pub fn category_enabled(category: &'static CStr) -> bool {
46 unsafe { sys::trace_is_category_enabled(category.as_ptr()) }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub enum TraceState {
53 Stopped,
54 Started,
55 Stopping,
56}
57
58pub fn trace_state() -> TraceState {
59 match unsafe { sys::trace_state() } {
60 sys::TRACE_STOPPED => TraceState::Stopped,
61 sys::TRACE_STARTED => TraceState::Started,
62 sys::TRACE_STOPPING => TraceState::Stopping,
63 s => panic!("Unknown trace state {:?}", s),
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68#[repr(i32)]
69pub enum BufferingMode {
70 OneShot = sys::TRACE_BUFFERING_MODE_ONESHOT,
71 Circular = sys::TRACE_BUFFERING_MODE_CIRCULAR,
72 Streaming = sys::TRACE_BUFFERING_MODE_STREAMING,
73}
74
75#[repr(transparent)]
77#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub struct Id(u64);
79
80impl Id {
81 pub fn new() -> Self {
88 Self(unsafe { sys::trace_generate_nonce() })
90 }
91
92 pub fn random() -> Self {
102 let ts = zx::BootInstant::get().into_nanos() as u64;
103 let high_order = ts << 16;
104 let low_order = rand::random::<u16>() as u64;
105 Self(high_order | low_order)
106 }
107}
108
109impl From<u64> for Id {
110 fn from(u: u64) -> Self {
111 Self(u)
112 }
113}
114
115impl From<Id> for u64 {
116 fn from(id: Id) -> Self {
117 id.0
118 }
119}
120
121#[repr(transparent)]
123pub struct Arg<'a>(sys::trace_arg_t, PhantomData<&'a ()>);
124
125pub trait ArgValue {
131 fn of<'a>(key: &'a str, value: Self) -> Arg<'a>
132 where
133 Self: 'a;
134}
135
136macro_rules! arg_from {
142 ($valname:ident, $(($type:ty, $tag:expr, $value:expr))*) => {
143 $(
144 impl ArgValue for $type {
145 #[inline]
146 fn of<'a>(key: &'a str, $valname: Self) -> Arg<'a>
147 where Self: 'a
148 {
149 #[allow(unused)]
150 let $valname = $valname;
151
152 Arg(sys::trace_arg_t {
153 name_ref: trace_make_inline_string_ref(key),
154 value: sys::trace_arg_value_t {
155 type_: $tag,
156 value: $value,
157 },
158 }, PhantomData)
159 }
160 }
161 )*
162 }
163}
164
165#[rustfmt::skip]
167arg_from!(val,
168 ((), sys::TRACE_ARG_NULL, sys::trace_arg_union_t { int32_value: 0 })
169 (bool, sys::TRACE_ARG_BOOL, sys::trace_arg_union_t { bool_value: val })
170 (i32, sys::TRACE_ARG_INT32, sys::trace_arg_union_t { int32_value: val })
171 (u32, sys::TRACE_ARG_UINT32, sys::trace_arg_union_t { uint32_value: val })
172 (i64, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val })
173 (u64, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val })
174 (isize, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val as i64 })
175 (usize, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val as u64 })
176 (f64, sys::TRACE_ARG_DOUBLE, sys::trace_arg_union_t { double_value: val })
177 (zx::Koid, sys::TRACE_ARG_KOID, sys::trace_arg_union_t { koid_value: val.raw_koid() })
178);
179
180impl<T> ArgValue for *const T {
181 #[inline]
182 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
183 where
184 Self: 'a,
185 {
186 Arg(
187 sys::trace_arg_t {
188 name_ref: trace_make_inline_string_ref(key),
189 value: sys::trace_arg_value_t {
190 type_: sys::TRACE_ARG_POINTER,
191 value: sys::trace_arg_union_t { pointer_value: val as usize },
192 },
193 },
194 PhantomData,
195 )
196 }
197}
198
199impl<T> ArgValue for *mut T {
200 #[inline]
201 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
202 where
203 Self: 'a,
204 {
205 Arg(
206 sys::trace_arg_t {
207 name_ref: trace_make_inline_string_ref(key),
208 value: sys::trace_arg_value_t {
209 type_: sys::TRACE_ARG_POINTER,
210 value: sys::trace_arg_union_t { pointer_value: val as usize },
211 },
212 },
213 PhantomData,
214 )
215 }
216}
217
218impl<'a> ArgValue for &'a str {
219 #[inline]
220 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
221 where
222 Self: 'b,
223 {
224 Arg(
225 sys::trace_arg_t {
226 name_ref: trace_make_inline_string_ref(key),
227 value: sys::trace_arg_value_t {
228 type_: sys::TRACE_ARG_STRING,
229 value: sys::trace_arg_union_t {
230 string_value_ref: trace_make_inline_string_ref(val),
231 },
232 },
233 },
234 PhantomData,
235 )
236 }
237}
238
239#[macro_export]
261macro_rules! instant {
262 ($category:expr, $name:expr, $scope:expr $(, $key:expr => $val:expr)*) => {
263 {
264 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
265 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
266 $crate::instant(&context, $name, $scope, &[$($crate::ArgValue::of($key, $val)),*]);
267 }
268 }
269 }
270}
271
272#[inline]
275pub fn instant(
276 context: &TraceCategoryContext,
277 name: &'static CStr,
278 scope: Scope,
279 args: &[Arg<'_>],
280) {
281 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
282
283 let name_ref = context.register_string_literal(name);
284 context.write_instant(name_ref, scope, args);
285}
286
287#[macro_export]
301macro_rules! alert {
302 ($category:expr, $name:expr) => {
303 $crate::alert($category, $name)
304 };
305}
306
307pub fn alert(category: &'static CStr, name: &'static CStr) {
309 unsafe {
313 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
314 let context =
315 sys::trace_acquire_context_for_category(category.as_ptr(), category_ref.as_mut_ptr());
316 if context != ptr::null() {
317 sys::trace_context_send_alert(context, name.as_ptr());
318 sys::trace_release_context(context);
319 }
320 }
321}
322
323#[macro_export]
340macro_rules! counter {
341 ($category:expr, $name:expr, $counter_id:expr $(, $key:expr => $val:expr)*) => {
342 {
343 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
344 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
345 $crate::counter(&context, $name, $counter_id,
346 &[$($crate::ArgValue::of($key, $val)),*])
347 }
348 }
349 }
350}
351
352pub fn counter(
362 context: &TraceCategoryContext,
363 name: &'static CStr,
364 counter_id: u64,
365 args: &[Arg<'_>],
366) {
367 assert!(args.len() >= 1, "trace counter args must include at least one numeric argument");
368 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
369
370 let name_ref = context.register_string_literal(name);
371 context.write_counter(name_ref, counter_id, args);
372}
373
374#[must_use = "DurationScope must be `end`ed to be recorded"]
377pub struct DurationScope<'a> {
378 category: &'static CStr,
379 name: &'static CStr,
380 args: &'a [Arg<'a>],
381 start_time: zx::BootTicks,
382}
383
384impl<'a> DurationScope<'a> {
385 pub fn begin(category: &'static CStr, name: &'static CStr, args: &'a [Arg<'_>]) -> Self {
388 let start_time = zx::BootTicks::get();
389 Self { category, name, args, start_time }
390 }
391}
392
393impl<'a> Drop for DurationScope<'a> {
394 fn drop(&mut self) {
395 if let Some(context) = TraceCategoryContext::acquire(self.category) {
396 let name_ref = context.register_string_literal(self.name);
397 context.write_duration(name_ref, self.start_time, self.args);
398 }
399 }
400}
401
402pub fn complete_duration(
404 category: &'static CStr,
405 name: &'static CStr,
406 start_time: zx::BootTicks,
407 args: &[Arg<'_>],
408) {
409 if let Some(context) = TraceCategoryContext::acquire(category) {
410 let name_ref = context.register_string_literal(name);
411 context.write_duration(name_ref, start_time, args);
412 }
413}
414
415#[macro_export]
450macro_rules! duration {
451 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
452 let mut args;
453 let _scope = {
454 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
455 if let Some(_context) =
462 $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
463 args = [$($crate::ArgValue::of($key, $val)),*];
464 Some($crate::duration($category, $name, &args))
465 } else {
466 None
467 }
468 };
469 }
470}
471
472pub fn duration<'a>(
484 category: &'static CStr,
485 name: &'static CStr,
486 args: &'a [Arg<'_>],
487) -> DurationScope<'a> {
488 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
489 DurationScope::begin(category, name, args)
490}
491
492#[macro_export]
506macro_rules! duration_begin {
507 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
508 {
509 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
510 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
511 $crate::duration_begin(&context, $name,
512 &[$($crate::ArgValue::of($key, $val)),*])
513 }
514 }
515 };
516}
517
518#[macro_export]
532macro_rules! duration_end {
533 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
534 {
535 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
536 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
537 $crate::duration_end(&context, $name, &[$($crate::ArgValue::of($key, $val)),*])
538 }
539 }
540 };
541}
542
543pub fn duration_begin(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
554 let ticks = zx::BootTicks::get();
555 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
556
557 let name_ref = context.register_string_literal(name);
558 context.write_duration_begin(ticks, name_ref, args);
559}
560
561pub fn duration_end(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
571 let ticks = zx::BootTicks::get();
572 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
573
574 let name_ref = context.register_string_literal(name);
575 context.write_duration_end(ticks, name_ref, args);
576}
577
578#[must_use = "emits an end event when dropped, so if dropped immediately creates an essentially \
581 zero length duration that should just be an instant instead"]
582pub struct AsyncScope {
583 id: Id,
586 category: &'static CStr,
587 name: &'static CStr,
588}
589impl AsyncScope {
590 pub fn begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) -> Self {
593 async_begin(id, category, name, args);
594 Self { id, category, name }
595 }
596
597 pub fn end(self, args: &[Arg<'_>]) {
600 let Self { id, category, name } = self;
601 async_end(id, category, name, args);
602 std::mem::forget(self);
603 }
604}
605
606impl Drop for AsyncScope {
607 fn drop(&mut self) {
608 let Self { id, category, name } = *self;
612 async_end(id, category, name, &[]);
613 }
614}
615
616pub fn async_enter(
625 id: Id,
626 category: &'static CStr,
627 name: &'static CStr,
628 args: &[Arg<'_>],
629) -> AsyncScope {
630 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
631 AsyncScope::begin(id, category, name, args)
632}
633
634#[macro_export]
665macro_rules! async_enter {
666 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
667 {
668 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
669 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
670 Some($crate::AsyncScope::begin($id, $category, $name, &[$($crate::ArgValue::of($key, $val)),*]))
671 } else {
672 None
673 }
674 }
675 }
676}
677
678#[macro_export]
702macro_rules! async_instant {
703 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
704 {
705 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
706 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
707 $crate::async_instant($id, &context, $name, &[$($crate::ArgValue::of($key, $val)),*]);
708 }
709 }
710 }
711}
712
713pub fn async_begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
725 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
726
727 if let Some(context) = TraceCategoryContext::acquire(category) {
728 let name_ref = context.register_string_literal(name);
729 context.write_async_begin(id, name_ref, args);
730 }
731}
732
733pub fn async_end(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
745 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
746
747 if let Some(context) = TraceCategoryContext::acquire(category) {
748 let name_ref = context.register_string_literal(name);
749 context.write_async_end(id, name_ref, args);
750 }
751}
752
753pub fn async_instant(
765 id: Id,
766 context: &TraceCategoryContext,
767 name: &'static CStr,
768 args: &[Arg<'_>],
769) {
770 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
771
772 let name_ref = context.register_string_literal(name);
773 context.write_async_instant(id, name_ref, args);
774}
775
776#[macro_export]
777macro_rules! blob {
778 ($category:expr, $name:expr, $bytes:expr $(, $key:expr => $val:expr)*) => {
779 {
780 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
781 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
782 $crate::blob_fn(&context, $name, $bytes, &[$($crate::ArgValue::of($key, $val)),*])
783 }
784 }
785 }
786}
787pub fn blob_fn(
788 context: &TraceCategoryContext,
789 name: &'static CStr,
790 bytes: &[u8],
791 args: &[Arg<'_>],
792) {
793 let name_ref = context.register_string_literal(name);
794 context.write_blob(name_ref, bytes, args);
795}
796
797#[macro_export]
812macro_rules! flow_begin {
813 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
814 {
815 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
816 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
817 $crate::flow_begin(&context, $name, $flow_id,
818 &[$($crate::ArgValue::of($key, $val)),*])
819 }
820 }
821 }
822}
823
824#[macro_export]
839macro_rules! flow_step {
840 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
841 {
842 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
843 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
844 $crate::flow_step(&context, $name, $flow_id,
845 &[$($crate::ArgValue::of($key, $val)),*])
846 }
847 }
848 }
849}
850
851#[macro_export]
866macro_rules! flow_end {
867 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
868 {
869 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
870 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
871 $crate::flow_end(&context, $name, $flow_id,
872 &[$($crate::ArgValue::of($key, $val)),*])
873 }
874 }
875 }
876}
877
878pub fn flow_begin(
897 context: &TraceCategoryContext,
898 name: &'static CStr,
899 flow_id: Id,
900 args: &[Arg<'_>],
901) {
902 let ticks = zx::BootTicks::get();
903 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
904
905 let name_ref = context.register_string_literal(name);
906 context.write_flow_begin(ticks, name_ref, flow_id, args);
907}
908
909pub fn flow_end(
926 context: &TraceCategoryContext,
927 name: &'static CStr,
928 flow_id: Id,
929 args: &[Arg<'_>],
930) {
931 let ticks = zx::BootTicks::get();
932 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
933
934 let name_ref = context.register_string_literal(name);
935 context.write_flow_end(ticks, name_ref, flow_id, args);
936}
937
938pub fn flow_step(
955 context: &TraceCategoryContext,
956 name: &'static CStr,
957 flow_id: Id,
958 args: &[Arg<'_>],
959) {
960 let ticks = zx::BootTicks::get();
961 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
962
963 let name_ref = context.register_string_literal(name);
964 context.write_flow_step(ticks, name_ref, flow_id, args);
965}
966
967#[macro_export]
981macro_rules! instaflow_begin {
982 (
983 $category:expr,
984 $flow_name:expr,
985 $step_name:expr,
986 $flow_id:expr
987 $(, $key:expr => $val:expr)*
988 ) => {
989 {
990 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
991 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
992 $crate::instaflow_begin(
993 &context,
994 $flow_name,
995 $step_name,
996 $flow_id,
997 &[$($crate::ArgValue::of($key, $val)),*],
998 )
999 }
1000 }
1001 }
1002}
1003
1004#[macro_export]
1018macro_rules! instaflow_end {
1019 (
1020 $category:expr,
1021 $flow_name:expr,
1022 $step_name:expr,
1023 $flow_id:expr
1024 $(, $key:expr => $val:expr)*
1025 ) => {
1026 {
1027 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1028 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1029 $crate::instaflow_end(
1030 &context,
1031 $flow_name,
1032 $step_name,
1033 $flow_id,
1034 &[$($crate::ArgValue::of($key, $val)),*],
1035 )
1036 }
1037 }
1038 }
1039}
1040
1041#[macro_export]
1055macro_rules! instaflow_step {
1056 (
1057 $category:expr,
1058 $flow_name:expr,
1059 $step_name:expr,
1060 $flow_id:expr
1061 $(, $key:expr => $val:expr)*
1062 ) => {
1063 {
1064 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1065 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1066 $crate::instaflow_step(
1067 &context,
1068 $flow_name,
1069 $step_name,
1070 $flow_id,
1071 &[$($crate::ArgValue::of($key, $val)),*],
1072 )
1073 }
1074 }
1075 }
1076}
1077
1078pub fn instaflow_begin(
1090 context: &TraceCategoryContext,
1091 flow_name: &'static CStr,
1092 step_name: &'static CStr,
1093 flow_id: Id,
1094 args: &[Arg<'_>],
1095) {
1096 let ticks = zx::BootTicks::get();
1097 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1098
1099 let flow_name_ref = context.register_string_literal(flow_name);
1100 let step_name_ref = context.register_string_literal(step_name);
1101
1102 context.write_duration_begin(ticks, step_name_ref, args);
1103 context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1104 context.write_duration_end(ticks, step_name_ref, args);
1105}
1106
1107pub fn instaflow_end(
1119 context: &TraceCategoryContext,
1120 flow_name: &'static CStr,
1121 step_name: &'static CStr,
1122 flow_id: Id,
1123 args: &[Arg<'_>],
1124) {
1125 let ticks = zx::BootTicks::get();
1126 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1127
1128 let flow_name_ref = context.register_string_literal(flow_name);
1129 let step_name_ref = context.register_string_literal(step_name);
1130
1131 context.write_duration_begin(ticks, step_name_ref, args);
1132 context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1133 context.write_duration_end(ticks, step_name_ref, args);
1134}
1135
1136pub fn instaflow_step(
1148 context: &TraceCategoryContext,
1149 flow_name: &'static CStr,
1150 step_name: &'static CStr,
1151 flow_id: Id,
1152 args: &[Arg<'_>],
1153) {
1154 let ticks = zx::BootTicks::get();
1155 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1156
1157 let flow_name_ref = context.register_string_literal(flow_name);
1158 let step_name_ref = context.register_string_literal(step_name);
1159
1160 context.write_duration_begin(ticks, step_name_ref, args);
1161 context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1162 context.write_duration_end(ticks, step_name_ref, args);
1163}
1164
1165const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1167 sys::trace_string_ref_t {
1168 encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1169 inline_string: ptr::null(),
1170 }
1171}
1172
1173#[inline]
1174fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1175 let mut len = string.len();
1176 if string.len() > max_len {
1177 len = max_len;
1181 while len > 0 {
1182 if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1183 break;
1184 }
1185 len -= 1;
1186 }
1187 }
1188 &string.as_bytes()[0..len]
1189}
1190
1191#[inline]
1194fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1195 let len = string.len() as u16;
1196 if len == 0 {
1197 return trace_make_empty_string_ref();
1198 }
1199
1200 let string = trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH);
1201
1202 sys::trace_string_ref_t {
1203 encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1204 inline_string: string.as_ptr() as *const libc::c_char,
1205 }
1206}
1207
1208pub struct TraceCategoryContext {
1210 raw: *const sys::trace_context_t,
1211 category_ref: sys::trace_string_ref_t,
1212}
1213
1214impl TraceCategoryContext {
1215 #[inline]
1216 pub fn acquire_cached(
1217 category: &'static CStr,
1218 site: &sys::trace_site_t,
1219 ) -> Option<TraceCategoryContext> {
1220 unsafe {
1221 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1226 let raw = sys::trace_acquire_context_for_category_cached(
1227 category.as_ptr(),
1228 site.as_ptr(),
1229 category_ref.as_mut_ptr(),
1230 );
1231 if raw != ptr::null() {
1232 Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1233 } else {
1234 None
1235 }
1236 }
1237 }
1238
1239 pub fn acquire(category: &'static CStr) -> Option<TraceCategoryContext> {
1240 unsafe {
1241 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1242 let raw = sys::trace_acquire_context_for_category(
1243 category.as_ptr(),
1244 category_ref.as_mut_ptr(),
1245 );
1246 if raw != ptr::null() {
1247 Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1248 } else {
1249 None
1250 }
1251 }
1252 }
1253
1254 #[inline]
1255 pub fn register_string_literal(&self, name: &'static CStr) -> sys::trace_string_ref_t {
1256 unsafe {
1257 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1258 sys::trace_context_register_string_literal(
1259 self.raw,
1260 name.as_ptr(),
1261 name_ref.as_mut_ptr(),
1262 );
1263 name_ref.assume_init()
1264 }
1265 }
1266
1267 #[inline]
1268 fn register_current_thread(&self) -> sys::trace_thread_ref_t {
1269 unsafe {
1270 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1271 sys::trace_context_register_current_thread(self.raw, thread_ref.as_mut_ptr());
1272 thread_ref.assume_init()
1273 }
1274 }
1275
1276 #[inline]
1277 pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
1278 let ticks = zx::BootTicks::get();
1279 let thread_ref = self.register_current_thread();
1280 unsafe {
1281 sys::trace_context_write_instant_event_record(
1282 self.raw,
1283 ticks.into_raw(),
1284 &thread_ref,
1285 &self.category_ref,
1286 &name_ref,
1287 scope.into_raw(),
1288 args.as_ptr() as *const sys::trace_arg_t,
1289 args.len(),
1290 );
1291 }
1292 }
1293
1294 pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
1295 let name_ref = trace_make_inline_string_ref(name);
1296 self.write_instant(name_ref, scope, args)
1297 }
1298
1299 fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
1300 let ticks = zx::BootTicks::get();
1301 let thread_ref = self.register_current_thread();
1302 unsafe {
1303 sys::trace_context_write_counter_event_record(
1304 self.raw,
1305 ticks.into_raw(),
1306 &thread_ref,
1307 &self.category_ref,
1308 &name_ref,
1309 counter_id,
1310 args.as_ptr() as *const sys::trace_arg_t,
1311 args.len(),
1312 );
1313 }
1314 }
1315
1316 pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
1317 let name_ref = trace_make_inline_string_ref(name);
1318 self.write_counter(name_ref, counter_id, args);
1319 }
1320
1321 fn write_duration(
1322 &self,
1323 name_ref: sys::trace_string_ref_t,
1324 start_time: zx::BootTicks,
1325 args: &[Arg<'_>],
1326 ) {
1327 let ticks = zx::BootTicks::get();
1328 let thread_ref = self.register_current_thread();
1329 unsafe {
1330 sys::trace_context_write_duration_event_record(
1331 self.raw,
1332 start_time.into_raw(),
1333 ticks.into_raw(),
1334 &thread_ref,
1335 &self.category_ref,
1336 &name_ref,
1337 args.as_ptr() as *const sys::trace_arg_t,
1338 args.len(),
1339 );
1340 }
1341 }
1342
1343 pub fn write_duration_with_inline_name(
1344 &self,
1345 name: &str,
1346 start_time: zx::BootTicks,
1347 args: &[Arg<'_>],
1348 ) {
1349 let name_ref = trace_make_inline_string_ref(name);
1350 self.write_duration(name_ref, start_time, args);
1351 }
1352
1353 fn write_duration_begin(
1354 &self,
1355 ticks: zx::BootTicks,
1356 name_ref: sys::trace_string_ref_t,
1357 args: &[Arg<'_>],
1358 ) {
1359 let thread_ref = self.register_current_thread();
1360 unsafe {
1361 sys::trace_context_write_duration_begin_event_record(
1362 self.raw,
1363 ticks.into_raw(),
1364 &thread_ref,
1365 &self.category_ref,
1366 &name_ref,
1367 args.as_ptr() as *const sys::trace_arg_t,
1368 args.len(),
1369 );
1370 }
1371 }
1372
1373 pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1374 let name_ref = trace_make_inline_string_ref(name);
1375 self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
1376 }
1377
1378 fn write_duration_end(
1379 &self,
1380 ticks: zx::BootTicks,
1381 name_ref: sys::trace_string_ref_t,
1382 args: &[Arg<'_>],
1383 ) {
1384 let thread_ref = self.register_current_thread();
1385 unsafe {
1386 sys::trace_context_write_duration_end_event_record(
1387 self.raw,
1388 ticks.into_raw(),
1389 &thread_ref,
1390 &self.category_ref,
1391 &name_ref,
1392 args.as_ptr() as *const sys::trace_arg_t,
1393 args.len(),
1394 );
1395 }
1396 }
1397
1398 pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1399 let name_ref = trace_make_inline_string_ref(name);
1400 self.write_duration_end(zx::BootTicks::get(), name_ref, args);
1401 }
1402
1403 fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1404 let ticks = zx::BootTicks::get();
1405 let thread_ref = self.register_current_thread();
1406 unsafe {
1407 sys::trace_context_write_async_begin_event_record(
1408 self.raw,
1409 ticks.into_raw(),
1410 &thread_ref,
1411 &self.category_ref,
1412 &name_ref,
1413 id.into(),
1414 args.as_ptr() as *const sys::trace_arg_t,
1415 args.len(),
1416 );
1417 }
1418 }
1419
1420 pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1421 let name_ref = trace_make_inline_string_ref(name);
1422 self.write_async_begin(id, name_ref, args);
1423 }
1424
1425 fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1426 let ticks = zx::BootTicks::get();
1427 let thread_ref = self.register_current_thread();
1428 unsafe {
1429 sys::trace_context_write_async_end_event_record(
1430 self.raw,
1431 ticks.into_raw(),
1432 &thread_ref,
1433 &self.category_ref,
1434 &name_ref,
1435 id.into(),
1436 args.as_ptr() as *const sys::trace_arg_t,
1437 args.len(),
1438 );
1439 }
1440 }
1441
1442 pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1443 let name_ref = trace_make_inline_string_ref(name);
1444 self.write_async_end(id, name_ref, args);
1445 }
1446
1447 fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1448 let ticks = zx::BootTicks::get();
1449 let thread_ref = self.register_current_thread();
1450 unsafe {
1451 sys::trace_context_write_async_instant_event_record(
1452 self.raw,
1453 ticks.into_raw(),
1454 &thread_ref,
1455 &self.category_ref,
1456 &name_ref,
1457 id.into(),
1458 args.as_ptr() as *const sys::trace_arg_t,
1459 args.len(),
1460 );
1461 }
1462 }
1463
1464 fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
1465 let ticks = zx::BootTicks::get();
1466 let thread_ref = self.register_current_thread();
1467 unsafe {
1468 sys::trace_context_write_blob_event_record(
1469 self.raw,
1470 ticks.into_raw(),
1471 &thread_ref,
1472 &self.category_ref,
1473 &name_ref,
1474 bytes.as_ptr() as *const core::ffi::c_void,
1475 bytes.len(),
1476 args.as_ptr() as *const sys::trace_arg_t,
1477 args.len(),
1478 );
1479 }
1480 }
1481
1482 fn write_flow_begin(
1483 &self,
1484 ticks: zx::BootTicks,
1485 name_ref: sys::trace_string_ref_t,
1486 flow_id: Id,
1487 args: &[Arg<'_>],
1488 ) {
1489 let thread_ref = self.register_current_thread();
1490 unsafe {
1491 sys::trace_context_write_flow_begin_event_record(
1492 self.raw,
1493 ticks.into_raw(),
1494 &thread_ref,
1495 &self.category_ref,
1496 &name_ref,
1497 flow_id.into(),
1498 args.as_ptr() as *const sys::trace_arg_t,
1499 args.len(),
1500 );
1501 }
1502 }
1503
1504 fn write_flow_end(
1505 &self,
1506 ticks: zx::BootTicks,
1507 name_ref: sys::trace_string_ref_t,
1508 flow_id: Id,
1509 args: &[Arg<'_>],
1510 ) {
1511 let thread_ref = self.register_current_thread();
1512 unsafe {
1513 sys::trace_context_write_flow_end_event_record(
1514 self.raw,
1515 ticks.into_raw(),
1516 &thread_ref,
1517 &self.category_ref,
1518 &name_ref,
1519 flow_id.into(),
1520 args.as_ptr() as *const sys::trace_arg_t,
1521 args.len(),
1522 );
1523 }
1524 }
1525
1526 fn write_flow_step(
1527 &self,
1528 ticks: zx::BootTicks,
1529 name_ref: sys::trace_string_ref_t,
1530 flow_id: Id,
1531 args: &[Arg<'_>],
1532 ) {
1533 let thread_ref = self.register_current_thread();
1534 unsafe {
1535 sys::trace_context_write_flow_step_event_record(
1536 self.raw,
1537 ticks.into_raw(),
1538 &thread_ref,
1539 &self.category_ref,
1540 &name_ref,
1541 flow_id.into(),
1542 args.as_ptr() as *const sys::trace_arg_t,
1543 args.len(),
1544 );
1545 }
1546 }
1547}
1548
1549impl std::ops::Drop for TraceCategoryContext {
1550 fn drop(&mut self) {
1551 unsafe {
1552 sys::trace_release_context(self.raw);
1553 }
1554 }
1555}
1556
1557pub struct Context {
1559 context: *const sys::trace_context_t,
1560}
1561
1562impl Context {
1563 #[inline]
1564 pub fn acquire() -> Option<Self> {
1565 let context = unsafe { sys::trace_acquire_context() };
1566 if context.is_null() {
1567 None
1568 } else {
1569 Some(Self { context })
1570 }
1571 }
1572
1573 #[inline]
1574 pub fn register_string_literal(&self, s: &'static CStr) -> sys::trace_string_ref_t {
1575 unsafe {
1576 let mut s_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1577 sys::trace_context_register_string_literal(
1578 self.context,
1579 s.as_ptr(),
1580 s_ref.as_mut_ptr(),
1581 );
1582 s_ref.assume_init()
1583 }
1584 }
1585
1586 pub fn write_blob_record(
1587 &self,
1588 type_: sys::trace_blob_type_t,
1589 name_ref: &sys::trace_string_ref_t,
1590 data: &[u8],
1591 ) {
1592 unsafe {
1593 sys::trace_context_write_blob_record(
1594 self.context,
1595 type_,
1596 name_ref as *const sys::trace_string_ref_t,
1597 data.as_ptr() as *const libc::c_void,
1598 data.len(),
1599 );
1600 }
1601 }
1602
1603 pub fn copy_record(&self, buffer: &[u64]) -> Option<usize> {
1607 unsafe {
1608 let ptr =
1609 sys::trace_context_alloc_record(self.context, 8 * buffer.len() as libc::size_t);
1610 if ptr == std::ptr::null_mut() {
1611 return None;
1612 }
1613 ptr.cast::<u64>().copy_from(buffer.as_ptr(), buffer.len());
1614 };
1615 Some(buffer.len())
1616 }
1617
1618 pub fn buffering_mode(&self) -> BufferingMode {
1619 match unsafe { sys::trace_context_get_buffering_mode(self.context) } {
1620 sys::TRACE_BUFFERING_MODE_ONESHOT => BufferingMode::OneShot,
1621 sys::TRACE_BUFFERING_MODE_CIRCULAR => BufferingMode::Circular,
1622 sys::TRACE_BUFFERING_MODE_STREAMING => BufferingMode::Streaming,
1623 m => panic!("Unknown trace buffering mode: {:?}", m),
1624 }
1625 }
1626}
1627
1628impl std::ops::Drop for Context {
1629 fn drop(&mut self) {
1630 unsafe { sys::trace_release_context(self.context) }
1631 }
1632}
1633
1634pub struct ProlongedContext {
1635 context: *const sys::trace_prolonged_context_t,
1636}
1637
1638impl ProlongedContext {
1639 pub fn acquire() -> Option<Self> {
1640 let context = unsafe { sys::trace_acquire_prolonged_context() };
1641 if context.is_null() {
1642 None
1643 } else {
1644 Some(Self { context })
1645 }
1646 }
1647}
1648
1649impl Drop for ProlongedContext {
1650 fn drop(&mut self) {
1651 unsafe { sys::trace_release_prolonged_context(self.context) }
1652 }
1653}
1654
1655unsafe impl Send for ProlongedContext {}
1656
1657mod sys {
1658 #![allow(non_camel_case_types, unused)]
1659 use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
1660
1661 pub type trace_ticks_t = zx_ticks_t;
1662 pub type trace_counter_id_t = u64;
1663 pub type trace_async_id_t = u64;
1664 pub type trace_flow_id_t = u64;
1665 pub type trace_thread_state_t = u32;
1666 pub type trace_cpu_number_t = u32;
1667 pub type trace_string_index_t = u32;
1668 pub type trace_thread_index_t = u32;
1669 pub type trace_context_t = libc::c_void;
1670 pub type trace_prolonged_context_t = libc::c_void;
1671
1672 pub type trace_encoded_string_ref_t = u16;
1673 pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
1674 pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
1675 pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
1676 pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: usize = 32000;
1677 pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
1678 pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
1679
1680 pub type trace_encoded_thread_ref_t = u32;
1681 pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
1682 pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
1683 pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
1684
1685 pub type trace_state_t = libc::c_int;
1686 pub const TRACE_STOPPED: trace_state_t = 0;
1687 pub const TRACE_STARTED: trace_state_t = 1;
1688 pub const TRACE_STOPPING: trace_state_t = 2;
1689
1690 pub type trace_scope_t = libc::c_int;
1691 pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
1692 pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
1693 pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
1694
1695 pub type trace_blob_type_t = libc::c_int;
1696 pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
1697 pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
1698 pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
1699
1700 pub type trace_buffering_mode_t = libc::c_int;
1701 pub const TRACE_BUFFERING_MODE_ONESHOT: trace_buffering_mode_t = 0;
1702 pub const TRACE_BUFFERING_MODE_CIRCULAR: trace_buffering_mode_t = 1;
1703 pub const TRACE_BUFFERING_MODE_STREAMING: trace_buffering_mode_t = 2;
1704
1705 #[repr(C)]
1706 #[derive(Copy, Clone)]
1707 pub struct trace_string_ref_t {
1708 pub encoded_value: trace_encoded_string_ref_t,
1709 pub inline_string: *const libc::c_char,
1710 }
1711
1712 pub type trace_site_t = std::sync::atomic::AtomicU64;
1716
1717 unsafe impl Send for trace_string_ref_t {}
1727 unsafe impl Sync for trace_string_ref_t {}
1728
1729 #[repr(C)]
1730 pub struct trace_thread_ref_t {
1731 pub encoded_value: trace_encoded_thread_ref_t,
1732 pub inline_process_koid: zx_koid_t,
1733 pub inline_thread_koid: zx_koid_t,
1734 }
1735
1736 #[repr(C)]
1737 pub struct trace_arg_t {
1738 pub name_ref: trace_string_ref_t,
1739 pub value: trace_arg_value_t,
1740 }
1741
1742 #[repr(C)]
1743 pub union trace_arg_union_t {
1744 pub int32_value: i32,
1745 pub uint32_value: u32,
1746 pub int64_value: i64,
1747 pub uint64_value: u64,
1748 pub double_value: libc::c_double,
1749 pub string_value_ref: trace_string_ref_t,
1750 pub pointer_value: libc::uintptr_t,
1751 pub koid_value: zx_koid_t,
1752 pub bool_value: bool,
1753 pub reserved_for_future_expansion: [libc::uintptr_t; 2],
1754 }
1755
1756 pub type trace_arg_type_t = libc::c_int;
1757 pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
1758 pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
1759 pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
1760 pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
1761 pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
1762 pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
1763 pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
1764 pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
1765 pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
1766 pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
1767
1768 #[repr(C)]
1769 pub struct trace_arg_value_t {
1770 pub type_: trace_arg_type_t,
1771 pub value: trace_arg_union_t,
1772 }
1773
1774 #[repr(C)]
1775 pub struct trace_handler_ops_t {
1776 pub is_category_enabled:
1777 unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
1778 pub trace_started: unsafe fn(handler: *const trace_handler_t),
1779 pub trace_stopped: unsafe fn(
1780 handler: *const trace_handler_t,
1781 async_ptr: *const (), disposition: zx_status_t,
1783 buffer_bytes_written: libc::size_t,
1784 ),
1785 pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
1786 }
1787
1788 #[repr(C)]
1789 pub struct trace_handler_t {
1790 pub ops: *const trace_handler_ops_t,
1791 }
1792
1793 extern "C" {
1795 pub fn trace_context_is_category_enabled(
1798 context: *const trace_context_t,
1799 category_literal: *const libc::c_char,
1800 ) -> bool;
1801
1802 pub fn trace_context_register_string_copy(
1803 context: *const trace_context_t,
1804 string: *const libc::c_char,
1805 length: libc::size_t,
1806 out_ref: *mut trace_string_ref_t,
1807 );
1808
1809 pub fn trace_context_register_string_literal(
1810 context: *const trace_context_t,
1811 string_literal: *const libc::c_char,
1812 out_ref: *mut trace_string_ref_t,
1813 );
1814
1815 pub fn trace_context_register_category_literal(
1816 context: *const trace_context_t,
1817 category_literal: *const libc::c_char,
1818 out_ref: *mut trace_string_ref_t,
1819 ) -> bool;
1820
1821 pub fn trace_context_register_current_thread(
1822 context: *const trace_context_t,
1823 out_ref: *mut trace_thread_ref_t,
1824 );
1825
1826 pub fn trace_context_register_thread(
1827 context: *const trace_context_t,
1828 process_koid: zx_koid_t,
1829 thread_koid: zx_koid_t,
1830 out_ref: *mut trace_thread_ref_t,
1831 );
1832
1833 pub fn trace_context_write_kernel_object_record(
1834 context: *const trace_context_t,
1835 koid: zx_koid_t,
1836 type_: zx_obj_type_t,
1837 args: *const trace_arg_t,
1838 num_args: libc::size_t,
1839 );
1840
1841 pub fn trace_context_write_kernel_object_record_for_handle(
1842 context: *const trace_context_t,
1843 handle: zx_handle_t,
1844 args: *const trace_arg_t,
1845 num_args: libc::size_t,
1846 );
1847
1848 pub fn trace_context_write_process_info_record(
1849 context: *const trace_context_t,
1850 process_koid: zx_koid_t,
1851 process_name_ref: *const trace_string_ref_t,
1852 );
1853
1854 pub fn trace_context_write_thread_info_record(
1855 context: *const trace_context_t,
1856 process_koid: zx_koid_t,
1857 thread_koid: zx_koid_t,
1858 thread_name_ref: *const trace_string_ref_t,
1859 );
1860
1861 pub fn trace_context_write_context_switch_record(
1862 context: *const trace_context_t,
1863 event_time: trace_ticks_t,
1864 cpu_number: trace_cpu_number_t,
1865 outgoing_thread_state: trace_thread_state_t,
1866 outgoing_thread_ref: *const trace_thread_ref_t,
1867 incoming_thread_ref: *const trace_thread_ref_t,
1868 );
1869
1870 pub fn trace_context_write_log_record(
1871 context: *const trace_context_t,
1872 event_time: trace_ticks_t,
1873 thread_ref: *const trace_thread_ref_t,
1874 log_message: *const libc::c_char,
1875 log_message_length: libc::size_t,
1876 );
1877
1878 pub fn trace_context_write_instant_event_record(
1879 context: *const trace_context_t,
1880 event_time: trace_ticks_t,
1881 thread_ref: *const trace_thread_ref_t,
1882 category_ref: *const trace_string_ref_t,
1883 name_ref: *const trace_string_ref_t,
1884 scope: trace_scope_t,
1885 args: *const trace_arg_t,
1886 num_args: libc::size_t,
1887 );
1888
1889 pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
1890
1891 pub fn trace_context_write_counter_event_record(
1892 context: *const trace_context_t,
1893 event_time: trace_ticks_t,
1894 thread_ref: *const trace_thread_ref_t,
1895 category_ref: *const trace_string_ref_t,
1896 name_ref: *const trace_string_ref_t,
1897 counter_id: trace_counter_id_t,
1898 args: *const trace_arg_t,
1899 num_args: libc::size_t,
1900 );
1901
1902 pub fn trace_context_write_duration_event_record(
1903 context: *const trace_context_t,
1904 start_time: trace_ticks_t,
1905 end_time: trace_ticks_t,
1906 thread_ref: *const trace_thread_ref_t,
1907 category_ref: *const trace_string_ref_t,
1908 name_ref: *const trace_string_ref_t,
1909 args: *const trace_arg_t,
1910 num_args: libc::size_t,
1911 );
1912
1913 pub fn trace_context_write_blob_event_record(
1914 context: *const trace_context_t,
1915 event_time: trace_ticks_t,
1916 thread_ref: *const trace_thread_ref_t,
1917 category_ref: *const trace_string_ref_t,
1918 name_ref: *const trace_string_ref_t,
1919 blob: *const libc::c_void,
1920 blob_size: libc::size_t,
1921 args: *const trace_arg_t,
1922 num_args: libc::size_t,
1923 );
1924
1925 pub fn trace_context_write_duration_begin_event_record(
1926 context: *const trace_context_t,
1927 event_time: trace_ticks_t,
1928 thread_ref: *const trace_thread_ref_t,
1929 category_ref: *const trace_string_ref_t,
1930 name_ref: *const trace_string_ref_t,
1931 args: *const trace_arg_t,
1932 num_args: libc::size_t,
1933 );
1934
1935 pub fn trace_context_write_duration_end_event_record(
1936 context: *const trace_context_t,
1937 event_time: trace_ticks_t,
1938 thread_ref: *const trace_thread_ref_t,
1939 category_ref: *const trace_string_ref_t,
1940 name_ref: *const trace_string_ref_t,
1941 args: *const trace_arg_t,
1942 num_args: libc::size_t,
1943 );
1944
1945 pub fn trace_context_write_async_begin_event_record(
1946 context: *const trace_context_t,
1947 event_time: trace_ticks_t,
1948 thread_ref: *const trace_thread_ref_t,
1949 category_ref: *const trace_string_ref_t,
1950 name_ref: *const trace_string_ref_t,
1951 async_id: trace_async_id_t,
1952 args: *const trace_arg_t,
1953 num_args: libc::size_t,
1954 );
1955
1956 pub fn trace_context_write_async_instant_event_record(
1957 context: *const trace_context_t,
1958 event_time: trace_ticks_t,
1959 thread_ref: *const trace_thread_ref_t,
1960 category_ref: *const trace_string_ref_t,
1961 name_ref: *const trace_string_ref_t,
1962 async_id: trace_async_id_t,
1963 args: *const trace_arg_t,
1964 num_args: libc::size_t,
1965 );
1966
1967 pub fn trace_context_write_async_end_event_record(
1968 context: *const trace_context_t,
1969 event_time: trace_ticks_t,
1970 thread_ref: *const trace_thread_ref_t,
1971 category_ref: *const trace_string_ref_t,
1972 name_ref: *const trace_string_ref_t,
1973 async_id: trace_async_id_t,
1974 args: *const trace_arg_t,
1975 num_args: libc::size_t,
1976 );
1977
1978 pub fn trace_context_write_flow_begin_event_record(
1979 context: *const trace_context_t,
1980 event_time: trace_ticks_t,
1981 thread_ref: *const trace_thread_ref_t,
1982 category_ref: *const trace_string_ref_t,
1983 name_ref: *const trace_string_ref_t,
1984 flow_id: trace_flow_id_t,
1985 args: *const trace_arg_t,
1986 num_args: libc::size_t,
1987 );
1988
1989 pub fn trace_context_write_flow_step_event_record(
1990 context: *const trace_context_t,
1991 event_time: trace_ticks_t,
1992 thread_ref: *const trace_thread_ref_t,
1993 category_ref: *const trace_string_ref_t,
1994 name_ref: *const trace_string_ref_t,
1995 flow_id: trace_flow_id_t,
1996 args: *const trace_arg_t,
1997 num_args: libc::size_t,
1998 );
1999
2000 pub fn trace_context_write_flow_end_event_record(
2001 context: *const trace_context_t,
2002 event_time: trace_ticks_t,
2003 thread_ref: *const trace_thread_ref_t,
2004 category_ref: *const trace_string_ref_t,
2005 name_ref: *const trace_string_ref_t,
2006 flow_id: trace_flow_id_t,
2007 args: *const trace_arg_t,
2008 num_args: libc::size_t,
2009 );
2010
2011 pub fn trace_context_write_initialization_record(
2012 context: *const trace_context_t,
2013 ticks_per_second: u64,
2014 );
2015
2016 pub fn trace_context_write_string_record(
2017 context: *const trace_context_t,
2018 index: trace_string_index_t,
2019 string: *const libc::c_char,
2020 length: libc::size_t,
2021 );
2022
2023 pub fn trace_context_write_thread_record(
2024 context: *const trace_context_t,
2025 index: trace_thread_index_t,
2026 procss_koid: zx_koid_t,
2027 thread_koid: zx_koid_t,
2028 );
2029
2030 pub fn trace_context_write_blob_record(
2031 context: *const trace_context_t,
2032 type_: trace_blob_type_t,
2033 name_ref: *const trace_string_ref_t,
2034 data: *const libc::c_void,
2035 size: libc::size_t,
2036 );
2037
2038 pub fn trace_context_alloc_record(
2039 context: *const trace_context_t,
2040 num_bytes: libc::size_t,
2041 ) -> *mut libc::c_void;
2042
2043 pub fn trace_generate_nonce() -> u64;
2046
2047 pub fn trace_state() -> trace_state_t;
2048
2049 pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2050
2051 pub fn trace_acquire_context() -> *const trace_context_t;
2052
2053 pub fn trace_acquire_context_for_category(
2054 category_literal: *const libc::c_char,
2055 out_ref: *mut trace_string_ref_t,
2056 ) -> *const trace_context_t;
2057
2058 pub fn trace_acquire_context_for_category_cached(
2059 category_literal: *const libc::c_char,
2060 trace_site: *const u64,
2061 out_ref: *mut trace_string_ref_t,
2062 ) -> *const trace_context_t;
2063
2064 pub fn trace_release_context(context: *const trace_context_t);
2065
2066 pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2067
2068 pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2069
2070 pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2071
2072 pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2073
2074 pub fn trace_notify_observer_updated(event: zx_handle_t);
2075
2076 pub fn trace_context_get_buffering_mode(
2077 context: *const trace_context_t,
2078 ) -> trace_buffering_mode_t;
2079 }
2080}
2081
2082pub struct TraceFutureArgs<'a> {
2085 pub category: &'static CStr,
2086 pub name: &'static CStr,
2087
2088 pub context: Option<TraceCategoryContext>,
2092
2093 pub args: Vec<Arg<'a>>,
2096
2097 pub flow_id: Option<Id>,
2100
2101 pub _use_trace_future_args: (),
2103}
2104
2105#[doc(hidden)]
2106#[macro_export]
2107macro_rules! __impl_trace_future_args {
2108 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2109 {
2110 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2111 let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2112 let args = if context.is_some() {
2113 vec![$($crate::ArgValue::of($key, $val)),*]
2114 } else {
2115 vec![]
2116 };
2117 $crate::TraceFutureArgs {
2118 category: $category,
2119 name: $name,
2120 context: context,
2121 args: args,
2122 flow_id: $flow_id,
2123 _use_trace_future_args: (),
2124 }
2125 }
2126 }};
2127}
2128
2129#[macro_export]
2141macro_rules! trace_future_args {
2142 ($category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
2143 $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
2144 };
2145 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
2146 $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
2147 };
2148}
2149
2150pub trait TraceFutureExt: Future + Sized {
2152 fn trace<'a>(self, args: TraceFutureArgs<'a>) -> TraceFuture<'a, Self> {
2166 TraceFuture::new(args, self)
2167 }
2168}
2169
2170impl<T: Future + Sized> TraceFutureExt for T {}
2171
2172#[pin_project(PinnedDrop)]
2175pub struct TraceFuture<'a, Fut: Future> {
2176 category: &'static CStr,
2177 name: &'static CStr,
2178 args: Vec<Arg<'a>>,
2179 flow_id: Option<Id>,
2180 #[pin]
2181 future: Pin<Box<Fut>>,
2183}
2184
2185impl<'a, Fut: Future> TraceFuture<'a, Fut> {
2186 pub fn new(args: TraceFutureArgs<'a>, future: Fut) -> Self {
2187 debug_assert!(
2188 args.context.is_some() || args.args.is_empty(),
2189 "There should not be any trace arguments when the category is disabled"
2190 );
2191 let mut this = Self {
2192 category: args.category,
2193 name: args.name,
2194 args: args.args,
2195 flow_id: args.flow_id,
2196 future: Box::pin(future),
2197 };
2198 if let Some(context) = args.context {
2199 this.trace_create(context);
2200 }
2201 this
2202 }
2203
2204 #[cold]
2205 fn trace_create(&mut self, context: TraceCategoryContext) {
2206 let name_ref = context.register_string_literal(self.name);
2207 let flow_id = self.flow_id.get_or_insert_with(Id::new);
2208 let duration_start = zx::BootTicks::get();
2209 context.write_flow_begin(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2210 self.args.push(ArgValue::of("state", "created"));
2211 context.write_duration(name_ref, duration_start, &self.args);
2212 self.args.pop();
2213 }
2214
2215 #[cold]
2216 fn trace_poll(
2217 self: Pin<&mut Self>,
2218 context: TraceCategoryContext,
2219 cx: &mut std::task::Context<'_>,
2220 ) -> Poll<Fut::Output> {
2221 let this = self.project();
2222 let name_ref = context.register_string_literal(this.name);
2223 let flow_id = this.flow_id.get_or_insert_with(Id::new);
2224 let duration_start = zx::BootTicks::get();
2225 context.write_flow_step(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2226 let result = this.future.poll(cx);
2227 let result_str: &'static str = if result.is_pending() { "pending" } else { "ready" };
2228 this.args.push(ArgValue::of("state", result_str));
2229 context.write_duration(name_ref, duration_start, &this.args);
2230 this.args.pop();
2231 result
2232 }
2233
2234 #[cold]
2235 fn trace_drop(self: Pin<&mut Self>, context: TraceCategoryContext) {
2236 let this = self.project();
2237 let name_ref = context.register_string_literal(this.name);
2238 let flow_id = this.flow_id.get_or_insert_with(Id::new);
2239 let duration_start = zx::BootTicks::get();
2240 context.write_flow_end(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2241 this.args.push(ArgValue::of("state", "dropped"));
2242 context.write_duration(name_ref, duration_start, &this.args);
2243 this.args.pop();
2244 }
2245}
2246
2247impl<Fut: Future> Future for TraceFuture<'_, Fut> {
2248 type Output = Fut::Output;
2249 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
2250 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2251 self.trace_poll(context, cx)
2252 } else {
2253 self.project().future.poll(cx)
2254 }
2255 }
2256}
2257
2258#[pin_project::pinned_drop]
2259impl<Fut: Future> PinnedDrop for TraceFuture<'_, Fut> {
2260 fn drop(self: Pin<&mut Self>) {
2261 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2262 self.trace_drop(context);
2263 }
2264 }
2265}
2266
2267#[cfg(test)]
2268mod test {
2269 use super::{trim_to_last_char_boundary, Id};
2270
2271 #[test]
2272 fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
2273 assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
2274 assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
2275 assert_eq!(b"", trim_to_last_char_boundary("x", 0));
2276 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
2277 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
2278 assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
2279
2280 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
2281 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
2282 assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
2283 }
2284
2285 #[test]
2289 fn test_id_new() {
2290 assert_ne!(Id::new(), Id::new());
2291 }
2292}