ittapi/
event.rs

1use std::{ffi::CString, marker::PhantomData};
2
3/// See the [Event API] documentation.
4///
5/// [Event API]: https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top/api-support/instrumentation-and-tracing-technology-apis/instrumentation-tracing-technology-api-reference/event-api.html
6///
7/// ```
8/// let event = ittapi::Event::new("foo");
9/// {
10///   let span = event.start();
11///   // do some work...
12///   // ...the event is stopped when `span` is dropped
13/// }
14/// ```
15pub struct Event(ittapi_sys::__itt_event);
16impl Event {
17    /// Create the event.
18    #[must_use]
19    pub fn new(name: &str) -> Self {
20        #[cfg(unix)]
21        let create_fn = unsafe { ittapi_sys::__itt_event_create_ptr__3_0 };
22        #[cfg(windows)]
23        let create_fn = unsafe { ittapi_sys::__itt_event_createA_ptr__3_0 };
24        if let Some(create_fn) = create_fn {
25            let c_string =
26                CString::new(name).expect("unable to create a CString; does it contain a 0 byte?");
27            let size = name
28                .len()
29                .try_into()
30                .expect("unable to fit the name length into an i32");
31            let event = unsafe { create_fn(c_string.as_ptr(), size) };
32            Self(event)
33        } else {
34            Self(-1)
35        }
36    }
37
38    /// Start the event.
39    ///
40    /// # Panics
41    ///
42    /// This will panic if the ITT library cannot start the event.
43    #[must_use]
44    pub fn start(&self) -> StartedEvent {
45        if let Some(start_fn) = unsafe { ittapi_sys::__itt_event_start_ptr__3_0 } {
46            let result = unsafe { start_fn(self.0) };
47            assert!(result == 0, "unable to start event");
48        }
49        StartedEvent {
50            event: self.0,
51            phantom: PhantomData,
52        }
53    }
54}
55
56pub struct StartedEvent<'a> {
57    event: ittapi_sys::__itt_event,
58    phantom: PhantomData<&'a mut ()>,
59}
60
61impl StartedEvent<'_> {
62    /// End the event.
63    #[allow(clippy::unused_self)]
64    pub fn end(self) {
65        // Do nothing; the `Drop` implementation does the work. See discussion at
66        // https://stackoverflow.com/questions/53254645.
67    }
68}
69
70impl<'a> Drop for StartedEvent<'a> {
71    fn drop(&mut self) {
72        if let Some(end_fn) = unsafe { ittapi_sys::__itt_event_end_ptr__3_0 } {
73            let result = unsafe { end_fn(self.event) };
74            assert!(result == 0, "unable to stop event");
75        }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn sanity() {
85        let event = Event::new("test");
86        let _started_event = event.start();
87        // Dropping `started_event` ends the event.
88    }
89}