hitrace/lib.rs
1//! HiTrace
2//!
3//! Safe bindings for the [`HiTrace`] tracing system on OpenHarmony.
4//! This crate does nothing if not compiled for OpenHarmony (`target_env = ohos`).
5//!
6//!
7//! # Usage
8//!
9//! `HiTrace` allows tracing Spans in a synchronous and stack based fashion.
10//!
11//! ## Examples
12//!
13//! ##
14//! ```
15//! # fn OH_HiTrace_StartTrace(_: * const core::ffi::c_char) {}
16//! # fn OH_HiTrace_FinishTrace() {}
17//! # fn step1() {}
18//! # fn step2() {}
19//! # use hitrace::{start_trace, finish_trace};
20//! # use std::ffi::CString;
21//! fn load_website() {
22//! start_trace(&c"step1");
23//! step1();
24//! finish_trace();
25//! start_trace(&CString::new("step2").unwrap());
26//! step2();
27//! finish_trace();
28//! }
29//! start_trace(&c"LoadingWebsite");
30//! load_website();
31//! finish_trace();
32//! ```
33//!
34//!
35//! [`HiTrace`]: <https://gitee.com/openharmony/hiviewdfx_hitrace>
36
37use std::ffi::{CStr, CString};
38use std::marker::PhantomData;
39
40pub fn start_trace<T: AsRef<CStr>>(name: &T) {
41 start_trace_cstr(name.as_ref())
42}
43
44#[cfg(all(target_env = "ohos", not(feature = "max_level_off")))]
45fn start_trace_cstr(name: &CStr) {
46 // SAFETY: We have a valid CStr, which is copied by `OH_HiTrace_StartTrace`.
47 unsafe {
48 hitrace_sys::OH_HiTrace_StartTrace(name.as_ptr());
49 }
50}
51
52#[cfg(any(not(target_env = "ohos"), feature = "max_level_off"))]
53fn start_trace_cstr(_: &CStr) {}
54
55/// Finishes the most recently started trace span
56pub fn finish_trace() {
57 #[cfg(all(target_env = "ohos", not(feature = "max_level_off")))]
58 fn finish_trace_() {
59 // Todo: We should check in the OpenHarmony code to make sure that
60 // `OH_HiTrace_FinishTrace` does not cause Memory Safety issues, if called
61 // without a corresponding previous `OH_HiTrace_StartTrace`.
62 unsafe {
63 hitrace_sys::OH_HiTrace_FinishTrace();
64 }
65 }
66
67 #[cfg(any(not(target_env = "ohos"), feature = "max_level_off"))]
68 fn finish_trace_() {}
69
70 finish_trace_()
71}
72
73pub struct ScopedTrace {
74 // Remove Send / Sync, since the trace needs to be finished on the same thread.
75 phantom_data: PhantomData<*mut u8>,
76}
77
78impl ScopedTrace {
79 /// Starts a new ScopedTrace, which ends when the returned object is dropped.
80 ///
81 /// Keep in mind the general limitations of HiTrace, where a call to
82 /// finish_trace will end the span of the most recently started trace.
83 /// Users should try not to mix `ScopedTrace` with manual calls to `finish_trace()`,
84 /// and should avoid passing the `ScopedTrace` object around.
85 #[must_use]
86 pub fn start_trace<T: AsRef<CStr>>(name: &T) -> Self {
87 start_trace(name);
88 Self {
89 phantom_data: PhantomData,
90 }
91 }
92
93 /// Like `start_trace()` but accepts a `&str`.
94 ///
95 /// # Panic
96 ///
97 /// Panics if the provided name can't be converted into a CString.
98 #[must_use]
99 pub fn start_trace_str(name: &str) -> Self {
100 Self::start_trace(&CString::new(name).expect("Contained null-byte"))
101 }
102
103 // A hidden function, which should only be used by hitrace-macro,
104 // until `c""` syntax is available.
105 #[doc(hidden)]
106 pub unsafe fn _start_trace_str_with_null(name_with_null: &str) -> Self {
107 #[cfg(any(not(target_env = "ohos"), feature = "max_level_off"))]
108 let _ = name_with_null;
109 // SAFETY: The User promises that the `str` slice is a valid null-terminated C-style string.
110 #[cfg(all(target_env = "ohos", not(feature = "max_level_off")))]
111 unsafe {
112 hitrace_sys::OH_HiTrace_StartTrace(name_with_null.as_ptr());
113 }
114 Self {
115 phantom_data: PhantomData,
116 }
117 }
118}
119
120impl Drop for ScopedTrace {
121 fn drop(&mut self) {
122 finish_trace()
123 }
124}
125
126#[cfg(test)]
127mod test {
128 use static_assertions::assert_not_impl_any;
129
130 use crate::ScopedTrace;
131
132 assert_not_impl_any!(ScopedTrace: Send, Sync);
133}