1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use crate::{domain::Domain, string::StringHandle};

/// A task is a logical unit of work performed by a particular thread. See the [Task API]
/// documentation for more information.
///
/// [Task 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/task-api.html
///
/// ```
/// # use ittapi::{Domain, StringHandle, Task};
/// let _env_path = scoped_env::ScopedEnv::set("INTEL_LIBITTNOTIFY64", "<some path>");
/// let domain = Domain::new("domain");
/// let name = StringHandle::new("task");
/// // Measure a task using a pre-initialized string handle (most efficient).
/// {
///     let task = Task::begin(&domain, name);
///     let _ = 2 + 2;
///     task.end(); // Task ended here.
///     let _ = 3 + 3;
/// }
/// // Measure a task using a string reference (most convenient).
/// {
///     let _task = Task::begin(&domain, "task");
///     let _ = 2 + 2;
///     // Task ended here, when dropped.
/// }
/// ```
pub struct Task<'a>(&'a Domain);
impl<'a> Task<'a> {
    /// Start a task on the current thread.
    pub fn begin(domain: &'a Domain, name: impl Into<StringHandle>) -> Self {
        if let Some(create_fn) = unsafe { ittapi_sys::__itt_task_begin_ptr__3_0 } {
            // Currently the `taskid` and `parentid` parameters are unimplemented (TODO).
            unsafe { create_fn(domain.as_ptr(), ITT_NULL, ITT_NULL, name.into().as_ptr()) };
        }
        Self(domain)
    }

    /// Finish the task.
    #[allow(clippy::unused_self)]
    pub fn end(self) {
        // Do nothing; the `Drop` implementation does the work. See discussion at
        // https://stackoverflow.com/questions/53254645.
    }
}

impl<'a> Drop for Task<'a> {
    fn drop(&mut self) {
        // If `ittnotify` has not been initialized, this function may not be wired up.
        if let Some(end_fn) = unsafe { ittapi_sys::__itt_task_end_ptr__3_0 } {
            unsafe { end_fn(self.0.as_ptr()) }
        }
    }
}

/// Using the `__itt_null` symbol results in errors so we redefine it here.
const ITT_NULL: ittapi_sys::__itt_id = ittapi_sys::__itt_id {
    d1: 0,
    d2: 0,
    d3: 0,
};

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn sanity() {
        let domain = Domain::new("domain");
        let name = StringHandle::new("task");
        let _task = Task::begin(&domain, name);
    }
}