summaryrefslogtreecommitdiff
path: root/libatrace_rust
diff options
context:
space:
mode:
authorNikita Putikhin <nputikhin@google.com>2023-07-24 14:35:10 +0000
committerNikita Putikhin <nputikhin@google.com>2023-07-24 14:35:10 +0000
commitcedfc50bf160b3dd60d9352a5566f81662e6bf9c (patch)
treec81188041241c59cc2e1821b0ff7c9fb7b26d1f1 /libatrace_rust
parentb6d9a784e39943de3e6da4c7a8d87b7b2f489d49 (diff)
downloadextras-cedfc50bf160b3dd60d9352a5566f81662e6bf9c.tar.gz
Wrap instant events and counters
These are the last remaining methods from ATrace to add. Bug: 289989828 Test: atest Test: Manually collected trace Change-Id: I95a1494a0109c84ef20fccc5c565332f5698c912
Diffstat (limited to 'libatrace_rust')
-rw-r--r--libatrace_rust/example/src/main.rs13
-rw-r--r--libatrace_rust/src/lib.rs259
2 files changed, 272 insertions, 0 deletions
diff --git a/libatrace_rust/example/src/main.rs b/libatrace_rust/example/src/main.rs
index 158dd7d7..562cdf03 100644
--- a/libatrace_rust/example/src/main.rs
+++ b/libatrace_rust/example/src/main.rs
@@ -34,6 +34,15 @@ fn spawn_async_event_with_track() -> JoinHandle<()> {
})
}
+fn spawn_counter_thread() -> JoinHandle<()> {
+ std::thread::spawn(|| {
+ for i in 1..=10 {
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ atrace::atrace_int(AtraceTag::App, "Count of i", i);
+ }
+ })
+}
+
fn main() {
let enabled_tags = atrace::atrace_get_enabled_tags();
println!("Enabled tags: {:?}", enabled_tags);
@@ -41,6 +50,9 @@ fn main() {
println!("Spawning async trace events");
let async_event_handler = spawn_async_event();
let async_event_with_track_handler = spawn_async_event_with_track();
+ let counter_thread_handler = spawn_counter_thread();
+
+ atrace::atrace_instant(AtraceTag::App, "Instant event");
println!("Calling atrace_begin and sleeping for 1 sec...");
atrace::atrace_begin(AtraceTag::App, "Hello tracing!");
@@ -50,6 +62,7 @@ fn main() {
println!("Joining async events...");
async_event_handler.join().unwrap();
async_event_with_track_handler.join().unwrap();
+ counter_thread_handler.join().unwrap();
println!("Done!");
}
diff --git a/libatrace_rust/src/lib.rs b/libatrace_rust/src/lib.rs
index 62df2da3..b5e58db1 100644
--- a/libatrace_rust/src/lib.rs
+++ b/libatrace_rust/src/lib.rs
@@ -226,6 +226,81 @@ pub fn atrace_async_for_track_end(tag: AtraceTag, track_name: &str, cookie: i32)
}
}
+/// Trace an instantaneous context. `name` is used to identify the context.
+///
+/// An "instant" is an event with no defined duration. Visually is displayed like a single marker
+/// in the timeline (rather than a span, in the case of begin/end events).
+///
+/// By default, instant events are added into a dedicated track that has the same name of the event.
+/// Use `atrace_instant_for_track` to put different instant events into the same timeline track/row.
+pub fn atrace_instant(tag: AtraceTag, name: &str) {
+ if !atrace_is_tag_enabled(tag) {
+ return;
+ }
+
+ let name_cstr = CString::new(name.as_bytes()).expect("CString::new failed");
+ // SAFETY: The function does not accept the pointer ownership, only reads its contents.
+ // The passed string is guaranteed to be null-terminated by CString.
+ unsafe {
+ trace_bind::atrace_instant_wrap(tag.bits(), name_cstr.as_ptr());
+ }
+}
+
+/// Trace an instantaneous context. `name` is used to identify the context. `track_name` is the name
+/// of the row where the event should be recorded.
+///
+/// An "instant" is an event with no defined duration. Visually is displayed like a single marker
+/// in the timeline (rather than a span, in the case of begin/end events).
+pub fn atrace_instant_for_track(tag: AtraceTag, track_name: &str, name: &str) {
+ if !atrace_is_tag_enabled(tag) {
+ return;
+ }
+
+ let name_cstr = CString::new(name.as_bytes()).expect("CString::new failed");
+ let track_name_cstr = CString::new(track_name.as_bytes()).expect("CString::new failed");
+ // SAFETY: The function does not accept the pointer ownership, only reads its contents.
+ // The passed string is guaranteed to be null-terminated by CString.
+ unsafe {
+ trace_bind::atrace_instant_for_track_wrap(
+ tag.bits(),
+ track_name_cstr.as_ptr(),
+ name_cstr.as_ptr(),
+ );
+ }
+}
+
+/// Traces an integer counter value. `name` is used to identify the counter.
+///
+/// This can be used to track how a value changes over time.
+pub fn atrace_int(tag: AtraceTag, name: &str, value: i32) {
+ if !atrace_is_tag_enabled(tag) {
+ return;
+ }
+
+ let name_cstr = CString::new(name.as_bytes()).expect("CString::new failed");
+ // SAFETY: The function does not accept the pointer ownership, only reads its contents.
+ // The passed string is guaranteed to be null-terminated by CString.
+ unsafe {
+ trace_bind::atrace_int_wrap(tag.bits(), name_cstr.as_ptr(), value);
+ }
+}
+
+/// Traces a 64-bit integer counter value. `name` is used to identify the counter.
+///
+/// This can be used to track how a value changes over time.
+pub fn atrace_int64(tag: AtraceTag, name: &str, value: i64) {
+ if !atrace_is_tag_enabled(tag) {
+ return;
+ }
+
+ let name_cstr = CString::new(name.as_bytes()).expect("CString::new failed");
+ // SAFETY: The function does not accept the pointer ownership, only reads its contents.
+ // The passed string is guaranteed to be null-terminated by CString.
+ unsafe {
+ trace_bind::atrace_int64_wrap(tag.bits(), name_cstr.as_ptr(), value);
+ }
+}
+
#[cfg(test)]
use self::tests::mock_atrace as trace_bind;
@@ -290,6 +365,23 @@ mod tests {
) {
panic!("Unexpected call");
}
+ fn atrace_instant_wrap(&mut self, _tag: u64, _name: *const c_char) {
+ panic!("Unexpected call");
+ }
+ fn atrace_instant_for_track_wrap(
+ &mut self,
+ _tag: u64,
+ _track_name: *const c_char,
+ _name: *const c_char,
+ ) {
+ panic!("Unexpected call");
+ }
+ fn atrace_int_wrap(&mut self, _tag: u64, _name: *const c_char, _value: i32) {
+ panic!("Unexpected call");
+ }
+ fn atrace_int64_wrap(&mut self, _tag: u64, _name: *const c_char, _value: i64) {
+ panic!("Unexpected call");
+ }
/// This method should contain checks to be performed at the end of the test.
fn finish(&self) {}
@@ -388,6 +480,22 @@ mod tests {
) {
with_mocker(|m| m.atrace_async_for_track_end_wrap(tag, track_name, cookie))
}
+ pub unsafe fn atrace_instant_wrap(tag: u64, name: *const c_char) {
+ with_mocker(|m| m.atrace_instant_wrap(tag, name))
+ }
+ pub unsafe fn atrace_instant_for_track_wrap(
+ tag: u64,
+ track_name: *const c_char,
+ name: *const c_char,
+ ) {
+ with_mocker(|m| m.atrace_instant_for_track_wrap(tag, track_name, name))
+ }
+ pub unsafe fn atrace_int_wrap(tag: u64, name: *const c_char, value: i32) {
+ with_mocker(|m| m.atrace_int_wrap(tag, name, value))
+ }
+ pub unsafe fn atrace_int64_wrap(tag: u64, name: *const c_char, value: i64) {
+ with_mocker(|m| m.atrace_int64_wrap(tag, name, value))
+ }
}
#[test]
@@ -781,4 +889,155 @@ mod tests {
mock_atrace::mocker_finish();
}
+
+ #[test]
+ fn forwards_trace_instant() {
+ #[derive(Default)]
+ struct CallCheck {
+ trace_instant_count: u32,
+ }
+
+ impl mock_atrace::ATraceMocker for CallCheck {
+ fn atrace_is_tag_enabled_wrap(&mut self, _tag: u64) -> u64 {
+ 1
+ }
+ fn atrace_instant_wrap(&mut self, tag: u64, name: *const c_char) {
+ self.trace_instant_count += 1;
+ assert!(self.trace_instant_count < 2);
+ assert_eq!(tag, cutils_trace_bindgen::ATRACE_TAG_APP as u64);
+ // SAFETY: If the code under test is correct, the pointer is guaranteed to satisfy
+ // the requirements of `CStr::from_ptr`. If the code is not correct, this section is
+ // unsafe and will hopefully fail the test.
+ unsafe {
+ assert_eq!(CStr::from_ptr(name).to_str().expect("to_str failed"), "Test Name");
+ }
+ }
+
+ fn finish(&self) {
+ assert_eq!(self.trace_instant_count, 1);
+ }
+ }
+
+ let _guard = mock_atrace::set_scoped_mocker(CallCheck::default());
+
+ atrace_instant(AtraceTag::App, "Test Name");
+
+ mock_atrace::mocker_finish();
+ }
+
+ #[test]
+ fn forwards_trace_instant_for_track() {
+ #[derive(Default)]
+ struct CallCheck {
+ trace_instant_for_track_count: u32,
+ }
+
+ impl mock_atrace::ATraceMocker for CallCheck {
+ fn atrace_is_tag_enabled_wrap(&mut self, _tag: u64) -> u64 {
+ 1
+ }
+ fn atrace_instant_for_track_wrap(
+ &mut self,
+ tag: u64,
+ track_name: *const c_char,
+ name: *const c_char,
+ ) {
+ self.trace_instant_for_track_count += 1;
+ assert!(self.trace_instant_for_track_count < 2);
+ assert_eq!(tag, cutils_trace_bindgen::ATRACE_TAG_APP as u64);
+ // SAFETY: If the code under test is correct, the pointer is guaranteed to satisfy
+ // the requirements of `CStr::from_ptr`. If the code is not correct, this section is
+ // unsafe and will hopefully fail the test.
+ unsafe {
+ assert_eq!(
+ CStr::from_ptr(track_name).to_str().expect("to_str failed"),
+ "Track"
+ );
+ assert_eq!(CStr::from_ptr(name).to_str().expect("to_str failed"), "Test Name");
+ }
+ }
+
+ fn finish(&self) {
+ assert_eq!(self.trace_instant_for_track_count, 1);
+ }
+ }
+
+ let _guard = mock_atrace::set_scoped_mocker(CallCheck::default());
+
+ atrace_instant_for_track(AtraceTag::App, "Track", "Test Name");
+
+ mock_atrace::mocker_finish();
+ }
+
+ #[test]
+ fn forwards_trace_int() {
+ #[derive(Default)]
+ struct CallCheck {
+ trace_int_count: u32,
+ }
+
+ impl mock_atrace::ATraceMocker for CallCheck {
+ fn atrace_is_tag_enabled_wrap(&mut self, _tag: u64) -> u64 {
+ 1
+ }
+ fn atrace_int_wrap(&mut self, tag: u64, name: *const c_char, value: i32) {
+ self.trace_int_count += 1;
+ assert!(self.trace_int_count < 2);
+ assert_eq!(tag, cutils_trace_bindgen::ATRACE_TAG_APP as u64);
+ // SAFETY: If the code under test is correct, the pointer is guaranteed to satisfy
+ // the requirements of `CStr::from_ptr`. If the code is not correct, this section is
+ // unsafe and will hopefully fail the test.
+ unsafe {
+ assert_eq!(CStr::from_ptr(name).to_str().expect("to_str failed"), "Test Name");
+ }
+ assert_eq!(value, 32);
+ }
+
+ fn finish(&self) {
+ assert_eq!(self.trace_int_count, 1);
+ }
+ }
+
+ let _guard = mock_atrace::set_scoped_mocker(CallCheck::default());
+
+ atrace_int(AtraceTag::App, "Test Name", 32);
+
+ mock_atrace::mocker_finish();
+ }
+
+ #[test]
+ fn forwards_trace_int64() {
+ #[derive(Default)]
+ struct CallCheck {
+ trace_int64_count: u32,
+ }
+
+ impl mock_atrace::ATraceMocker for CallCheck {
+ fn atrace_is_tag_enabled_wrap(&mut self, _tag: u64) -> u64 {
+ 1
+ }
+ fn atrace_int64_wrap(&mut self, tag: u64, name: *const c_char, value: i64) {
+ self.trace_int64_count += 1;
+ assert!(self.trace_int64_count < 2);
+ assert_eq!(tag, cutils_trace_bindgen::ATRACE_TAG_APP as u64);
+ // SAFETY: If the code under test is correct, the pointer is guaranteed to satisfy
+ // the requirements of `CStr::from_ptr`. If the code is not correct, this section is
+ // unsafe and will hopefully fail the test.
+ unsafe {
+ assert_eq!(CStr::from_ptr(name).to_str().expect("to_str failed"), "Test Name");
+ }
+ assert_eq!(value, 64);
+ }
+
+ fn finish(&self) {
+ assert_eq!(self.trace_int64_count, 1);
+ }
+ }
+
+ let _guard = mock_atrace::set_scoped_mocker(CallCheck::default());
+
+ atrace_int64(AtraceTag::App, "Test Name", 64);
+
+ mock_atrace::mocker_finish();
+ }
}