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
121pub trait AsTraceStrRef {
122 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t;
123}
124
125impl AsTraceStrRef for &'static str {
126 fn as_trace_str_ref(&self, context: &TraceCategoryContext) -> sys::trace_string_ref_t {
127 context.register_str(self)
128 }
129}
130
131impl AsTraceStrRef for String {
132 fn as_trace_str_ref(&self, _context: &TraceCategoryContext) -> sys::trace_string_ref_t {
133 trace_make_inline_string_ref(self.as_str())
134 }
135}
136
137#[repr(transparent)]
139pub struct Arg<'a>(sys::trace_arg_t, PhantomData<&'a ()>);
140
141pub trait ArgValue {
147 fn of<'a>(key: &'a str, value: Self) -> Arg<'a>
148 where
149 Self: 'a;
150 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, value: Self) -> Arg<'a>
151 where
152 Self: 'a;
153}
154
155macro_rules! arg_from {
161 ($valname:ident, $(($type:ty, $tag:expr, $value:expr))*) => {
162 $(
163 impl ArgValue for $type {
164 #[inline]
165 fn of<'a>(key: &'a str, $valname: Self) -> Arg<'a>
166 where Self: 'a
167 {
168 #[allow(unused)]
169 let $valname = $valname;
170
171 Arg(sys::trace_arg_t {
172 name_ref: trace_make_inline_string_ref(key),
173 value: sys::trace_arg_value_t {
174 type_: $tag,
175 value: $value,
176 },
177 }, PhantomData)
178 }
179 #[inline]
180 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, $valname: Self) -> Arg<'a>
181 where Self: 'a
182 {
183 #[allow(unused)]
184 let $valname = $valname;
185
186 Arg(sys::trace_arg_t {
187 name_ref,
188 value: sys::trace_arg_value_t {
189 type_: $tag,
190 value: $value,
191 },
192 }, PhantomData)
193 }
194 }
195 )*
196 }
197}
198
199#[rustfmt::skip]
201arg_from!(val,
202 ((), sys::TRACE_ARG_NULL, sys::trace_arg_union_t { int32_value: 0 })
203 (bool, sys::TRACE_ARG_BOOL, sys::trace_arg_union_t { bool_value: val })
204 (i32, sys::TRACE_ARG_INT32, sys::trace_arg_union_t { int32_value: val })
205 (u32, sys::TRACE_ARG_UINT32, sys::trace_arg_union_t { uint32_value: val })
206 (i64, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val })
207 (u64, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val })
208 (isize, sys::TRACE_ARG_INT64, sys::trace_arg_union_t { int64_value: val as i64 })
209 (usize, sys::TRACE_ARG_UINT64, sys::trace_arg_union_t { uint64_value: val as u64 })
210 (f64, sys::TRACE_ARG_DOUBLE, sys::trace_arg_union_t { double_value: val })
211 (zx::Koid, sys::TRACE_ARG_KOID, sys::trace_arg_union_t { koid_value: val.raw_koid() })
212);
213
214impl<T> ArgValue for *const T {
215 #[inline]
216 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
217 where
218 Self: 'a,
219 {
220 Arg(
221 sys::trace_arg_t {
222 name_ref: trace_make_inline_string_ref(key),
223 value: sys::trace_arg_value_t {
224 type_: sys::TRACE_ARG_POINTER,
225 value: sys::trace_arg_union_t { pointer_value: val as usize },
226 },
227 },
228 PhantomData,
229 )
230 }
231 #[inline]
232 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
233 where
234 Self: 'a,
235 {
236 Arg(
237 sys::trace_arg_t {
238 name_ref,
239 value: sys::trace_arg_value_t {
240 type_: sys::TRACE_ARG_POINTER,
241 value: sys::trace_arg_union_t { pointer_value: val as usize },
242 },
243 },
244 PhantomData,
245 )
246 }
247}
248
249impl<T> ArgValue for *mut T {
250 #[inline]
251 fn of<'a>(key: &'a str, val: Self) -> Arg<'a>
252 where
253 Self: 'a,
254 {
255 Arg(
256 sys::trace_arg_t {
257 name_ref: trace_make_inline_string_ref(key),
258 value: sys::trace_arg_value_t {
259 type_: sys::TRACE_ARG_POINTER,
260 value: sys::trace_arg_union_t { pointer_value: val as usize },
261 },
262 },
263 PhantomData,
264 )
265 }
266 #[inline]
267 fn of_registered<'a>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'a>
268 where
269 Self: 'a,
270 {
271 Arg(
272 sys::trace_arg_t {
273 name_ref,
274 value: sys::trace_arg_value_t {
275 type_: sys::TRACE_ARG_POINTER,
276 value: sys::trace_arg_union_t { pointer_value: val as usize },
277 },
278 },
279 PhantomData,
280 )
281 }
282}
283
284impl<'a> ArgValue for &'a str {
285 #[inline]
286 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
287 where
288 Self: 'b,
289 {
290 Arg(
291 sys::trace_arg_t {
292 name_ref: trace_make_inline_string_ref(key),
293 value: sys::trace_arg_value_t {
294 type_: sys::TRACE_ARG_STRING,
295 value: sys::trace_arg_union_t {
296 string_value_ref: trace_make_inline_string_ref(val),
297 },
298 },
299 },
300 PhantomData,
301 )
302 }
303 #[inline]
304 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
305 where
306 Self: 'b,
307 {
308 Arg(
309 sys::trace_arg_t {
310 name_ref,
311 value: sys::trace_arg_value_t {
312 type_: sys::TRACE_ARG_STRING,
313 value: sys::trace_arg_union_t {
314 string_value_ref: trace_make_inline_string_ref(val),
315 },
316 },
317 },
318 PhantomData,
319 )
320 }
321}
322
323impl<'a> ArgValue for sys::trace_string_ref_t {
324 #[inline]
325 fn of<'b>(key: &'b str, val: Self) -> Arg<'b>
326 where
327 Self: 'b,
328 {
329 Arg(
330 sys::trace_arg_t {
331 name_ref: trace_make_inline_string_ref(key),
332 value: sys::trace_arg_value_t {
333 type_: sys::TRACE_ARG_STRING,
334 value: sys::trace_arg_union_t { string_value_ref: val },
335 },
336 },
337 PhantomData,
338 )
339 }
340 #[inline]
341 fn of_registered<'b>(name_ref: sys::trace_string_ref_t, val: Self) -> Arg<'b>
342 where
343 Self: 'b,
344 {
345 Arg(
346 sys::trace_arg_t {
347 name_ref,
348 value: sys::trace_arg_value_t {
349 type_: sys::TRACE_ARG_STRING,
350 value: sys::trace_arg_union_t { string_value_ref: val },
351 },
352 },
353 PhantomData,
354 )
355 }
356}
357
358#[macro_export]
380macro_rules! instant {
381 ($category:expr, $name:expr, $scope:expr $(, $key:expr => $val:expr)*) => {
382 {
383 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
384 use $crate::AsTraceStrRef;
385 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
386 $crate::instant(&context, $name, $scope, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
387 }
388 }
389 }
390}
391
392#[inline]
395pub fn instant(
396 context: &TraceCategoryContext,
397 name: &'static CStr,
398 scope: Scope,
399 args: &[Arg<'_>],
400) {
401 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
402
403 let name_ref = context.register_string_literal(name);
404 context.write_instant(name_ref, scope, args);
405}
406
407#[macro_export]
421macro_rules! alert {
422 ($category:expr, $name:expr) => {
423 $crate::alert($category, $name)
424 };
425}
426
427pub fn alert(category: &'static CStr, name: &'static CStr) {
429 unsafe {
433 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
434 let context =
435 sys::trace_acquire_context_for_category(category.as_ptr(), category_ref.as_mut_ptr());
436 if context != ptr::null() {
437 sys::trace_context_send_alert(context, name.as_ptr());
438 sys::trace_release_context(context);
439 }
440 }
441}
442
443#[macro_export]
460macro_rules! counter {
461 ($category:expr, $name:expr, $counter_id:expr $(, $key:expr => $val:expr)*) => {
462 {
463 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
464 use $crate::AsTraceStrRef;
465 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
466 $crate::counter(&context, $name, $counter_id,
467 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
468 }
469 }
470 }
471}
472
473pub fn counter(
483 context: &TraceCategoryContext,
484 name: &'static CStr,
485 counter_id: u64,
486 args: &[Arg<'_>],
487) {
488 assert!(args.len() >= 1, "trace counter args must include at least one numeric argument");
489 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
490
491 let name_ref = context.register_string_literal(name);
492 context.write_counter(name_ref, counter_id, args);
493}
494
495#[must_use = "DurationScope must be `end`ed to be recorded"]
498pub struct DurationScope<'a> {
499 category: &'static CStr,
500 name: &'static CStr,
501 args: &'a [Arg<'a>],
502 start_time: zx::BootTicks,
503}
504
505impl<'a> DurationScope<'a> {
506 pub fn begin(category: &'static CStr, name: &'static CStr, args: &'a [Arg<'_>]) -> Self {
509 let start_time = zx::BootTicks::get();
510 Self { category, name, args, start_time }
511 }
512}
513
514impl<'a> Drop for DurationScope<'a> {
515 fn drop(&mut self) {
516 if let Some(context) = TraceCategoryContext::acquire(self.category) {
517 let name_ref = context.register_string_literal(self.name);
518 context.write_duration(name_ref, self.start_time, self.args);
519 }
520 }
521}
522
523pub fn complete_duration(
525 category: &'static CStr,
526 name: &'static CStr,
527 start_time: zx::BootTicks,
528 args: &[Arg<'_>],
529) {
530 if let Some(context) = TraceCategoryContext::acquire(category) {
531 let name_ref = context.register_string_literal(name);
532 context.write_duration(name_ref, start_time, args);
533 }
534}
535
536#[macro_export]
571macro_rules! duration {
572 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
573 let mut args;
574 let _scope = {
575 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
576 use $crate::AsTraceStrRef;
583 if let Some(context) =
584 $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
585 args = [$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*];
586 Some($crate::duration($category, $name, &args))
587 } else {
588 None
589 }
590 };
591 }
592}
593
594pub fn duration<'a>(
606 category: &'static CStr,
607 name: &'static CStr,
608 args: &'a [Arg<'_>],
609) -> DurationScope<'a> {
610 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
611 DurationScope::begin(category, name, args)
612}
613
614#[macro_export]
628macro_rules! duration_begin {
629 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
630 {
631 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
632 use $crate::AsTraceStrRef;
633 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
634 $crate::duration_begin(&context, $name,
635 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
636 }
637 }
638 };
639}
640
641#[macro_export]
655macro_rules! duration_end {
656 ($category:expr, $name:expr $(, $key:expr => $val:expr)* $(,)?) => {
657 {
658 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
659 use $crate::AsTraceStrRef;
660 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
661 $crate::duration_end(&context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
662 }
663 }
664 };
665}
666
667pub fn duration_begin(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
678 let ticks = zx::BootTicks::get();
679 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
680
681 let name_ref = context.register_string_literal(name);
682 context.write_duration_begin(ticks, name_ref, args);
683}
684
685pub fn duration_end(context: &TraceCategoryContext, name: &'static CStr, args: &[Arg<'_>]) {
695 let ticks = zx::BootTicks::get();
696 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
697
698 let name_ref = context.register_string_literal(name);
699 context.write_duration_end(ticks, name_ref, args);
700}
701
702#[must_use = "emits an end event when dropped, so if dropped immediately creates an essentially \
705 zero length duration that should just be an instant instead"]
706pub struct AsyncScope {
707 id: Id,
710 category: &'static CStr,
711 name: &'static CStr,
712}
713impl AsyncScope {
714 pub fn begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) -> Self {
717 async_begin(id, category, name, args);
718 Self { id, category, name }
719 }
720
721 pub fn end(self, args: &[Arg<'_>]) {
724 let Self { id, category, name } = self;
725 async_end(id, category, name, args);
726 std::mem::forget(self);
727 }
728}
729
730impl Drop for AsyncScope {
731 fn drop(&mut self) {
732 let Self { id, category, name } = *self;
736 async_end(id, category, name, &[]);
737 }
738}
739
740pub fn async_enter(
749 id: Id,
750 category: &'static CStr,
751 name: &'static CStr,
752 args: &[Arg<'_>],
753) -> AsyncScope {
754 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
755 AsyncScope::begin(id, category, name, args)
756}
757
758#[macro_export]
789macro_rules! async_enter {
790 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
791 {
792 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
793 use $crate::AsTraceStrRef;
794 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
795 Some($crate::AsyncScope::begin($id, $category, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]))
796 } else {
797 None
798 }
799 }
800 }
801}
802
803#[macro_export]
827macro_rules! async_instant {
828 ($id:expr, $category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
829 {
830 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
831 use $crate::AsTraceStrRef;
832 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
833 $crate::async_instant($id, &context, $name, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]);
834 }
835 }
836 }
837}
838
839pub fn async_begin(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
851 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
852
853 if let Some(context) = TraceCategoryContext::acquire(category) {
854 let name_ref = context.register_string_literal(name);
855 context.write_async_begin(id, name_ref, args);
856 }
857}
858
859pub fn async_end(id: Id, category: &'static CStr, name: &'static CStr, args: &[Arg<'_>]) {
871 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
872
873 if let Some(context) = TraceCategoryContext::acquire(category) {
874 let name_ref = context.register_string_literal(name);
875 context.write_async_end(id, name_ref, args);
876 }
877}
878
879pub fn async_instant(
891 id: Id,
892 context: &TraceCategoryContext,
893 name: &'static CStr,
894 args: &[Arg<'_>],
895) {
896 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
897
898 let name_ref = context.register_string_literal(name);
899 context.write_async_instant(id, name_ref, args);
900}
901
902#[macro_export]
903macro_rules! blob {
904 ($category:expr, $name:expr, $bytes:expr $(, $key:expr => $val:expr)*) => {
905 {
906 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
907 use $crate::AsTraceStrRef;
908 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
909 $crate::blob_fn(&context, $name, $bytes, &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
910 }
911 }
912 }
913}
914pub fn blob_fn(
915 context: &TraceCategoryContext,
916 name: &'static CStr,
917 bytes: &[u8],
918 args: &[Arg<'_>],
919) {
920 let name_ref = context.register_string_literal(name);
921 context.write_blob(name_ref, bytes, args);
922}
923
924#[macro_export]
939macro_rules! flow_begin {
940 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
941 {
942 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
943 use $crate::AsTraceStrRef;
944 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
945 $crate::flow_begin(&context, $name, $flow_id,
946 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
947 }
948 }
949 }
950}
951
952#[macro_export]
967macro_rules! flow_step {
968 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
969 {
970 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
971 use $crate::AsTraceStrRef;
972 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
973 $crate::flow_step(&context, $name, $flow_id,
974 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
975 }
976 }
977 }
978}
979
980#[macro_export]
995macro_rules! flow_end {
996 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
997 {
998 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
999 use $crate::AsTraceStrRef;
1000 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1001 $crate::flow_end(&context, $name, $flow_id,
1002 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*])
1003 }
1004 }
1005 }
1006}
1007
1008pub fn flow_begin(
1027 context: &TraceCategoryContext,
1028 name: &'static CStr,
1029 flow_id: Id,
1030 args: &[Arg<'_>],
1031) {
1032 let ticks = zx::BootTicks::get();
1033 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1034
1035 let name_ref = context.register_string_literal(name);
1036 context.write_flow_begin(ticks, name_ref, flow_id, args);
1037}
1038
1039pub fn flow_end(
1056 context: &TraceCategoryContext,
1057 name: &'static CStr,
1058 flow_id: Id,
1059 args: &[Arg<'_>],
1060) {
1061 let ticks = zx::BootTicks::get();
1062 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1063
1064 let name_ref = context.register_string_literal(name);
1065 context.write_flow_end(ticks, name_ref, flow_id, args);
1066}
1067
1068pub fn flow_step(
1085 context: &TraceCategoryContext,
1086 name: &'static CStr,
1087 flow_id: Id,
1088 args: &[Arg<'_>],
1089) {
1090 let ticks = zx::BootTicks::get();
1091 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1092
1093 let name_ref = context.register_string_literal(name);
1094 context.write_flow_step(ticks, name_ref, flow_id, args);
1095}
1096
1097#[macro_export]
1111macro_rules! instaflow_begin {
1112 (
1113 $category:expr,
1114 $flow_name:expr,
1115 $step_name:expr,
1116 $flow_id:expr
1117 $(, $key:expr => $val:expr)*
1118 ) => {
1119 {
1120 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1121 use $crate::AsTraceStrRef;
1122 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1123 $crate::instaflow_begin(
1124 &context,
1125 $flow_name,
1126 $step_name,
1127 $flow_id,
1128 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1129 )
1130 }
1131 }
1132 }
1133}
1134
1135#[macro_export]
1149macro_rules! instaflow_end {
1150 (
1151 $category:expr,
1152 $flow_name:expr,
1153 $step_name:expr,
1154 $flow_id:expr
1155 $(, $key:expr => $val:expr)*
1156 ) => {
1157 {
1158 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1159 use $crate::AsTraceStrRef;
1160 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1161 $crate::instaflow_end(
1162 &context,
1163 $flow_name,
1164 $step_name,
1165 $flow_id,
1166 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1167 )
1168 }
1169 }
1170 }
1171}
1172
1173#[macro_export]
1187macro_rules! instaflow_step {
1188 (
1189 $category:expr,
1190 $flow_name:expr,
1191 $step_name:expr,
1192 $flow_id:expr
1193 $(, $key:expr => $val:expr)*
1194 ) => {
1195 {
1196 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
1197 use $crate::AsTraceStrRef;
1198 if let Some(context) = $crate::TraceCategoryContext::acquire_cached($category, &CACHE) {
1199 $crate::instaflow_step(
1200 &context,
1201 $flow_name,
1202 $step_name,
1203 $flow_id,
1204 &[$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*],
1205 )
1206 }
1207 }
1208 }
1209}
1210
1211pub fn instaflow_begin(
1223 context: &TraceCategoryContext,
1224 flow_name: &'static CStr,
1225 step_name: &'static CStr,
1226 flow_id: Id,
1227 args: &[Arg<'_>],
1228) {
1229 let ticks = zx::BootTicks::get();
1230 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1231
1232 let flow_name_ref = context.register_string_literal(flow_name);
1233 let step_name_ref = context.register_string_literal(step_name);
1234
1235 context.write_duration_begin(ticks, step_name_ref, args);
1236 context.write_flow_begin(ticks, flow_name_ref, flow_id, args);
1237 context.write_duration_end(ticks, step_name_ref, args);
1238}
1239
1240pub fn instaflow_end(
1252 context: &TraceCategoryContext,
1253 flow_name: &'static CStr,
1254 step_name: &'static CStr,
1255 flow_id: Id,
1256 args: &[Arg<'_>],
1257) {
1258 let ticks = zx::BootTicks::get();
1259 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1260
1261 let flow_name_ref = context.register_string_literal(flow_name);
1262 let step_name_ref = context.register_string_literal(step_name);
1263
1264 context.write_duration_begin(ticks, step_name_ref, args);
1265 context.write_flow_end(ticks, flow_name_ref, flow_id, args);
1266 context.write_duration_end(ticks, step_name_ref, args);
1267}
1268
1269pub fn instaflow_step(
1281 context: &TraceCategoryContext,
1282 flow_name: &'static CStr,
1283 step_name: &'static CStr,
1284 flow_id: Id,
1285 args: &[Arg<'_>],
1286) {
1287 let ticks = zx::BootTicks::get();
1288 assert!(args.len() <= 15, "no more than 15 trace arguments are supported");
1289
1290 let flow_name_ref = context.register_string_literal(flow_name);
1291 let step_name_ref = context.register_string_literal(step_name);
1292
1293 context.write_duration_begin(ticks, step_name_ref, args);
1294 context.write_flow_step(ticks, flow_name_ref, flow_id, args);
1295 context.write_duration_end(ticks, step_name_ref, args);
1296}
1297
1298const fn trace_make_empty_string_ref() -> sys::trace_string_ref_t {
1300 sys::trace_string_ref_t {
1301 encoded_value: sys::TRACE_ENCODED_STRING_REF_EMPTY,
1302 inline_string: ptr::null(),
1303 }
1304}
1305
1306#[inline]
1307fn trim_to_last_char_boundary(string: &str, max_len: usize) -> &[u8] {
1308 let mut len = string.len();
1309 if string.len() > max_len {
1310 len = max_len;
1314 while len > 0 {
1315 if string.is_char_boundary(len - 1) && string.is_char_boundary(len) {
1316 break;
1317 }
1318 len -= 1;
1319 }
1320 }
1321 &string.as_bytes()[0..len]
1322}
1323
1324#[inline]
1327fn trace_make_inline_string_ref(string: &str) -> sys::trace_string_ref_t {
1328 let len = string.len() as u16;
1329 if len == 0 {
1330 return trace_make_empty_string_ref();
1331 }
1332
1333 let string = trim_to_last_char_boundary(string, sys::TRACE_ENCODED_STRING_REF_MAX_LENGTH);
1334
1335 sys::trace_string_ref_t {
1336 encoded_value: sys::TRACE_ENCODED_STRING_REF_INLINE_FLAG | len,
1337 inline_string: string.as_ptr() as *const libc::c_char,
1338 }
1339}
1340
1341pub struct TraceCategoryContext {
1343 raw: *const sys::trace_context_t,
1344 category_ref: sys::trace_string_ref_t,
1345}
1346
1347impl TraceCategoryContext {
1348 #[inline]
1349 pub fn acquire_cached(
1350 category: &'static CStr,
1351 site: &sys::trace_site_t,
1352 ) -> Option<TraceCategoryContext> {
1353 unsafe {
1354 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1359 let raw = sys::trace_acquire_context_for_category_cached(
1360 category.as_ptr(),
1361 site.as_ptr(),
1362 category_ref.as_mut_ptr(),
1363 );
1364 if raw != ptr::null() {
1365 Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1366 } else {
1367 None
1368 }
1369 }
1370 }
1371
1372 pub fn acquire(category: &'static CStr) -> Option<TraceCategoryContext> {
1373 unsafe {
1374 let mut category_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1375 let raw = sys::trace_acquire_context_for_category(
1376 category.as_ptr(),
1377 category_ref.as_mut_ptr(),
1378 );
1379 if raw != ptr::null() {
1380 Some(TraceCategoryContext { raw, category_ref: category_ref.assume_init() })
1381 } else {
1382 None
1383 }
1384 }
1385 }
1386
1387 #[inline]
1388 pub fn register_string_literal(&self, name: &'static CStr) -> sys::trace_string_ref_t {
1389 unsafe {
1390 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1391 sys::trace_context_register_string_literal(
1392 self.raw,
1393 name.as_ptr(),
1394 name_ref.as_mut_ptr(),
1395 );
1396 name_ref.assume_init()
1397 }
1398 }
1399
1400 #[inline]
1401 #[cfg(fuchsia_api_level_at_least = "27")]
1402 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1403 unsafe {
1404 let mut name_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1405 sys::trace_context_register_bytestring(
1406 self.raw,
1407 name.as_ptr().cast::<libc::c_char>(),
1408 name.len(),
1409 name_ref.as_mut_ptr(),
1410 );
1411 name_ref.assume_init()
1412 }
1413 }
1414 #[inline]
1415 #[cfg(not(fuchsia_api_level_at_least = "27"))]
1416 pub fn register_str(&self, name: &'static str) -> sys::trace_string_ref_t {
1417 trace_make_inline_string_ref(name)
1418 }
1419
1420 #[inline]
1421 fn register_current_thread(&self) -> sys::trace_thread_ref_t {
1422 unsafe {
1423 let mut thread_ref = mem::MaybeUninit::<sys::trace_thread_ref_t>::uninit();
1424 sys::trace_context_register_current_thread(self.raw, thread_ref.as_mut_ptr());
1425 thread_ref.assume_init()
1426 }
1427 }
1428
1429 #[inline]
1430 pub fn write_instant(&self, name_ref: sys::trace_string_ref_t, scope: Scope, args: &[Arg<'_>]) {
1431 let ticks = zx::BootTicks::get();
1432 let thread_ref = self.register_current_thread();
1433 unsafe {
1434 sys::trace_context_write_instant_event_record(
1435 self.raw,
1436 ticks.into_raw(),
1437 &thread_ref,
1438 &self.category_ref,
1439 &name_ref,
1440 scope.into_raw(),
1441 args.as_ptr() as *const sys::trace_arg_t,
1442 args.len(),
1443 );
1444 }
1445 }
1446
1447 pub fn write_instant_with_inline_name(&self, name: &str, scope: Scope, args: &[Arg<'_>]) {
1448 let name_ref = trace_make_inline_string_ref(name);
1449 self.write_instant(name_ref, scope, args)
1450 }
1451
1452 fn write_counter(&self, name_ref: sys::trace_string_ref_t, counter_id: u64, args: &[Arg<'_>]) {
1453 let ticks = zx::BootTicks::get();
1454 let thread_ref = self.register_current_thread();
1455 unsafe {
1456 sys::trace_context_write_counter_event_record(
1457 self.raw,
1458 ticks.into_raw(),
1459 &thread_ref,
1460 &self.category_ref,
1461 &name_ref,
1462 counter_id,
1463 args.as_ptr() as *const sys::trace_arg_t,
1464 args.len(),
1465 );
1466 }
1467 }
1468
1469 pub fn write_counter_with_inline_name(&self, name: &str, counter_id: u64, args: &[Arg<'_>]) {
1470 let name_ref = trace_make_inline_string_ref(name);
1471 self.write_counter(name_ref, counter_id, args);
1472 }
1473
1474 fn write_duration(
1475 &self,
1476 name_ref: sys::trace_string_ref_t,
1477 start_time: zx::BootTicks,
1478 args: &[Arg<'_>],
1479 ) {
1480 let ticks = zx::BootTicks::get();
1481 let thread_ref = self.register_current_thread();
1482 unsafe {
1483 sys::trace_context_write_duration_event_record(
1484 self.raw,
1485 start_time.into_raw(),
1486 ticks.into_raw(),
1487 &thread_ref,
1488 &self.category_ref,
1489 &name_ref,
1490 args.as_ptr() as *const sys::trace_arg_t,
1491 args.len(),
1492 );
1493 }
1494 }
1495
1496 pub fn write_duration_with_inline_name(
1497 &self,
1498 name: &str,
1499 start_time: zx::BootTicks,
1500 args: &[Arg<'_>],
1501 ) {
1502 let name_ref = trace_make_inline_string_ref(name);
1503 self.write_duration(name_ref, start_time, args);
1504 }
1505
1506 fn write_duration_begin(
1507 &self,
1508 ticks: zx::BootTicks,
1509 name_ref: sys::trace_string_ref_t,
1510 args: &[Arg<'_>],
1511 ) {
1512 let thread_ref = self.register_current_thread();
1513 unsafe {
1514 sys::trace_context_write_duration_begin_event_record(
1515 self.raw,
1516 ticks.into_raw(),
1517 &thread_ref,
1518 &self.category_ref,
1519 &name_ref,
1520 args.as_ptr() as *const sys::trace_arg_t,
1521 args.len(),
1522 );
1523 }
1524 }
1525
1526 pub fn write_duration_begin_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1527 let name_ref = trace_make_inline_string_ref(name);
1528 self.write_duration_begin(zx::BootTicks::get(), name_ref, args);
1529 }
1530
1531 fn write_duration_end(
1532 &self,
1533 ticks: zx::BootTicks,
1534 name_ref: sys::trace_string_ref_t,
1535 args: &[Arg<'_>],
1536 ) {
1537 let thread_ref = self.register_current_thread();
1538 unsafe {
1539 sys::trace_context_write_duration_end_event_record(
1540 self.raw,
1541 ticks.into_raw(),
1542 &thread_ref,
1543 &self.category_ref,
1544 &name_ref,
1545 args.as_ptr() as *const sys::trace_arg_t,
1546 args.len(),
1547 );
1548 }
1549 }
1550
1551 pub fn write_duration_end_with_inline_name(&self, name: &str, args: &[Arg<'_>]) {
1552 let name_ref = trace_make_inline_string_ref(name);
1553 self.write_duration_end(zx::BootTicks::get(), name_ref, args);
1554 }
1555
1556 fn write_async_begin(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1557 let ticks = zx::BootTicks::get();
1558 let thread_ref = self.register_current_thread();
1559 unsafe {
1560 sys::trace_context_write_async_begin_event_record(
1561 self.raw,
1562 ticks.into_raw(),
1563 &thread_ref,
1564 &self.category_ref,
1565 &name_ref,
1566 id.into(),
1567 args.as_ptr() as *const sys::trace_arg_t,
1568 args.len(),
1569 );
1570 }
1571 }
1572
1573 pub fn write_async_begin_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1574 let name_ref = trace_make_inline_string_ref(name);
1575 self.write_async_begin(id, name_ref, args);
1576 }
1577
1578 fn write_async_end(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1579 let ticks = zx::BootTicks::get();
1580 let thread_ref = self.register_current_thread();
1581 unsafe {
1582 sys::trace_context_write_async_end_event_record(
1583 self.raw,
1584 ticks.into_raw(),
1585 &thread_ref,
1586 &self.category_ref,
1587 &name_ref,
1588 id.into(),
1589 args.as_ptr() as *const sys::trace_arg_t,
1590 args.len(),
1591 );
1592 }
1593 }
1594
1595 pub fn write_async_end_with_inline_name(&self, id: Id, name: &str, args: &[Arg<'_>]) {
1596 let name_ref = trace_make_inline_string_ref(name);
1597 self.write_async_end(id, name_ref, args);
1598 }
1599
1600 fn write_async_instant(&self, id: Id, name_ref: sys::trace_string_ref_t, args: &[Arg<'_>]) {
1601 let ticks = zx::BootTicks::get();
1602 let thread_ref = self.register_current_thread();
1603 unsafe {
1604 sys::trace_context_write_async_instant_event_record(
1605 self.raw,
1606 ticks.into_raw(),
1607 &thread_ref,
1608 &self.category_ref,
1609 &name_ref,
1610 id.into(),
1611 args.as_ptr() as *const sys::trace_arg_t,
1612 args.len(),
1613 );
1614 }
1615 }
1616
1617 fn write_blob(&self, name_ref: sys::trace_string_ref_t, bytes: &[u8], args: &[Arg<'_>]) {
1618 let ticks = zx::BootTicks::get();
1619 let thread_ref = self.register_current_thread();
1620 unsafe {
1621 sys::trace_context_write_blob_event_record(
1622 self.raw,
1623 ticks.into_raw(),
1624 &thread_ref,
1625 &self.category_ref,
1626 &name_ref,
1627 bytes.as_ptr() as *const core::ffi::c_void,
1628 bytes.len(),
1629 args.as_ptr() as *const sys::trace_arg_t,
1630 args.len(),
1631 );
1632 }
1633 }
1634
1635 fn write_flow_begin(
1636 &self,
1637 ticks: zx::BootTicks,
1638 name_ref: sys::trace_string_ref_t,
1639 flow_id: Id,
1640 args: &[Arg<'_>],
1641 ) {
1642 let thread_ref = self.register_current_thread();
1643 unsafe {
1644 sys::trace_context_write_flow_begin_event_record(
1645 self.raw,
1646 ticks.into_raw(),
1647 &thread_ref,
1648 &self.category_ref,
1649 &name_ref,
1650 flow_id.into(),
1651 args.as_ptr() as *const sys::trace_arg_t,
1652 args.len(),
1653 );
1654 }
1655 }
1656
1657 fn write_flow_end(
1658 &self,
1659 ticks: zx::BootTicks,
1660 name_ref: sys::trace_string_ref_t,
1661 flow_id: Id,
1662 args: &[Arg<'_>],
1663 ) {
1664 let thread_ref = self.register_current_thread();
1665 unsafe {
1666 sys::trace_context_write_flow_end_event_record(
1667 self.raw,
1668 ticks.into_raw(),
1669 &thread_ref,
1670 &self.category_ref,
1671 &name_ref,
1672 flow_id.into(),
1673 args.as_ptr() as *const sys::trace_arg_t,
1674 args.len(),
1675 );
1676 }
1677 }
1678
1679 fn write_flow_step(
1680 &self,
1681 ticks: zx::BootTicks,
1682 name_ref: sys::trace_string_ref_t,
1683 flow_id: Id,
1684 args: &[Arg<'_>],
1685 ) {
1686 let thread_ref = self.register_current_thread();
1687 unsafe {
1688 sys::trace_context_write_flow_step_event_record(
1689 self.raw,
1690 ticks.into_raw(),
1691 &thread_ref,
1692 &self.category_ref,
1693 &name_ref,
1694 flow_id.into(),
1695 args.as_ptr() as *const sys::trace_arg_t,
1696 args.len(),
1697 );
1698 }
1699 }
1700}
1701
1702impl std::ops::Drop for TraceCategoryContext {
1703 fn drop(&mut self) {
1704 unsafe {
1705 sys::trace_release_context(self.raw);
1706 }
1707 }
1708}
1709
1710pub struct Context {
1712 context: *const sys::trace_context_t,
1713}
1714
1715impl Context {
1716 #[inline]
1717 pub fn acquire() -> Option<Self> {
1718 let context = unsafe { sys::trace_acquire_context() };
1719 if context.is_null() {
1720 None
1721 } else {
1722 Some(Self { context })
1723 }
1724 }
1725
1726 #[inline]
1727 pub fn register_string_literal(&self, s: &'static CStr) -> sys::trace_string_ref_t {
1728 unsafe {
1729 let mut s_ref = mem::MaybeUninit::<sys::trace_string_ref_t>::uninit();
1730 sys::trace_context_register_string_literal(
1731 self.context,
1732 s.as_ptr(),
1733 s_ref.as_mut_ptr(),
1734 );
1735 s_ref.assume_init()
1736 }
1737 }
1738
1739 pub fn write_blob_record(
1740 &self,
1741 type_: sys::trace_blob_type_t,
1742 name_ref: &sys::trace_string_ref_t,
1743 data: &[u8],
1744 ) {
1745 unsafe {
1746 sys::trace_context_write_blob_record(
1747 self.context,
1748 type_,
1749 name_ref as *const sys::trace_string_ref_t,
1750 data.as_ptr() as *const libc::c_void,
1751 data.len(),
1752 );
1753 }
1754 }
1755
1756 pub fn copy_record(&self, buffer: &[u64]) -> Option<usize> {
1760 unsafe {
1761 let ptr =
1762 sys::trace_context_alloc_record(self.context, 8 * buffer.len() as libc::size_t);
1763 if ptr == std::ptr::null_mut() {
1764 return None;
1765 }
1766 ptr.cast::<u64>().copy_from(buffer.as_ptr(), buffer.len());
1767 };
1768 Some(buffer.len())
1769 }
1770
1771 pub fn buffering_mode(&self) -> BufferingMode {
1772 match unsafe { sys::trace_context_get_buffering_mode(self.context) } {
1773 sys::TRACE_BUFFERING_MODE_ONESHOT => BufferingMode::OneShot,
1774 sys::TRACE_BUFFERING_MODE_CIRCULAR => BufferingMode::Circular,
1775 sys::TRACE_BUFFERING_MODE_STREAMING => BufferingMode::Streaming,
1776 m => panic!("Unknown trace buffering mode: {:?}", m),
1777 }
1778 }
1779}
1780
1781impl std::ops::Drop for Context {
1782 fn drop(&mut self) {
1783 unsafe { sys::trace_release_context(self.context) }
1784 }
1785}
1786
1787pub struct ProlongedContext {
1788 context: *const sys::trace_prolonged_context_t,
1789}
1790
1791impl ProlongedContext {
1792 pub fn acquire() -> Option<Self> {
1793 let context = unsafe { sys::trace_acquire_prolonged_context() };
1794 if context.is_null() {
1795 None
1796 } else {
1797 Some(Self { context })
1798 }
1799 }
1800}
1801
1802impl Drop for ProlongedContext {
1803 fn drop(&mut self) {
1804 unsafe { sys::trace_release_prolonged_context(self.context) }
1805 }
1806}
1807
1808unsafe impl Send for ProlongedContext {}
1809
1810mod sys {
1811 #![allow(non_camel_case_types, unused)]
1812 use zx::sys::{zx_handle_t, zx_koid_t, zx_obj_type_t, zx_status_t, zx_ticks_t};
1813
1814 pub type trace_ticks_t = zx_ticks_t;
1815 pub type trace_counter_id_t = u64;
1816 pub type trace_async_id_t = u64;
1817 pub type trace_flow_id_t = u64;
1818 pub type trace_thread_state_t = u32;
1819 pub type trace_cpu_number_t = u32;
1820 pub type trace_string_index_t = u32;
1821 pub type trace_thread_index_t = u32;
1822 pub type trace_context_t = libc::c_void;
1823 pub type trace_prolonged_context_t = libc::c_void;
1824
1825 pub type trace_encoded_string_ref_t = u16;
1826 pub const TRACE_ENCODED_STRING_REF_EMPTY: trace_encoded_string_ref_t = 0;
1827 pub const TRACE_ENCODED_STRING_REF_INLINE_FLAG: trace_encoded_string_ref_t = 0x8000;
1828 pub const TRACE_ENCODED_STRING_REF_LENGTH_MASK: trace_encoded_string_ref_t = 0x7fff;
1829 pub const TRACE_ENCODED_STRING_REF_MAX_LENGTH: usize = 32000;
1830 pub const TRACE_ENCODED_STRING_REF_MIN_INDEX: trace_encoded_string_ref_t = 0x1;
1831 pub const TRACE_ENCODED_STRING_REF_MAX_INDEX: trace_encoded_string_ref_t = 0x7fff;
1832
1833 pub type trace_encoded_thread_ref_t = u32;
1834 pub const TRACE_ENCODED_THREAD_REF_INLINE: trace_encoded_thread_ref_t = 0;
1835 pub const TRACE_ENCODED_THREAD_MIN_INDEX: trace_encoded_thread_ref_t = 0x01;
1836 pub const TRACE_ENCODED_THREAD_MAX_INDEX: trace_encoded_thread_ref_t = 0xff;
1837
1838 pub type trace_state_t = libc::c_int;
1839 pub const TRACE_STOPPED: trace_state_t = 0;
1840 pub const TRACE_STARTED: trace_state_t = 1;
1841 pub const TRACE_STOPPING: trace_state_t = 2;
1842
1843 pub type trace_scope_t = libc::c_int;
1844 pub const TRACE_SCOPE_THREAD: trace_scope_t = 0;
1845 pub const TRACE_SCOPE_PROCESS: trace_scope_t = 1;
1846 pub const TRACE_SCOPE_GLOBAL: trace_scope_t = 2;
1847
1848 pub type trace_blob_type_t = libc::c_int;
1849 pub const TRACE_BLOB_TYPE_DATA: trace_blob_type_t = 1;
1850 pub const TRACE_BLOB_TYPE_LAST_BRANCH: trace_blob_type_t = 2;
1851 pub const TRACE_BLOB_TYPE_PERFETTO: trace_blob_type_t = 3;
1852
1853 pub type trace_buffering_mode_t = libc::c_int;
1854 pub const TRACE_BUFFERING_MODE_ONESHOT: trace_buffering_mode_t = 0;
1855 pub const TRACE_BUFFERING_MODE_CIRCULAR: trace_buffering_mode_t = 1;
1856 pub const TRACE_BUFFERING_MODE_STREAMING: trace_buffering_mode_t = 2;
1857
1858 #[repr(C)]
1859 #[derive(Copy, Clone)]
1860 pub struct trace_string_ref_t {
1861 pub encoded_value: trace_encoded_string_ref_t,
1862 pub inline_string: *const libc::c_char,
1863 }
1864
1865 pub type trace_site_t = std::sync::atomic::AtomicU64;
1869
1870 unsafe impl Send for trace_string_ref_t {}
1880 unsafe impl Sync for trace_string_ref_t {}
1881
1882 #[repr(C)]
1883 pub struct trace_thread_ref_t {
1884 pub encoded_value: trace_encoded_thread_ref_t,
1885 pub inline_process_koid: zx_koid_t,
1886 pub inline_thread_koid: zx_koid_t,
1887 }
1888
1889 #[repr(C)]
1890 pub struct trace_arg_t {
1891 pub name_ref: trace_string_ref_t,
1892 pub value: trace_arg_value_t,
1893 }
1894
1895 #[repr(C)]
1896 pub union trace_arg_union_t {
1897 pub int32_value: i32,
1898 pub uint32_value: u32,
1899 pub int64_value: i64,
1900 pub uint64_value: u64,
1901 pub double_value: libc::c_double,
1902 pub string_value_ref: trace_string_ref_t,
1903 pub pointer_value: libc::uintptr_t,
1904 pub koid_value: zx_koid_t,
1905 pub bool_value: bool,
1906 pub reserved_for_future_expansion: [libc::uintptr_t; 2],
1907 }
1908
1909 pub type trace_arg_type_t = libc::c_int;
1910 pub const TRACE_ARG_NULL: trace_arg_type_t = 0;
1911 pub const TRACE_ARG_INT32: trace_arg_type_t = 1;
1912 pub const TRACE_ARG_UINT32: trace_arg_type_t = 2;
1913 pub const TRACE_ARG_INT64: trace_arg_type_t = 3;
1914 pub const TRACE_ARG_UINT64: trace_arg_type_t = 4;
1915 pub const TRACE_ARG_DOUBLE: trace_arg_type_t = 5;
1916 pub const TRACE_ARG_STRING: trace_arg_type_t = 6;
1917 pub const TRACE_ARG_POINTER: trace_arg_type_t = 7;
1918 pub const TRACE_ARG_KOID: trace_arg_type_t = 8;
1919 pub const TRACE_ARG_BOOL: trace_arg_type_t = 9;
1920
1921 #[repr(C)]
1922 pub struct trace_arg_value_t {
1923 pub type_: trace_arg_type_t,
1924 pub value: trace_arg_union_t,
1925 }
1926
1927 #[repr(C)]
1928 pub struct trace_handler_ops_t {
1929 pub is_category_enabled:
1930 unsafe fn(handler: *const trace_handler_t, category: *const libc::c_char) -> bool,
1931 pub trace_started: unsafe fn(handler: *const trace_handler_t),
1932 pub trace_stopped: unsafe fn(
1933 handler: *const trace_handler_t,
1934 async_ptr: *const (), disposition: zx_status_t,
1936 buffer_bytes_written: libc::size_t,
1937 ),
1938 pub buffer_overflow: unsafe fn(handler: *const trace_handler_t),
1939 }
1940
1941 #[repr(C)]
1942 pub struct trace_handler_t {
1943 pub ops: *const trace_handler_ops_t,
1944 }
1945
1946 extern "C" {
1948 pub fn trace_context_is_category_enabled(
1951 context: *const trace_context_t,
1952 category_literal: *const libc::c_char,
1953 ) -> bool;
1954
1955 pub fn trace_context_register_string_literal(
1956 context: *const trace_context_t,
1957 string_literal: *const libc::c_char,
1958 out_ref: *mut trace_string_ref_t,
1959 );
1960
1961 #[cfg(fuchsia_api_level_at_least = "27")]
1962 pub fn trace_context_register_bytestring(
1963 context: *const trace_context_t,
1964 string_literal: *const libc::c_char,
1965 length: libc::size_t,
1966 out_ref: *mut trace_string_ref_t,
1967 );
1968
1969 pub fn trace_context_register_category_literal(
1970 context: *const trace_context_t,
1971 category_literal: *const libc::c_char,
1972 out_ref: *mut trace_string_ref_t,
1973 ) -> bool;
1974
1975 pub fn trace_context_register_current_thread(
1976 context: *const trace_context_t,
1977 out_ref: *mut trace_thread_ref_t,
1978 );
1979
1980 pub fn trace_context_register_thread(
1981 context: *const trace_context_t,
1982 process_koid: zx_koid_t,
1983 thread_koid: zx_koid_t,
1984 out_ref: *mut trace_thread_ref_t,
1985 );
1986
1987 pub fn trace_context_write_kernel_object_record(
1988 context: *const trace_context_t,
1989 koid: zx_koid_t,
1990 type_: zx_obj_type_t,
1991 args: *const trace_arg_t,
1992 num_args: libc::size_t,
1993 );
1994
1995 pub fn trace_context_write_kernel_object_record_for_handle(
1996 context: *const trace_context_t,
1997 handle: zx_handle_t,
1998 args: *const trace_arg_t,
1999 num_args: libc::size_t,
2000 );
2001
2002 pub fn trace_context_write_process_info_record(
2003 context: *const trace_context_t,
2004 process_koid: zx_koid_t,
2005 process_name_ref: *const trace_string_ref_t,
2006 );
2007
2008 pub fn trace_context_write_thread_info_record(
2009 context: *const trace_context_t,
2010 process_koid: zx_koid_t,
2011 thread_koid: zx_koid_t,
2012 thread_name_ref: *const trace_string_ref_t,
2013 );
2014
2015 pub fn trace_context_write_context_switch_record(
2016 context: *const trace_context_t,
2017 event_time: trace_ticks_t,
2018 cpu_number: trace_cpu_number_t,
2019 outgoing_thread_state: trace_thread_state_t,
2020 outgoing_thread_ref: *const trace_thread_ref_t,
2021 incoming_thread_ref: *const trace_thread_ref_t,
2022 );
2023
2024 pub fn trace_context_write_log_record(
2025 context: *const trace_context_t,
2026 event_time: trace_ticks_t,
2027 thread_ref: *const trace_thread_ref_t,
2028 log_message: *const libc::c_char,
2029 log_message_length: libc::size_t,
2030 );
2031
2032 pub fn trace_context_write_instant_event_record(
2033 context: *const trace_context_t,
2034 event_time: trace_ticks_t,
2035 thread_ref: *const trace_thread_ref_t,
2036 category_ref: *const trace_string_ref_t,
2037 name_ref: *const trace_string_ref_t,
2038 scope: trace_scope_t,
2039 args: *const trace_arg_t,
2040 num_args: libc::size_t,
2041 );
2042
2043 pub fn trace_context_send_alert(context: *const trace_context_t, name: *const libc::c_char);
2044
2045 pub fn trace_context_write_counter_event_record(
2046 context: *const trace_context_t,
2047 event_time: trace_ticks_t,
2048 thread_ref: *const trace_thread_ref_t,
2049 category_ref: *const trace_string_ref_t,
2050 name_ref: *const trace_string_ref_t,
2051 counter_id: trace_counter_id_t,
2052 args: *const trace_arg_t,
2053 num_args: libc::size_t,
2054 );
2055
2056 pub fn trace_context_write_duration_event_record(
2057 context: *const trace_context_t,
2058 start_time: trace_ticks_t,
2059 end_time: trace_ticks_t,
2060 thread_ref: *const trace_thread_ref_t,
2061 category_ref: *const trace_string_ref_t,
2062 name_ref: *const trace_string_ref_t,
2063 args: *const trace_arg_t,
2064 num_args: libc::size_t,
2065 );
2066
2067 pub fn trace_context_write_blob_event_record(
2068 context: *const trace_context_t,
2069 event_time: trace_ticks_t,
2070 thread_ref: *const trace_thread_ref_t,
2071 category_ref: *const trace_string_ref_t,
2072 name_ref: *const trace_string_ref_t,
2073 blob: *const libc::c_void,
2074 blob_size: libc::size_t,
2075 args: *const trace_arg_t,
2076 num_args: libc::size_t,
2077 );
2078
2079 pub fn trace_context_write_duration_begin_event_record(
2080 context: *const trace_context_t,
2081 event_time: trace_ticks_t,
2082 thread_ref: *const trace_thread_ref_t,
2083 category_ref: *const trace_string_ref_t,
2084 name_ref: *const trace_string_ref_t,
2085 args: *const trace_arg_t,
2086 num_args: libc::size_t,
2087 );
2088
2089 pub fn trace_context_write_duration_end_event_record(
2090 context: *const trace_context_t,
2091 event_time: trace_ticks_t,
2092 thread_ref: *const trace_thread_ref_t,
2093 category_ref: *const trace_string_ref_t,
2094 name_ref: *const trace_string_ref_t,
2095 args: *const trace_arg_t,
2096 num_args: libc::size_t,
2097 );
2098
2099 pub fn trace_context_write_async_begin_event_record(
2100 context: *const trace_context_t,
2101 event_time: trace_ticks_t,
2102 thread_ref: *const trace_thread_ref_t,
2103 category_ref: *const trace_string_ref_t,
2104 name_ref: *const trace_string_ref_t,
2105 async_id: trace_async_id_t,
2106 args: *const trace_arg_t,
2107 num_args: libc::size_t,
2108 );
2109
2110 pub fn trace_context_write_async_instant_event_record(
2111 context: *const trace_context_t,
2112 event_time: trace_ticks_t,
2113 thread_ref: *const trace_thread_ref_t,
2114 category_ref: *const trace_string_ref_t,
2115 name_ref: *const trace_string_ref_t,
2116 async_id: trace_async_id_t,
2117 args: *const trace_arg_t,
2118 num_args: libc::size_t,
2119 );
2120
2121 pub fn trace_context_write_async_end_event_record(
2122 context: *const trace_context_t,
2123 event_time: trace_ticks_t,
2124 thread_ref: *const trace_thread_ref_t,
2125 category_ref: *const trace_string_ref_t,
2126 name_ref: *const trace_string_ref_t,
2127 async_id: trace_async_id_t,
2128 args: *const trace_arg_t,
2129 num_args: libc::size_t,
2130 );
2131
2132 pub fn trace_context_write_flow_begin_event_record(
2133 context: *const trace_context_t,
2134 event_time: trace_ticks_t,
2135 thread_ref: *const trace_thread_ref_t,
2136 category_ref: *const trace_string_ref_t,
2137 name_ref: *const trace_string_ref_t,
2138 flow_id: trace_flow_id_t,
2139 args: *const trace_arg_t,
2140 num_args: libc::size_t,
2141 );
2142
2143 pub fn trace_context_write_flow_step_event_record(
2144 context: *const trace_context_t,
2145 event_time: trace_ticks_t,
2146 thread_ref: *const trace_thread_ref_t,
2147 category_ref: *const trace_string_ref_t,
2148 name_ref: *const trace_string_ref_t,
2149 flow_id: trace_flow_id_t,
2150 args: *const trace_arg_t,
2151 num_args: libc::size_t,
2152 );
2153
2154 pub fn trace_context_write_flow_end_event_record(
2155 context: *const trace_context_t,
2156 event_time: trace_ticks_t,
2157 thread_ref: *const trace_thread_ref_t,
2158 category_ref: *const trace_string_ref_t,
2159 name_ref: *const trace_string_ref_t,
2160 flow_id: trace_flow_id_t,
2161 args: *const trace_arg_t,
2162 num_args: libc::size_t,
2163 );
2164
2165 pub fn trace_context_write_initialization_record(
2166 context: *const trace_context_t,
2167 ticks_per_second: u64,
2168 );
2169
2170 pub fn trace_context_write_string_record(
2171 context: *const trace_context_t,
2172 index: trace_string_index_t,
2173 string: *const libc::c_char,
2174 length: libc::size_t,
2175 );
2176
2177 pub fn trace_context_write_thread_record(
2178 context: *const trace_context_t,
2179 index: trace_thread_index_t,
2180 procss_koid: zx_koid_t,
2181 thread_koid: zx_koid_t,
2182 );
2183
2184 pub fn trace_context_write_blob_record(
2185 context: *const trace_context_t,
2186 type_: trace_blob_type_t,
2187 name_ref: *const trace_string_ref_t,
2188 data: *const libc::c_void,
2189 size: libc::size_t,
2190 );
2191
2192 pub fn trace_context_alloc_record(
2193 context: *const trace_context_t,
2194 num_bytes: libc::size_t,
2195 ) -> *mut libc::c_void;
2196
2197 pub fn trace_generate_nonce() -> u64;
2200
2201 pub fn trace_state() -> trace_state_t;
2202
2203 pub fn trace_is_category_enabled(category_literal: *const libc::c_char) -> bool;
2204
2205 pub fn trace_acquire_context() -> *const trace_context_t;
2206
2207 pub fn trace_acquire_context_for_category(
2208 category_literal: *const libc::c_char,
2209 out_ref: *mut trace_string_ref_t,
2210 ) -> *const trace_context_t;
2211
2212 pub fn trace_acquire_context_for_category_cached(
2213 category_literal: *const libc::c_char,
2214 trace_site: *const u64,
2215 out_ref: *mut trace_string_ref_t,
2216 ) -> *const trace_context_t;
2217
2218 pub fn trace_release_context(context: *const trace_context_t);
2219
2220 pub fn trace_acquire_prolonged_context() -> *const trace_prolonged_context_t;
2221
2222 pub fn trace_release_prolonged_context(context: *const trace_prolonged_context_t);
2223
2224 pub fn trace_register_observer(event: zx_handle_t) -> zx_status_t;
2225
2226 pub fn trace_unregister_observer(event: zx_handle_t) -> zx_status_t;
2227
2228 pub fn trace_notify_observer_updated(event: zx_handle_t);
2229
2230 pub fn trace_context_get_buffering_mode(
2231 context: *const trace_context_t,
2232 ) -> trace_buffering_mode_t;
2233 }
2234}
2235
2236pub struct TraceFutureArgs<'a> {
2239 pub category: &'static CStr,
2240 pub name: &'static CStr,
2241
2242 pub context: Option<TraceCategoryContext>,
2246
2247 pub args: Vec<Arg<'a>>,
2250
2251 pub flow_id: Option<Id>,
2254
2255 pub _use_trace_future_args: (),
2257}
2258
2259#[doc(hidden)]
2260#[macro_export]
2261macro_rules! __impl_trace_future_args {
2262 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
2263 {
2264 static CACHE: $crate::trace_site_t = $crate::trace_site_t::new(0);
2265 use $crate::AsTraceStrRef;
2266 let context = $crate::TraceCategoryContext::acquire_cached($category, &CACHE);
2267 let args = if let Some(ref context) = &context {
2268 vec![$($crate::ArgValue::of_registered($key.as_trace_str_ref(&context), $val)),*]
2269 } else {
2270 vec![]
2271 };
2272 $crate::TraceFutureArgs {
2273 category: $category,
2274 name: $name,
2275 context: context,
2276 args: args,
2277 flow_id: $flow_id,
2278 _use_trace_future_args: (),
2279 }
2280 }
2281 }};
2282}
2283
2284#[macro_export]
2296macro_rules! trace_future_args {
2297 ($category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
2298 $crate::__impl_trace_future_args!($category, $name, None $(,$key => $val)*)
2299 };
2300 ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {
2301 $crate::__impl_trace_future_args!($category, $name, Some($flow_id) $(,$key => $val)*)
2302 };
2303}
2304
2305pub trait TraceFutureExt: Future + Sized {
2307 fn trace<'a>(self, args: TraceFutureArgs<'a>) -> TraceFuture<'a, Self> {
2321 TraceFuture::new(args, self)
2322 }
2323}
2324
2325impl<T: Future + Sized> TraceFutureExt for T {}
2326
2327#[pin_project(PinnedDrop)]
2330pub struct TraceFuture<'a, Fut: Future> {
2331 category: &'static CStr,
2332 name: &'static CStr,
2333 args: Vec<Arg<'a>>,
2334 flow_id: Option<Id>,
2335 #[pin]
2336 future: Pin<Box<Fut>>,
2338}
2339
2340impl<'a, Fut: Future> TraceFuture<'a, Fut> {
2341 pub fn new(args: TraceFutureArgs<'a>, future: Fut) -> Self {
2342 debug_assert!(
2343 args.context.is_some() || args.args.is_empty(),
2344 "There should not be any trace arguments when the category is disabled"
2345 );
2346 let mut this = Self {
2347 category: args.category,
2348 name: args.name,
2349 args: args.args,
2350 flow_id: args.flow_id,
2351 future: Box::pin(future),
2352 };
2353 if let Some(context) = args.context {
2354 this.trace_create(context);
2355 }
2356 this
2357 }
2358
2359 #[cold]
2360 fn trace_create(&mut self, context: TraceCategoryContext) {
2361 let name_ref = context.register_string_literal(self.name);
2362 let flow_id = self.flow_id.get_or_insert_with(Id::new);
2363 let duration_start = zx::BootTicks::get();
2364 context.write_flow_begin(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2365 self.args.push(ArgValue::of_registered(
2366 context.register_str("state"),
2367 context.register_str("created"),
2368 ));
2369 context.write_duration(name_ref, duration_start, &self.args);
2370 self.args.pop();
2371 }
2372
2373 #[cold]
2374 fn trace_poll(
2375 self: Pin<&mut Self>,
2376 context: TraceCategoryContext,
2377 cx: &mut std::task::Context<'_>,
2378 ) -> Poll<Fut::Output> {
2379 let this = self.project();
2380 let name_ref = context.register_string_literal(this.name);
2381 let flow_id = this.flow_id.get_or_insert_with(Id::new);
2382 let duration_start = zx::BootTicks::get();
2383 context.write_flow_step(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2384 let result = this.future.poll(cx);
2385 let result_str: sys::trace_string_ref_t = if result.is_pending() {
2386 context.register_str("pending")
2387 } else {
2388 context.register_str("ready")
2389 };
2390 this.args.push(ArgValue::of_registered(context.register_str("state"), result_str));
2391 context.write_duration(name_ref, duration_start, &this.args);
2392 this.args.pop();
2393 result
2394 }
2395
2396 #[cold]
2397 fn trace_drop(self: Pin<&mut Self>, context: TraceCategoryContext) {
2398 let this = self.project();
2399 let name_ref = context.register_string_literal(this.name);
2400 let flow_id = this.flow_id.get_or_insert_with(Id::new);
2401 let duration_start = zx::BootTicks::get();
2402 context.write_flow_end(zx::BootTicks::get(), name_ref, *flow_id, &[]);
2403 this.args.push(ArgValue::of_registered(
2404 context.register_str("state"),
2405 context.register_str("dropped"),
2406 ));
2407 context.write_duration(name_ref, duration_start, &this.args);
2408 this.args.pop();
2409 }
2410}
2411
2412impl<Fut: Future> Future for TraceFuture<'_, Fut> {
2413 type Output = Fut::Output;
2414 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Fut::Output> {
2415 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2416 self.trace_poll(context, cx)
2417 } else {
2418 self.project().future.poll(cx)
2419 }
2420 }
2421}
2422
2423#[pin_project::pinned_drop]
2424impl<Fut: Future> PinnedDrop for TraceFuture<'_, Fut> {
2425 fn drop(self: Pin<&mut Self>) {
2426 if let Some(context) = TraceCategoryContext::acquire(self.as_ref().get_ref().category) {
2427 self.trace_drop(context);
2428 }
2429 }
2430}
2431
2432#[cfg(test)]
2433mod test {
2434 use super::{trim_to_last_char_boundary, Id};
2435
2436 #[test]
2437 fn trim_to_last_char_boundary_trims_to_last_character_boundary() {
2438 assert_eq!(b"x", trim_to_last_char_boundary("x", 5));
2439 assert_eq!(b"x", trim_to_last_char_boundary("x", 1));
2440 assert_eq!(b"", trim_to_last_char_boundary("x", 0));
2441 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 6));
2442 assert_eq!(b"xxxxx", trim_to_last_char_boundary("xxxxx", 5));
2443 assert_eq!(b"xxxx", trim_to_last_char_boundary("xxxxx", 4));
2444
2445 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 5));
2446 assert_eq!("💩".as_bytes(), trim_to_last_char_boundary("💩", 4));
2447 assert_eq!(b"", trim_to_last_char_boundary("💩", 3));
2448 }
2449
2450 #[test]
2454 fn test_id_new() {
2455 assert_ne!(Id::new(), Id::new());
2456 }
2457}