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