Coverage Report

Created: 2023-04-25 07:07

/rust/registry/src/index.crates.io-6f17d22bba15001f/ittapi-0.3.3/src/jit.rs
Line
Count
Source (jump to first uncovered line)
1
//! The JIT (Just-In-Time) Profiling API provides functionality to report information about
2
//! just-in-time generated code that can be used by performance tools. The [Jit] Rust structure is a
3
//! high-level view of a subset of the full functionality available. See the [JIT Profiling API] for
4
//! more information.
5
//!
6
//! [JIT Profiling API]:
7
///     https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top/api-support/jit-profiling-api.html
8
use anyhow::Context;
9
use std::{ffi::CString, os, ptr};
10
11
/// Register JIT-compiled methods with a performance tool (e.g., VTune). This structure assumes
12
/// single-threaded access; if your program may be multi-threaded, make sure to guard multi-threaded
13
/// access with a mutex.
14
0
#[derive(Default)]
Unexecuted instantiation: <ittapi::jit::Jit as core::default::Default>::default
Unexecuted instantiation: <ittapi::jit::Jit as core::default::Default>::default
15
pub struct Jit {
16
    shutdown_complete: bool,
17
}
18
19
impl Jit {
20
    /// Returns a new `MethodId` for use in `MethodLoad` events.
21
    #[allow(clippy::unused_self)]
22
0
    pub fn get_method_id(&self) -> MethodId {
23
0
        MethodId(unsafe { ittapi_sys::iJIT_GetNewMethodID() })
24
0
    }
25
26
    /// Notifies any `EventType` to VTune.
27
    ///
28
    /// # Errors
29
    ///
30
    /// May fail if the underlying call to the ITT library fails.
31
    #[allow(clippy::unused_self)]
32
0
    pub fn notify_event(&self, mut event: EventType) -> anyhow::Result<()> {
33
0
        let tag = event.tag();
34
0
        let data = event.data();
35
0
        log::trace!("notify_event: tag={:?}", tag);
36
0
        let res = unsafe { ittapi_sys::iJIT_NotifyEvent(tag, data) };
37
0
        if res == 1 {
38
0
            Ok(())
39
        } else {
40
0
            anyhow::bail!("error when notifying event")
41
        }
42
0
    }
43
44
    // High-level helpers.
45
46
    /// Notifies VTune that a new function described by the `MethodLoadBuilder` has been jitted.
47
    ///
48
    /// # Errors
49
    ///
50
    /// May fail if the builder has invalid data or if the ITT library fails to notify the method
51
    /// load event.
52
0
    pub fn load_method(&self, builder: MethodLoadBuilder) -> anyhow::Result<()> {
53
0
        let method_id = self.get_method_id();
54
0
        let method_load = builder.build(method_id)?;
55
0
        self.notify_event(method_load)
56
0
    }
57
58
    /// Notifies VTune that profiling is being shut down.
59
    ///
60
    /// # Errors
61
    ///
62
    /// May fail if the ITT library fails to notify the shutdown event.
63
0
    pub fn shutdown(&mut self) -> anyhow::Result<()> {
64
0
        let res = self.notify_event(EventType::Shutdown);
65
0
        if res.is_ok() {
66
0
            self.shutdown_complete = true;
67
0
        }
68
0
        res
69
0
    }
70
}
71
72
impl Drop for Jit {
73
0
    fn drop(&mut self) {
74
0
        if !self.shutdown_complete {
75
            // There's not much we can do when an error happens here.
76
0
            if let Err(err) = self.shutdown() {
77
0
                log::error!("Error when shutting down VTune: {}", err);
78
0
            }
79
0
        }
80
0
    }
81
}
82
83
/// Type of event to be dispatched through ittapi's JIT event API.
84
pub enum EventType {
85
    /// Send this event after a JITted method has been loaded into memory, and possibly JIT
86
    /// compiled, but before the code is executed.
87
    MethodLoadFinished(MethodLoad),
88
89
    /// Send this notification to terminate profiling.
90
    Shutdown,
91
}
92
93
impl EventType {
94
    /// Returns the C event type to be used when notifying this event to VTune.
95
0
    fn tag(&self) -> ittapi_sys::iJIT_jvm_event {
96
0
        match self {
97
            EventType::MethodLoadFinished(_) => {
98
0
                ittapi_sys::iJIT_jvm_event_iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED
99
            }
100
0
            EventType::Shutdown => ittapi_sys::iJIT_jvm_event_iJVM_EVENT_TYPE_SHUTDOWN,
101
        }
102
0
    }
103
104
    /// Returns a raw C pointer to the event-specific data that must be used when notifying this
105
    /// event to VTune.
106
0
    fn data(&mut self) -> *mut os::raw::c_void {
107
0
        match self {
108
0
            EventType::MethodLoadFinished(method_load) => ptr::addr_of_mut!(method_load.0).cast(),
109
0
            EventType::Shutdown => ptr::null_mut(),
110
        }
111
0
    }
112
}
113
114
/// Newtype wrapper for a method id returned by ittapi's `iJIT_GetNewMethodID`, as returned by
115
/// `VtuneState::get_method_id` in the high-level API.
116
0
#[derive(Clone, Copy)]
117
pub struct MethodId(u32);
118
119
/// Newtype wrapper for a JIT method load.
120
pub struct MethodLoad(ittapi_sys::_iJIT_Method_Load);
121
122
/// Multi-step constructor using the builder pattern for a `MethodLoad` event.
123
pub struct MethodLoadBuilder {
124
    method_name: String,
125
    addr: *const u8,
126
    len: usize,
127
    class_file_name: Option<String>,
128
    source_file_name: Option<String>,
129
}
130
131
impl MethodLoadBuilder {
132
    /// Creates a new `MethodLoadBuilder` from scratch.
133
    ///
134
    /// `addr` is the pointer to the start of the code region, `len` is the size of this code
135
    /// region in bytes.
136
0
    pub fn new(method_name: String, addr: *const u8, len: usize) -> Self {
137
0
        Self {
138
0
            method_name,
139
0
            addr,
140
0
            len,
141
0
            class_file_name: None,
142
0
            source_file_name: None,
143
0
        }
144
0
    }
145
146
    /// Attache a class file.
147
0
    pub fn class_file_name(mut self, class_file_name: String) -> Self {
148
0
        self.class_file_name = Some(class_file_name);
149
0
        self
150
0
    }
151
152
    /// Attach a source file.
153
0
    pub fn source_file_name(mut self, source_file_name: String) -> Self {
154
0
        self.source_file_name = Some(source_file_name);
155
0
        self
156
0
    }
157
158
    /// Build a "method load" event for the given `method_id`.
159
    ///
160
    /// # Errors
161
    ///
162
    /// May fail if the various names passed to this builder are not valid C strings.
163
0
    pub fn build(self, method_id: MethodId) -> anyhow::Result<EventType> {
164
0
        Ok(EventType::MethodLoadFinished(MethodLoad(
165
0
            ittapi_sys::_iJIT_Method_Load {
166
0
                method_id: method_id.0,
167
0
                method_name: CString::new(self.method_name)
168
0
                    .context("CString::new failed")?
169
0
                    .into_raw(),
170
0
                method_load_address: self.addr as *mut os::raw::c_void,
171
0
                method_size: self.len.try_into().expect("cannot fit length into 32 bits"),
172
0
                line_number_size: 0,
173
0
                line_number_table: ptr::null_mut(),
174
0
                class_id: 0, // Field officially obsolete in Intel's doc.
175
0
                class_file_name: CString::new(
176
0
                    self.class_file_name
177
0
                        .as_deref()
178
0
                        .unwrap_or("<unknown class file name>"),
179
0
                )
180
0
                .context("CString::new failed")?
181
0
                .into_raw(),
182
0
                source_file_name: CString::new(
183
0
                    self.source_file_name
184
0
                        .as_deref()
185
0
                        .unwrap_or("<unknown source file name>"),
186
0
                )
187
0
                .context("CString::new failed")?
188
0
                .into_raw(),
189
            },
190
        )))
191
0
    }
192
}